STM32 CAN receive interrupt issues

skv19 wrote on Thursday, July 05, 2012:

Hi All,

I have an issue  with CAN interrupt in STM32 Cortex-M3 and couldn’t figure out what is wrong. Here is my code design:
///////CAN Receive interrupt////////////////////
CAN_Receive(CAN1, CAN_FIFO0, &RxMsg);
/***Do some processing on received message***/
portBASE_TYPE xHigherPriorityTaskWoken = 0;
xSemaphoreGiveFromISR(SEM_DEVICE_COMP_TASK_ID, &xHigherPriorityTaskWoken);
//////Task waiting on semaphore////// - Task created using “xTaskCreate()” & priority set as “3”, Stack size as 256 bytes
Wakes up this task and process received data & do a CAN Tx message which causes other node to send back another CAN message
/////////////////CAN interrupt is set as follows///////////////
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_KERNEL_INTERRUPT_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
Also used NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
Used defaults settings for Freertos as below:
/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255 (lowest) to 0 (1?) (highest). */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */
/* This is the value being used as per the ST library which permits 16 priority values, 0 to 15. This must correspond to the configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest NVIC value of 255. */

In a slower message communication it works, but if I send lots of messages to STM32 it fails. It doesn’t receive all & CAN receive interrupt doesn’t work anymore. Ideally I want ISR to be completed & then run the task. Don’t want to interrupt ISR. Any help would be appreciated.


rtel wrote on Friday, July 06, 2012:

From a kernel usage point of view, I cannot see anything obviously wrong, but I don’t know what the call:

CAN_Receive(CAN1, CAN_FIFO0, &RxMsg);

does - although that it outside the scope of FreeRTOS support I have some comments.

It looks like CAN_Receive is placing data into RxMsg?  How does the task that handles the CAN data read the data received by the interrupt - is RxMsg simply a global variable?  Is there anything to prevent another interrupt (when interrupts are coming in a bit faster) overwriting the data in RxMsg either before the task has processes it, or worse still, while the task is still processing it?

Ideally I want ISR to be completed & then run the task

The task can’t possible run before the ISR has completed, and if you want the task to run immediately after the ISR completes ensure the priority of the task is relatively high (compared to other tasks in the system) and call

portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );

as the last line in your interrupt handler.

[if you post more code, please ensure the code is inside the codify tags to make it easier to read - the little icon above the text input box with “<>” on it).


cd334 wrote on Friday, July 06, 2012:

Hi all!

I’ve an other idea:
Don’t process the CAN message in the interrupt. Make a queue and send the message to a task through queue. And in this task process the message.
If the message processing in interrupt too long, then the input FIFO in the uC CAN pherpherie is full, then you can lost messages.

///////CAN Receive interrupt////////////////////
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

    CanRxMsg RxMsg;

    CAN_Receive(CAN1, CAN_FIFO0, &RxMsg);

    xQueueSendFromISR( xQueue_CAN_RX, &RxMsg, &xHigherPriorityTaskWoken );

    portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );

skv19 wrote on Friday, July 06, 2012:

Richard & cd334,

Thanks for your suggestions. CAN_Receive() is ST library function & if copies received data to RxMsg a global buffer.
At this point I am not worried about the data integrity (may be later) because there are only 2 nodes on CAN bus & I am trying to establish a reliable messaging scheme here. The idea is Node1 sends data and Node 2 responds with an ack, during this time Node1 is in waiting state & once it receives Ack it send another packet & it goes on like that for about 18 messages.

On Node2 it receives msg in an interrupt handler posts a semaphore & the task waiting on this semaphore wakes up & sends ACK.

I have tested this on an Eval board before porting to Freertos. In eval board it worked just fine with out any RTOS & tasks.

The issue I am seeing here is, it starts working good for about 8 of 18 packets & from there on no more receive interrupts getting generated in STM32. The tasks are still working good.

At this point I don’t know where to look for. Any ideas???
What happens when it receives a CAN message when RTOS is executing a critical section?


richard_damon wrote on Saturday, July 07, 2012:

One thought is that you may want to try stopping the processor after things sop working and with a debugger look at the status registers to see if the can controller is locked in an error state.

It wouldn’t hurt to also check that everything in the hardware is setup right. One thought, especially if it normally processes the same number of message each time, is to check if the hardware is being used in a fifo mode and something isn’t freeing buffers back to the controller.

skv19 wrote on Wednesday, July 11, 2012:

After some more testing I found it is going to HardFault_Handler() and I added code in HardFault_Handler() to capture different registers and one of them is PC where the fault occurred and it always pointing to

pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;

in vListRemove() in list.c file.
Any idea what is going on??

If I don’t post semaphore in interrupt handler then everything works fine, but I don’t want that way.

One more thing to notify here is the same semaphore is used in different places (All other places are Non ISR) because this task needs to wake-up for other functionality also.