MCP2515 驱动程序

前段时间接手一个项目一个CAN总线的扩展板,由于CAN口不够用故采用MCP2515扩展,驱动代码如下:


/*! \file MCP2515.h
    \brief API to control the Microchip MCP2515 CAN controller. This CAN
    controller use the SPI link. For that reason, SPI initiation and data
    control should custom by the user.

     \author Sy Sech VONG
             Fr��d��ric Nadeau
             FangZheng @2014.9.10
*/


#ifndef MCP2515_H_
#define MCP2515_H_

#define USE_INT_STAT            1   // use INT pin indicate recived data

//MCP2515 RX/TX buffers selection
#define MCP2515_RX_BUF_0        0
#define MCP2515_RX_BUF_1        1
#define MCP2515_TX_BUF_0        0
#define MCP2515_TX_BUF_1        1
#define MCP2515_TX_BUF_2        2


//MCP2515 SPI instructions
#define MCP2515_RESET                   0xC0
#define MCP2515_READ                    0x03
#define MCP2515_READ_BUF_RXB0SIDH       0x90    //read data from begin address of Standard ID (MSB) of RX buffer 0
#define MCP2515_READ_BUF_RXB0D0         0x92    //read data from begin address of data byte 0 of RX buffer 0
#define MCP2515_READ_BUF_RXB1SIDH       0x94    //...RX buffer 1
#define MCP2515_READ_BUF_RXB1D0         0x96    //...RX buffer 1
#define MCP2515_WRITE                   0x02
#define MCP2515_LOAD_BUF_TXB0SIDH       0x40    //load data from begin address of Standard ID (MSB) of TX buffer 0
#define MCP2515_LOAD_BUF_TXB0D0         0X41    //load data from begin address of data byte 0 of TX buffer 0
#define MCP2515_LOAD_BUF_TXB1SIDH       0x42    //...TX buffer 1
#define MCP2515_LOAD_BUF_TXB1D0         0X43    //...TX buffer 1
#define MCP2515_LOAD_BUF_TXB2SIDH       0x44    //...TX buffer 2
#define MCP2515_LOAD_BUF_TXB2D0         0X45    //...TX buffer 2
#define MCP2515_RTS_TXB0                0x81    //activate the RTS of TX buffer 0.
#define MCP2515_RTS_TXB1                0x82    //...TX buffer 1.
#define MCP2515_RTS_TXB2                0x84    //...TX buffer 2.
#define MCP2515_RTS_ALL                 0x87    //...TX buffer 0, 1 and 2.
#define MCP2515_READ_RXTX_STATUS        0xA0
#define MCP2515_RX_STATUS               0xB0
#define MCP2515_BIT_MODIFY              0x05


//MCP2515 control settings register address.
//All can be used with the Bit Modify command, except the CANSTAT register.
#define MCP2515_BFPCTRL         0x0C    //RXnBF pin control/status
#define MCP2515_TXRTSCTRL       0x0D    //TXnRTS pin control/status
#define MCP2515_CANSTAT         0x0E    //CAN status. any addr of MSB will give the same info???
#define MCP2515_CANCTRL         0x0F    //CAN control status. any addr of MSB will give the same info???
#define MCP2515_TEC             0x1C    //Transmit Error Counter
#define MCP2515_REC             0x1D    //Receive Error Counter
#define MCP2515_CNF3            0x28    //Phase segment 2
#define MCP2515_CNF2            0x29    //Propagation segment & Phase segment 1 & n sample setting
#define MCP2515_CNF1            0x2A    //Baud rate prescaler & Sync Jump Width
#define MCP2515_CANINTE         0x2B    //CAN interrupt enable
#define MCP2515_CANINTF         0x2C    //Interrupt flag
#define MCP2515_EFLG            0x2D    //Error flag
#define MCP2515_TXB0CTRL        0x30    //TX buffer 0 control
#define MCP2515_TXB1CTRL        0x40    //TX buffer 1 control
#define MCP2515_TXB2CTRL        0x50    //TX buffer 2 control
#define MCP2515_RXB0CTRL        0x60    //RX buffer 0 control
#define MCP2515_RXB1CTRL        0x70    //RX buffer 1 control


//MCP2515 relate to CAN settings/status register address.
//Only the most used are listed below. please see the datasheet MCP2515.pdf p61 for complete info.
#define MCP2515_RXF0SIDH        0x00    //RX standard ID (High bits) filter 0
#define MCP2515_RXF0SIDL        0x01    //RX standard ID (Low bits) filter 0
#define MCP2515_RXF0EID8        0x02    //RX Extended ID (High bits) filter 0 ->can be reached by bust read/write Standard ID then Ext. ID
#define MCP2515_RXF0EID0        0x03    //RX Extended ID (Low bits) filter 0
#define MCP2515_RXF1SIDH        0x04    //RX standard ID (High bits) filter 1
#define MCP2515_RXF1SIDL        0x05    //RX standard ID (Low bits) filter 1
#define MCP2515_RXF1EID8        0x06    //RX Extended ID (High bits) filter 1
#define MCP2515_RXF1EID0        0x07    //RX Extended ID (Low bits) filter 1
#define MCP2515_RXF2SIDH        0x08    //RX standard ID (High bits) filter 2
#define MCP2515_RXF2SIDL        0x09    //RX standard ID (Low bits) filter 2
#define MCP2515_RXF2EID8        0x0A    //RX Extended ID (High bits) filter 2
#define MCP2515_RXF2EID0        0x0B    //RX Extended ID (Low bits) filter 2
#define MCP2515_RXF3SIDH        0x10    //RX standard ID (High bits) filter 3
#define MCP2515_RXF3SIDL        0x11    //RX standard ID (Low bits) filter 3
#define MCP2515_RXF3EID8        0x12    //RX Extended ID (High bits) filter 3
#define MCP2515_RXF3EID0        0x13    //RX Extended ID (Low bits) filter 3
#define MCP2515_RXF4SIDH        0x14    //RX standard ID (High bits) filter 4
#define MCP2515_RXF4SIDL        0x15    //RX standard ID (Low bits) filter 4
#define MCP2515_RXF4EID8        0x16    //RX Extended ID (High bits) filter 4
#define MCP2515_RXF4EID0        0x17    //RX Extended ID (Low bits) filter 4
#define MCP2515_RXF5SIDH        0x18    //RX standard ID (High bits) filter 5
#define MCP2515_RXF5SIDL        0x19    //RX standard ID (Low bits) filter 5
#define MCP2515_RXF5EID8        0x1A    //RX Extended ID (High bits) filter 5
#define MCP2515_RXF5EID0        0x1B    //RX Extended ID (Low bits) filter 5
#define MCP2515_RXM0SIDH        0x20    //RX standard ID (High bits) mask filter 0
#define MCP2515_RXM0SIDL        0x21    //RX standard ID (Low bits) mask filter 0
#define MCP2515_RXM0EID8        0x22    //RX Extended ID (High bits) mask filter 0
#define MCP2515_RXM0EID0        0x23    //RX Extended ID (Low bits) mask filter 0
#define MCP2515_RXM1SIDH        0x24    //RX standard ID (High bits) mask filter 1
#define MCP2515_RXM1SIDL        0x25    //RX standard ID (Low bits) mask filter 1
#define MCP2515_RXM1EID8        0x26    //RX Extended ID (High bits) mask filter 1
#define MCP2515_RXM1EID0        0x27    //RX Extended ID (Low bits) mask filter 1
#define MCP2515_RXB0SIDH        0x61    //RX buffer 0 standard ID (High bits)
#define MCP2515_RXB0SIDL        0x62    //RX buffer 0 standard ID (Low bits)
#define MCP2515_RXB0EID8        0x63    //RX buffer 0 Extended ID (High bits) ->can be reached by bust read/write Standard ID then Ext. ID
#define MCP2515_RXB0EID0        0x64    //RX buffer 0 Extended ID (Low bits)
#define MCP2515_RXB0DLC         0x65    //RX buffer 0 DLC  ->can be reached by bust read/write Standard ID, Ext. ID then DLC
#define MCP2515_RXB0D0          0x66    //RX buffer 0 data byte0
#define MCP2515_RXB1SIDH        0x71    //RX buffer 1 standard ID (High bits)
#define MCP2515_RXB1SIDL        0x72    //RX buffer 1 standard ID (Low bits)
#define MCP2515_RXB1EID8        0x73    //RX buffer 1 Extended ID (High bits)
#define MCP2515_RXB1EID0        0x74    //RX buffer 1 Extended ID (Low bits)
#define MCP2515_RXB1DLC         0x75    //RX buffer 1 DLC
#define MCP2515_RXB1D0          0x76    //RX buffer 1 data byte0

#define MCP2515_TXB0SIDH        0x31    //TX buffer 0 standard ID (High bits)
#define MCP2515_TXB0SIDL        0x32    //TX buffer 0 standard ID (Low bits)
#define MCP2515_TXB0EID8        0x33    //TX buffer 0 Extended ID (High bits) ->can be reached by bust read/write Standard ID then Ext. ID
#define MCP2515_TXB0EID0        0x34    //TX buffer 0 Extended ID (Low bits)
#define MCP2515_TXB0DLC         0x35    //TX buffer 0 DLC  ->can be reached by bust read/write Standard ID, Ext. ID then DLC
#define MCP2515_TXB0D0          0x36    //TX buffer 0 data byte0
#define MCP2515_TXB1SIDH        0x41    //TX buffer 1 standard ID (High bits)
#define MCP2515_TXB1SIDL        0x42    //TX buffer 1 standard ID (Low bits)
#define MCP2515_TXB1EID8        0x43    //TX buffer 1 Extended ID (High bits)
#define MCP2515_TXB1EID0        0x44    //TX buffer 1 Extended ID (Low bits)
#define MCP2515_TXB1DLC         0x45    //TX buffer 1 DLC
#define MCP2515_TXB1D0          0x46    //TX buffer 1 data byte0
#define MCP2515_TXB2SIDH        0x51    //TX buffer 2 standard ID (High bits)
#define MCP2515_TXB2SIDL        0x52    //TX buffer 2 standard ID (Low bits)
#define MCP2515_TXB2EID8        0x53    //TX buffer 2 Extended ID (High bits)
#define MCP2515_TXB2EID0        0x54    //TX buffer 2 Extended ID (Low bits)
#define MCP2515_TXB2DLC         0x55    //TX buffer 2 DLC
#define MCP2515_TXB2D0          0x56    //TX buffer 2 data byte0


//MCP2515 limit values
#define MCP2515_MIN_TQ          0x07    //7 = Minimum TQ in 1 bit of CAN bus time
#define MCP2515_MAX_TQ          0x19    //25 = Maximum TQ in 1 bit of CAN bus time
#define MCP2515_MIN_BRP         0x00    //0 = Minimum baud rate prescaler clock
#define MCP2515_MAX_BRP         0x3F    //63 = Maximum baud rate prescaler clock
#define MCP2515_MAX_SJW         0x03    //4 = Maximum Synchronization Jump Width. 4-1 = 3 actually
#define MCP2515_MAX_BYTE_CANFRM 0x08//8 = Maximun bytes in a CAN frame


//MCP2515 register values: CANCTRL register
#define MCP2515_MODE_NORMAL     0x00
#define MCP2515_MODE_SLEEP      0x20
#define MCP2515_MODE_LOOPBACK   0x40
#define MCP2515_MODE_LISTENONLY 0x60
#define MCP2515_MODE_CONFIG     0x80
#define MCP2515_ABORT_TX        0x10
#define MCP2515_MODE_MASK       0xE0
#define MCP2515_MODE_ONESHOT    0x08
#define MCP2515_CLKOUT_ENABLE   0x04
#define MCP2515_CLKOUT_PS1      0x00    //Set CLK out prescaler to 1. Note: not the same as the CAN CLK prescaler.
#define MCP2515_CLKOUT_PS2      0x01    //... to 2
#define MCP2515_CLKOUT_PS4      0x02    //... to 4
#define MCP2515_CLKOUT_PS8      0x03    //... to 8


//MCP2515 CAN Status Register bits (CANSTAT 0xXE, ICOD)
#define MCP2515_CANSTAT_NO_INT   0x00
#define MCP2515_CANSTAT_ERR_INT  0x02
#define MCP2515_CANSTAT_WAK_INT  0x04 //Wake-up Interrupt
#define MCP2515_CANSTAT_TXB0_INT 0x06
#define MCP2515_CANSTAT_TXB1_INT 0x08
#define MCP2515_CANSTAT_TXB2_INT 0x0A
#define MCP2515_CANSTAT_RXB0_INT 0x0C
#define MCP2515_CANSTAT_RXB1_INT 0x0E

//MCP2515 CAN Interrupt Flag Define
#define MCP2515_CANINTF_MERRF   0x80
#define MCP2515_CANINTF_WAKIF   0x40
#define MCP2515_CANINTF_ERRIF   0x20
#define MCP2515_CANINTF_TX2IF   0x10
#define MCP2515_CANINTF_TX1IF   0x08
#define MCP2515_CANINTF_TX0IF   0x04
#define MCP2515_CANINTF_RX1IF   0x02
#define MCP2515_CANINTF_RX0IF   0x01

#define MCP2515_CANINT_MERR     0x80
#define MCP2515_CANINT_WAKI     0x40
#define MCP2515_CANINT_ERRI     0x20
#define MCP2515_CANINT_TX2I     0x10
#define MCP2515_CANINT_TX1I     0x08
#define MCP2515_CANINT_TX0I     0x04
#define MCP2515_CANINT_RX1I     0x02
#define MCP2515_CANINT_RX0I     0x01

// porting for F2808 edit by fz 
#define ASSERT(expr)   ((void)0) //assert function not use here, so ...
typedef unsigned long  uint32_t;
typedef unsigned int   uint8_t;
/*! \struct mcp2515_can_frame_s
 *  Structure of a CANbus frame.
 */
#if 0
typedef struct mcp2515_can_frame_s{
    uint32_t id;        /**< Standard or Extented ID*/
    uint8_t dlc;        /**< Data Length Code*/
    uint8_t data[8];    /**< Data*/
}mcp2515_can_frame_t;   /**< Typedef of #mcp2515_can_frame_s*/
#endif
// end


typedef struct canfd_frame mcp2515_can_frame_t;


typedef enum mcp2515_rx_e
{
        mcp2515_rx_0,
        mcp2515_rx_1
}mcp2515_rx_t;

typedef enum mcp2515_tx_e
{
        mcp2515_tx_0,
        mcp2515_tx_1,
        mcp2515_tx_2
}mcp2515_tx_t;

typedef enum mcp2515_op_mode_e
{
        mcp2515_op_mode_normal = 0,
        mcp2515_op_mode_sleep,
        mcp2515_op_mode_loopback,
        mcp2515_op_mode_listen,
        mcp2515_op_mode_config
}mcp2515_op_mode_t;

typedef enum mcp2515_rx_op_mode_e
{
        mcp2515_rx_op_mode_filter_any = 0,
        mcp2515_rx_op_mode_filter_standard,
        mcp2515_rx_op_mode_filter_extended,
        mcp2515_rx_op_mode_any
}mcp2515_rx_op_mode_t;

typedef enum mcp2515_rx_filter_mask_e
{
        mcp2515_rx_filter_mask_RXF0 = 0x00,
        mcp2515_rx_filter_mask_RXF1 = 0x04,
        mcp2515_rx_filter_mask_RXF2 = 0x08,
        mcp2515_rx_filter_mask_RXF3 = 0x10,
        mcp2515_rx_filter_mask_RXF4 = 0x14,
        mcp2515_rx_filter_mask_RXF5 = 0x18,
        mcp2515_rx_filter_mask_RXM0 = 0x20,
        mcp2515_rx_filter_mask_RXM1 = 0x24
}mcp2515_rx_filter_mask_t;

enum
{
        MCP2515_SPIA = 0,
        MCP2515_SPIB,
        MCP2515_SPIC,
        MCP2515_SPID,
        MCP2515_DBG   
};

extern void mcp2515_spi_port_init(void);
extern void mcp2515_chn_select(uint8_t chn);
extern int16 mcp2515_sendmsg(struct canfd_frame *cf);
extern int16 mcp2515_recvmsg(struct canfd_frame *cf);
extern Uint16 mcp2515_init(uint32_t canID, uint8_t ext);
extern void read(uint8_t regAddr, uint8_t *dataAddr);
extern void write(uint8_t regAddr, uint8_t data);

//extern void mcp2515_init_ext(uint32_t canID, uint32_t mask, uint8_t ext);
extern void mcp2515_init_ext(uint32_t canID1, uint32_t canID2, uint8_t ext);
extern int16 mcp2515_sendext(struct canfd_frame *cf);
extern int16 mcp2515_recvext(struct canfd_frame *cf);

#endif /*MCP2515_H_*/


/*! \file MCP2515.c
    \brief API for Microchip MCP2515 CAN controller.

    This CAN controller use the SPI link. For that reason, SPI initiation and data
    control should custom by the user.

     \author Sy Sech VONG
             Fr��d��ric Nadeau
             FangZheng @2014.9.20
 */


#include "global.h"

#define DEBUG_MCP 1

extern void mcp2515_spi_port_init(void);


//extern void mcp2515_spi_select(void);


//extern void mcp2515_spi_unselect(void);


//extern void mcp2515_spi_transfer(uint8_t dataOut, uint8_t *dataIn);


void mcp2515_reset(void);


void mcp2515_read_rx_buf(mcp2515_rx_t channel, mcp2515_can_frame_t *canData);


void mcp2515_load_tx_buf(uint8_t nBuf, mcp2515_can_frame_t *canData);


void mcp2515_rts(uint8_t nBuf);


void mcp2515_read_rxtx_status(uint8_t* canRxTxStatus);


void mcp2515_rx_status(uint8_t* canRxStatus);

void mcp2515_set_rx_filter_mask(mcp2515_rx_filter_mask_t regAddr, uint32_t canID, uint8_t ext);

int mcp2515_get_int_flag(void);
void mcp2515_clear_interrupt(void);

void mcp2515_set_op_mode(mcp2515_op_mode_t mode);

void mcp2515_set_rx_op_mode(mcp2515_rx_t channel, mcp2515_rx_op_mode_t mode);

void mcp2515_enable_rx_int(mcp2515_rx_t channel);
void mcp2515_enable_tx_int(mcp2515_tx_t channel);

static void (*mcp2515_spi_select)(void);
static void (*mcp2515_spi_unselect)(void);
//static void (*mcp2515_spi_transfer)(uint8_t ubDataOut, uint8_t *pubDataIn);
static void (*mcp2515_spi_transfer)(uint8_t tdata, uint8_t *prdata);

void mcp2515_chn_select(uint8_t chn)
{
    switch(chn)
    {
        case MCP2515_SPIA:
            mcp2515_spi_select = spi_select_spia;
            mcp2515_spi_unselect = spi_unselect_spia;
            mcp2515_spi_transfer = spi_transfer_spia;
            break;
        case MCP2515_SPIB:
            mcp2515_spi_select = spi_select_spib;
            mcp2515_spi_unselect = spi_unselect_spib;
            mcp2515_spi_transfer = spi_transfer_spib;
            break; 
        case MCP2515_SPIC:
            mcp2515_spi_select = spi_select_spic;
            mcp2515_spi_unselect = spi_unselect_spic;
            mcp2515_spi_transfer = spi_transfer_spic;
            break;
        case MCP2515_SPID:
            mcp2515_spi_select = spi_select_spid;
            mcp2515_spi_unselect = spi_unselect_spid;
            mcp2515_spi_transfer = spi_transfer_spid;
            break;
        case MCP2515_DBG:
            mcp2515_spi_select = spi_select_spic;
            mcp2515_spi_unselect = spi_unselect_spic;
            mcp2515_spi_transfer = spi_dbg_transfer;
            break;   
        default :
            break;
    }
}



void mcp2515_spi_port_init(void)
{
    mcp2515_status_init();
    mcp2515_cs_init();
    mcp2515_en_init();
}

#if 0
void mcp2515_spi_select(void){}
void mcp2515_spi_unselect(void){}

void mcp2515_spi_transfer(uint8_t ubDataOut, uint8_t *pubDataIn)
{
    /*SPDR = ubDataOut;

    loop_until_bit_is_set(SPSR, SPIF);

    if (pubDataIn != (void*) 0)
    {
        *pubDataIn = SPDR;
    }
    else
    {
        uint8_t tmp;
        tmp = SPDR;
    }*/
}
#endif
static void id_read(uint32_t *canID)
{
    uint8_t dataIn;
    volatile uint32_t uwID = 0;

    mcp2515_spi_transfer(0, &dataIn);//read XXXnSIDH
    uwID = (((uint32_t)dataIn) << 21);
    mcp2515_spi_transfer(0, &dataIn);//read XXXnSIDL
    uwID |= ( ((uint32_t)(dataIn & 0xE0)) << 13);
    uwID |= ( ((uint32_t)(dataIn & 0x03)) << 16);

    if (dataIn & 0x08) //Ext. ID? (bit mask on bit3)
        uwID |= 0x80000000;

    mcp2515_spi_transfer(0, &dataIn);//read XXXnEID8
    uwID |= (((uint32_t)dataIn) << 8);
    mcp2515_spi_transfer(0, &dataIn);//read XXXnEID0
    uwID |= (uint32_t)dataIn;
    *canID = uwID;
}


static void id_write(uint32_t canID)
{
    uint8_t ubtempo = 0;

    mcp2515_spi_transfer((uint8_t) (canID >> 21), NULL);//send XXXnSIDH
    ubtempo = ( (uint8_t)(canID >> 13) ) & 0xE0;
    ubtempo |= ( (uint8_t)(canID >> 16) ) & 0x03;

    if (canID & 0x80000000)//Ext. ID?
        ubtempo |= 0x08;

    mcp2515_spi_transfer(ubtempo, NULL);//send XXXnSIDL
    mcp2515_spi_transfer((uint8_t) (canID >> 8), NULL);//Send XXXnEID8
    mcp2515_spi_transfer((uint8_t) canID, NULL);//Send XXXnEID0
}


void read(uint8_t regAddr, uint8_t *dataAddr)
{
    ASSERT(dataAddr != 0);

    mcp2515_spi_select();//Select the MCP2515 on the SPI bus
    mcp2515_spi_transfer(MCP2515_READ, NULL);
    mcp2515_spi_transfer(regAddr, NULL);
    mcp2515_spi_transfer(0, dataAddr);
    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus
}

void write(uint8_t regAddr, uint8_t data)
{
    mcp2515_spi_select();//Select the MCP2515 on the SPI bus
    mcp2515_spi_transfer(MCP2515_WRITE, NULL);
    mcp2515_spi_transfer(regAddr, NULL);
    mcp2515_spi_transfer(data, NULL);
    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus
}

#if 0
static void write_bust(uint8_t regAddr, uint8_t *dataAddr, uint8_t size)
{
    uint8_t i;

    ASSERT(dataAddr != NULL);

    mcp2515_spi_select();//Select the MCP2515 on the SPI bus
    mcp2515_spi_transfer(MCP2515_WRITE, NULL);
    mcp2515_spi_transfer(regAddr, NULL);

    for (i=0; i < size; i++)
        mcp2515_spi_transfer(dataAddr[i], NULL);

    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus
}

static void read_bust(uint8_t regAddr, uint8_t *dataAddr, uint8_t size)
{
    uint8_t i;

    ASSERT((dataAddr != NULL) && (size != 0));

    mcp2515_spi_select();//Select the MCP2515 on the SPI bus
    mcp2515_spi_transfer(MCP2515_READ, NULL);
    mcp2515_spi_transfer(regAddr, NULL);

    for (i=0; i <= size; i++)
        mcp2515_spi_transfer(0, dataAddr++);

    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus
}
#endif

static void bit_modify(uint8_t regAddr, uint8_t bitMask, uint8_t val)
{
    mcp2515_spi_select();//Select the MCP2515 on the SPI bus
    mcp2515_spi_transfer(MCP2515_BIT_MODIFY, NULL);
    mcp2515_spi_transfer(regAddr, NULL);
    mcp2515_spi_transfer(bitMask, NULL);
    mcp2515_spi_transfer(val, NULL);
    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus
}

void mcp2515_reset(void)
{
    mcp2515_spi_select();//Select the MCP2515 on the SPI bus
    mcp2515_spi_transfer(MCP2515_RESET, NULL);
    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus
}

void mcp2515_read_rx_buf(mcp2515_rx_t channel, mcp2515_can_frame_t *canData)
{
    uint8_t i;

    ASSERT(canData != NULL);

    mcp2515_spi_select();//Select the MCP2515 on the SPI bus

    switch (channel)
    {
        case mcp2515_rx_0:
            mcp2515_spi_transfer(MCP2515_READ_BUF_RXB0SIDH, NULL);
            break;
        case mcp2515_rx_1:
            mcp2515_spi_transfer(MCP2515_READ_BUF_RXB1SIDH, NULL);
            break;
        default:
            ASSERT(0);
            break;
    }
    id_read(&canData->id);

    // add by fz
    if(canData->id & 0x80000000UL)
    {
        canData->ext = 1;
        canData->id &= 0x1FFFFFFF;
    }
    else
    {
        canData->ext = 0;
        canData->id &= 0x1FFFFFFF;
        canData->id >>= 18;
    }

    mcp2515_spi_transfer(0, &canData->dlc);//read DLC
    canData->dlc &= 0x0F;
    for (i = 0; i < canData->dlc; i++)
    {
        mcp2515_spi_transfer(0, &canData->data[i]);
    }
    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus
}


void mcp2515_load_tx_buf(uint8_t nBuf, mcp2515_can_frame_t *canData)
{
    uint8_t i;

    ASSERT(canData != NULL);

    switch (nBuf)
    {
    case MCP2515_TX_BUF_0:
        mcp2515_spi_select();//Select the MCP2515 on the SPI bus
        mcp2515_spi_transfer(MCP2515_LOAD_BUF_TXB0SIDH, NULL);
        break;
    case MCP2515_TX_BUF_1:
        mcp2515_spi_select();//Select the MCP2515 on the SPI bus
        mcp2515_spi_transfer(MCP2515_LOAD_BUF_TXB1SIDH, NULL);
        break;
    case MCP2515_TX_BUF_2:
        mcp2515_spi_select();//Select the MCP2515 on the SPI bus
        mcp2515_spi_transfer(MCP2515_LOAD_BUF_TXB2SIDH, NULL);
        break;
    default:
        ASSERT(0);
        //break;
    }

    // add by fz
    if(canData->ext)
    {
        canData->id |= 0x80000000UL;
    }
    else
    {
        canData->id &= ~0x80000000UL;
        canData->id <<= 18;
    }
        
    id_write(canData->id);
    mcp2515_spi_transfer(canData->dlc & 0x0F, NULL);
    for (i = 0; (i < canData->dlc) && (i < MCP2515_MAX_BYTE_CANFRM); i++)
    {
        mcp2515_spi_transfer(canData->data[i], NULL);
    }
    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus
}

void mcp2515_rts(uint8_t nBuf)
{
    //uint8_t ubRetVal = SPI_OK;
    //uint8_t dataIn;

    mcp2515_spi_select();//Select the MCP2515 on the SPI bus

    switch (nBuf)
    {
    case MCP2515_TX_BUF_0:
        //mcp2515_spi_transfer(MCP2515_RTS_TXB0, &dataIn);
        mcp2515_spi_transfer(MCP2515_RTS_TXB0, NULL);
        break;
    case MCP2515_TX_BUF_1:
        //mcp2515_spi_transfer(MCP2515_RTS_TXB1, &dataIn);
        mcp2515_spi_transfer(MCP2515_RTS_TXB1, NULL);
        break;
    case MCP2515_TX_BUF_2:
        //mcp2515_spi_transfer(MCP2515_RTS_TXB2, &dataIn);
        mcp2515_spi_transfer(MCP2515_RTS_TXB2, NULL);
        break;
    default:
        ASSERT(0);
        //break;
    }
    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus
}

void mcp2515_read_rxtx_status(uint8_t* canRxTxStatus)
{
    ASSERT(canRxTxStatus != NULL);

    mcp2515_spi_select();//Select the MCP2515 on the SPI bus
    mcp2515_spi_transfer(MCP2515_READ_RXTX_STATUS, NULL);
    mcp2515_spi_transfer(0, canRxTxStatus);

    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus
}

void mcp2515_rx_status(uint8_t* canRxStatus)
{

    ASSERT(canRxStatus != NULL);

    mcp2515_spi_select();//Select the MCP2515 on the SPI bus
    mcp2515_spi_transfer(MCP2515_RX_STATUS, NULL);
    mcp2515_spi_transfer(0, canRxStatus);
    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus
}

void mcp2515_clear_interrupt(void)
{
    mcp2515_spi_select();//Select the MCP2515 on the SPI bus
    mcp2515_spi_transfer(MCP2515_WRITE, NULL);
    mcp2515_spi_transfer(MCP2515_CANINTF, NULL);
    mcp2515_spi_transfer(0, NULL);
    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus
}

void mcp2515_set_rx_filter_mask(mcp2515_rx_filter_mask_t regAddr, uint32_t canID, uint8_t ext)
{
    if(ext)
    {
        canID |= 0x80000000UL;
    }
    else
    {
        canID &= ~0x80000000UL;
        canID <<= 18;
    }
    mcp2515_spi_select();//Select the MCP2515 on the SPI bus
    mcp2515_spi_transfer(MCP2515_WRITE, NULL);
    mcp2515_spi_transfer((uint8_t)regAddr, NULL);
    id_write(canID);
    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus
}

int mcp2515_get_int_flag(void)
{
    uint8_t value;
    mcp2515_spi_select();//Select the MCP2515 on the SPI bus
    mcp2515_spi_transfer(MCP2515_READ, NULL);
    mcp2515_spi_transfer(MCP2515_CANINTF, NULL);
    mcp2515_spi_transfer(0, &value);
    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus

    return (int)value;
}

void mcp2515_set_op_mode(mcp2515_op_mode_t mode)
{
    bit_modify(MCP2515_CANCTRL, 0xE0, mode<<5);
}

void mcp2515_set_rx_op_mode(mcp2515_rx_t channel, mcp2515_rx_op_mode_t mode)
{
    switch(channel)
    {
        case mcp2515_rx_0:
            bit_modify(MCP2515_RXB0CTRL, 0x60, mode<<5);
            break;
        case mcp2515_rx_1:
            bit_modify(MCP2515_RXB1CTRL, 0x60, mode<<5);
            break;
        default:
            ASSERT(0);
            break;
    }
}

void mcp2515_enable_rx_int(mcp2515_rx_t channel)
{
    switch(channel)
    {
        case mcp2515_rx_0:
            bit_modify(MCP2515_CANINTE, 0x01, 0x01);
            break;
        case mcp2515_rx_1:
            bit_modify(MCP2515_CANINTE, 0x02, 0x02);
            break;
        default:
            ASSERT(0);
            break;
    }
}

void mcp2515_enable_tx_int(mcp2515_tx_t channel)
{
    switch(channel)
    {
        case mcp2515_tx_0:
            bit_modify(MCP2515_CANINTE, 0x04, 0x04);
            break;
        case mcp2515_tx_1:
            bit_modify(MCP2515_CANINTE, 0x08, 0x08);
            break;
        case mcp2515_tx_2:
            bit_modify(MCP2515_CANINTE, 0x10, 0x10);
            break;
        default:
            ASSERT(0);
            break;
    }
}
/* ---- Beispiel zum Einstellen des Bit Timings ----
 *	
 *	Fosc		= 16MHz
 *	BRP			= 1
 *	TQ 			= 2 * (BRP + 1) / Fosc
 *				= 1/4 uS
 *
 *	Sync Seg	= 					= 1 TQ
 *	Prop Seg	= (PRSEG + 1) * TQ	= 5 TQ
 *	Phase Seg1	= (PHSEG1 + 1) * TQ	= 6 TQ
 *	Phase Seg2	= (PHSEG2 + 1) * TQ = 4 TQ
 *									--------
 *									  16 TQ
 *	
 *	Bus speed	= 1 / ((Total # of TQ) * TQ)
 *				= 1 / (4 * TQ) = 250 kHz
 // 250 kbps
	{	0x03, // CNF3
		0xac, // CNF2
		0x81  // CNF1
	},
	// 500 kbps
	{	0x03,
		0xac,
		0x80
	},
 */
int mcp2515_set_baudrate(uint8_t bdr)
{
    Uint16 tmp = 0xFF; 
    #if 0
    static uint8_t prs, phs1, phs2, BRP, sjw;
    
    if(bdr == CAN_BAUD_250K)
    {
        BRP = 1;
        prs = 4;
        phs1 = 5;
        phs2 = 3;
        sjw = 2;
    }
    else
    {

        BRP = 0;
        prs = 4;
        phs1 = 5;
        phs2 = 3;
        sjw = 2;
    }

    //SET ALL THE REGISTER OF THE MCP 2515 FOR THE DESIRED BAUD RATE
    mcp2515_spi_select();//Select the MCP2515 on the SPI bus
    mcp2515_spi_transfer(MCP2515_WRITE, NULL);
    mcp2515_spi_transfer(MCP2515_CNF3, NULL);
    mcp2515_spi_transfer(phs2, NULL);//CF3
    mcp2515_spi_transfer(prs|(phs1<<3)|0x80, NULL);//CF2
    //CF1 : 1TQ for SJW and BRP = 5 for 1TQ = 12/F_CPU
    mcp2515_spi_transfer((sjw<<6)|BRP, NULL);
    mcp2515_spi_unselect();//Unselect the MCP2515 on the SPI bus

    #else
    write(MCP2515_CNF1, 0x81);
    write(MCP2515_CNF2, 0xAC);
    write(MCP2515_CNF3, 0x03);

    read(MCP2515_CNF1, &tmp);
    if(tmp != 0x81)
    {
        return 1; // err!
    }
    #endif

    return 0;
}

int16 mcp2515_sendmsg(struct canfd_frame *cf)
{
    cf->id = 0x1807E5F4;
    cf->ext = 1;
    mcp2515_load_tx_buf(MCP2515_TX_BUF_0, cf);
    mcp2515_rts(MCP2515_TX_BUF_0);

    return SUCCESS;
}

int16 mcp2515_recvmsg(struct canfd_frame *cf)
{
    Uint16 status;

#if USE_INT_STAT
    if(mcp2515_spi_transfer == spi_transfer_spia)
    {
        if(mcpa_int_stat())
            return FAILURE;
    }
    else if(mcp2515_spi_transfer == spi_transfer_spib)
    {
        if(mcpb_int_stat())
            return FAILURE;
    }
    else if(mcp2515_spi_transfer == spi_transfer_spic)
    {
        if(mcpc_int_stat())
            return FAILURE;
    }
    else if(mcp2515_spi_transfer == spi_transfer_spid)
    {
        if(mcpd_int_stat())
            return FAILURE;
    }
    else
    {
        if(mcpc_int_stat())
            return FAILURE;
    }
    
#else
    mcp2515_read_rxtx_status(&status);
    if((status&0x01) != 0x01) 
        return FAILURE;
        
#endif
    mcp2515_read_rx_buf(mcp2515_rx_0, cf);

    return SUCCESS;  
}
/*
int16 send_data_spia(struct canfd_frame *cf, Uint16 noblock)
{
    mcp2515_chn_select(MCP2515_SPIA);
    return mcp2515_sendmsg(cf);
}

int16 recv_data_spia(struct canfd_frame *cf, Uint16 noblock)
{
    mcp2515_chn_select(MCP2515_SPIA);
    return mcp2515_recvmsg(cf);
}
*/
Uint16 mcp2515_init(uint32_t canID, uint8_t ext)
{
    Uint16 err = 0;
    //mcp2515_spi_port_init();
    mcp2515_reset();
    DELAY_US(1000); // 1ms

    write(MCP2515_CANCTRL, 0);
    mcp2515_set_op_mode(mcp2515_op_mode_config);
    write(MCP2515_TXRTSCTRL, 0); // disable TXnRTS
    write(MCP2515_BFPCTRL, 0);   // disable RxnBF
    
    
#if USE_INT_STAT
    write(MCP2515_CANINTE, MCP2515_CANINT_RX0I); // RX0 interrupt enable
#else
    write(MCP2515_CANINTE, 0);
#endif

    write(MCP2515_RXB0CTRL, 0x60); // receive any message, Rollover disavle
    //mcp2515_set_rx_op_mode(mcp2515_rx_0, mcp2515_rx_op_mode_any);
    err = mcp2515_set_baudrate(CAN_BAUD_RATE);
    bit_modify(MCP2515_CANCTRL, 0x08, 1<<3); // one shot mode

    mcp2515_set_rx_filter_mask(mcp2515_rx_filter_mask_RXM0, 0x1FFFFFFF, ext);
    //mcp2515_set_rx_filter_mask(mcp2515_rx_filter_mask_RXM1, 0x1FFFFFFF, 0);

    //mcp2515_set_rx_filter_mask(mcp2515_rx_filter_mask_RXM0, 0x00000000, 0);
    //mcp2515_set_rx_filter_mask(mcp2515_rx_filter_mask_RXM1, 0x00000000, 0);

    mcp2515_set_rx_filter_mask(mcp2515_rx_filter_mask_RXF0, canID, ext);
    mcp2515_set_rx_op_mode(mcp2515_rx_0, mcp2515_rx_op_mode_filter_any);

    //mcp2515_set_rx_op_mode(mcp2515_rx_1, mcp2515_rx_op_mode_filter_any);
    //write(MCP2515_RXB0CTRL, 0);

    
    mcp2515_set_op_mode(mcp2515_op_mode_normal); 

    return err;
}

/*
void mcp2515_init_ext(uint32_t canID, uint32_t mask, uint8_t ext)
{
    mcp2515_set_op_mode(mcp2515_op_mode_config);
    write(MCP2515_RXB1CTRL, 0x62); // receive any message, Rollover disavle

    mcp2515_set_rx_filter_mask(mcp2515_rx_filter_mask_RXM1, mask, ext);

    mcp2515_set_rx_filter_mask(mcp2515_rx_filter_mask_RXF2, canID, ext);

    mcp2515_set_rx_op_mode(mcp2515_rx_1, mcp2515_rx_op_mode_filter_any);

    
    mcp2515_set_op_mode(mcp2515_op_mode_normal); 
}
*/
void mcp2515_init_ext(uint32_t canID1, uint32_t canID2, uint8_t ext)
{
    uint32_t mask = ~(canID1 ^ canID2) & 0x1FFFFFFF;
    //uint32_t mask = 0x00;
    
    mcp2515_set_op_mode(mcp2515_op_mode_config);
    write(MCP2515_RXB1CTRL, 0x62); // receive any message, Rollover disavle

    mcp2515_set_rx_filter_mask(mcp2515_rx_filter_mask_RXM1, mask, ext);

    mcp2515_set_rx_filter_mask(mcp2515_rx_filter_mask_RXF2, canID1, ext);

    //mcp2515_set_rx_op_mode(mcp2515_rx_1, mcp2515_rx_op_mode_filter_any);
    mcp2515_set_rx_op_mode(mcp2515_rx_1, mcp2515_rx_op_mode_any);

    
    mcp2515_set_op_mode(mcp2515_op_mode_normal); 
}

int16 mcp2515_sendext(struct canfd_frame *cf)
{

    mcp2515_load_tx_buf(MCP2515_TX_BUF_1, cf);
    mcp2515_rts(MCP2515_TX_BUF_1);

    return SUCCESS;
}

int16 mcp2515_recvext(struct canfd_frame *cf)
{
    Uint16 status;

    mcp2515_read_rxtx_status(&status);
    if((status&0x02) != 0x02) 
        return FAILURE;
        
    mcp2515_read_rx_buf(mcp2515_rx_1, cf);

    return SUCCESS;  
}



void spi_transfer_spia(Uint16 tdata, Uint16 *prdata)
{

    spi_transfer_chn(tdata, prdata, &SpiaRegs);
}
void spi_transfer_chn(Uint16 tdata, Uint16 *prdata, volatile struct SPI_REGS *pREGS)
{
    Uint16 tx = DUMMY_BYTE, rx = DUMMY_BYTE;
    
    if(prdata == NULL) tx = tdata;
    
    pREGS->SPITXBUF = tx << 8; // dummy write
    
    while(pREGS->SPISTS.bit.INT_FLAG != 1);
    // Check against sent data
    rx = pREGS->SPIRXBUF; // right-justified

    if(prdata != NULL) *prdata = rx;
}



给大家提供一个思路,在遇到相同的问题是可以减少码农的工作负担~~
  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: MCP2515是一种控制器区域网络(CAN)控制器芯片,而FPGA(可编程逻辑门阵列)是一种可编程的数字电路设备。MCP2515驱动程序是一种软件,用于控制FPGA来与MCP2515通信和操作。 通过MCP2515驱动程序,FPGA可以实现对CAN总线的控制和操作。MCP2515提供了CAN总线控制器所需的所有功能,包括消息传输、帧过滤和错误检测等。FPGA作为一个可编程的硬件设备,可以通过MCP2515驱动程序来配置和控制MCP2515的功能,实现CAN总线通信。 MCP2515驱动程序通过FPGA与MCP2515之间的SPI(串行外设接口)进行通信。SPI是一种串行数据交换协议,允许FPGA与外部设备进行通信。MCP2515驱动程序会定义SPI通信协议,包括数据传输速率、字节顺序和信号控制等。FPGA根据这些定义来与MCP2515进行通信,发送控制命令和接收数据。 通过MCP2515驱动程序,FPGA可以实现CAN总线的各种功能,如发送消息、接收消息和帧过滤等。FPGA可以根据MCP2515提供的控制寄存器来配置CAN总线的参数,如波特率和工作模式等。FPGA还可以根据MCP2515提供的接收缓冲区来接收CAN总线上的消息,并根据定义的过滤器进行帧过滤。 总之,通过MCP2515驱动程序,FPGA可以实现对MCP2515芯片的控制和操作。这样,FPGA可以作为一个功能强大且灵活可编程的平台,与MCP2515一起实现CAN总线的控制与通信。 ### 回答2: MCP2515是一款CAN总线控制器芯片,它具有高性能的SPI接口以及完整的CAN通信协议支持。FPGA是可编程逻辑芯片,可以通过配置内部逻辑电路来实现特定功能。因此,MCP2515驱动程序可以用于驱动FPGA模块与CAN总线之间的通信。 MCP2515驱动程序首先需要在FPGA中配置SPI接口,并将其与MCP2515进行连接。SPI接口是一种串行通信协议,通过发送和接收数据帧来实现FPGA与MCP2515之间的数据传输。驱动程序需要实现SPI接口的初始化、数据发送和接收等功能。通过配置SPI接口,驱动程序可以控制MCP2515的工作模式、寄存器读写以及CAN消息的发送和接收。 另外,MCP2515驱动程序还需要实现CAN通信协议的支持。CAN(Controller Area Network)是一种广泛应用于汽车、工业控制和嵌入式系统的串行通信协议,它具有高可靠性和实时性能。驱动程序需要解析CAN消息的标识符、数据和控制位,以实现CAN消息的发送和接收。同时,驱动程序还可以实现CAN消息的过滤、屏蔽和ACK等功能,以满足不同应用场景的需求。 在FPGA中使用MCP2515驱动程序,可以实现FPGA与CAN总线之间的高速数据传输和实时通信。这对于需要与CAN设备进行数据交换的应用非常重要,例如汽车电子、工业自动化和机器人控制等领域。同时,由于FPGA具有可编程性,驱动程序可以根据实际应用需求进行灵活配置和优化,以提高系统性能和可扩展性。 总结来说,MCP2515驱动程序可以用于驱动FPGA模块与CAN总线之间的通信。驱动程序需要实现SPI接口的配置和数据传输,以及CAN通信协议的解析和支持。这样的驱动程序可以实现高速实时数据传输和与CAN设备的可靠通信,为各种应用领域提供了强大的功能和灵活性。 ### 回答3: MCP2515是一款常用于CAN总线通信的控制器,而FPGA则是一种可编程逻辑器件。在使用MCP2515驱动程序时,FPGA可以作为控制器的主要载体,负责将MCP2515的功能集成进系统中。 首先,FPGA可以通过对MCP2515进行逻辑控制来完成CAN总线通信的主要功能。它可以配置和控制MCP2515的寄存器,设置CAN总线的通信速率、数据格式等参数。通过FPGA的逻辑控制,可以将MCP2515与其他外设进行连接,实现MCP2515与其他模块的数据交互。 其次,FPGA可以提供更多的灵活性和可编程性。通过使用Verilog或VHDL等硬件描述语言,可以在FPGA中实现更复杂的控制逻辑和算法。相比传统的固定功能芯片,FPGA可以根据具体应用的需求进行定制,从而提供更高的性能和定制化的功能。 此外,FPGA还可以与其他外设和传感器进行连接。例如,可以通过SPI接口将FPGA与MCP2515进行通信,并通过CAN总线与其他设备进行数据交换。FPGA还可以与处理器或微控制器等设备进行串口通信,实现更多的功能集成。 综上所述,将MCP2515驱动程序集成到FPGA中可以实现更高的灵活性和可编程性,同时可以与其他外设和处理器进行集成,提供更高级、更复杂的功能。这种集成方式为CAN总线通信提供了更多的应用场景和灵活性,适用于各种不同的工业控制和汽车电子等领域。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值