diff --git a/examples/NoRetransmissionAttemptsDemoTeensy3x/NoRetransmissionAttemptsDemoTeensy3x.ino b/examples/NoRetransmissionAttemptsDemoTeensy3x/NoRetransmissionAttemptsDemoTeensy3x.ino new file mode 100644 index 0000000..3d35bc1 --- /dev/null +++ b/examples/NoRetransmissionAttemptsDemoTeensy3x/NoRetransmissionAttemptsDemoTeensy3x.ino @@ -0,0 +1,155 @@ +//—————————————————————————————————————————————————————————————————————————————— +// ACAN2517FD Demo for "ThreeAttempts" and "Disabled" setting, +// using hardware SPI1, with an external interrupt +// For this sketch, the MCP2517FD should be alone on the CAN bus. +// +// A CAN message should be acknowledged by a receiver. +// By default, no receiver -> no acknnowledge, the message is sent indefinitely +// The settings.mControllerTransmitFIFORetransmissionAttempts can be used for +// specifying: +// - only one attempt (ACAN2517Settings::Disabled); +// - three attempts (ACAN2517Settings::ThreeAttempts); +// - unlimited number of attempts (ACAN2517Settings::Unlimited, default setting). +//—————————————————————————————————————————————————————————————————————————————— + +#include + +//—————————————————————————————————————————————————————————————————————————————— +// MCP2517 connections: adapt theses settings to your design +// As hardware SPI is used, you should select pins that support SPI functions. +// This sketch is designed for a Teensy 3.5, using SPI1 +// But standard Teensy 3.5 SPI1 pins are not used +// SCK input of MCP2517 is connected to pin #32 +// SDI input of MCP2517 is connected to pin #0 +// SDO output of MCP2517 is connected to pin #1 +// CS input of MCP2517 should be connected to a digital output port +// INT output of MCP2517 should be connected to a digital input port, with interrupt capability +//—————————————————————————————————————————————————————————————————————————————— + +static const byte MCP2517_SCK = 32 ; // SCK input of MCP2517 +static const byte MCP2517_SDI = 0 ; // SDI input of MCP2517 +static const byte MCP2517_SDO = 1 ; // SDO output of MCP2517 + +static const byte MCP2517_CS = 31 ; // CS input of MCP2517 +static const byte MCP2517_INT = 38 ; // INT output of MCP2517 + +//—————————————————————————————————————————————————————————————————————————————— +// MCP2517 Driver object +//—————————————————————————————————————————————————————————————————————————————— + +ACAN2517FD can (MCP2517_CS, SPI1, MCP2517_INT) ; + +//—————————————————————————————————————————————————————————————————————————————— +// SETUP +//—————————————————————————————————————————————————————————————————————————————— + +void setup () { +//--- Switch on builtin led + pinMode (LED_BUILTIN, OUTPUT) ; + digitalWrite (LED_BUILTIN, HIGH) ; +//--- Start serial + Serial.begin (38400) ; +//--- Wait for serial (blink led at 10 Hz during waiting) + while (!Serial) { + delay (50) ; + digitalWrite (LED_BUILTIN, !digitalRead (LED_BUILTIN)) ; + } +//--- Define alternate pins for SPI1 (see https://www.pjrc.com/teensy/td_libs_SPI.html) + Serial.print ("Using pin #") ; + Serial.print (MCP2517_SDI) ; + Serial.print (" for MOSI: ") ; + Serial.println (SPI1.pinIsMOSI (MCP2517_SDI) ? "yes" : "NO!!!") ; + Serial.print ("Using pin #") ; + Serial.print (MCP2517_SDO) ; + Serial.print (" for MISO: ") ; + Serial.println (SPI1.pinIsMISO (MCP2517_SDO) ? "yes" : "NO!!!") ; + Serial.print ("Using pin #") ; + Serial.print (MCP2517_SCK) ; + Serial.print (" for SCK: ") ; + Serial.println (SPI1.pinIsSCK (MCP2517_SCK) ? "yes" : "NO!!!") ; + SPI1.setMOSI (MCP2517_SDI) ; + SPI1.setMISO (MCP2517_SDO) ; + SPI1.setSCK (MCP2517_SCK) ; +//----------------------------------- Begin SPI1 + SPI1.begin () ; +//--- Configure ACAN2517 + Serial.print ("sizeof (ACAN2517Settings): ") ; + Serial.print (sizeof (ACAN2517FDSettings)) ; + Serial.println (" bytes") ; + Serial.println ("Configure ACAN2517") ; + ACAN2517FDSettings settings (ACAN2517FDSettings::OSC_4MHz10xPLL, 125 * 1000, DataBitRateFactor::x4) ; +//--- The MCP2517FD internal RAM is limited, the size of the receive buffer is reduced + settings.mControllerReceiveFIFOSize = 2 ; +//--- Configure regular transmit chain (used when message.idx == 0, default) + settings.mDriverTransmitFIFOSize = 0 ; + settings.mControllerTransmitFIFOSize = 1 ; + settings.mControllerTransmitFIFORetransmissionAttempts = ACAN2517FDSettings::Disabled ; +//--- Configure TXQ transmit chain (used when message.idx == 255) + settings.mControllerTXQSize = 1 ; + settings.mControllerTXQBufferRetransmissionAttempts = ACAN2517FDSettings::Disabled ; + const uint32_t errorCode = can.begin (settings, [] { can.isr () ; }) ; + if (errorCode == 0) { + Serial.print ("Bit Rate prescaler: ") ; + Serial.println (settings.mBitRatePrescaler) ; + Serial.print ("Arbitration Phase segment 1: ") ; + Serial.println (settings.mArbitrationPhaseSegment1) ; + Serial.print ("Arbitration Phase segment 2: ") ; + Serial.println (settings.mArbitrationPhaseSegment2) ; + Serial.print ("Arbitration SJW:") ; + Serial.println (settings.mArbitrationSJW) ; + Serial.print ("Actual Arbitration Bit Rate: ") ; + Serial.print (settings.actualArbitrationBitRate ()) ; + Serial.println (" bit/s") ; + Serial.print ("Exact Arbitration Bit Rate ? ") ; + Serial.println (settings.exactArbitrationBitRate () ? "yes" : "no") ; + Serial.print ("Arbitration Sample point: ") ; + Serial.print (settings.arbitrationSamplePointFromBitStart ()) ; + Serial.println ("%") ; + Serial.print ("Data Phase segment 1: ") ; + Serial.println (settings.mDataPhaseSegment1) ; + Serial.print ("Data Phase segment 2: ") ; + Serial.println (settings.mDataPhaseSegment2) ; + Serial.print ("Data SJW:") ; + Serial.println (settings.mDataSJW) ; + }else{ + Serial.print ("Configuration error 0x") ; + Serial.println (errorCode, HEX) ; + } +} + +//---------------------------------------------------------------------------------------------------------------------- + +static uint32_t gBlinkLedDate = 1000 ; +static uint32_t gReceivedFrameCount = 0 ; +static uint32_t gSentFrameCount = 0 ; + +//—————————————————————————————————————————————————————————————————————————————— + +void loop() { + CANFDMessage frame ; + if (gBlinkLedDate < millis ()) { + gBlinkLedDate += 500 ; + digitalWrite (LED_BUILTIN, !digitalRead (LED_BUILTIN)) ; + frame.len = 64 ; + for (uint8_t i=0 ; i sentence=Driver for MCP2517FD and MCP2518FD CAN Controller (CAN FD mode) diff --git a/src/ACAN2517FD.cpp b/src/ACAN2517FD.cpp index 225bb8a..60f41df 100644 --- a/src/ACAN2517FD.cpp +++ b/src/ACAN2517FD.cpp @@ -412,7 +412,7 @@ uint32_t ACAN2517FD::begin (const ACAN2517FDSettings & inSettings, // Bit 0: RTXAT ---> 1: Enable CiFIFOCONm.TXAT to control retransmission attempts data8 = 0x01 ; // Enable RTXAT to limit retransmissions (Flole) data8 |= mUsesTXQ ? (1 << 4) : 0x00 ; // Bug fix in 1.1.4 (thanks to danielhenz) - writeRegister8 (CON_REGISTER + 2, data8); // DS20005688B, page 24 + writeRegister8 (CON_REGISTER + 2, data8) ; // DS20005688B, page 24 //----------------------------------- Configure RX FIFO (FIFOCON, DS20005688B, page 52) data8 = inSettings.mControllerReceiveFIFOSize - 1 ; // Set receive FIFO size data8 |= inSettings.mControllerReceiveFIFOPayload << 5 ; // Payload @@ -430,6 +430,7 @@ uint32_t ACAN2517FD::begin (const ACAN2517FDSettings & inSettings, data8 |= inSettings.mControllerTransmitFIFOPayload << 5 ; // Payload writeRegister8 (FIFOCON_REGISTER (TRANSMIT_FIFO_INDEX) + 3, data8) ; data8 = 1 << 7 ; // FIFO is a Tx FIFO + data8 |= 1 << 4 ; // TXATIE ---> 1: Enable Transmit Attempts Exhausted Interrupt writeRegister8 (FIFOCON_REGISTER (TRANSMIT_FIFO_INDEX), data8) ; mTransmitFIFOPayload = ACAN2517FDSettings::objectSizeForPayload (inSettings.mControllerTransmitFIFOPayload) ; //----------------------------------- Configure receive filters @@ -450,6 +451,8 @@ uint32_t ACAN2517FD::begin (const ACAN2517FDSettings & inSettings, data8 = (1 << 1) ; // Receive FIFO Interrupt Enable data8 |= (1 << 0) ; // Transmit FIFO Interrupt Enable writeRegister8 (INT_REGISTER + 2, data8) ; + data8 = (1 << 2) ; // TXATIE ---> 1: Transmit Attempt Interrupt Enable bit + writeRegister8 (INT_REGISTER + 3, data8) ; //----------------------------------- Program nominal bit rate (NBTCFG register) // bits 31-24: BRP - 1 // bits 23-16: TSEG1 - 1 @@ -484,7 +487,7 @@ uint32_t ACAN2517FD::begin (const ACAN2517FDSettings & inSettings, data |= inSettings.mDataSJW - 1 ; writeRegister32 (DBTCFG_REGISTER, data) ; } - //----------------------------------- Request mode (CON_REGISTER + 3) + //----------------------------------- Request mode (CON_REGISTER + 3, DS20005688B, page 24) // bits 7-4: Transmit Bandwith Sharing Bits ---> 0 // bit 3: Abort All Pending Transmissions bit --> 0 mTXBWS_RequestedMode = inSettings.mRequestedMode | (TXBWS << 4) ; @@ -571,6 +574,7 @@ bool ACAN2517FD::enterInTransmitBuffer (const CANFDMessage & inMessage) { if ((status & 1) == 0) { // FIFO is full uint8_t data8 = 1 << 7 ; // FIFO is a transmit FIFO data8 |= 1 ; // Enable "FIFO not full" interrupt + data8 |= 1 << 4 ; // TXATIE ---> 1: Enable Transmit Attempts Exhausted Interrupt writeRegister8Assume_SPI_transaction (FIFOCON_REGISTER (TRANSMIT_FIFO_INDEX), data8) ; mHardwareTxFIFOFull = true ; } @@ -650,59 +654,69 @@ void ACAN2517FD::appendInControllerTxFIFO (const CANFDMessage & inMessage) { //---------------------------------------------------------------------------------------------------------------------- bool ACAN2517FD::sendViaTXQ (const CANFDMessage & inMessage) { -//--- Enter message only if TXQ FIFO is not full (see DS20005688B, page 50) - const bool TXQNotFull = mUsesTXQ && (readRegister8Assume_SPI_transaction (TXQSTA_REGISTER) & 1) != 0 ; - if (TXQNotFull) { - const uint16_t ramAddress = (uint16_t) (0x400 + readRegister32Assume_SPI_transaction (TXQUA_REGISTER)) ; - //--- Write identifier: if an extended frame is sent, identifier bits sould be reordered (see DS20005678B, page 27) - uint32_t idf = inMessage.id ; - if (inMessage.ext) { - idf = ((inMessage.id >> 18) & 0x7FF) | ((inMessage.id & 0x3FFFF) << 11) ; - } - //--- Write DLC field, FDF, BRS, RTR, IDE bits - uint32_t flags = lengthCodeForLength (inMessage.len) ; - if (inMessage.ext) { - flags |= 1 << 4 ; // Set EXT bit + bool ok = mUsesTXQ ; + if (ok) { + uint8_t sta = readRegister8Assume_SPI_transaction (TXQSTA_REGISTER) ; + //--- Check Transmit Attempts Exhausted Interrupt Pending bit + ok = (sta & (1 << 4)) != 0 ; + if (ok) { + writeRegister8Assume_SPI_transaction (TXQSTA_REGISTER, ~ (1 << 4)) ; + }else{ + //--- Enter message only if TXQ FIFO is not full (see DS20005688B, page 50) + ok = (sta & 1) != 0 ; } - switch (inMessage.type) { - case CANFDMessage::CAN_REMOTE : - flags |= 1 << 5 ; // Set RTR bit - break ; - case CANFDMessage::CAN_DATA : - break ; - case CANFDMessage::CANFD_NO_BIT_RATE_SWITCH : - flags |= 1 << 7 ; // Set FDF bit - break ; - case CANFDMessage::CANFD_WITH_BIT_RATE_SWITCH : - flags |= 1 << 7 ; // Set FDF bit - if (mHasDataBitRate) { - flags |= 1 << 6 ; // Set BRS bit + if (ok) { + const uint16_t ramAddress = (uint16_t) (0x400 + readRegister32Assume_SPI_transaction (TXQUA_REGISTER)) ; + //--- Write identifier: if an extended frame is sent, identifier bits sould be reordered (see DS20005678B, page 27) + uint32_t idf = inMessage.id ; + if (inMessage.ext) { + idf = ((inMessage.id >> 18) & 0x7FF) | ((inMessage.id & 0x3FFFF) << 11) ; } - break ; - } - //--- Word count - const uint32_t wordCount = (inMessage.len + 3) / 4 ; - //--- Transfer frame to the MCP2517FD - uint8_t buff[74] = {0} ; - //--- Enter command - const uint16_t writeCommand = (ramAddress & 0x0FFF) | (0b0010 << 12) ; - buff[0] = writeCommand >> 8 ; - buff[1] = writeCommand & 0xFF ; - //--- Enter values - enterU32InBufferAtIndex (idf, buff, 2) ; - enterU32InBufferAtIndex (flags, buff, 6) ; - for (uint32_t i=0 ; i < wordCount ; i++) { - enterU32InBufferAtIndex (inMessage.data32 [i], buff, 10 + 4 * i) ; + //--- Write DLC field, FDF, BRS, RTR, IDE bits + uint32_t flags = lengthCodeForLength (inMessage.len) ; + if (inMessage.ext) { + flags |= 1 << 4 ; // Set EXT bit + } + switch (inMessage.type) { + case CANFDMessage::CAN_REMOTE : + flags |= 1 << 5 ; // Set RTR bit + break ; + case CANFDMessage::CAN_DATA : + break ; + case CANFDMessage::CANFD_NO_BIT_RATE_SWITCH : + flags |= 1 << 7 ; // Set FDF bit + break ; + case CANFDMessage::CANFD_WITH_BIT_RATE_SWITCH : + flags |= 1 << 7 ; // Set FDF bit + if (mHasDataBitRate) { + flags |= 1 << 6 ; // Set BRS bit + } + break ; + } + //--- Word count + const uint32_t wordCount = (inMessage.len + 3) / 4 ; + //--- Transfer frame to the MCP2517FD + uint8_t buff[74] = {0} ; + //--- Enter command + const uint16_t writeCommand = (ramAddress & 0x0FFF) | (0b0010 << 12) ; + buff[0] = writeCommand >> 8 ; + buff[1] = writeCommand & 0xFF ; + //--- Enter values + enterU32InBufferAtIndex (idf, buff, 2) ; + enterU32InBufferAtIndex (flags, buff, 6) ; + for (uint32_t i=0 ; i < wordCount ; i++) { + enterU32InBufferAtIndex (inMessage.data32 [i], buff, 10 + 4 * i) ; + } + //--- SPI transfer + assertCS () ; + mSPI.transfer (buff, 10 + 4 * wordCount) ; + deassertCS () ; + //--- Increment FIFO, send message (see DS20005688B, page 48) + const uint8_t data8 = (1 << 0) | (1 << 1) ; // Set UINC bit, TXREQ bit + writeRegister8Assume_SPI_transaction (TXQCON_REGISTER + 1, data8); } - //--- SPI transfer - assertCS () ; - mSPI.transfer (buff, 10 + 4 * wordCount) ; - deassertCS () ; - //--- Increment FIFO, send message (see DS20005688B, page 48) - const uint8_t data8 = (1 << 0) | (1 << 1) ; // Set UINC bit, TXREQ bit - writeRegister8Assume_SPI_transaction (TXQCON_REGISTER + 1, data8); } - return TXQNotFull ; + return ok ; } //---------------------------------------------------------------------------------------------------------------------- @@ -825,7 +839,12 @@ bool ACAN2517FD::isr_core (void) { receiveInterrupt () ; handled = true ; } - if ((it & (1 << 0)) != 0) { // Transmit FIFO interrupt + if ((it & (1 << 10)) != 0) { // Transmit Attempt interrupt + //--- Clear Pending Transmit Attempt interrupt bit + writeRegister8Assume_SPI_transaction (FIFOSTA_REGISTER (TRANSMIT_FIFO_INDEX), ~ (1 << 4)) ; + transmitInterrupt () ; + handled = true ; + }else if ((it & (1 << 0)) != 0) { // Transmit FIFO interrupt transmitInterrupt () ; handled = true ; } @@ -863,7 +882,8 @@ void ACAN2517FD::transmitInterrupt (void) { // Generated if hardware transmit FI if (hasMessage) { appendInControllerTxFIFO (message) ; }else{ // No message in transmit FIFO: disable "FIFO not full" interrupt - const uint8_t data8 = 1 << 7 ; // FIFO is a transmit FIFO + uint8_t data8 = 1 << 7 ; // FIFO is a transmit FIFO + data8 |= 1 << 4 ; // TXATIE ---> 1: Enable Transmit Attempts Exhausted Interrupt writeRegister8Assume_SPI_transaction (FIFOCON_REGISTER (TRANSMIT_FIFO_INDEX), data8) ; mHardwareTxFIFOFull = false ; } diff --git a/src/ACAN2517FDSettings.h b/src/ACAN2517FDSettings.h index 1a5cf55..2b69c06 100644 --- a/src/ACAN2517FDSettings.h +++ b/src/ACAN2517FDSettings.h @@ -61,7 +61,7 @@ class ACAN2517FDSettings { } PayloadSize ; //······················································································································ -// Deprecated enumeration (now use DataBitRateFactor declared in ACANFD_DataBitRateFactor.h +// Deprecated enumeration (now use DataBitRateFactor declared in ACANFD_DataBitRateFactor.h) //······················································································································ public : typedef enum : uint8_t {