diff --git a/extras/acan2515.pdf b/extras/acan2515.pdf index c7d8503..68932c8 100644 Binary files a/extras/acan2515.pdf and b/extras/acan2515.pdf differ diff --git a/library.properties b/library.properties index cb431a7..b486823 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ACAN2515 -version=2.0.7 +version=2.0.8 author=Pierre Molinaro maintainer=Pierre Molinaro sentence=Driver for MCP2515 CAN Controller diff --git a/src/ACAN2515.cpp b/src/ACAN2515.cpp index c0b6ab3..aa5c7b6 100644 --- a/src/ACAN2515.cpp +++ b/src/ACAN2515.cpp @@ -1,14 +1,14 @@ -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // A CAN driver for MCP2515 // by Pierre Molinaro // https://github.com/pierremolinaro/acan2515 -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· #include -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // MCP2515 COMMANDS -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· static const uint8_t RESET_COMMAND = 0xC0 ; static const uint8_t WRITE_COMMAND = 0x02 ; @@ -21,9 +21,9 @@ static const uint8_t READ_FROM_RXB1SIDH_COMMAND = 0x94 ; static const uint8_t READ_STATUS_COMMAND = 0xA0 ; static const uint8_t RX_STATUS_COMMAND = 0xB0 ; -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // MCP2515 REGISTERS -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· static const uint8_t BFPCTRL_REGISTER = 0x0C ; static const uint8_t TXRTSCTRL_REGISTER = 0x0D ; @@ -37,6 +37,7 @@ static const uint8_t CNF3_REGISTER = 0x28 ; static const uint8_t CNF2_REGISTER = 0x29 ; static const uint8_t CNF1_REGISTER = 0x2A ; static const uint8_t CANINTF_REGISTER = 0x2C ; +static const uint8_t EFLG_REGISTER = 0x2D ; static const uint8_t TXB0CTRL_REGISTER = 0x30 ; static const uint8_t TXB1CTRL_REGISTER = 0x40 ; static const uint8_t TXB2CTRL_REGISTER = 0x50 ; @@ -45,10 +46,10 @@ static const uint8_t RXB1CTRL_REGISTER = 0x70 ; static const uint8_t RXFSIDH_REGISTER [6] = {0x00, 0x04, 0x08, 0x10, 0x14, 0x18} ; -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // Note about ESP32 -//---------------------------------------------------------------------------------------------------------------------- - +//·································································································· +// // It appears that Arduino ESP32 interrupts are managed in a completely different way from "usual" Arduino: // - SPI.usingInterrupt is not implemented; // - noInterrupts() and interrupts() are NOPs; @@ -62,7 +63,7 @@ static const uint8_t RXFSIDH_REGISTER [6] = {0x00, 0x04, 0x08, 0x10, 0x14, 0x18} // - as this task runs in parallel with setup / loop routines, SPI access is natively protected by the // beginTransaction / endTransaction pair, that manages a mutex. -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· #ifdef ARDUINO_ARCH_ESP32 static void myESP32Task (void * pData) { @@ -77,9 +78,9 @@ static const uint8_t RXFSIDH_REGISTER [6] = {0x00, 0x04, 0x08, 0x10, 0x14, 0x18} } #endif -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // CONSTRUCTOR, HARDWARE SPI -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· ACAN2515::ACAN2515 (const uint8_t inCS, // CS input of MCP2515 SPIClass & inSPI, // Hardware SPI object @@ -99,9 +100,9 @@ mTXBIsFree () { } } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // BEGIN -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· uint16_t ACAN2515::begin (const ACAN2515Settings & inSettings, void (* inInterruptServiceRoutine) (void)) { @@ -109,7 +110,7 @@ uint16_t ACAN2515::begin (const ACAN2515Settings & inSettings, return beginWithoutFilterCheck (inSettings, inInterruptServiceRoutine, ACAN2515Mask (), ACAN2515Mask (), NULL, 0) ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· uint16_t ACAN2515::begin (const ACAN2515Settings & inSettings, void (* inInterruptServiceRoutine) (void), @@ -130,7 +131,7 @@ uint16_t ACAN2515::begin (const ACAN2515Settings & inSettings, return errorCode ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· uint16_t ACAN2515::begin (const ACAN2515Settings & inSettings, void (* inInterruptServiceRoutine) (void), @@ -152,7 +153,7 @@ uint16_t ACAN2515::begin (const ACAN2515Settings & inSettings, return errorCode ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· uint16_t ACAN2515::beginWithoutFilterCheck (const ACAN2515Settings & inSettings, void (* inInterruptServiceRoutine) (void), @@ -211,9 +212,9 @@ uint16_t ACAN2515::beginWithoutFilterCheck (const ACAN2515Settings & inSettings, return errorCode ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // MESSAGE RECEPTION -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· bool ACAN2515::available (void) { #ifdef ARDUINO_ARCH_ESP32 @@ -230,7 +231,7 @@ bool ACAN2515::available (void) { return hasReceivedMessage ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· bool ACAN2515::receive (CANMessage & outMessage) { #ifdef ARDUINO_ARCH_ESP32 @@ -248,7 +249,7 @@ bool ACAN2515::receive (CANMessage & outMessage) { return hasReceivedMessage ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· bool ACAN2515::dispatchReceivedMessage (const tFilterMatchCallBack inFilterMatchCallBack) { CANMessage receivedMessage ; @@ -266,9 +267,9 @@ bool ACAN2515::dispatchReceivedMessage (const tFilterMatchCallBack inFilterMatch return hasReceived ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // INTERRUPTS ARE DISABLED WHEN THESE FUNCTIONS ARE EXECUTED -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· uint16_t ACAN2515::internalBeginOperation (const ACAN2515Settings & inSettings, const ACAN2515Mask inRXM0, @@ -416,9 +417,9 @@ uint16_t ACAN2515::internalBeginOperation (const ACAN2515Settings & inSettings, return errorCode ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // setRequestedMode (private method) -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· uint16_t ACAN2515::setRequestedMode (const uint8_t inCANControlRegister) { uint16_t errorCode = 0 ; @@ -443,9 +444,9 @@ uint16_t ACAN2515::setRequestedMode (const uint8_t inCANControlRegister) { return errorCode ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // Change Mode -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· uint16_t ACAN2515::changeModeOnTheFly (const ACAN2515Settings::RequestedMode inRequestedMode) { //--- Read current mode register (for saving settings of bits 0 ... 4) @@ -460,15 +461,15 @@ uint16_t ACAN2515::changeModeOnTheFly (const ACAN2515Settings::RequestedMode inR return errorCode ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // Set filters on the fly -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· uint16_t ACAN2515::setFiltersOnTheFly (void) { return internalSetFiltersOnTheFly (ACAN2515Mask (), ACAN2515Mask (), NULL, 0) ; } -//······················································································································ +//·································································································· uint16_t ACAN2515::setFiltersOnTheFly (const ACAN2515Mask inRXM0, const ACAN2515AcceptanceFilter inAcceptanceFilters [], @@ -486,7 +487,7 @@ uint16_t ACAN2515::setFiltersOnTheFly (const ACAN2515Mask inRXM0, return errorCode ; } -//······················································································································ +//·································································································· uint16_t ACAN2515::setFiltersOnTheFly (const ACAN2515Mask inRXM0, const ACAN2515Mask inRXM1, @@ -505,7 +506,7 @@ uint16_t ACAN2515::setFiltersOnTheFly (const ACAN2515Mask inRXM0, return errorCode ; } -//······················································································································ +//·································································································· uint16_t ACAN2515::internalSetFiltersOnTheFly (const ACAN2515Mask inRXM0, const ACAN2515Mask inRXM1, @@ -544,9 +545,9 @@ uint16_t ACAN2515::internalSetFiltersOnTheFly (const ACAN2515Mask inRXM0, return errorCode ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // end -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· void ACAN2515::end (void) { //--- Remove interrupt capability of mINT pin @@ -564,9 +565,9 @@ void ACAN2515::end (void) { } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // POLLING (ESP32) -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· #ifdef ARDUINO_ARCH_ESP32 void ACAN2515::poll (void) { @@ -574,9 +575,9 @@ void ACAN2515::end (void) { } #endif -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // POLLING (other than ESP32) -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· #ifndef ARDUINO_ARCH_ESP32 void ACAN2515::poll (void) { @@ -586,10 +587,10 @@ void ACAN2515::end (void) { } #endif -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // INTERRUPT SERVICE ROUTINE (ESP32) // https://stackoverflow.com/questions/51750377/how-to-disable-interrupt-watchdog-in-esp32-or-increase-isr-time-limit -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· #ifdef ARDUINO_ARCH_ESP32 void ACAN2515::isr (void) { @@ -599,9 +600,9 @@ void ACAN2515::end (void) { } #endif -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // INTERRUPT SERVICE ROUTINE (other than ESP32) -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· #ifndef ARDUINO_ARCH_ESP32 void ACAN2515::isr (void) { @@ -609,7 +610,7 @@ void ACAN2515::end (void) { } #endif -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· bool ACAN2515::isr_core (void) { bool handled = false ; @@ -646,7 +647,7 @@ bool ACAN2515::isr_core (void) { return handled ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // This function is called by ISR when a MCP2515 receive buffer becomes full void ACAN2515::handleRXBInterrupt (void) { @@ -701,7 +702,7 @@ void ACAN2515::handleRXBInterrupt (void) { } } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // This function is called by ISR when a MCP2515 transmit buffer becomes empty void ACAN2515::handleTXBInterrupt (const uint8_t inTXB) { // inTXB value is 0, 1 or 2 @@ -717,7 +718,7 @@ void ACAN2515::handleTXBInterrupt (const uint8_t inTXB) { // inTXB value is 0, 1 } } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· void ACAN2515::internalSendMessage (const CANMessage & inFrame, const uint8_t inTXB) { // inTXB is 0, 1 or 2 //--- Send command @@ -774,9 +775,9 @@ void ACAN2515::internalSendMessage (const CANMessage & inFrame, const uint8_t in unselect () ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // INTERNAL SPI FUNCTIONS -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· void ACAN2515::write2515Register (const uint8_t inRegister, const uint8_t inValue) { select () ; @@ -786,7 +787,7 @@ void ACAN2515::write2515Register (const uint8_t inRegister, const uint8_t inValu unselect () ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· uint8_t ACAN2515::read2515Register (const uint8_t inRegister) { select () ; @@ -797,7 +798,7 @@ uint8_t ACAN2515::read2515Register (const uint8_t inRegister) { return readValue ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· uint8_t ACAN2515::read2515Status (void) { select () ; @@ -807,7 +808,7 @@ uint8_t ACAN2515::read2515Status (void) { return readValue ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· uint8_t ACAN2515::read2515RxStatus (void) { select () ; @@ -817,7 +818,7 @@ uint8_t ACAN2515::read2515RxStatus (void) { return readValue ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· void ACAN2515::bitModify2515Register (const uint8_t inRegister, const uint8_t inMask, @@ -830,7 +831,7 @@ void ACAN2515::bitModify2515Register (const uint8_t inRegister, unselect () ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· void ACAN2515::setupMaskRegister (const ACAN2515Mask inMask, const uint8_t inRegister) { select () ; @@ -843,9 +844,9 @@ void ACAN2515::setupMaskRegister (const ACAN2515Mask inMask, const uint8_t inReg unselect () ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· // MCP2515 controller state -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· uint8_t ACAN2515::transmitErrorCounter (void) { mSPI.beginTransaction (mSPISettings) ; @@ -854,7 +855,7 @@ uint8_t ACAN2515::transmitErrorCounter (void) { return result ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· uint8_t ACAN2515::receiveErrorCounter (void) { mSPI.beginTransaction (mSPISettings) ; @@ -863,9 +864,18 @@ uint8_t ACAN2515::receiveErrorCounter (void) { return result ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· + +uint8_t ACAN2515::errorFlagRegister (void) { + mSPI.beginTransaction (mSPISettings) ; + const uint8_t result = read2515Register (EFLG_REGISTER) ; + mSPI.endTransaction () ; + return result ; +} + +//·································································································· // MESSAGE EMISSION -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· bool ACAN2515::tryToSend (const CANMessage & inMessage) { //--- Fix send buffer index @@ -893,4 +903,4 @@ bool ACAN2515::tryToSend (const CANMessage & inMessage) { return ok ; } -//---------------------------------------------------------------------------------------------------------------------- +//·································································································· diff --git a/src/ACAN2515.h b/src/ACAN2515.h index 6b878f8..c6705db 100644 --- a/src/ACAN2515.h +++ b/src/ACAN2515.h @@ -17,18 +17,18 @@ class ACAN2515 { -//······················································································································ +//·································································································· // Constructor: using hardware SPI -//······················································································································ +//·································································································· public: ACAN2515 (const uint8_t inCS, // CS input of MCP2515 SPIClass & inSPI, // Hardware SPI object const uint8_t inINT) ; // INT output of MCP2515 -//······················································································································ +//·································································································· // Initialisation: returns 0 if ok, otherwise see error codes below -//······················································································································ +//·································································································· public: uint16_t begin (const ACAN2515Settings & inSettings, void (* inInterruptServiceRoutine) (void)) ; @@ -46,9 +46,9 @@ class ACAN2515 { const ACAN2515AcceptanceFilter inAcceptanceFilters [], const uint8_t inAcceptanceFilterCount) ; -//······················································································································ +//·································································································· // Error codes returned by begin -//······················································································································ +//·································································································· public: static const uint16_t kNoMCP2515 = 1 << 0 ; public: static const uint16_t kTooFarFromDesiredBitRate = 1 << 1 ; @@ -66,16 +66,16 @@ class ACAN2515 { public: static const uint32_t kISRNotNullAndNoIntPin = 1 << 13 ; -//······················································································································ +//·································································································· // Change Mode on the fly -//······················································································································ +//·································································································· public: uint16_t changeModeOnTheFly (const ACAN2515Settings::RequestedMode inRequestedMode) ; -//······················································································································ +//·································································································· // Set filters on the fly -//······················································································································ +//·································································································· public: uint16_t setFiltersOnTheFly (void) ; @@ -89,16 +89,16 @@ class ACAN2515 { const uint8_t inAcceptanceFilterCount) ; -//······················································································································ +//·································································································· // end -//······················································································································ +//·································································································· public: void end (void) ; -//······················································································································ +//·································································································· // Receiving messages -//······················································································································ +//·································································································· public: bool available (void) ; @@ -109,9 +109,9 @@ class ACAN2515 { public: bool dispatchReceivedMessage (const tFilterMatchCallBack inFilterMatchCallBack = NULL) ; -//······················································································································ +//·································································································· // Handling messages to send and receiving messages -//······················································································································ +//·································································································· public: void isr (void) ; public: bool isr_core (void) ; @@ -119,9 +119,9 @@ class ACAN2515 { private: void handleRXBInterrupt (void) ; -//······················································································································ +//·································································································· // Properties -//······················································································································ +//·································································································· private: SPIClass & mSPI ; private: const SPISettings mSPISettings ; @@ -132,57 +132,57 @@ class ACAN2515 { #endif -//······················································································································ +//·································································································· // Receive buffer -//······················································································································ +//·································································································· private: ACANBuffer16 mReceiveBuffer ; -//······················································································································ +//·································································································· // Receive buffer size -//······················································································································ +//·································································································· public: inline uint16_t receiveBufferSize (void) const { return mReceiveBuffer.size () ; } -//······················································································································ +//·································································································· // Receive buffer count -//······················································································································ +//·································································································· public: inline uint16_t receiveBufferCount (void) const { return mReceiveBuffer.count () ; } -//······················································································································ +//·································································································· // Receive buffer peak count -//······················································································································ +//·································································································· public: inline uint16_t receiveBufferPeakCount (void) const { return mReceiveBuffer.peakCount () ; } -//······················································································································ +//·································································································· // Call back function array -//······················································································································ +//·································································································· private: ACANCallBackRoutine mCallBackFunctionArray [6] ; -//······················································································································ +//·································································································· // Transmitting messages -//······················································································································ +//·································································································· public: bool tryToSend (const CANMessage & inMessage) ; -//······················································································································ +//·································································································· // Driver transmit buffer -//······················································································································ +//·································································································· private: ACANBuffer16 mTransmitBuffer [3] ; private: bool mTXBIsFree [3] ; @@ -201,16 +201,16 @@ class ACAN2515 { private: void internalSendMessage (const CANMessage & inFrame, const uint8_t inTXB) ; -//······················································································································ +//·································································································· // Polling -//······················································································································ +//·································································································· public: void poll (void) ; -//······················································································································ +//·································································································· // Private methods -//······················································································································ +//·································································································· private: inline void select (void) { digitalWrite (mCS, LOW) ; } @@ -250,22 +250,23 @@ class ACAN2515 { const uint8_t inAcceptanceFilterCount) ; -//······················································································································ +//·································································································· // MCP2515 controller state -//······················································································································ +//·································································································· public: uint8_t receiveErrorCounter (void) ; public: uint8_t transmitErrorCounter (void) ; + public: uint8_t errorFlagRegister (void) ; -//······················································································································ +//·································································································· // No Copy -//······················································································································ +//·································································································· private: ACAN2515 (const ACAN2515 &) = delete ; private: ACAN2515 & operator = (const ACAN2515 &) = delete ; -//······················································································································ +//·································································································· } ;