From d0575d1763a316f607068ae60d5fa5bc872be66a Mon Sep 17 00:00:00 2001 From: ttlappalainen Date: Wed, 13 Sep 2017 17:25:12 +0300 Subject: [PATCH] Applied changes to base on latest Seeed version - Backward compatibility should be OK. - mcp2515_write_canMsg and mcp2515_read_canMsg does transfer now with single SPI session by using SPI READ RX BUFFER and LOAD TX BUFFER - mcp2515_start_transmit uses directly SPI instruction RTS - removed internal data buffer. Read and write uses directly provided buffer - works with 8Mhz clock - Possible to set SPI. Some boards has 2 SPI. - Works with NMEA2000 library - New functions for better interrupt handling --- mcp_can.cpp | 1025 ++++++++++++++++++++++++++++++++----------------- mcp_can.h | 58 ++- mcp_can_dfs.h | 92 ++++- 3 files changed, 797 insertions(+), 378 deletions(-) diff --git a/mcp_can.cpp b/mcp_can.cpp index d58a481..fada5a3 100644 --- a/mcp_can.cpp +++ b/mcp_can.cpp @@ -21,6 +21,7 @@ Btetz Hurvajs xboxpro1 + ttlappalainen The MIT License (MIT) @@ -46,10 +47,107 @@ */ #include "mcp_can.h" -#define spi_readwrite SPI.transfer -#define spi_read() spi_readwrite(0x00) -#define SPI_BEGIN() SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)) -#define SPI_END() SPI.endTransaction() +#define spi_readwrite pSPI->transfer +#define spi_read() spi_readwrite(0x00) +#define spi_write(spi_val) spi_readwrite(spi_val) +#define SPI_BEGIN() pSPI->beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)) +#define SPI_END() pSPI->endTransaction() + +/********************************************************************************************************* +** Function name: txCtrlReg +** Descriptions: return tx ctrl reg according to tx buffer index. +** According to my tests this is faster and saves memory compared using vector +*********************************************************************************************************/ +byte txCtrlReg(byte i) { + switch (i) { + case 0: return MCP_TXB0CTRL; + case 1: return MCP_TXB1CTRL; + case 2: return MCP_TXB2CTRL; + } + return MCP_TXB2CTRL; +} + +/********************************************************************************************************* +** Function name: statusToBuffer +** Descriptions: converts CANINTF status to tx buffer index +*********************************************************************************************************/ +byte statusToTxBuffer(byte status) +{ + switch ( status ) { + case MCP_TX0IF : return 0; + case MCP_TX1IF : return 1; + case MCP_TX2IF : return 2; + } + + return 0xff; +} + +/********************************************************************************************************* +** Function name: statusToBuffer +** Descriptions: converts CANINTF status to tx buffer sidh +*********************************************************************************************************/ +byte statusToTxSidh(byte status) +{ + switch ( status ) { + case MCP_TX0IF : return MCP_TXB0SIDH; + case MCP_TX1IF : return MCP_TXB1SIDH; + case MCP_TX2IF : return MCP_TXB2SIDH; + } + + return 0; +} + +/********************************************************************************************************* +** Function name: txSidhToTxLoad +** Descriptions: return tx load command according to tx buffer sidh register +*********************************************************************************************************/ +byte txSidhToRTS(byte sidh) { + switch (sidh) { + case MCP_TXB0SIDH: return MCP_RTS_TX0; + case MCP_TXB1SIDH: return MCP_RTS_TX1; + case MCP_TXB2SIDH: return MCP_RTS_TX2; + } + return 0; +} + +/********************************************************************************************************* +** Function name: txSidhToTxLoad +** Descriptions: return tx load command according to tx buffer sidh register +*********************************************************************************************************/ +byte txSidhToTxLoad(byte sidh) { + switch (sidh) { + case MCP_TXB0SIDH: return MCP_LOAD_TX0; + case MCP_TXB1SIDH: return MCP_LOAD_TX1; + case MCP_TXB2SIDH: return MCP_LOAD_TX2; + } + return 0; +} + +/********************************************************************************************************* +** Function name: txIfFlag +** Descriptions: return tx interrupt flag +*********************************************************************************************************/ +byte txIfFlag(byte i) { + switch (i) { + case 0: return MCP_TX0IF; + case 1: return MCP_TX1IF; + case 2: return MCP_TX2IF; + } + return 0; +} + +/********************************************************************************************************* +** Function name: txStatusPendingFlag +** Descriptions: return buffer tx pending flag on status +*********************************************************************************************************/ +byte txStatusPendingFlag(byte i) { + switch (i) { + case 0: return MCP_STAT_TX0_PENDING; + case 1: return MCP_STAT_TX1_PENDING; + case 2: return MCP_STAT_TX2_PENDING; + } + return 0xff; +} /********************************************************************************************************* ** Function name: mcp2515_reset @@ -106,9 +204,9 @@ void MCP_CAN::mcp2515_readRegisterS(const byte address, byte values[], const byt spi_readwrite(MCP_READ); spi_readwrite(address); // mcp2515 has auto-increment of address-pointer - for(i=0; i 0) + if (res > 0) { #if DEBUG_EN - Serial.print("Enter setting mode fall\r\n"); + Serial.print("Enter setting mode fail\r\n"); #else - delay(10); + delay(10); #endif - return res; + return res; } #if DEBUG_EN Serial.print("Enter setting mode success \r\n"); @@ -407,14 +601,14 @@ byte MCP_CAN::mcp2515_init(const byte canSpeed) #endif // set boadrate - if(mcp2515_configRate(canSpeed)) + if (mcp2515_configRate(canSpeed, clock)) { #if DEBUG_EN - Serial.print("set rate fall!!\r\n"); + Serial.print("set rate fall!!\r\n"); #else - delay(10); + delay(10); #endif - return res; + return res; } #if DEBUG_EN Serial.print("set rate success!!\r\n"); @@ -422,81 +616,91 @@ byte MCP_CAN::mcp2515_init(const byte canSpeed) delay(10); #endif - if(res == MCP2515_OK) { + if ( res == MCP2515_OK ) { - // init canbuffers - mcp2515_initCANBuffers(); + // init canbuffers + mcp2515_initCANBuffers(); - // interrupt mode - mcp2515_setRegister(MCP_CANINTE, MCP_RX0IF | MCP_RX1IF); + // interrupt mode + mcp2515_setRegister(MCP_CANINTE, MCP_RX0IF | MCP_RX1IF); #if (DEBUG_RXANY==1) - // enable both receive-buffers to receive any message and enable rollover - mcp2515_modifyRegister(MCP_RXB0CTRL, - MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK, - MCP_RXB_RX_ANY | MCP_RXB_BUKT_MASK); - mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK, - MCP_RXB_RX_ANY); + // enable both receive-buffers to receive any message and enable rollover + mcp2515_modifyRegister(MCP_RXB0CTRL, + MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK, + MCP_RXB_RX_ANY | MCP_RXB_BUKT_MASK); + mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK, + MCP_RXB_RX_ANY); #else - // enable both receive-buffers to receive messages with std. and ext. identifiers and enable rollover - mcp2515_modifyRegister(MCP_RXB0CTRL, - MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK, - MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK); - mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK, - MCP_RXB_RX_STDEXT); + // enable both receive-buffers to receive messages with std. and ext. identifiers and enable rollover + mcp2515_modifyRegister(MCP_RXB0CTRL, + MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK, + MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK); + mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK, + MCP_RXB_RX_STDEXT); #endif - // enter normal mode - res = mcp2515_setCANCTRL_Mode(MODE_NORMAL); - if(res) - { + // enter normal mode + res = mcp2515_setCANCTRL_Mode(MODE_NORMAL); + if (res) + { #if DEBUG_EN - Serial.print("Enter Normal Mode Fall!!\r\n"); -#else - delay(10); -#endif - return res; - } - - -#if DEBUG_EN - Serial.print("Enter Normal Mode Success!!\r\n"); + Serial.print("Enter Normal Mode Fail!!\r\n"); #else delay(10); #endif + return res; + } + + +#if DEBUG_EN + Serial.print("Enter Normal Mode Success!!\r\n"); +#else + delay(10); +#endif } return res; } +/********************************************************************************************************* +** Function name: mcp2515_id_to_buf +** Descriptions: configure tbufdata[4] from id and ext +*********************************************************************************************************/ +void mcp2515_id_to_buf(const byte ext, const unsigned long id, byte *tbufdata) +{ + uint16_t canid; + + canid = (uint16_t)(id & 0x0FFFF); + + if ( ext == 1) + { + tbufdata[MCP_EID0] = (byte) (canid & 0xFF); + tbufdata[MCP_EID8] = (byte) (canid >> 8); + canid = (uint16_t)(id >> 16); + tbufdata[MCP_SIDL] = (byte) (canid & 0x03); + tbufdata[MCP_SIDL] += (byte) ((canid & 0x1C) << 3); + tbufdata[MCP_SIDL] |= MCP_TXB_EXIDE_M; + tbufdata[MCP_SIDH] = (byte) (canid >> 5 ); + } + else + { + tbufdata[MCP_SIDH] = (byte) (canid >> 3 ); + tbufdata[MCP_SIDL] = (byte) ((canid & 0x07 ) << 5); + tbufdata[MCP_EID0] = 0; + tbufdata[MCP_EID8] = 0; + } +} + /********************************************************************************************************* ** Function name: mcp2515_write_id ** Descriptions: write can id *********************************************************************************************************/ void MCP_CAN::mcp2515_write_id(const byte mcp_addr, const byte ext, const unsigned long id) { - uint16_t canid; byte tbufdata[4]; - canid = (uint16_t)(id & 0x0FFFF); - - if(ext == 1) - { - tbufdata[MCP_EID0] = (byte) (canid & 0xFF); - tbufdata[MCP_EID8] = (byte) (canid >> 8); - canid = (uint16_t)(id >> 16); - tbufdata[MCP_SIDL] = (byte) (canid & 0x03); - tbufdata[MCP_SIDL] += (byte) ((canid & 0x1C) << 3); - tbufdata[MCP_SIDL] |= MCP_TXB_EXIDE_M; - tbufdata[MCP_SIDH] = (byte) (canid >> 5); - } - else - { - tbufdata[MCP_SIDH] = (byte) (canid >> 3); - tbufdata[MCP_SIDL] = (byte) ((canid & 0x07) << 5); - tbufdata[MCP_EID0] = 0; - tbufdata[MCP_EID8] = 0; - } + mcp2515_id_to_buf(ext,id,tbufdata); mcp2515_setRegisterS(mcp_addr, tbufdata, 4); } @@ -513,113 +717,195 @@ void MCP_CAN::mcp2515_read_id(const byte mcp_addr, byte* ext, unsigned long* id) mcp2515_readRegisterS(mcp_addr, tbufdata, 4); - *id = (tbufdata[MCP_SIDH]<<3) + (tbufdata[MCP_SIDL]>>5); + *id = (tbufdata[MCP_SIDH] << 3) + (tbufdata[MCP_SIDL] >> 5); - if((tbufdata[MCP_SIDL] & MCP_TXB_EXIDE_M) == MCP_TXB_EXIDE_M) + if ( (tbufdata[MCP_SIDL] & MCP_TXB_EXIDE_M) == MCP_TXB_EXIDE_M ) { - // extended id - *id = (*id<<2) + (tbufdata[MCP_SIDL] & 0x03); - *id = (*id<<8) + tbufdata[MCP_EID8]; - *id = (*id<<8) + tbufdata[MCP_EID0]; - *ext = 1; + // extended id + *id = (*id << 2) + (tbufdata[MCP_SIDL] & 0x03); + *id = (*id << 8) + tbufdata[MCP_EID8]; + *id = (*id << 8) + tbufdata[MCP_EID0]; + *ext = 1; } } /********************************************************************************************************* ** Function name: mcp2515_write_canMsg ** Descriptions: write msg +** Note! There is no check for right address! *********************************************************************************************************/ -void MCP_CAN::mcp2515_write_canMsg(const byte buffer_sidh_addr, int rtrBit) +void MCP_CAN::mcp2515_write_canMsg(const byte buffer_sidh_addr, unsigned long id, byte ext, byte rtrBit, byte len, volatile const byte *buf) { - byte mcp_addr; - mcp_addr = buffer_sidh_addr; - mcp2515_setRegisterS(mcp_addr+5, dta, dta_len); // write data bytes - // Serial.print("RTR: "); - // Serial.println(rtrBit); - if(rtrBit == 1) // if RTR set bit in byte - { - dta_len |= MCP_RTR_MASK; - } - mcp2515_setRegister((mcp_addr+4), dta_len); // write the RTR and DLC - mcp2515_write_id(mcp_addr, ext_flg, can_id); // write CAN id + byte load_addr=txSidhToTxLoad(buffer_sidh_addr); + + byte tbufdata[4]; + byte dlc = len | ( rtrBit ? MCP_RTR_MASK : 0 ) ; + byte i; + mcp2515_id_to_buf(ext,id,tbufdata); + +#ifdef SPI_HAS_TRANSACTION + SPI_BEGIN(); +#endif + MCP2515_SELECT(); + spi_readwrite(load_addr); + for (i = 0; i < 4; i++) spi_write(tbufdata[i]); + spi_write(dlc); + for (i = 0; i < len && i> 5); - mcp_addr = buffer_sidh_addr; - mcp2515_read_id(mcp_addr, &ext_flg,&can_id); - ctrl = mcp2515_readRegister(mcp_addr-1); - dta_len = mcp2515_readRegister(mcp_addr+4); - - rtr = (ctrl & 0x08) ? 1 : 0; - - dta_len &= MCP_DLC_MASK; - mcp2515_readRegisterS(mcp_addr+5, &(dta[0]), dta_len); + if ( (tbufdata[MCP_SIDL] & MCP_TXB_EXIDE_M) == MCP_TXB_EXIDE_M ) + { + /* extended id */ + *id = (*id << 2) + (tbufdata[MCP_SIDL] & 0x03); + *id = (*id << 8) + tbufdata[MCP_EID8]; + *id = (*id << 8) + tbufdata[MCP_EID0]; + *ext = 1; + } + + *len=spi_read() & MCP_DLC_MASK; + for (i = 0; i < *len && i=MCP_N_TXBUFFERS || + (mcp2515_readStatus() & txStatusPendingFlag(iBuf))!=0 ) return MCP_ALLTXBUSY; + + *txbuf_n = txCtrlReg(iBuf) + 1; /* return SIDH-address of Buffer */ + mcp2515_modifyRegister(MCP_CANINTF, txIfFlag(iBuf), 0); + + return MCP2515_OK; } /********************************************************************************************************* ** Function name: mcp2515_getNextFreeTXBuf -** Descriptions: get Next free txbuf +** Descriptions: finds next free tx buffer for sending. Return MCP_ALLTXBUSY, if there is none. *********************************************************************************************************/ byte MCP_CAN::mcp2515_getNextFreeTXBuf(byte *txbuf_n) // get Next free txbuf { - byte res, i, ctrlval; - byte ctrlregs[MCP_N_TXBUFFERS] = { MCP_TXB0CTRL, MCP_TXB1CTRL, MCP_TXB2CTRL }; + byte status=mcp2515_readStatus() & MCP_STAT_TX_PENDING_MASK; + byte i; - res = MCP_ALLTXBUSY; *txbuf_n = 0x00; + + if ( status==MCP_STAT_TX_PENDING_MASK ) return MCP_ALLTXBUSY; // All buffers are pending - // check all 3 TX-Buffers - for(i=0; ibegin(); + byte res = mcp2515_init(speedset, clockset); return ((res == MCP2515_OK) ? CAN_OK : CAN_FAILINIT); } +/********************************************************************************************************* +** Function name: enableTxInterrupt +** Descriptions: enable interrupt for all tx buffers +*********************************************************************************************************/ +void MCP_CAN::enableTxInterrupt(bool enable) +{ + byte interruptStatus=mcp2515_readRegister(MCP_CANINTE); + + if ( enable ) { + interruptStatus |= MCP_TX_INT; + } else { + interruptStatus &= ~MCP_TX_INT; + } + + mcp2515_setRegister(MCP_CANINTE, interruptStatus); +} + /********************************************************************************************************* ** Function name: init_Mask ** Descriptions: init canid Masks @@ -633,7 +919,7 @@ byte MCP_CAN::init_Mask(byte num, byte ext, unsigned long ulData) delay(10); #endif res = mcp2515_setCANCTRL_Mode(MODE_CONFIG); - if(res > 0){ + if (res > 0) { #if DEBUG_EN Serial.print("Enter setting mode fall\r\n"); #else @@ -642,17 +928,17 @@ byte MCP_CAN::init_Mask(byte num, byte ext, unsigned long ulData) return res; } - if(num == 0){ + if (num == 0) { mcp2515_write_id(MCP_RXM0SIDH, ext, ulData); } - else if(num == 1){ + else if (num == 1) { mcp2515_write_id(MCP_RXM1SIDH, ext, ulData); } else res = MCP2515_FAIL; res = mcp2515_setCANCTRL_Mode(MODE_NORMAL); - if(res > 0){ + if (res > 0) { #if DEBUG_EN Serial.print("Enter normal mode fall\r\n"); #else @@ -681,7 +967,7 @@ byte MCP_CAN::init_Filt(byte num, byte ext, unsigned long ulData) delay(10); #endif res = mcp2515_setCANCTRL_Mode(MODE_CONFIG); - if(res > 0) + if (res > 0) { #if DEBUG_EN Serial.print("Enter setting mode fall\r\n"); @@ -691,38 +977,38 @@ byte MCP_CAN::init_Filt(byte num, byte ext, unsigned long ulData) return res; } - switch(num) + switch ( num ) { - case 0: + case 0: mcp2515_write_id(MCP_RXF0SIDH, ext, ulData); break; - case 1: + case 1: mcp2515_write_id(MCP_RXF1SIDH, ext, ulData); break; - case 2: + case 2: mcp2515_write_id(MCP_RXF2SIDH, ext, ulData); break; - case 3: + case 3: mcp2515_write_id(MCP_RXF3SIDH, ext, ulData); break; - case 4: + case 4: mcp2515_write_id(MCP_RXF4SIDH, ext, ulData); break; - case 5: + case 5: mcp2515_write_id(MCP_RXF5SIDH, ext, ulData); break; - default: + default: res = MCP2515_FAIL; } res = mcp2515_setCANCTRL_Mode(MODE_NORMAL); - if(res > 0) + if (res > 0) { #if DEBUG_EN Serial.print("Enter normal mode fall\r\nSet filter fail!!\r\n"); @@ -741,85 +1027,82 @@ byte MCP_CAN::init_Filt(byte num, byte ext, unsigned long ulData) } /********************************************************************************************************* -** Function name: setMsg -** Descriptions: set can message, such as dlc, id, dta[] and so on +** Function name: sendMsgBuf +** Descriptions: Send message by using buffer read as free from CANINTF status +** Status has to be read with readRxTxStatus and filtered with checkClearTxStatus *********************************************************************************************************/ -byte MCP_CAN::setMsg(unsigned long id, byte ext, byte len, byte rtr, byte *pData) +byte MCP_CAN::sendMsgBuf(byte status, unsigned long id, byte ext, byte rtrBit, byte len, volatile const byte *buf) { - ext_flg = ext; - can_id = id; - dta_len = min(len, MAX_CHAR_IN_MESSAGE); - rtr = rtr; - for(int i = 0; i 0) delayMicroseconds(10); res = mcp2515_getNextFreeTXBuf(&txbuf_n); // info = addr. uiTimeOut++; } while (res == MCP_ALLTXBUSY && (uiTimeOut < TIMEOUTVALUE)); - if(uiTimeOut == TIMEOUTVALUE) + if (uiTimeOut == TIMEOUTVALUE) { return CAN_GETTXBFTIMEOUT; // get tx buff time out } + mcp2515_write_canMsg(txbuf_n, id, ext, rtrBit, len, buf); - uiTimeOut = 0; - mcp2515_write_canMsg(txbuf_n, rtrBit); - mcp2515_start_transmit(txbuf_n); + if (wait_sent) { + uiTimeOut = 0; + do + { + if (uiTimeOut > 0) delayMicroseconds(10); + uiTimeOut++; + res1 = mcp2515_readRegister(txbuf_n - 1); // read send buff ctrl reg + res1 = res1 & 0x08; + } while (res1 && (uiTimeOut < TIMEOUTVALUE)); - do { - uiTimeOut++; - res1= mcp2515_readRegister(txbuf_n-1 /* the ctrl reg is located at txbuf_n-1 */); // read send buff ctrl reg - res1 = res1 & 0x08; - }while(res1 && (uiTimeOut < TIMEOUTVALUE)); - - if(uiTimeOut == TIMEOUTVALUE) // send msg timeout - { - return CAN_SENDMSGTIMEOUT; + if (uiTimeOut == TIMEOUTVALUE) // send msg timeout + { + return CAN_SENDMSGTIMEOUT; + } } + return CAN_OK; } @@ -828,74 +1111,28 @@ byte MCP_CAN::sendMsg(int rtrBit) ** Function name: sendMsgBuf ** Descriptions: send buf *********************************************************************************************************/ -byte MCP_CAN::sendMsgBuf(unsigned long id, byte ext, byte rtr, byte len, byte *buf) +byte MCP_CAN::sendMsgBuf(unsigned long id, byte ext, byte rtrBit, byte len, const byte *buf, bool wait_sent) { - setMsg(id, ext, len, rtr, buf); - // Serial.print("RTR00: "); - // Serial.println(rtr, HEX); - return sendMsg(rtr); + return sendMsg(id,ext,rtrBit,len,buf,wait_sent); } /********************************************************************************************************* ** Function name: sendMsgBuf ** Descriptions: send buf *********************************************************************************************************/ -byte MCP_CAN::sendMsgBuf(unsigned long id, byte ext, byte len, byte *buf) +byte MCP_CAN::sendMsgBuf(unsigned long id, byte ext, byte len, const byte *buf, bool wait_sent) { - setMsg(id, ext, len, buf); - return sendMsg(0); + return sendMsg(id,ext,0,len,buf,wait_sent); } -/********************************************************************************************************* -** Function name: readMsg -** Descriptions: read message -*********************************************************************************************************/ -byte MCP_CAN::readMsg() -{ - byte stat, res; - - stat = mcp2515_readStatus(); - - if(stat & MCP_STAT_RX0IF) // Msg in Buffer 0 - { - mcp2515_read_canMsg(MCP_RXBUF_0); - mcp2515_modifyRegister(MCP_CANINTF, MCP_RX0IF, 0); - res = CAN_OK; - } - else if(stat & MCP_STAT_RX1IF) // Msg in Buffer 1 - { - mcp2515_read_canMsg(MCP_RXBUF_1); - mcp2515_modifyRegister(MCP_CANINTF, MCP_RX1IF, 0); - res = CAN_OK; - } - else - { - res = CAN_NOMSG; - } - return res; -} - /********************************************************************************************************* ** Function name: readMsgBuf ** Descriptions: read message buf *********************************************************************************************************/ byte MCP_CAN::readMsgBuf(byte *len, byte buf[]) { - byte rc; - - rc = readMsg(); - - if(rc == CAN_OK) { - *len = dta_len; - for(int i = 0; i