zoukankan      html  css  js  c++  java
  • MCP2515 : SPI CAN controller management

    #ifndef __MCP2515_H
    #define __MCP2515_H
    
    /*
    mcp2515.h
    
    This file contains constants that are specific to the MCP2515.
    
    Version     Date        Description
    ----------------------------------------------------------------------
    v1.00       2003/12/11  Initial release
    
    Copyright 2003 Kimberly Otten Software Consulting
    */
    
    // Define MCP2515 register addresses
    
    #define MCP_RXF0SIDH    0x00
    #define MCP_RXF0SIDL    0x01
    #define MCP_RXF0EID8    0x02
    #define MCP_RXF0EID0    0x03
    #define MCP_RXF1SIDH    0x04
    #define MCP_RXF1SIDL    0x05
    #define MCP_RXF1EID8    0x06
    #define MCP_RXF1EID0    0x07
    #define MCP_RXF2SIDH    0x08
    #define MCP_RXF2SIDL    0x09
    #define MCP_RXF2EID8    0x0A
    #define MCP_RXF2EID0    0x0B
    #define MCP_CANSTAT        0x0E
    #define MCP_CANCTRL        0x0F
    #define MCP_RXF3SIDH    0x10
    #define MCP_RXF3SIDL    0x11
    #define MCP_RXF3EID8    0x12
    #define MCP_RXF3EID0    0x13
    #define MCP_RXF4SIDH    0x14
    #define MCP_RXF4SIDL    0x15
    #define MCP_RXF4EID8    0x16
    #define MCP_RXF4EID0    0x17
    #define MCP_RXF5SIDH    0x18
    #define MCP_RXF5SIDL    0x19
    #define MCP_RXF5EID8    0x1A
    #define MCP_RXF5EID0    0x1B
    #define MCP_TEC            0x1C
    #define MCP_REC            0x1D
    #define MCP_RXM0SIDH    0x20
    #define MCP_RXM0SIDL    0x21
    #define MCP_RXM0EID8    0x22
    #define MCP_RXM0EID0    0x23
    #define MCP_RXM1SIDH    0x24
    #define MCP_RXM1SIDL    0x25
    #define MCP_RXM1EID8    0x26
    #define MCP_RXM1EID0    0x27
    #define MCP_CNF3        0x28
    #define MCP_CNF2        0x29
    #define MCP_CNF1        0x2A
    #define MCP_CANINTE        0x2B
    #define MCP_CANINTF        0x2C
    #define MCP_EFLG        0x2D
    #define MCP_TXB0CTRL    0x30
    #define MCP_TXB1CTRL    0x40
    #define MCP_TXB2CTRL    0x50
    #define MCP_RXB0CTRL    0x60
    #define MCP_RXB0SIDH    0x61
    #define MCP_RXB1CTRL    0x70
    #define MCP_RXB1SIDH    0x71
    
    
    #define MCP_TX_INT        0x1C        // Enable all transmit interrupts
    #define MCP_TX01_INT    0x0C        // Enable TXB0 and TXB1 interrupts
    #define MCP_RX_INT        0x03        // Enable receive interrupts
    #define MCP_NO_INT        0x00        // Disable all interrupts
    
    #define MCP_TX01_MASK    0x14
    #define MCP_TX_MASK        0x54
    
    // Define SPI Instruction Set
    
    #define MCP_WRITE        0x02
    
    #define MCP_READ        0x03
    
    #define MCP_BITMOD        0x05
    
    #define MCP_LOAD_TX0    0x40
    #define MCP_LOAD_TX1    0x42
    #define MCP_LOAD_TX2    0x44
    
    #define MCP_RTS_TX0        0x81
    #define MCP_RTS_TX1        0x82
    #define MCP_RTS_TX2        0x84
    #define MCP_RTS_ALL        0x87
    
    #define MCP_READ_RX0    0x90
    #define MCP_READ_RX1    0x94
    
    #define MCP_READ_STATUS    0xA0
    
    #define MCP_RX_STATUS    0xB0
    
    #define MCP_RESET        0xC0
    
    
    // CANCTRL Register Values
    
    #define MODE_NORMAL     0x00
    #define MODE_SLEEP      0x20
    #define MODE_LOOPBACK   0x40
    #define MODE_LISTENONLY 0x60
    #define MODE_CONFIG     0x80
    #define MODE_POWERUP    0xE0
    #define MODE_MASK        0xE0
    #define ABORT_TX        0x10
    #define MODE_ONESHOT    0x08
    #define CLKOUT_ENABLE    0x04
    #define CLKOUT_DISABLE    0x00
    #define CLKOUT_PS1        0x00
    #define CLKOUT_PS2        0x01
    #define CLKOUT_PS4        0x02
    #define CLKOUT_PS8        0x03
    
    
    // CNF1 Register Values
    
    #define SJW1            0x00
    #define SJW2            0x40
    #define SJW3            0x80
    #define SJW4            0xC0
    
    
    // CNF2 Register Values
    
    #define BTLMODE            0x80
    #define SAMPLE_1X       0x00
    #define SAMPLE_3X       0x40
    
    
    // CNF3 Register Values
    
    #define SOF_ENABLE        0x80
    #define SOF_DISABLE        0x00
    #define WAKFIL_ENABLE    0x40
    #define WAKFIL_DISABLE    0x00
    
    
    // CANINTF Register Bits
    
    #define MCP_RX0IF        0x01
    #define MCP_RX1IF        0x02
    #define MCP_TX0IF        0x04
    #define MCP_TX1IF        0x08
    #define MCP_TX2IF        0x10
    #define MCP_ERRIF        0x20
    #define MCP_WAKIF        0x40
    #define MCP_MERRF        0x80
    
    
    
    #endif
    /**********************************************************************/
    /*                                                                    */
    /* File name: drv_mcp2515.c                                           */
    /*                                                                    */
    /* Since:     2005-Nov-30                                             */
    /*                                                                    */
    /* Version:   PICos18 v2.04                                           */
    /*            Copyright (C) 2003, 2004, 2005 Pragmatec.               */
    /*            MCP2515 CAN driver v1.00                                */
    /*                                                                    */
    /* Author:    Designed by Pragmatec S.A.R.L.        www.pragmatec.net */
    /*            ROZIER Bertrand [RZR]     bertrand.rozier@pragmatec.net */
    /*                                                                    */
    /* Purpose:   MCP2515 : SPI CAN controller management.                */
    /*            It allows task tosend data at the send time through a   */
    /*            dedicated FIFO, and to wait for a certain CAN frame.    */
    /*                                                                    */
    /* Distribution: This file is part of PICos18.                        */
    /*            PICos18 is free software; you can redistribute it       */
    /*            and/or modify it under the terms of the GNU General     */
    /*            Public License as published by the Free Software        */
    /*            Foundation; either version 2, or (at your option)       */
    /*            any later version.                                      */
    /*                                                                    */
    /*            PICos18 is distributed in the hope that it will be      */
    /*            useful, but WITHOUT ANY WARRANTY; without even the      */
    /*            implied warranty of MERCHANTABILITY or FITNESS FOR A    */
    /*            PARTICULAR PURPOSE.  See the GNU General Public         */
    /*            License for more details.                               */
    /*                                                                    */
    /*            You should have received a copy of the GNU General      */
    /*            Public License along with gpsim; see the file           */
    /*            COPYING.txt. If not, write to the Free Software         */
    /*            Foundation, 59 Temple Place - Suite 330,                */
    /*            Boston, MA 02111-1307, USA.                             */
    /*                                                                    */
    /*          > A special exception to the GPL can be applied should    */
    /*            you wish to distribute a combined work that includes    */
    /*            PICos18, without being obliged to provide the source    */
    /*            code for any proprietary components.                    */
    /*                                                                    */
    /* History:                                                           */
    /* 2005/11/30 [RZR] Create this file                                  */
    /**********************************************************************/
    
    #include "define.h"
    #include "drv_mcp2515.h"
    #include "drv_spi.h"
    
    #define MCP2515_CS_PORT       PORTC
    #define MCP2515_CS_BIT            0
    
    /**********************************************************************
     * Definition dedicated to the local functions.
     **********************************************************************/
    void MCP2515_Init(void);
    void MCP2515_Config(void);
    void MCP2515_Reset(void);
    void MCP2515_GetStatus(void);
    void MCP2515_SetMode(unsigned char mode);
    void MCP2515_BitModify(unsigned char addr, unsigned char mask, unsigned char data);
    void MCP2515_ByteWrite(unsigned char addr, unsigned char data);
    void MCP2515_ByteRead(unsigned char addr, unsigned char * pdata);
    void MCP2515_RTS(unsigned char buffer_TX);
    void MCP2515_ReadRXbuffer0(void);
    void MCP2515_ReadRXbuffer1(void);
    void ManageISR(void);
    
    StatusType mcp2515_write_buffer(unsigned char registre, unsigned char *pdata);
    
    EventMaskType       CAN_event;
    
    CAN_message_tRef    CAN_list_head;            //    Start of message queue
    CAN_message_tRef    CAN_current_message;    //    Current message
    unsigned char        CAN_list_count = 0;        //    Number of items currently in queue
    
    CAN_message_tRef    CAN_list_head_rcv;        //    Start of message queue
    CAN_message_tRef    CAN_current_message_rcv;//    Current message
    unsigned char        CAN_list_count_rcv = 0;    //    Number of items currently in queue
    
    SPI_message_t       SPI_MCP2515;
    
    TXBn_t                TXB0,TXB1,TXB2;
    TXBn_tRef            pTXBn;
    RXBn_t                RXB0,RXB1;
    RXBn_tRef            pRXBn;
    
    // Local mcp2515 control register
    unsigned char     CANSTAT;
    unsigned char     CANCTRL;
    unsigned char     CNF1;
    unsigned char     CNF2;
    unsigned char     CNF3;
    unsigned char     TXRTSCTRL;
    unsigned char     CANINTE;
    unsigned char     CANINTF;
    unsigned char     EFLG;
    unsigned char     RXB0CTRL;
    
    unsigned char mcp2515_cmd[15];
    
    // Fort debug only
    #define ALARM_MCP2515      1
    
    /**********************************************************************
     * Task of the CAN driver, waiting for any of these 4 events :
     *  CAN_TX_EVENT  : A message has been sent then a hardware transmitter
     *                  is free. The driver will tranfer a software buffer
     *                  into a free TX[0,1,2] hardware buffer.
     *  CAN_RX_EVENT  : A message is arrived in the RX[0,1] buffer.
     *                  the driver transfer the *§bjjcontent of the message into
     *                  a software buffer waiting for this message ID or
     *                  discard the message to free the hardware.
     *  CAN_ERR_EVENT : Something wrong appended and the driver must clean
     *                  the hardware before being disconnected. To be
     *                  completed...
     *  ALARM_EVENT   : Sometimes a task waiting for a specific message is
     *                  not fast enough to read all the content of the
     *                  hardware buffers. The driver have to keep available
     *                  this content the time needed by other tasks.
     *                  Then the driver periodicaly checks if the other tasks
     *                  have finished to read the hardware buffers or needs
     *                  more time.
     *
     * @param  void
     * @return void
     **********************************************************************/
    TASK(MCP2515_Drv)
    {
    
          MCP2515_Init();
        MCP2515_Config();
    
      // Just for cyclique update of CAN register
      // useful until on debug
      // SetRelAlarm(ALARM_MCP2515, 500, 500);
    
      while(1)
      {
    
        WaitEvent(CAN_NEW_MSG | CAN_RCV_MSG | CAN_ERR_MSG | MCP2515_IRQ_REQUEST | ALARM_EVENT);
        GetEvent(MCP2515_DRV_ID, &CAN_event);
    
        if (CAN_event & ALARM_EVENT)
        {
          ClearEvent(ALARM_EVENT);
          // Mainly for debug
          MCP2515_ByteRead(CAN2510_REG_CANINTF, &CANINTF);
          MCP2515_ByteRead(CAN2510_REG_EFLG, &EFLG);
           MCP2515_GetStatus();
           }
    
        if (CAN_event & CAN_NEW_MSG)
        {
          ClearEvent(CAN_NEW_MSG);
          CopyFrameBuffer2Hard();
        }
    
        if (CAN_event & CAN_RCV_MSG)
        {
          ClearEvent(CAN_RCV_MSG);
          CopyHard2FrameBuffer();
        }
    
        if (CAN_event & CAN_ERR_MSG)
        {
          ClearEvent(CAN_ERR_MSG);
        }
    
        if (CAN_event & MCP2515_IRQ_REQUEST)
        {
          ClearEvent(MCP2515_IRQ_REQUEST);
          // Get back the flag code
          MCP2515_ByteRead(CAN2510_REG_CANINTF, &CANINTF);
          MCP2515_ByteRead(CAN2510_REG_EFLG, &EFLG);
          MCP2515_GetStatus();
    
              if ( CANINTF & 0x01) // RXB0 full
            {
                // Clear the flag
                MCP2515_BitModify(CAN2510_REG_CANINTF, 0x01, 0x00);
                // Clear the local variable
                CANINTF &= 0xFE;
                // Get RX buffer
                MCP2515_ReadRXbuffer0();
                SetEvent(MCP2515_DRV_ID,CAN_RCV_MSG);
            }
            if ( CANINTF & 0x02) // RXB1 full
            {
                // Clear the flag
                MCP2515_BitModify(CAN2510_REG_CANINTF, 0x02, 0x00);
                // Clear the local variable
                CANINTF &= 0xFD;
                // Get RX buffer
                MCP2515_ReadRXbuffer1();
                SetEvent(MCP2515_DRV_ID,CAN_RCV_MSG);
            }
            if ( CANINTF & 0x04) // TXB0 full
                MCP2515_BitModify(CAN2510_REG_CANINTF, 0x04, 0x00);
            if ( CANINTF & 0x08) // TXB1 full
                MCP2515_BitModify(CAN2510_REG_CANINTF, 0x08, 0x00);
            if ( CANINTF & 0x10) // TXB2 full
                MCP2515_BitModify(CAN2510_REG_CANINTF, 0x10, 0x00);
            if ( CANINTF & 0x20) // Error
                MCP2515_BitModify(CAN2510_REG_CANINTF, 0x20, 0x00);
            if ( CANINTF & 0x40) // WAKEIF
                MCP2515_BitModify(CAN2510_REG_CANINTF, 0x40, 0x00);
            if ( CANINTF & 0x80) // message error
                MCP2515_BitModify(CAN2510_REG_CANINTF, 0x80, 0x00);
        }
      }
    }
    
    
    
    void MCP2515_Init(void)
    {
        // define the CS pin
          // See the drv_spi.h and set the correct value
          SPI_MCP2515.CS_address = (ram char*)&MCP2515_CS_PORT;
          SPI_MCP2515.CS_bit = MCP2515_CS_BIT;
    
          // ID of the calling task
          GetTaskID (&SPI_MCP2515.CallerID);
    
        // Enable INT1 for MCP2515 interrupt
        ADCON1 = 0x0F;
        INTCON3bits.INT1IP = 0;
        INTCON2bits.INTEDG1 = 0;
        INTCON3bits.INT1IF = 0;
        INTCON3bits.INT1IE = 1;
    
        MCP2515_Reset();
        return;
    }
    
    
    void MCP2515_Config(void)
    {
        // First: enter in configuration mode
        MCP2515_BitModify(CAN2510_REG_CANCTRL, 0xE0, 0x80);
        MCP2515_GetStatus();
        if ( (CANSTAT & 0xE0) != 0x80)
        {
            Nop(); // config error !
        }
    
        // bit timing configuration 125khz Q=10Mhz
        CNF1 = 0x41; // Synchro = 1 Tq et BRP = 1
        MCP2515_ByteWrite(CAN2510_REG_CNF1, CNF1);
        CNF2 = 0xac;
        MCP2515_ByteWrite(CAN2510_REG_CNF2, CNF2);
        CNF3 = 0x07;
        MCP2515_ByteWrite(CAN2510_REG_CNF3, CNF3);
    
        TXRTSCTRL = 0x00; // No IT pin or RTS pin
        MCP2515_ByteWrite(CAN2510_REG_TXRTSCTRL, TXRTSCTRL);
        // No filter and mask for this release
    
        CANINTE = 0xE3; // All interrupts enable without TX
        MCP2515_ByteWrite(CAN2510_REG_CANINTE, CANINTE);
        CANINTF = 0x00; // Clear interrupt flags
        MCP2515_ByteWrite(CAN2510_REG_CANINTF, CANINTF);
    
        #ifdef __LOOPBACK__
          MCP2515_BitModify(CAN2510_REG_CANCTRL, 0xE0, 0x40);
          #else
          MCP2515_BitModify(CAN2510_REG_CANCTRL, 0xE0, 0x00);
          #endif
    
        // Test
        MCP2515_ByteRead(CAN2510_REG_RXB0CTRL, &RXB0CTRL);
    
        /* Init the different FIFO */
          CAN_current_message = NULL;
          CAN_list_head       = NULL;
          CAN_list_head_rcv   = NULL;
    
    
        return;
    }
    
    void MCP2515_Reset(void)
    {
        mcp2515_cmd[0] = CAN2510_CMD_RESET;
        // Address of the raw data to send
        SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
        SPI_MCP2515.SDO_num_bytes = 1;
        SPI_MCP2515.SDI_num_bytes = 0;
          // Place the message in the SPI driver queue
          SPI_enqMsg(&SPI_MCP2515);
          SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
          // Wait for the end of operation
          WaitEvent(SPI_QUEUE_EMPTY);
          ClearEvent(SPI_QUEUE_EMPTY);
    }
    
    void MCP2515_GetStatus(void)
    {
        mcp2515_cmd[0] = CAN2510_CMD_READ;
        mcp2515_cmd[1] = CAN2510_REG_CANSTAT;
        // It is not necessary to send instruction
        // Address of the raw data to send
        SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
          // Length of the message to send ( 0 = no SDO)
        SPI_MCP2515.SDO_num_bytes = 2;
    
        // Address of the raw data to receive
          SPI_MCP2515.SDI_ram_data = &CANSTAT;
          SPI_MCP2515.SDI_num_bytes = 1;
          //SPI_MCP2515.instruction = CAN2510_CMD_READ;
    
          // Place the message in the SPI driver queue
          SPI_enqMsg(&SPI_MCP2515);
          SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
          // Wait for the end of operation
          WaitEvent(SPI_QUEUE_EMPTY);
          ClearEvent(SPI_QUEUE_EMPTY);
    }
    
    void MCP2515_BitModify(unsigned char addr, unsigned char mask, unsigned char data)
    {
        mcp2515_cmd[0] = CAN2510_CMD_BITMOD;
        mcp2515_cmd[1] = addr;
        mcp2515_cmd[2] = mask;
        mcp2515_cmd[3] = data;
    
        // It is not necessary to send instruction
        // Address of the raw data to send
          SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
          // Length of the message to send ( 0 = no SDO)
        SPI_MCP2515.SDO_num_bytes = 4;
    
          SPI_MCP2515.SDI_num_bytes = 0;
    
          // Place the message in the SPI driver queue
          SPI_enqMsg(&SPI_MCP2515);
          SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
          // Wait for the end of operation
          WaitEvent(SPI_QUEUE_EMPTY);
          ClearEvent(SPI_QUEUE_EMPTY);
    }
    
    
    void MCP2515_ByteWrite(unsigned char addr, unsigned char data)
    {
        mcp2515_cmd[0] = CAN2510_CMD_WRITE;
        mcp2515_cmd[1] = addr;
        mcp2515_cmd[2] = data;
    
        // Address of the raw data to send
        SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
        // Length of the message to send ( 0 = no SDO)
          SPI_MCP2515.SDO_num_bytes = 3;
          SPI_MCP2515.SDI_num_bytes = 0;
    
          // Place the message in the SPI driver queue
          SPI_enqMsg(&SPI_MCP2515);
          SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
          // Wait for the end of operation
          WaitEvent(SPI_QUEUE_EMPTY);
          ClearEvent(SPI_QUEUE_EMPTY);
    }
    
    void MCP2515_ByteRead(unsigned char addr, unsigned char* pdata)
    {
        mcp2515_cmd[0] = CAN2510_CMD_READ;
        mcp2515_cmd[1] = addr;
    
        // Address of the raw data to send
        SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
          // Length of the message to send ( 0 = no SDO)
        SPI_MCP2515.SDO_num_bytes = 2;
        SPI_MCP2515.SDI_ram_data = pdata;
          SPI_MCP2515.SDI_num_bytes = 1;
    
          // Place the message in the SPI driver queue
          SPI_enqMsg(&SPI_MCP2515);
          SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
          // Wait for the end of operation
          WaitEvent(SPI_QUEUE_EMPTY);
          ClearEvent(SPI_QUEUE_EMPTY);
    }
    
    void MCP2515_RTS(unsigned char buffer_TX)
    {
        mcp2515_cmd[0] = CAN2510_CMD_RTS | buffer_TX;
    
        // Address of the raw data to send
        SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
          // Length of the message to send ( 0 = no SDO)
        SPI_MCP2515.SDO_num_bytes = 1;
          SPI_MCP2515.SDI_num_bytes = 0;
    
          // Place the message in the SPI driver queue
          SPI_enqMsg(&SPI_MCP2515);
          SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
          // Wait for the end of operation
          WaitEvent(SPI_QUEUE_EMPTY);
          ClearEvent(SPI_QUEUE_EMPTY);
    }
    
    void MCP2515_LoadTXbuffer0(void)
    {
        unsigned char i;
        unsigned char *pst;
    
        pst = (unsigned char*)&TXB0;
        mcp2515_cmd[0] = 0x40; // TXB0 0x31
        for (i=1;i<14;i++)
        {
            mcp2515_cmd[i]= *pst;
            pst++;
        }
    
        // Length of the message to send ( 0 = no SDO)
        SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
          SPI_MCP2515.SDO_num_bytes = 14;
          SPI_MCP2515.SDI_num_bytes = 0;
    
          // Place the message in the SPI driver queue
          SPI_enqMsg(&SPI_MCP2515);
          SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
          // Wait for the end of operation
          WaitEvent(SPI_QUEUE_EMPTY);
          ClearEvent(SPI_QUEUE_EMPTY);
    }
    
    void MCP2515_ReadRXbuffer0(void)
    {
        mcp2515_cmd[0] = 0x90; // Adress -> 0x61
        SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
        // Length of the message to send ( 0 = no SDO)
          SPI_MCP2515.SDO_num_bytes = 1;
    
        // Address of the raw data to receive
        SPI_MCP2515.SDI_ram_data = (unsigned char*)&RXB0;
          SPI_MCP2515.SDI_num_bytes = 13;
    
          // Place the message in the SPI driver queue
          SPI_enqMsg(&SPI_MCP2515);
          SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
          // Wait for the end of operation
          WaitEvent(SPI_QUEUE_EMPTY);
          ClearEvent(SPI_QUEUE_EMPTY);
    }
    
    void MCP2515_ReadRXbuffer1(void)
    {
        mcp2515_cmd[0] = 0x94; // Adress -> 0x71
        SPI_MCP2515.SDO_ram_data = &mcp2515_cmd[0];
        // Length of the message to send ( 0 = no SDO)
          SPI_MCP2515.SDO_num_bytes = 1;
    
        // Address of the raw data to receive
        SPI_MCP2515.SDI_ram_data = (unsigned char*)&RXB0;
          SPI_MCP2515.SDI_num_bytes = 13;
    
          // Place the message in the SPI driver queue
          SPI_enqMsg(&SPI_MCP2515);
          SetEvent(SPI_DRV_ID, SPI_NEW_MSG);
          // Wait for the end of operation
          WaitEvent(SPI_QUEUE_EMPTY);
          ClearEvent(SPI_QUEUE_EMPTY);
    }
    
    
    /**********************************************************************
     * Parse the entier TX message list to find any message to transfer.
     * Once a such message is found we post an event to the sending task
     * to tell the transfer is started and we break.
     * The event is used if the task want to send as fast as possible a
     * set of message. Doing so the task will be able to send a new message
     * every time a TASK_CAN_TX_EVENT event is received.
     *
     * @param  type    IN Number of the hardware buffer
     * @return Status     E_OK if tranfer initiated
     *                    E_OS_STATE otherwise
     **********************************************************************/
    StatusType CopyFrameBuffer2Hard(void)
    {
      StatusType returned_type;
      unsigned char foo;
      returned_type = E_OS_STATE;
    
      CAN_current_message = CAN_deqMsg();
    
      if (CAN_current_message == NULL)
        return(returned_type);
    
      #ifdef __EXT29BITS__
      TXB0.TXBnEID0 = CAN_current_message->CANID;
      TXB0.TXBnEID8 = CAN_current_message->CANID >> 8;
      TXB0.TXBnSIDL = (CAN_current_message->CANID >> 16) & 0x03;
      foo      = (CAN_current_message->CANID >> 13) & 0xE0;
      foo      = foo | 0x08;
      TXB0.TXBnSIDL = TXB0.TXBnSIDL + foo;
      TXB0.TXBnSIDH = CAN_current_message->CANID >> 21;
      #else
       #ifdef  __STD11BITS__
        TXB0.TXBnSIDL = CAN_current_message->CANID << 5;
        TXB0.TXBnSIDH = CAN_current_message->CANID >> 3;
       #else
        #error "you should define 11 or 29 bits for CANID !"
       #endif
      #endif
      TXB0.TXBnDLC  = CAN_current_message->length & 0x0F;
      TXB0.TXBnD0   = CAN_current_message->data[0];
      TXB0.TXBnD1   = CAN_current_message->data[1];
      TXB0.TXBnD2   = CAN_current_message->data[2];
      TXB0.TXBnD3   = CAN_current_message->data[3];
      TXB0.TXBnD4   = CAN_current_message->data[4];
      TXB0.TXBnD5   = CAN_current_message->data[5];
      TXB0.TXBnD6   = CAN_current_message->data[6];
      TXB0.TXBnD7   = CAN_current_message->data[7];
      CAN_current_message->state = CAN_MSG_SENT;
    
        // MCP2551 TX_buffer0 update
          MCP2515_LoadTXbuffer0();
    
        // Send the buffer0 transmit command
        MCP2515_RTS(0x01); // 1st buffer -> buffer0
    
        SetEvent(CAN_current_message->CallerID, CAN_QUEUE_EMPTY);
      //RXB0CONbits.RXRTRRO = 1;
      returned_type = E_OK;
    
      return(returned_type);
    }
    
    /**********************************************************************
     *    Enqueue a client packet object into the RS task queue.
     *
     *    Once placed in queue, client must not modify the data
     *    otherwise unpredictable results. To safely change the object,
     *    dequeue, modify, re-enqueue.
     *
     *  The code in mainly executed in critical region [SuspendAllInterrupt]
     *  because many tasks can call this function at the same time and break
     *  the FIFO list.
     *
     *    Returns 1 if successfull, 0 if message could not be enqueued
     **********************************************************************/
    StatusType CAN_enqMsg(CAN_message_tRef toEnqueue)
    {
      CAN_message_tRef CAN_list_itor;
    
      if (toEnqueue != NULL)
      {
        SuspendOSInterrupts();
        if (CAN_list_head == NULL)
          CAN_list_head = toEnqueue;
        else
        {
          CAN_list_itor = CAN_list_head;
          while (CAN_list_itor->next != NULL)
            CAN_list_itor = CAN_list_itor->next;
          CAN_list_itor->next = toEnqueue;
        }
        toEnqueue->next     = NULL;
        toEnqueue->CallerID = id_tsk_run;
        toEnqueue->state    = CAN_FULL;
        CAN_list_count++;
        ResumeOSInterrupts();
        return E_OK;
      }
      else
        return E_OS_STATE;
    }
    
    /**********************************************************************
     *    Dequeue a client message from the RS task queue.
     *
     *
     *********************************************************************/
    CAN_message_tRef CAN_deqMsg(void)
    {
      CAN_message_tRef CAN_list_itor;
    
      SuspendOSInterrupts();
      CAN_list_itor = NULL;
      if (CAN_list_head != NULL)
      {
        CAN_list_itor = CAN_list_head;
        CAN_list_head = CAN_list_head->next;
        CAN_list_count--;
      }
      ResumeOSInterrupts();
      return CAN_list_itor;
    }
    
    /**********************************************************************
     *    Enqueue a client packet object into the RS task queue.
     *
     *    Once placed in queue, client must not modify the data
     *    otherwise unpredictable results. To safely change the object,
     *    dequeue, modify, re-enqueue.
     *
     *  The code in mainly executed in critical region [SuspendAllInterrupt]
     *  because many tasks can call this function at the same time and break
     *  the FIFO list.
     *
     *    Returns 1 if successfull, 0 if message could not be enqueued
     **********************************************************************/
    StatusType CAN_RCV_Register(CAN_message_tRef toEnqueue)
    {
      CAN_message_tRef CAN_list_itor;
    
      if (toEnqueue != NULL)
      {
        SuspendOSInterrupts();
        if (CAN_list_head_rcv == NULL)
          CAN_list_head_rcv = toEnqueue;
        else
        {
          CAN_list_itor = CAN_list_head_rcv;
          while (CAN_list_itor->next != NULL)
            CAN_list_itor = CAN_list_itor->next;
          CAN_list_itor->next = toEnqueue;
        }
        toEnqueue->next     = NULL;
        toEnqueue->CallerID = id_tsk_run;
        CAN_list_count_rcv++;
        ResumeOSInterrupts();
        return E_OK;
      }
      else
        return E_OS_STATE;
    }
    
    /**********************************************************************
     * Parse the entier RX message list to find any task waiting for the
     * received message ID.
     * Once a such taks is found we post an event to the waiting task
     * to tell its software buffer is full and we break.
     * The event is used if the task want to wait for a particular message
     * ID without overloading the CPU by a pooling method.
     *
     * @param  type    IN Number of the hardware buffer
     * @return Status     E_OK if tranfer initiated
     *                    E_OS_STATE otherwise
     **********************************************************************/
    StatusType CopyHard2FrameBuffer(void)
    {
      StatusType returned_type;
      unsigned long ID_received;
      CAN_message_tRef CAN_list_itor;
    
      returned_type = E_OK;
    
      if (CAN_list_head_rcv != NULL)
      {
        CAN_list_itor = CAN_list_head_rcv;
        do
        {
          #ifdef __NOFILTER__
          if (1)
          #else
          #ifdef __EXT29BITS__
          ID_received  = 0;
          ID_received += (unsigned long)(RXB0.RXBnEID0);
          ID_received += (unsigned long)(RXB0.RXBnEID8) << 8;
          ID_received += (unsigned long)(RXB0.RXBnSIDL & 0x03) << 16;
          ID_received += (unsigned long)(RXB0.RXBnSIDL & 0xE0) << 13;
          ID_received += (unsigned long)(RXB0.RXBnSIDH & 0xFF) << 21;
          #else
           #ifdef  __STD11BITS__
            ID_received  = 0;
            ID_received += (unsigned long)(RXB0.RXBnSIDL) >> 5;
            ID_received += (unsigned long)(RXB0.RXBnSIDH) << 3;
           #else
            #error "you should define 11 or 29 bits for CANID !"
           #endif
          #endif
          if (CAN_list_itor->CANID == ID_received)
          #endif
          {
            if (CAN_list_itor->state == CAN_FREE)
            {
              CAN_list_itor->data[0] = RXB0.RXBnD0;
              CAN_list_itor->data[1] = RXB0.RXBnD1;
              CAN_list_itor->data[2] = RXB0.RXBnD2;
              CAN_list_itor->data[3] = RXB0.RXBnD3;
              CAN_list_itor->data[4] = RXB0.RXBnD4;
              CAN_list_itor->data[5] = RXB0.RXBnD5;
              CAN_list_itor->data[6] = RXB0.RXBnD6;
              CAN_list_itor->data[7] = RXB0.RXBnD7;
              CAN_list_itor->length  = RXB0.RXBnDLC & 0x0F;
              CAN_list_itor->state   = CAN_FULL;
              SetEvent(CAN_list_itor->CallerID, CAN_QUEUE_FULL);
            }
            else
              returned_type = E_OS_STATE;
          }
          CAN_list_itor = CAN_list_itor->next;
        }
        while (CAN_list_itor != NULL);
      }
    
      return(returned_type);
    }
    
    /**********************************************************************
     * ISR of the CAN driver.
     *
     * For each interrupt we disable the IE first to avoid any infinite loop
     * and we clear the IF in the dedicated function (Read or Write CAN mess).
     * Indeed we have to clear the IT when the message has been properly
     * accessed and is no more used. The IF lets the peripheral accept a new
     * message.
     * If 3 frames arrive at the same time, the two first are stored in the
     * RCV buffers and the third is discarded (temporary overload bus).
     *
     * @return void
     **********************************************************************/
    void MCP2551_INT(void)
    {
        INTCON3bits.INT1IF = 0;
        // Send a request to the driver
        SetEvent(MCP2515_DRV_ID,MCP2515_IRQ_REQUEST);
    }
    
    /* End of File : drv_mcp2515.c */
    /**********************************************************************/
    /*                                                                    */
    /* File name: drv_mcp2515.h                                           */
    /*                                                                    */
    /* Since:     2005-Nov-30                                             */
    /*                                                                    */
    /* Version:   PICos18 v2.04                                           */
    /*            Copyright (C) 2003, 2004, 2005 Pragmatec.               */
    /*            MCP2515 CAN driver v1.00                                */
    /*                                                                    */
    /* Author:    Designed by Pragmatec S.A.R.L.        www.pragmatec.net */
    /*            ROZIER Bertrand [RZR]      bertrand.rozier@pragmatec.net*/
    /*                                                                    */
    /* Purpose:   MCP2515 : SPI CAN controller management.                */
    /*            It allows task to send data at the same time through a  */
    /*            dedicated FIFO, and to wait for a certain CAN frame.    */
    /*                                                                    */
    /* Distribution: This file is part of PICos18.                        */
    /*            PICos18 is free software; you can redistribute it       */
    /*            and/or modify it under the terms of the GNU General     */
    /*            Public License as published by the Free Software        */
    /*            Foundation; either version 2, or (at your option)       */
    /*            any later version.                                      */
    /*                                                                    */
    /*            PICos18 is distributed in the hope that it will be      */
    /*            useful, but WITHOUT ANY WARRANTY; without even the      */
    /*            implied warranty of MERCHANTABILITY or FITNESS FOR A    */
    /*            PARTICULAR PURPOSE.  See the GNU General Public         */
    /*            License for more details.                               */
    /*                                                                    */
    /*            You should have received a copy of the GNU General      */
    /*            Public License along with gpsim; see the file           */
    /*            COPYING.txt. If not, write to the Free Software         */
    /*            Foundation, 59 Temple Place - Suite 330,                */
    /*            Boston, MA 02111-1307, USA.                             */
    /*                                                                    */
    /*          > A special exception to the GPL can be applied should    */
    /*            you wish to distribute a combined work that includes    */
    /*            PICos18, without being obliged to provide the source    */
    /*            code for any proprietary components.                    */
    /*                                                                    */
    /* History:                                                           */
    /* 2005/11/30 [RZR] Create this file.                                 */
    /*                                                                    */
    /**********************************************************************/
    
    
    #ifndef _MCP2515_DRV_H_
    #define _MCP2515_DRV_H_
    
    #include "pro_man.h"
    #include "even_man.h"
    #include "alarm.h"
    
    
    /*****************************************************
     * Definition dedicated to the local functions.
     ****************************************************/
    #define CAN_MSG_SENT        0x02
    #define CAN_FREE            0x00
    #define CAN_FULL            0x01
    #define CAN_EMPTY           0x00
    #define TRUE                0x01
    #define FALSE               0x00
    #define TX_MESSAGE          0x01
    #define RX_MESSAGE          0x00
    
    #define TXB0_REG            0x30
    #define TXB1_REG            0x40
    #define TXB2_REG            0x50
    #define RXB0_REG            0x60
    #define RXB1_REG            0x70
    
    struct _CAN_frame {
       unsigned long CANID;
       unsigned char length;
       unsigned char data[8];
       unsigned char CallerID;
       unsigned char state;
       struct _CAN_frame *next;
    };
    typedef struct _CAN_frame CAN_message_t, *CAN_message_tRef;
    
    struct _TX_buffer {
    //    unsigned char TXBnCTRL;
        unsigned char TXBnSIDH;
        unsigned char TXBnSIDL;
        unsigned char TXBnEID8;
        unsigned char TXBnEID0;
        unsigned char TXBnDLC;
        unsigned char TXBnD0;
        unsigned char TXBnD1;
        unsigned char TXBnD2;
        unsigned char TXBnD3;
        unsigned char TXBnD4;
        unsigned char TXBnD5;
        unsigned char TXBnD6;
        unsigned char TXBnD7;
    };
    typedef struct _TX_buffer TXBn_t, *TXBn_tRef;
    
    struct _RX_buffer {
    //    unsigned char RXBnCTRL;
        unsigned char RXBnSIDH; //0x61
        unsigned char RXBnSIDL;
        unsigned char RXBnEID8;
        unsigned char RXBnEID0;
        unsigned char RXBnDLC;
        unsigned char RXBnD0;
        unsigned char RXBnD1;
        unsigned char RXBnD2;
        unsigned char RXBnD3;
        unsigned char RXBnD4;
        unsigned char RXBnD5;
        unsigned char RXBnD6;
        unsigned char RXBnD7;
    
    };
    typedef struct _RX_buffer RXBn_t, *RXBn_tRef;
    
    
    #define          CAN_freeMsg(x)        x.state = CAN_FREE;
    
    StatusType       CAN_enqMsg(CAN_message_tRef toEnqueue);
    CAN_message_tRef CAN_deqMsg(void);
    StatusType       CopyHard2FrameBuffer(void);
    StatusType       CopyFrameBuffer2Hard(void);
    StatusType       CAN_RCV_Register(CAN_message_tRef toEnqueue);
    void             CAN_config(void);
    
    
    // CAN configuration registers
    #define CAN2510_REG_BFPCTRL    0x0C
    #define CAN2510_REG_TXRTSCTRL  0x0D
    #define CAN2510_REG_CANSTAT    0x0E // Repeated every 16 locations (1E, 2E, ...)
    #define CAN2510_REG_CANCTRL    0x0F // Repeated every 16 locations (1F, 2F, ...)
    
    #define CAN2510_REG_TEC        0x1C
    #define CAN2510_REG_REC        0x1D
    
    #define CAN2510_REG_CNF3       0x28
    #define CAN2510_REG_CNF2       0x29
    #define CAN2510_REG_CNF1       0x2A
    #define CAN2510_REG_CANINTE    0x2B
    #define CAN2510_REG_CANINTF    0x2C
    #define CAN2510_REG_EFLG       0x2D
    
    
    
    // CAN Receive Mask/Filter registers
    #define CAN2510_REG_RXM0SIDH   0x20
    #define CAN2510_REG_RXM0SIDL   0x21
    #define CAN2510_REG_RXM0EID8   0x22
    #define CAN2510_REG_RXM0EID0   0x23
    #define CAN2510_REG_RXM1SIDH   0x24
    #define CAN2510_REG_RXM1SIDL   0x25
    #define CAN2510_REG_RXM1EID8   0x26
    #define CAN2510_REG_RXM1EID0   0x27
    #define CAN2510_REG_RXF0SIDH   0x00
    #define CAN2510_REG_RXF0SIDL   0x01
    #define CAN2510_REG_RXF0EID8   0x02
    #define CAN2510_REG_RXF0EID0   0x03
    #define CAN2510_REG_RXF1SIDH   0x04
    #define CAN2510_REG_RXF1SIDL   0x05
    #define CAN2510_REG_RXF1EID8   0x06
    #define CAN2510_REG_RXF1EID0   0x07
    #define CAN2510_REG_RXF2SIDH   0x08
    #define CAN2510_REG_RXF2SIDL   0x09
    #define CAN2510_REG_RXF2EID8   0x0A
    #define CAN2510_REG_RXF2EID0   0x0B
    #define CAN2510_REG_RXF3SIDH   0x10
    #define CAN2510_REG_RXF3SIDL   0x11
    #define CAN2510_REG_RXF3EID8   0x12
    #define CAN2510_REG_RXF3EID0   0x13
    #define CAN2510_REG_RXF4SIDH   0x14
    #define CAN2510_REG_RXF4SIDL   0x15
    #define CAN2510_REG_RXF4EID8   0x16
    #define CAN2510_REG_RXF4EID0   0x17
    #define CAN2510_REG_RXF5SIDH   0x18
    #define CAN2510_REG_RXF5SIDL   0x19
    #define CAN2510_REG_RXF5EID8   0x1A
    #define CAN2510_REG_RXF5EID0   0x1B
    
    // CAN Transmit Control/Header/Data registers
    #define CAN2510_REG_TXB0CTRL   0x30
    #define CAN2510_REG_TXB0SIDH   0x31
    #define CAN2510_REG_TXB0SIDL   0x32
    #define CAN2510_REG_TXB0EID8   0x33
    #define CAN2510_REG_TXB0EID0   0x34
    #define CAN2510_REG_TXB0DLC    0x35
    #define CAN2510_REG_TXB0D0     0x36
    #define CAN2510_REG_TXB0D1     0x37
    #define CAN2510_REG_TXB0D2     0x38
    #define CAN2510_REG_TXB0D3     0x39
    #define CAN2510_REG_TXB0D4     0x3A
    #define CAN2510_REG_TXB0D5     0x3B
    #define CAN2510_REG_TXB0D6     0x3C
    #define CAN2510_REG_TXB0D7     0x3D
    
    #define CAN2510_REG_TXB1CTRL   0x40
    #define CAN2510_REG_TXB1SIDH   0x41
    #define CAN2510_REG_TXB1SIDL   0x42
    #define CAN2510_REG_TXB1EID8   0x43
    #define CAN2510_REG_TXB1EID0   0x44
    #define CAN2510_REG_TXB1DLC    0x45
    #define CAN2510_REG_TXB1D0     0x46
    #define CAN2510_REG_TXB1D1     0x47
    #define CAN2510_REG_TXB1D2     0x48
    #define CAN2510_REG_TXB1D3     0x49
    #define CAN2510_REG_TXB1D4     0x4A
    #define CAN2510_REG_TXB1D5     0x4B
    #define CAN2510_REG_TXB1D6     0x4C
    #define CAN2510_REG_TXB1D7     0x4D
    
    #define CAN2510_REG_TXB2CTRL   0x50
    #define CAN2510_REG_TXB2SIDH   0x51
    #define CAN2510_REG_TXB2SIDL   0x52
    #define CAN2510_REG_TXB2EID8   0x53
    #define CAN2510_REG_TXB2EID0   0x54
    #define CAN2510_REG_TXB2DLC    0x55
    #define CAN2510_REG_TXB2D0     0x56
    #define CAN2510_REG_TXB2D1     0x57
    #define CAN2510_REG_TXB2D2     0x58
    #define CAN2510_REG_TXB2D3     0x59
    #define CAN2510_REG_TXB2D4     0x5A
    #define CAN2510_REG_TXB2D5     0x5B
    #define CAN2510_REG_TXB2D6     0x5C
    #define CAN2510_REG_TXB2D7     0x5D
    
    // CAN Transmit Control/Header/Data registers
    #define CAN2510_REG_RXB0CTRL   0x60
    #define CAN2510_REG_RXB0SIDH   0x61
    #define CAN2510_REG_RXB0SIDL   0x62
    #define CAN2510_REG_RXB0EID8   0x63
    #define CAN2510_REG_RXB0EID0   0x64
    #define CAN2510_REG_RXB0DLC    0x65
    #define CAN2510_REG_RXB0D0     0x66
    #define CAN2510_REG_RXB0D1     0x67
    #define CAN2510_REG_RXB0D2     0x68
    #define CAN2510_REG_RXB0D3     0x69
    #define CAN2510_REG_RXB0D4     0x6A
    #define CAN2510_REG_RXB0D5     0x6B
    #define CAN2510_REG_RXB0D6     0x6C
    #define CAN2510_REG_RXB0D7     0x6D
    
    #define CAN2510_REG_RXB1CTRL   0x70
    #define CAN2510_REG_RXB1SIDH   0x71
    #define CAN2510_REG_RXB1SIDL   0x72
    #define CAN2510_REG_RXB1EID8   0x73
    #define CAN2510_REG_RXB1EID0   0x74
    #define CAN2510_REG_RXB1DLC    0x75
    #define CAN2510_REG_RXB1D0     0x76
    #define CAN2510_REG_RXB1D1     0x77
    #define CAN2510_REG_RXB1D2     0x78
    #define CAN2510_REG_RXB1D3     0x79
    #define CAN2510_REG_RXB1D4     0x7A
    #define CAN2510_REG_RXB1D5     0x7B
    #define CAN2510_REG_RXB1D6     0x7C
    #define CAN2510_REG_RXB1D7     0x7D
    
    #define CAN2510_CMD_RESET      0xC0
    #define CAN2510_CMD_WRITE      0x02
    #define CAN2510_CMD_READ       0x03
    #define CAN2510_CMD_RTS        0x80
    #define CAN2510_CMD_BITMOD     0x05
    #define CAN2510_CMD_STATUS     0xA0
    
    
    // Define for RTS ( Request to send)
    #define TX_B0                  0x01
    #define TX_B1                  0x02
    #define TX_B2                  0x04
    
    #endif /* _MCP2515_DRV_H_ */
    
    /* End of File : drv_mcp2515.h */
  • 相关阅读:
    modprobe命令
    CentOS实验七:配置RPMForge软件源
    Makefile中的cd用法
    shell 脚本重定向【转】
    自动登陆CentOS
    用UltraISO制作启动光盘
    解决PATH中没有/sbin目录的问题
    Linux系统信息命令大全
    隐藏CentOS桌面图标
    IIS 操作必须使用一个可更新的查询的解决方法
  • 原文地址:https://www.cnblogs.com/shangdawei/p/4538915.html
Copyright © 2011-2022 走看看