FreeRTOS crash caused by CAN task

seb67110 wrote on Thursday, December 18, 2014:


I am facing an issue regarding the implementation of a CAN peripheric in FreeRTOS.

Configuration : FreeRTOS V8.1.2
STM32F407VG (discovery board)

Indeed, i am using a binary semaphore in the reception interrupt of the CAN to trigger a task processing the received data.
The thing is that it makes my Os crash after a couple of minutes and i can’t figure out how to debug it.
The interrupts priorities are set correctly (priority of CAN Rx interrupt set to minimum for test) and i for test purposes i activated only the CANRx Task.

Here is my CAN Rx interruption :

void CAN1_RX0_IRQHandler(void){
	BaseType_t xHigherPriorityTaskWoken=pdFALSE;

	CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);

	xSemaphoreGiveFromISR(CANRx_semaphore, &xHigherPriorityTaskWoken);
	portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); 

Here is my CAN Rx Task :

xTaskCreate( CANRxTask, "CANRx", configMINIMAL_STACK_SIZE, ( void * ) NULL, 3, NULL );
void CANRxTask( void *pvParameters ){
		if(xSemaphoreTake(CANRx_semaphore, portMAX_DELAY)){

			else if(RxMessage.StdId==0x0C1){

I can post you my CAN_init function if needed.

I can’t figure out what is going wrong.
Any help is appreciated.
Thanks !

rtel wrote on Thursday, December 18, 2014:

Do you have configASSERT() defined?

As you are using an STM32, are you calling NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); before the RTOS scheduler is started?

How are you protecting the xRxMessage structure from simultaneous access from the interrupt and the task, or a second interrupt overwriting the structure before the task has had time to process the first? If this is a small structure then you may be better off posting a copy of the structure to a queue rather than using a semaphore. That way you will get both buffering and mutual exclusion on the data. However, if the interrupt is fast a queue may be a bit cumbersome and a circular buffer would be better. There is a thread safe circular buffer included in our TCP/IP stack that people are starting to use for this purpose.


jradoslav wrote on Monday, December 22, 2014:

RxMessage is global? its probably not good solution.Better is data frames queue.
Data transmition from ISR via global variable is unsafe. CANRx_semaphore not solve problem in your code.

Where is code to reenabling or enable/disable CAN_ISR? CAN_Receive function probably enables an interrupt handler at the end of subroutine.
you have to reenable CAN ISR after reading message, other solution will cause problem with rewriting message data.

seb67110 wrote on Monday, December 22, 2014:

First, thank you for your answers. I couldn’t work on it until today.

I called NVIC_PriorityGroupConfig at the beginning of my main() : i don’t think it is a interrupt priority issue. I had an issue of priorities some weeks ago and nothing worked at the time. Now it is working, it is just unstable because the OS crashes after few minutes or sometimes seconds.

Also i just configured configASSERT(). So it clearly shows me that when the OS crashes an assertion is created because xSemaphoreGiveFromISR returns 0 (errQUEUE_FULL).
Why ? Maybe because like you said the interrupt is faster than the task ?
If an assertion is created at this point, it is not a simultateous access of the memory problem, isn’t it ?
In all cases it is weird, because for my test, i am using a CAN sniffer by sending a frame each 100ms (250kbps can configuration). So i’m not overloading the bus and it still crashes.

@Radoslav: yes RxMessage is global. Can you enlighten me about why data transmition from ISR via global variables is unsafe please ?

I put my code for enabling the CAN ISR first in the CAN_Init function, but i moved it at the beginning of the CANRx Task because it made my OS crash if i was receiving a Frame before my CANRx Task was created. (i modified my first post with the code).

Why should i reenable the CAN ISR after reading each message ? I don’t think the CAN_Receive function does deactivate the ISR, it just resets a flag after reading i guess.

In all cases i am going to try to implement a queue with a structure. I keep you posted.
Thanks for your imputs !

jradoslav wrote on Monday, December 22, 2014:


In most SW/HW architectures CAN ISR is controled by PeriferialClock, enable-maskbit and status register.
If interrupt is enabled and ISR was occourred, status bit goes high.
Interrupt cannot run, while status bit is not cleared. This bit is usually cleared after reading CAN message register automatically or you have to manually enable next transmition/reception by writing control bit.

if CAN_Receive enables next reception, CANRxTask takes semaphore and reads message from the global variable, but the time interval is as follows(sequence):

from|(isr occurs, read message register to glob variable(*ISR is active) giving semaphore, taking, reading glob variable ) end|

Problem: *ISR - from this timepoint can occur CAN_ISR any time, which writes to same global variable. if time point is “reading glob variable” this variable can be corrupted by several writes from ISR.

this situations can be solved by relocating (*ISR is active) code after ‘reading glob variable’ in your case at and of if(xSemaphoreTake){ reading, here} block.

You have to study how CAN_Receive enable next reception, and read STM32F407VG CAN ISR behavior and register documentation.

jradoslav wrote on Monday, December 22, 2014:

The main idea is the same as Real Time Engineers ltd answered first. According to them TCP/IP stack contains implementation for solutions of similar problems.