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.

MSPM0G3507: Handle CAN Rx correctly

Part Number: MSPM0G3507


Tool/software:

Hello,

I have a few questions regarding receiving CAN RX frames from the interrupt handler. (Full handler code included at the bottom).

It is based on the example project implementation for CAN RX and it is operating in the fifo mode.

There are a few somewhat confusing moments that I would like to clarify with your help.

Firstly, is the following do while check necessary (I saw it in the example project for can rx) ?

do {

  DL_MCAN_getRxFIFOStatus(CANFD0, &rx_fs);

} while ((rx_fs.fillLvl) == 0);

I would think if we get the rx event, then there is already a message in the rx fifo and I do not need to poll for it.

Secondly. If there are several messages in the fifo buffered up, what is the correct way to read them all out ?

Currently I just do it like this:


do {
  DL_MCAN_readMsgRam(CANFD0, DL_MCAN_MEM_TYPE_FIFO, 0U, rx_fs.num, &rx_msg);
  DL_MCAN_writeRxFIFOAck(CANFD0, rx_fs.num, rx_fs.getIdx);

  for (int i = 0; i < rx_msg.dlc; i++) {
    frame[i] = rx_msg.data[i];
  }
  can_rx_handler(rx_msg.id, frame, rx_msg.dlc); // Process received frame

  DL_MCAN_getRxFIFOStatus(CANFD0, &rx_fs);
} while (rx_fs.fillLvl > 0);

Here is a complete code snippet of the handler:

void CANFD0_IRQHandler(void) {
uint32_t intr_status;
DL_MCAN_RxFIFOStatus rx_fs;
DL_MCAN_RxBufElement rx_msg;
uint8_t frame[8];

switch (DL_MCAN_getPendingInterrupt(CANFD0)) {
case DL_MCAN_IIDX_LINE0:
intr_status = DL_MCAN_getIntrStatus(CANFD0);
DL_MCAN_clearIntrStatus(CANFD0, intr_status, DL_MCAN_INTR_SRC_MCAN_LINE_0);

if ((intr_status & MCAN_IR_RF0N_MASK)) {
rx_fs.num = DL_MCAN_RX_FIFO_NUM_0;
// wait until the message is in the fifo
do {
DL_MCAN_getRxFIFOStatus(CANFD0, &rx_fs);
} while ((rx_fs.fillLvl) == 0);

// read until fifo is empty
do {
DL_MCAN_readMsgRam(CANFD0, DL_MCAN_MEM_TYPE_FIFO, 0U, rx_fs.num, &rx_msg);
DL_MCAN_writeRxFIFOAck(CANFD0, rx_fs.num, rx_fs.getIdx);

for (int i = 0; i < rx_msg.dlc; i++) {
frame[i] = rx_msg.data[i];
}
can_rx_handler(rx_msg.id, frame, rx_msg.dlc); // Process received frame

DL_MCAN_getRxFIFOStatus(CANFD0, &rx_fs);
} while (rx_fs.fillLvl > 0);
}

if (intr_status & MCAN_IR_BO_MASK) {
DL_MCAN_setOpMode(CANFD0, DL_MCAN_OPERATION_MODE_NORMAL);
}
break;

default:
break;
}
}
  • Let me check it, but out of curiosity have you tested your code now?

  • Of course I have tested it. It kind of works, but when I am stress testing the device by sending and receiving as many can messages as possible sometimes it seems to get stuck in the do while check I was asking you about:

    do {

      DL_MCAN_getRxFIFOStatus(CANFD0, &rx_fs);

    } while ((rx_fs.fillLvl) == 0);

  • Could it be related to the FIFO overload? We have tested the example code before for stress testing and it worked fine.

  • Hello,

    I am not sure what you mean by overload. If you mean RX FIFO getting full, shouldn't rx_fs.fillLvl be grater than 0 and not cause dead lock ?

    Regarding example code, it can work fine because cpu utilization is very low, so it can quickly read out can messages and the rx fifo never gets full.

    The corner case that I am trying to make sure does not happen is when cpu is also handling other higher priority things and is not able to read out CAN messages quick enough. By the time it is finally able to process CAN rx handler, can rx fifos can be full. So imagine we read out 1 can message and while handling it, we receive another can message into the fifo and it gets full. Then we finish handling that can message and exit the handler. But since the rx fifo is full, so we may not get another rx interrupt or we just read out one message when we do (and other fifo messages are not processed). So I am trying to make sure that before exiting the can rx handler I read out all the messages from the rx fifo. Then I am sure that I handled all of them and nothing stays buffered up.

    In the example code we only read out 1 rx message and we use that do while check that I was asking about.

    Would you agree with me that the example code does not cover the corner case I am trying to resolve ? If so, how should I implement the rx handler to have it implemented correctly?

    I hope my elaboration makes sense.

    Regards,

    Mykola

  • Hello. Have you had a chance to check my message ? Unfortunately we are still having issues with can rx handler. Would you be able to advice how to correctly implement the handler to use hardware  fifos correctly ?