cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 FreeRTOS task and SPI interrupt problem

nicolasdeng1989
Associate II
Posted on April 16, 2013 at 12:04

Hi,I am working on a project with STM32F4 and FreeRTOS. I have a SPI ISR for receiving data from SPI in the speed of about 5Mbps, I also have a task which handles those data. The Queue is used to be between the interrupt and task.

xQueue=xQueueCreate(10,sizeof(uint8_t)*BufferSize);

The problem is that the task stops working after some time of normal running. But the SPI receive seems to be still continuing because I can still see the waveforms in the oscillopscope. The implementation of SPI receive ISR is as follows:

void SPI1_IRQHandler(void){static portBASE_TYPE xHigherPriorityTaskWoken;portBASE_TYPE xStatus;xHigherPriorityTaskWoken = pdFALSE;while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);if(index_spi<512){lValueSend[index_spi]=SPI_I2S_ReceiveData(SPI1);index_spi++;SPI_I2S_SendData(SPI1,0x22);}else{index_spi=0;xStatus=xQueueSendToBackFromISR(xQueue,&lValueSend,&xHigherPriorityTaskWoken);portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);}}

And inside the task infinite loop:

xStatus=xQueueReceive(xQueue,&lValueReceive,xTicksToWait);if(xStatus==pdPASS){dataProcess(lValueReceive);}

After some debugging, I found out that the queue becomes full very easily, and the context switch doesn't happen. So it seems that my task just never gets a chance of running again. But if I understand correctly, after the ISR, either we switch the context to the task waiting for queue if this task waiting for the queue has a higher priority than the current one which was interrupted, either we return to the task which was interrupted. My Datahandling task is already set to configMAX_PRIORITIES, so even if we return to the privious task, my task should have been given control to run. Someone can help to analyse and understand?And also the interrupt priority thing makes me confused. My SPI IRQ settings is:

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 

In the FreeRTOS document, there are two which are absolutely not my settings at all. One is

http://www.freertos.org/RTOS-Cortex-M3-M4.html

,''If you are using an STM32 with the STM32 driver library then ensure all the priority bits are assigned to be preempt priority bits by calling NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); before the RTOS is started.''Another one is that the interrupt with priority between configMAX_SYSCALL_INTERRUPT_PRIRITY and configMAX_SYSCALL_INTERRUPT_PRIORITY can use the freeRTOS API functions. My settings are

#define configKERNEL_INTERRUPT_PRIORITY 255#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority  */

With the mapping of STM32, the priority between 11 and 15 can use FreeRTOS API. But my settings are completely out of these two rules, but after test, this is the best config. If I put the NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ) and set the PreemptionPriority to The task stops even more quickly. Someone may also help to understand with this?

#nvic
4 REPLIES 4
Posted on April 16, 2013 at 13:39

I'm not sure the formatting of this message could have been much worse, I skimmed it.

Strikes me that you're not processing the data quickly enough. You could test that by simply throwing away the data and seeing if it still saturates. You could benchmark your processing routine, perhaps independently, and perhaps by using a GPIO pin to mark entry/exit of the routine viewing throughput on a scope.

If your can't process the data quicker than it arrives, at some point the system will saturate. Process it quicker, or throttle the input.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
jpeacock2399
Associate II
Posted on April 16, 2013 at 15:55

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191

In Cortex M NVIC the lower the number the higher the priority. Your SPI interrupt is above the maximum for FreeRTOS, which means it cannot use FreeRTOS APIs. Lower your SPI priority to something below the SYSCALL priority (which is 0xbf or priority 11, STM32 only uses the high 4 bits). Any interrupt which uses FreeRTOS APIs must be at a lower priority than the SYSCALL. Try setting SPI priority to Jack Peacock
nicolasdeng1989
Associate II
Posted on April 16, 2013 at 16:14

Well. I've tried your suggestion. I only receive data but not doing any processing, but the task stops still. So it seems that the problem might not be the slow processing. 

nicolasdeng1989
Associate II
Posted on April 16, 2013 at 16:27

That's exactly what I tried. I know clearly that all the 4bits should be given as preemption bits

(which is NVIC_Group_4) and the interrupt using FreeRTOS API should have priority number between 11 and 15(which is mapped to 191 and 255). But this config (NVIC_Group_4 and preemption priority 14) which is supposed to be the right one makes my task stop almost immediately when SPI gets some data. The wrong setting that I used can still works normally for several seconds and then stops. So that's really weird.

And also I found something similar in the STM32 examples which seemed to be wrong. In the STM32F4  FreeRTOS  httpserver_netconn example, the Ethernet interrupt is used with FreeRTOS API functions. 

void ETH_IRQHandler(void)

{

  portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

  /* Frame received */

  if ( ETH_GetDMAFlagStatus(ETH_DMA_FLAG_R) == SET) {

    /* Give the semaphore to wakeup LwIP task */

    xSemaphoreGiveFromISR( s_xSemaphore, &xHigherPriorityTaskWoken );   

  }

  /* Clear the interrupt flags. */

  /* Clear the Eth DMA Rx IT pending bits */

  ETH_DMAClearITPendingBit(ETH_DMA_IT_R);

  ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS);

  /* Switch tasks if necessary. */

  if ( xHigherPriorityTaskWoken != pdFALSE ) {

    portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );

  }

}

However, its setting is also not like the recommandations:

void ETH_NVIC_Config(void)

{

  NVIC_InitTypeDef   NVIC_InitStructure;

  /* 2 bit for pre-emption priority, 2 bits for subpriority */

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 

  

  /* Enable the Ethernet global Interrupt */

  NVIC_InitStructure.NVIC_IRQChannel = ETH_IRQn;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);    

}

This is becoming more and more confusing, can anyone give a clear explanation?