STM32 crash in list.c

totalsam wrote on Tuesday, January 18, 2011:

Dear all,

Thank you very much for reading my post. I have some issues with a custom board based on a STM32 (Cortex M3).

I use FreeRTOS v6.1.0 with CodeSourcery’s GCC and Eclipse.

In my design, I communicate with a GPRS device through an USART port. The crash occurs when receiving a packet from the GPRS device, after a few minutes running.

When a data arrives on the USART, the DMA copies it to a buffer, and an interrupt is generated. In the ISR, I just give a semaphore, which unblocks an other task.

I paid attention to the special remarks for CM3 users. Here is the init of the NVIC:

	NVIC_InitStructure.NVIC_IRQChannel = UART_Gprs_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

In FreeRTOSconfig.h, is set to 255, which on the STM32 means 15. The interrupt priority is the same as the kernel interrupt priority. I tried to put it 1 above (set it to 14), but no change.

When the crash occurs, the code loops forever in list.c, in vListInsert(…), in the for(…) loop. By putting some traces, I was able to find that the code crashes either at the end of the ISR, either at the task side that waits for the semaphore.

Here is the ISR code :

void USART3_IRQHandler(void)
	long xHigherPriorityTaskWoken = pdFALSE;
	debug_flag = 51;
	//Don't need to clear the bit, 'cause the DMA controller normally does it
	USART_ITConfig(UART_Gprs, USART_IT_RXNE, DISABLE);//Disable interrupt
	xSemaphoreGiveFromISR(xGprsRxSemaphore, &xHigherPriorityTaskWoken);
	if (xHigherPriorityTaskWoken == pdTRUE)
		debug_hpw = 1;
		debug_flag = 52;
		debug_hpw = 0;
		debug_flag = 55;
	portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );

I also noticed that if I don’t put the portEND_SWITCHING_ISR(…) in this ISR, the crash does not occur.

Here is the code at the task side:

			debug_flag = 53;
			xSemaphoreTake(xGprsRxSemaphore,  ( portTickType ) 200 / portTICK_RATE_MS );
			debug_flag = 54;
			dma_cnt = DMA_GetCurrDataCounter(UART_Gprs_Rx_DMA_Channel);
			while( (gprsRxBuffIndex !=
					(UART_BUFFER_SIZE - dma_cnt) ) && (data_cnt < maxLength))
				buffer[*length] = gprsRxBuffer[gprsRxBuffIndex++];
				*length = (*length) + 1;
				if (gprsRxBuffIndex > UART_BUFFER_SIZE-1)
					gprsRxBuffIndex = 0;

Could someone give me a few hints to debug my code and try to find what’s going on ?

Thank you a lot in advance and best regards,


rtel wrote on Wednesday, January 19, 2011:

Thank you very much for reading my post.

…and thank you for doing some research before posting, and providing good information in your post.

Do you set the interrupt priority grouping anywhere?  On an STM32, this is normally done with the following line of code:
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );


totalsam wrote on Wednesday, January 19, 2011:

Dear Richard,

You are absolutely right, this step is missing, and it never crashed again since I made this change. Thank you very much for your help, and thank you as well for FreeRTOS !

Best regards,


gibot wrote on Sunday, June 19, 2011:

I have the same probleme. My code looks very the same like here shown but I’m waiting for receiving CAN messages so I use the interrupt for can. I have changed the priority group and have checked my settings for the interrupt. But the I get the same error, my programm stays in the for loop in list.c
I use libopenstm32.

This is my code:


	/* NVIC setup. */
	//set priority, configMAX_SYSCALL_INTERRUPT_PRIORITY is the highest priority interrupts can have which calls freertos functions
	nvic_set_priority(NVIC_USB_LP_CAN_RX0_IRQ, configKERNEL_INTERRUPT_PRIORITY - 32);
	/* Reset CAN. */
	/* CAN cell init. */
	if (can_init(CAN1,
		     false,           /* TTCM: Time triggered comm mode? */
		     false,            /* ABOM: Automatic bus-off management? */
		     false,           /* AWUM: Automatic wakeup mode? */
		     false,           /* NART: No automatic retransmission? */
		     false,           /* RFLM: Receive FIFO locked mode? */
		     false,           /* TXFP: Transmit FIFO priority? */
		     4))             /* BRP+1: Baud rate prescaler */
		/* Die because we failed to initialize. */
		while (1)
	/* CAN filter 0 init. */
				0,     /* Filter ID */
				0,     /* CAN ID */
				0,     /* CAN ID mask */
				0,     /* FIFO assignment (here: FIFO0) */
				true); /* Enable the filter. */

Code of the waiting task:

		//enable interrupt
		can_enable_irq(CAN1, CAN_IER_FMPIE0);
		//wait till new can data received
		xSemaphoreTake(xSemaphoreWaitingForCanReceive, LONG_TIME);
			//gets the number of waiting can packages from the FMP0 in the CAN receive Register of FIFO0
			waitingCanPackages = CAN_RF0R(CAN1) & CAN_RF0R_FMP0_MASK;
			while(waitingCanPackages > 0){
				gpio_clear(GPIOC, GPIO12);
				//gets can packages until the FIFO queue is empty
				for(;waitingCanPackages > 0;waitingCanPackages--){
					ticksSinceBooted = xTaskGetTickCount();
					//read data from can
					readCan(&sensorDataLength, sensorData, &canId);
					//reduce can data to required digits
					writeCanId = (uint16_t)canId;
					//puts canId to the array
					arCanId = (uint8_t*)&writeCanId;
					//calculate the data to write
					//header 1 Byte
					fileData[fileDataLength] = 0xCA;
					//timestamp 4 Byte
					memcpy(& (fileData[fileDataLength + 1]), (uint8_t*)&ticksSinceBooted, 4 * sizeof(uint8_t));
					//can Id 2 Byte
					fileData[fileDataLength + 5] = arCanId[0];
					fileData[fileDataLength + 6] = arCanId[1];
					//data length 1 Byte
					fileData[fileDataLength + 7] = sensorDataLength;
					//data 0 - 8 Byte (sensorDataLength)
					memcpy(&(fileData[fileDataLength + 8]), sensorData, sensorDataLength * sizeof(uint8_t));
					//calculate the full length of the data to write
					fileDataLength += (8 + sensorDataLength);
				//write the data on the card
				//writeFat(fileDataLength, fileData);
				//reset the length of the data that will be written
				fileDataLength = 0;
				gpio_set(GPIOC, GPIO12);
				//check if more can packages are waiting
				waitingCanPackages = CAN_RF0R(CAN1) & CAN_RF0R_FMP0_MASK;

Interrupt Handler:

void usb_lp_can_rx0_isr(void)
	long xHigherPriorityTaskWoken = pdFALSE;
	//disable interrupt
	can_disable_irq(CAN1, CAN_IER_FMPIE0);
	//unlock Log Task
	/* If xHigherPriorityTaskWoken was set to true you
	we should yield.  The actual macro used here is
	port specific. */
	portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );

Thanks for your Help

davedoors wrote on Sunday, June 19, 2011:

What number is configKERNEL_INTERRUPT_PRIORITY - 32 giving you? That does not look right.
Are you calling NVIC_PriorityGroupConfig() anywhere?

gibot wrote on Sunday, June 19, 2011:

This is the Priority Group Configuration:


scb_aircrTemp contains the value of the register before editing without VECTKEY
SCB_AIRCR_VECTKEY is the key you need to edit the register
SCB_AIRCR_PRIGROUP_GROUP16_NOSUB contains the value for no subriority bits
and SCB_AIRCR_PRIGROUP_LSB contains the position of the group priority bits

libopenstm32 does not contain a function to do this.

configKERNEL_INTERRUPT_PRIORITY is set to 255 for the lowest priority, I’ve tried it with -32 for a priority that is a littel higher but lower as the max Syscall priority. I have tried it with 255 without -32 to but that’s the same effect.

davedoors wrote on Sunday, June 19, 2011:

This is the Priority Group Configuration:


I don’t understand that at all, but am sure it is not configuring the priority grouping in the interrupt controller. Read post 2 in this thread.

configKERNEL_INTERRUPT_PRIORITY is set to 255 for the lowest priority, I’ve tried it with -32 for a priority that is a littel higher but lower as the max Syscall priority. I have tried it with 255 without -32 to but that’s the same effect.

Read point 3 here and check how nvic_set_priority() is expecting the priority to be specified. I am 99% sure it is not expecting a value above 15, in which case, you are not using the function correctly. I would also set the priority before enabling the interrupt, you have it the other way around.

I recommend reading the Cortex-M NVIC reference manual to understand how to set the NVIC up.

gibot wrote on Sunday, June 19, 2011:

I don’t use the stm32 stdperipheral lib, I use libopenstm32.
The NVIC_PriorityGroupConfig function of stm32 std lib does exactly the same as my line for setting the priority group.

In stm32 stdperipheral lib, the highest priority you can set is 15. But in libopenstm32 you set the priority to the value how it is set in the register and thats an 8bit value, so the highest number you can set is 255 and that’s the lowest interrupt priority

gibot wrote on Tuesday, June 21, 2011:

I have reread the stm32 manual und rechecked my register settings, by read out the registers and I think I’ve setted them right.

But I think there is an other reason for my problem.

I have a second task for increase a timer variable that should runs every 10ms. Here I use the vTaskDelayUntil function and I think it crashes if this function sets the scheduler in suspend mode and then the can interrupt happens and call api function while the scheduler is in suspend mode.

Is that possible? How it’s possible to call a function every 10ms in the right way? Can I use a hardware timer?

rtel wrote on Tuesday, June 21, 2011:

Suspending the scheduler will not stop interrupts from executing (as you know).  If an interrupt attempts a context switch while the scheduler is suspended then the context switch is held pending until the point where the scheduler is resumed (un-suspended).  That is normal sequence of events, and tested well, but that is not a guarantee of course.  I would be surprised however if that was causing the crash without any external/other factors.


gibot wrote on Tuesday, June 21, 2011:

void disk_timer_task(void *pvParameters) {
portTickType LastWakeTime;
const portTickType period = 10 / portTICK_RATE_MS;

LastWakeTime = xTaskGetTickCount();

vTaskDelayUntil(&LastWakeTime, period);

thats the second task

timeSinceBooted is definded global.

If I don’t start this task only the task that waits for can receive it doesn’t crash. If is start this task it crashes.

Other tasks don’t run.

davedoors wrote on Wednesday, June 22, 2011:

portTICK_RATE_MS is calculated from configTICK_RATE_HZ. What is configTICK_RATE_HZ set to? It is defined in FreeRTOSConfig.h. If 10 / portTICK_RATE_MS was zero or 1 then you will have a problem if disk_timer_task has a high priority because tasks that have a lower priority will never run.

gibot wrote on Thursday, June 30, 2011:

the disk_timer_task had the same priority as the other task.

But I don’t use it anymore, I use the systick hook for that. But my tasks crash if I’have more than that tasks that waits for the can receive.

gibot wrote on Thursday, June 30, 2011:

I think the problem is that the interrupt fires while the programm is in a critical section. I have checked the nvic priority register and that is set to 1111 0000 and I have checked the SCB register that is set to 11111010000001010000001100000000
011 at position 10:8 stands for the priority group and that is the right setting for no subpriority bits and 4 pre-emption priority bits.