This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TCAN4551-Q1: CAN data receive packet loss

Part Number: TCAN4551-Q1
Other Parts Discussed in Thread: TCAN4550

Tool/software:

Hello team,

We are working on TCAN4551 and used CAN stack from below link:

https://github.com/TexasInstruments/CC26XX-TCAN4550-EXAMPLES/tree/master/source/ti/can/tcan4x5x

We have used watermark feature where we have configured watermark level 60 and we do get watermark interrupt on receiving 60 packets and following configuration:

static void TCAN4550_SetConfiguration( void )
{
uint8_t tx_param_size;
uint8_t rx_param_size;

// Clear any SPI ERR flags that might be set as a result of our pin mux changing during MCU startup
TCAN4x5x_Device_ClearSPIERR();

/* Step one attempt to clear all interrupts */
/* Initialize to 0 to all bits are set to 0 */
TCAN4x5x_Device_Interrupt_Enable dev_ie = {0};

/* Disable all non-MCAN related interrupts for simplicity */
TCAN4x5x_Device_ConfigureInterruptEnable(&dev_ie);

/* Setup a new MCAN IR object for easy interrupt checking */
TCAN4x5x_Device_Interrupts dev_ir = {0};

/* Request that the struct be updated with current DEVICE (not MCAN) interrupt values */
TCAN4x5x_Device_ReadInterrupts(&dev_ir);

/* If the Power On interrupt flag is set */
if (dev_ir.PWRON)
{
/* Clear it because if it's not cleared within ~4 minutes, it goes to sleep */
TCAN4x5x_Device_ClearInterrupts(&dev_ir);
}

/* Configure the CAN bus speeds */
/* 500k arbitration with a 40 MHz crystal (40E6 / (57 + 22 + 1 (Sync)) = ) */
/* TCAN_Timing = ( (40E6 / BitRatePrescaler) / ( TqBeforeSamplePoint + TqAfterSamplePoint) ) */
/* Configure the CAN bus speeds */
/* 500k arbitration with a 40 MHz crystal (40E6 / (57 + 22 + 1 (Sync)) = 500E3) */
TCAN4x5x_MCAN_Nominal_Timing_Simple TCANNomTiming = {0};
TCANNomTiming.NominalBitRatePrescaler = 2;
TCANNomTiming.NominalTqBeforeSamplePoint = 32;
TCANNomTiming.NominalTqAfterSamplePoint = 8;

/* 2 Mbps CAN FD with a 40 MHz crystal (40E6 / (15 + 5) = 2E6) */
TCAN4x5x_MCAN_Data_Timing_Simple TCANDataTiming = {0};
TCANDataTiming.DataBitRatePrescaler = 1;
TCANDataTiming.DataTqBeforeSamplePoint = 15;
TCANDataTiming.DataTqAfterSamplePoint = 5;

/* Configure the MCAN core settings */
/* Remember to initialize to 0, or you'll get random garbage! */
TCAN4x5x_MCAN_CCCR_Config cccrConfig = {0};

/* CAN FD mode enable */
// cccrConfig.FDOE = 0;
cccrConfig.FDOE = 0;

/* CAN FD Bit rate switch enable*/
cccrConfig.BRSE = 1;

/* Configure the default CAN packet filtering settings */
TCAN4x5x_MCAN_Global_Filter_Configuration gfc = {0};

/* Reject remote frames (TCAN4x5x doesn't support this) */
gfc.RRFE = 1;

/* Reject remote frames (TCAN4x5x doesn't support this) */
gfc.RRFS = 1;

/* Default behavior if incoming message doesn't match a filter is to accept into RXFIO0 for extended ID messages (29 bit IDs) */
gfc.ANFE = TCAN4x5x_GFC_REJECT; //TCAN4x5x_GFC_ACCEPT_INTO_RXFIFO0;

/* Default behavior if incoming message doesn't match a filter is to accept into RXFIO0 for standard ID messages (11 bit IDs) */
gfc.ANFS = TCAN4x5x_GFC_REJECT; //TCAN4x5x_GFC_ACCEPT_INTO_RXFIFO0;


rx_param_size = 60;
tx_param_size = 0;

TCAN4x5x_MRAM_Config MRAMConfiguration = {0};
// Standard ID number of elements, you MUST have a filter written to MRAM for each element defined
MRAMConfiguration.SIDNumElements = 3;
// Extended ID number of elements, you MUST have a filter written to MRAM for each element defined
MRAMConfiguration.XIDNumElements = 16;
// RX0 Number of elements
MRAMConfiguration.Rx0NumElements = rx_param_size;
// RX0 data payload size (Use the defines)
MRAMConfiguration.Rx0ElementSize = MRAM_8_Byte_Data;
// MRAMConfiguration.Rx0ElementSize = MRAM_64_Byte_Data;
// RX1 number of elements
MRAMConfiguration.Rx1NumElements = 0;
// RX1 data payload size (use the defines)
MRAMConfiguration.Rx1ElementSize = MRAM_64_Byte_Data;
// RX buffer number of elements
MRAMConfiguration.RxBufNumElements = 0;
// RX buffer data payload size (use the defines)
MRAMConfiguration.RxBufElementSize = MRAM_64_Byte_Data;
// TX Event FIFO number of elements
MRAMConfiguration.TxEventFIFONumElements = 0;
// TX buffer number of elements
MRAMConfiguration.TxBufferNumElements = tx_param_size;
// TX buffer data payload size (use the defines)
MRAMConfiguration.TxBufferElementSize = MRAM_64_Byte_Data;

/* Configure the MCAN core with the settings above, the changes in this block are write protected registers,
* so it makes the most sense to do them all at once, so we only unlock and lock once */
// Start by making protected registers accessible
TCAN4x5x_MCAN_EnableProtectedRegisters();
// Enable FD mode and Bit rate switching
TCAN4x5x_MCAN_ConfigureCCCRRegister(&cccrConfig);
// Configure the global filter configuration (Default CAN message behavior)
TCAN4x5x_MCAN_ConfigureGlobalFilter(&gfc);
// Setup nominal/arbitration bit timing
TCAN4x5x_MCAN_ConfigureNominalTiming_Simple(&TCANNomTiming);
// Setup CAN FD timing
TCAN4x5x_MCAN_ConfigureDataTiming_Simple(&TCANDataTiming);
// Clear all of MRAM (Writes 0's to all of it)
TCAN4x5x_MRAM_Clear();
// Set up the applicable registers related to MRAM configuration
TCAN4x5x_MRAM_Configure(&MRAMConfiguration);
// Disable protected write and take device out of INIT mode
TCAN4x5x_MCAN_DisableProtectedRegisters();

/* Set the interrupts we want to enable for MCAN */
/* Remember to initialize to 0, or you'll get random garbage! */
TCAN4x5x_MCAN_Interrupt_Enable mcan_ie = {0};


/* RX FIFO 0 new water mark interrupt enable */
mcan_ie.RF0WE = 1;

/* Enable the appropriate registers */
TCAN4x5x_MCAN_ConfigureInterruptEnable(&mcan_ie);

//Initialize receive and transmit buffers
TCAN4550_SetRxTxMessageBuffers(CAN_RX_ID_MSG, CAN_RX_ID_MSG_TYPE);

/* Configure the TCAN4550 Non-CAN-related functions */
// Remember to initialize to 0, or you'll get random garbage!
TCAN4x5x_DEV_CONFIG devConfig = {0};
// Keep Sleep Wake Error Enabled (it's a disable bit, not an enable)
devConfig.SWE_DIS = 0;
// Not requesting a software reset
devConfig.DEVICE_RESET = 0;
// Watchdog disabled
devConfig.WD_EN = 0;
// Mirror INH function (default)
devConfig.nWKRQ_CONFIG = 0;
// INH enabled (default)
devConfig.INH_DIS = 0;
// MCAN nINT 1 (default)
devConfig.GPIO1_GPO_CONFIG = TCAN4x5x_DEV_CONFIG_GPO1_MCAN_INT1;
// Failsafe disabled (default)
devConfig.FAIL_SAFE_EN = 0;
// GPIO set as GPO (Default)
devConfig.GPIO1_CONFIG = TCAN4x5x_DEV_CONFIG_GPIO1_CONFIG_GPO;
// Watchdog set an interrupt (default)
devConfig.WD_ACTION = TCAN4x5x_DEV_CONFIG_WDT_ACTION_nINT;
// Don't reset the watchdog
devConfig.WD_BIT_RESET = 0;
// Set nWKRQ to internal voltage rail (default)
devConfig.nWKRQ_VOLTAGE = 0;
// GPO2 has no behavior (default)
devConfig.GPO2_CONFIG = TCAN4x5x_DEV_CONFIG_GPO2_NO_ACTION;
// Input crystal is a 40 MHz crystal (default)
devConfig.CLK_REF = 0;
// Wake pin can be triggered by either edge (default)
devConfig.WAKE_CONFIG = TCAN4x5x_DEV_CONFIG_WAKE_BOTH_EDGES;
// Configure the device with the above configuration
TCAN4x5x_Device_Configure(&devConfig);
}

Following is the Receive interrupt function:

void HW_ISR_Rx(uint32_t *msg_ID, uint8_t *msg_Payload, uint8_t *msg_DLC)
{


// Setup a new MCAN IR object for easy interrupt checking
TCAN4x5x_MCAN_Interrupts mcan_ir = {0};
// Read the interrupt register
TCAN4x5x_MCAN_ReadInterrupts(&mcan_ir);

// If a new message in RX FIFO 0
// if (mcan_ir.RF0N) { //new messsge interrupt
 if (mcan_ir.RF0W)
 {
    TCAN4x5x_MCAN_ClearInterrupts(&mcan_ir);

    /*Set receive flag */

    rxrcvd = TRUE;
  }
}

In below function, we check if receive flag is set or not, if set the we are reading data from FIFO.


void execute()
{
if(rxrcvd == TRUE)
{
rxrcvd = false;

uint32_t RF1W_reg_1 = AHB_READ_32(0x10A4);
cntlp = RF1W_reg_1;

for(uint8_t i = 0; i<cntlp; i++)
{
numBytes = TCAN4x5x_MCAN_ReadNextFIFO(RXFIFO0, &MsgHeader, dataPayload);

tcan_store_data_q[i].canId = MsgHeader.ID;
memcpy(tcan_store_data_q[i].dataBytes, dataPayload, sizeof(tcan_store_data_q[i].dataBytes));
tcan_store_data_q[i].dlc = MsgHeader.DLC;
}

}

With above configuration, we are observing packet loss in receiving data, i.e. number packet received is less compared to packet sent.

Could you please guide us to resolve this issue.

  • Hi Amit,

    You are losing RX messages because your watermark level is set at the maximum size of the RX FIFO.  When the watermark interrupt is triggered, the MCU will start to read the RX messages from the FIFO elements and free them up for new messages to be received.  However, because you are waiting for the RX FIFO to be completely Full before starting the read process (due to the watermark and RX FIFO size both equaling 60), any messages received while the RX is full will be either rejected, or the oldest message will be overwritten (depending on how the device is configured). 

    You should set the Watermark level at a lower level to allow enough time for the MCU to read the RX messages out of the FIFO Before it becomes full and prevent data loss.  For example try setting a watermark level of 30 which would allow 30 RX Buffer elements to be used by the device to receive and store messages while the MCU is reading the messages already received into the RX FIFO.  New messages can be received on the CAN bus while the MCU is reading the older messages through SPI as long as the RX FIFO has not become FULL.

    Regards,

    Jonathan