Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multi-isotp and error checking to CAN-FD #71

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 53 additions & 11 deletions FlexCAN_T4.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,41 @@
#include "circular_buffer.h"
#include "imxrt_flexcan.h"

static const char* CAN_STATE_STRINGS[] =
{
"Unknown",
"Idle",
"Not synchronized to CAN bus",
"Transmitting",
"Receiving"
};

static const char* CAN_FLTCONF_STRINGS[] =
{
"Unknown",
"Error Active",
"Error Passive",
"Bus Off"
};

enum CAN_STATE
{
CAN_STATE_UNK = 0,
CAN_STATE_IDLE,
CAN_STATE_NO_SYNC,
CAN_STATE_TX,
CAN_STATE_RX
};

enum FLT_CONF
{
FLTCONF_UNK = 0,
FLTCONF_ERR_ACTIVE,
FLTCONF_ERR_PASSIVE,
FLTCONF_BUS_OFF
};

typedef struct CAN_error_t {
char state[30] = "Idle";
bool BIT1_ERR = 0;
bool BIT0_ERR = 0;
bool ACK_ERR = 0;
Expand All @@ -44,14 +77,19 @@ typedef struct CAN_error_t {
bool STF_ERR = 0;
bool TX_WRN = 0;
bool RX_WRN = 0;
char FLT_CONF[14] = { 0 };
bool BIT1_ERR_FD = 0;
bool BIT0_ERR_FD = 0;
bool CRC_ERR_FD = 0;
bool FRM_ERR_FD = 0;
bool STF_ERR_FD = 0;
uint8_t RX_ERR_COUNTER = 0;
uint8_t TX_ERR_COUNTER = 0;
uint32_t ESR1 = 0;
uint16_t ECR = 0;
CAN_STATE canState = CAN_STATE_UNK;
FLT_CONF fltConf = FLTCONF_UNK;
} CAN_error_t;


typedef struct CAN_message_t {
uint32_t id = 0; // can identifier
uint16_t timestamp = 0; // FlexCAN time when message arrived
Expand Down Expand Up @@ -328,7 +366,13 @@ class FlexCAN_T4_Base {
virtual int write(const CANFD_message_t &msg) = 0;
virtual int write(const CAN_message_t &msg) = 0;
virtual bool isFD() = 0;
virtual uint8_t getFirstTxBoxSize() = 0;
virtual uint8_t getFirstTxBoxSize();
virtual bool error(CAN_error_t &error, bool printDetails);
virtual void printErrors(const CAN_error_t &error);
protected:
uint32_t nvicIrq = 0;
Circular_Buffer<uint32_t, 16> busESR1;
Circular_Buffer<uint16_t, 16> busECR;
};

#if defined(__IMXRT1062__)
Expand Down Expand Up @@ -374,6 +418,7 @@ FCTPFD_CLASS class FlexCAN_T4FD : public FlexCAN_T4_Base {
void enableMBInterrupts(bool status = 1);
void disableMBInterrupts() { enableMBInterrupts(0); }
uint64_t events();
bool error(CAN_error_t &error, bool printDetails);
void onReceive(const FLEXCAN_MAILBOX &mb_num, _MBFD_ptr handler); /* individual mailbox callback function */
void onReceive(_MBFD_ptr handler); /* global callback function */
void setMBFilter(FLEXCAN_FLTEN input); /* enable/disable traffic for all MBs (for individual masking) */
Expand Down Expand Up @@ -406,6 +451,7 @@ FCTPFD_CLASS class FlexCAN_T4FD : public FlexCAN_T4_Base {
void FLEXCAN_EnterFreezeMode();
void reset() { softReset(); } /* reset flexcan controller (needs register restore capabilities...) */
void flexcan_interrupt();
void printErrors(const CAN_error_t &error);
void writeIFLAG(uint64_t value);
void writeIFLAGBit(uint8_t mb_num);
uint8_t max_mailboxes();
Expand All @@ -419,7 +465,6 @@ FCTPFD_CLASS class FlexCAN_T4FD : public FlexCAN_T4_Base {
void writeIMASKBit(uint8_t mb_num, bool set = 1);
uint8_t busNumber;
uint8_t mailbox_reader_increment = 0;
uint32_t nvicIrq = 0;
uint8_t dlc_to_len(uint8_t val);
uint8_t len_to_dlc(uint8_t val);
uint32_t setBaudRateFD(CANFD_timings_t config, uint32_t flexdata_choice, bool advanced); /* internally used */
Expand Down Expand Up @@ -484,6 +529,7 @@ FCTP_CLASS class FlexCAN_T4 : public FlexCAN_T4_Base {
int write(const CANFD_message_t &msg) { return 0; } /* to satisfy base class for external pointers */
int write(FLEXCAN_MAILBOX mb_num, const CAN_message_t &msg); /* use a single mailbox for transmitting */
uint64_t events();
bool error(CAN_error_t &error, bool printDetails);
uint8_t setRFFN(FLEXCAN_RFFN_TABLE rffn = RFFN_8); /* Number Of Rx FIFO Filters (0 == 8 filters, 1 == 16 filters, etc.. */
uint8_t setRFFN(uint8_t rffn) { return setRFFN((FLEXCAN_RFFN_TABLE)constrain(rffn, 0, 15)); }
void setFIFOFilterTable(FLEXCAN_FIFOTABLE letter);
Expand Down Expand Up @@ -511,7 +557,6 @@ FCTP_CLASS class FlexCAN_T4 : public FlexCAN_T4_Base {
uint8_t getFirstTxBoxSize(){ return 8; }
void FLEXCAN_ExitFreezeMode();
void FLEXCAN_EnterFreezeMode();
bool error(CAN_error_t &error, bool printDetails);
uint32_t getRXQueueCount() { return rxBuffer.size(); }
uint32_t getTXQueueCount() { return txBuffer.size(); }

Expand All @@ -520,12 +565,10 @@ FCTP_CLASS class FlexCAN_T4 : public FlexCAN_T4_Base {
void writeTxMailbox(uint8_t mb_num, const CAN_message_t &msg);
uint64_t readIMASK();// { return (((uint64_t)FLEXCANb_IMASK2(_bus) << 32) | FLEXCANb_IMASK1(_bus)); }
void flexcan_interrupt();
void printErrors(const CAN_error_t &error);
void flexcanFD_interrupt() { ; } // dummy placeholder to satisfy base class
Circular_Buffer<uint8_t, (uint32_t)_rxSize, sizeof(CAN_message_t)> rxBuffer;
Circular_Buffer<uint8_t, (uint32_t)_txSize, sizeof(CAN_message_t)> txBuffer;
Circular_Buffer<uint32_t, 16> busESR1;
Circular_Buffer<uint16_t, 16> busECR;
void printErrors(const CAN_error_t &error);
#if defined(__IMXRT1062__)
uint32_t getClock();
#endif
Expand All @@ -550,8 +593,7 @@ FCTP_CLASS class FlexCAN_T4 : public FlexCAN_T4_Base {
void writeIFLAG(uint64_t value);
void writeIFLAGBit(uint8_t mb_num);
void writeIMASK(uint64_t value);
void writeIMASKBit(uint8_t mb_num, bool set = 1);
uint32_t nvicIrq = 0;
void writeIMASKBit(uint8_t mb_num, bool set = 1);
uint32_t currentBitrate = 0UL;
uint8_t mailbox_reader_increment = 0;
uint8_t busNumber;
Expand Down
19 changes: 10 additions & 9 deletions FlexCAN_T4.tpp
Original file line number Diff line number Diff line change
Expand Up @@ -1328,10 +1328,11 @@ FCTP_FUNC bool FCTP_OPT::error(CAN_error_t &error, bool printDetails) {
error.ESR1 = busESR1.read();
error.ECR = busECR.read();

if ( (error.ESR1 & 0x400C8) == 0x40080 ) strncpy((char*)error.state, "Idle", (sizeof(error.state) - 1));
else if ( (error.ESR1 & 0x400C8) == 0x0 ) strncpy((char*)error.state, "Not synchronized to CAN bus", (sizeof(error.state) - 1));
else if ( (error.ESR1 & 0x400C8) == 0x40040 ) strncpy((char*)error.state, "Transmitting", (sizeof(error.state) - 1));
else if ( (error.ESR1 & 0x400C8) == 0x40008 ) strncpy((char*)error.state, "Receiving", (sizeof(error.state) - 1));
error.canState = CAN_STATE_UNK;
if ( (error.ESR1 & 0x400C8) == 0x40080 ) error.canState = CAN_STATE_IDLE;
else if ( (error.ESR1 & 0x400C8) == 0x0 ) error.canState = CAN_STATE_NO_SYNC;
else if ( (error.ESR1 & 0x400C8) == 0x40040 ) error.canState = CAN_STATE_TX;
else if ( (error.ESR1 & 0x400C8) == 0x40008 ) error.canState = CAN_STATE_RX;

error.BIT1_ERR = (error.ESR1 & (1UL << 15)) ? 1 : 0;
error.BIT0_ERR = (error.ESR1 & (1UL << 14)) ? 1 : 0;
Expand All @@ -1342,9 +1343,9 @@ FCTP_FUNC bool FCTP_OPT::error(CAN_error_t &error, bool printDetails) {
error.TX_WRN = (error.ESR1 & (1UL << 9)) ? 1 : 0;
error.RX_WRN = (error.ESR1 & (1UL << 8)) ? 1 : 0;

if ( (error.ESR1 & 0x30) == 0x0 ) strncpy((char*)error.FLT_CONF, "Error Active", (sizeof(error.FLT_CONF) - 1));
else if ( (error.ESR1 & 0x30) == 0x1 ) strncpy((char*)error.FLT_CONF, "Error Passive", (sizeof(error.FLT_CONF) - 1));
else strncpy((char*)error.FLT_CONF, "Bus off", (sizeof(error.FLT_CONF) - 1));
if ( (error.ESR1 & 0x30) == 0x0 ) error.fltConf = FLTCONF_ERR_ACTIVE;
else if ( (error.ESR1 & 0x30) == 0x1 ) error.fltConf = FLTCONF_ERR_PASSIVE;
else error.fltConf = FLTCONF_BUS_OFF;

error.RX_ERR_COUNTER = (uint8_t)(error.ECR >> 8);
error.TX_ERR_COUNTER = (uint8_t)error.ECR;
Expand All @@ -1355,7 +1356,7 @@ FCTP_FUNC bool FCTP_OPT::error(CAN_error_t &error, bool printDetails) {
}

FCTP_FUNC void FCTP_OPT::printErrors(const CAN_error_t &error) {
Serial.print("FlexCAN State: "); Serial.print((char*)error.state);
Serial.print("FlexCAN State: "); Serial.print(CAN_STATE_STRINGS[(int)error.canState]);
if ( error.BIT1_ERR ) Serial.print(", BIT1_ERR");
if ( error.BIT0_ERR ) Serial.print(", BIT0_ERR");
if ( error.ACK_ERR ) Serial.print(", ACK_ERR");
Expand All @@ -1364,7 +1365,7 @@ FCTP_FUNC void FCTP_OPT::printErrors(const CAN_error_t &error) {
if ( error.STF_ERR ) Serial.print(", STF_ERR");
if ( error.RX_WRN ) Serial.printf(", RX_WRN: %d", error.RX_ERR_COUNTER);
if ( error.TX_WRN ) Serial.printf(", TX_WRN: %d", error.TX_ERR_COUNTER);
Serial.printf(", FLT_CONF: %s\n", (char*)error.FLT_CONF);
Serial.printf(", FLT_CONF: %s\n", CAN_FLTCONF_STRINGS[(int)error.fltConf]);
}

FCTP_FUNC void FCTP_OPT::enableDMA(bool state) { /* only CAN3 supports this on 1062, untested */
Expand Down
72 changes: 71 additions & 1 deletion FlexCAN_T4FD.tpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,64 @@ FCTPFD_FUNC void FCTPFD_OPT::begin() {
NVIC_ENABLE_IRQ(nvicIrq);
}

FCTPFD_FUNC bool FCTPFD_OPT::error(CAN_error_t &error, bool printDetails) {
if ( !busESR1.size() ) return 0;
NVIC_DISABLE_IRQ(nvicIrq);
error.ESR1 = busESR1.read();
error.ECR = busECR.read();

error.canState = CAN_STATE_UNK;
if ( (error.ESR1 & 0x400C8) == 0x40080 ) error.canState = CAN_STATE_IDLE;
else if ( (error.ESR1 & 0x400C8) == 0x0 ) error.canState = CAN_STATE_NO_SYNC;
else if ( (error.ESR1 & 0x400C8) == 0x40040 ) error.canState = CAN_STATE_TX;
else if ( (error.ESR1 & 0x400C8) == 0x40008 ) error.canState = CAN_STATE_RX;

error.BIT1_ERR = (error.ESR1 & (1UL << 15)) ? 1 : 0;
error.BIT0_ERR = (error.ESR1 & (1UL << 14)) ? 1 : 0;
error.ACK_ERR = (error.ESR1 & (1UL << 13)) ? 1 : 0;
error.CRC_ERR = (error.ESR1 & (1UL << 12)) ? 1 : 0;
error.FRM_ERR = (error.ESR1 & (1UL << 11)) ? 1 : 0;
error.STF_ERR = (error.ESR1 & (1UL << 10)) ? 1 : 0;
error.TX_WRN = (error.ESR1 & (1UL << 9)) ? 1 : 0;
error.RX_WRN = (error.ESR1 & (1UL << 8)) ? 1 : 0;
error.BIT1_ERR_FD = (error.ESR1 & (1UL << 31)) ? 1 : 0;
error.BIT0_ERR_FD = (error.ESR1 & (1UL << 30)) ? 1 : 0;
error.CRC_ERR_FD = (error.ESR1 & (1UL << 28)) ? 1 : 0;
error.FRM_ERR_FD = (error.ESR1 & (1UL << 27)) ? 1 : 0;
error.STF_ERR_FD = (error.ESR1 & (1UL << 26)) ? 1 : 0;

if ( (error.ESR1 & 0x30) == 0x0 ) error.fltConf = FLTCONF_ERR_ACTIVE;
else if ( (error.ESR1 & 0x30) == 0x1 ) error.fltConf = FLTCONF_ERR_PASSIVE;
else error.fltConf = FLTCONF_BUS_OFF;

error.RX_ERR_COUNTER = (uint8_t)(error.ECR >> 8);
error.TX_ERR_COUNTER = (uint8_t)error.ECR;

if ( printDetails ) printErrors(error);
NVIC_ENABLE_IRQ(nvicIrq);
return 1;
}

FCTPFD_FUNC void FCTPFD_OPT::printErrors(const CAN_error_t &error) {
Serial.print("FlexCAN State: "); Serial.print(CAN_STATE_STRINGS[(int)error.canState]);
if ( error.BIT1_ERR ) Serial.print(", BIT1_ERR");
if ( error.BIT0_ERR ) Serial.print(", BIT0_ERR");
if ( error.ACK_ERR ) Serial.print(", ACK_ERR");
if ( error.CRC_ERR ) Serial.print(", CRC_ERR");
if ( error.FRM_ERR ) Serial.print(", FRM_ERR");
if ( error.STF_ERR ) Serial.print(", STF_ERR");

if ( error.BIT1_ERR_FD ) Serial.print(", BIT1_ERR_FD");
if ( error.BIT0_ERR_FD ) Serial.print(", BIT0_ERR_FD");
if ( error.CRC_ERR_FD ) Serial.print(", CRC_ERR_FD");
if ( error.FRM_ERR_FD ) Serial.print(", FRM_ERR_FD");
if ( error.STF_ERR_FD ) Serial.print(", STF_ERR_FD");

if ( error.RX_WRN ) Serial.printf(", RX_WRN: %d", error.RX_ERR_COUNTER);
if ( error.TX_WRN ) Serial.printf(", TX_WRN: %d", error.TX_ERR_COUNTER);
Serial.printf(", FLT_CONF: %s\n", CAN_FLTCONF_STRINGS[(int)error.fltConf]);
}

FCTPFD_FUNC uint8_t FCTPFD_OPT::setRegions(uint8_t size) {
FLEXCAN_EnterFreezeMode();
FLEXCANb_FDCTRL(_bus) &= ~0x1B0000; /* clear both memory region bits */
Expand Down Expand Up @@ -473,7 +531,19 @@ FCTPFD_FUNC void FCTPFD_OPT::flexcan_interrupt() {
ext_outputFD3(msg);
}
}
FLEXCANb_ESR1(_bus) = FLEXCANb_ESR1(_bus);

uint32_t esr1 = FLEXCANb_ESR1(_bus);
static uint32_t last_esr1 = 0;
if ( (last_esr1 & 0x7FFBF) != (esr1 & 0x7FFBF) ) {
if ( busESR1.size() < busESR1.capacity() ) {
busESR1.write(esr1);
busECR.write(FLEXCANb_ECR(_bus));
last_esr1 = esr1;
}
}
FLEXCANb_ESR1(_bus) |= esr1;

asm volatile ("dsb");
}

FCTPFD_FUNC void FCTPFD_OPT::struct2queueRx(const CANFD_message_t &msg) {
Expand Down
22 changes: 18 additions & 4 deletions isotp.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@
#include "ESP32_CAN.h"
#endif

enum ISOTP_FLOW
{
FLOW_CTS = 0,
FLOW_WAIT= 1,
FLOW_ABORT = 2
};

typedef struct ISOTP_data {
uint32_t id = 0; /* can identifier */
struct {
Expand All @@ -50,7 +57,8 @@ typedef struct ISOTP_data {
} flags;
uint16_t len = 8; /* length of CAN message or callback payload */
uint16_t blockSize = 0; /* used for flow control, specify how many frame blocks per frame control request */
uint8_t flow_control_type = 0; /* flow control type: 0: Clear to Send, 1: Wait, 2: Abort */
uint16_t blockNum = 0; /* used with blockSize. This tracks how many blocks we're at. Redo flow control afterward */
ISOTP_FLOW flow_control_type = FLOW_CTS; /* flow control type */
uint16_t separation_time = 0; /* time between frames */
} ISOTP_data;

Expand Down Expand Up @@ -83,14 +91,20 @@ class isotp_Base {
public:
virtual void _process_frame_data(const CAN_message_t &msg) = 0;
virtual void write(const ISOTP_data &config, const uint8_t *buf, uint16_t size) = 0;
void setBoundID(int32_t newID) { boundID = newID; }
void setBoundBus(int32_t bus) { boundBus = bus; }
_isotp_cb_ptr _isotp_handler = nullptr;
static int buffer_hosts;
int thisBufferHost = 0;
int boundBus = -1;
int boundID = -1;
};

static isotp_Base* _ISOTP_OBJ = nullptr;
static isotp_Base* _ISOTP_OBJ[16] = { nullptr };

ISOTP_CLASS class isotp : public isotp_Base {
public:
isotp() { _ISOTP_OBJ = this; }
isotp();

#if defined(TEENSYDUINO) // Teensy
void setWriteBus(FlexCAN_T4_Base* _busWritePtr) {
Expand All @@ -111,7 +125,7 @@ ISOTP_CLASS class isotp : public isotp_Base {
void begin() { enable(); }
void enable(bool yes = 1) { isotp_enabled = yes; }
void setPadding(uint8_t _byte) { padding_value = _byte; }
void onReceive(_isotp_cb_ptr handler) { _ISOTP_OBJ->_isotp_handler = handler; }
void onReceive(_isotp_cb_ptr handler) { _ISOTP_OBJ[thisBufferHost]->_isotp_handler = handler; }
void write(const ISOTP_data &config, const uint8_t *buf, uint16_t size);
void write(const ISOTP_data &config, const char *buf, uint16_t size) { write(config, (const uint8_t*)buf, size); }
void sendFlowControl(const ISOTP_data &config);
Expand Down
Loading