Interrupt Configuration on STM32F407

kronanberg wrote on Wednesday, April 03, 2013:

Dear all,

I’m using a board (Core407V) based on a STM32F407 (Cortex M4) and I 'm having problems. I use FreeRTOS V7.1.0 with Keil uVision 4. My project consist to achieve a data acquisition system.

The system receives :
- data provided by the GPS throught UART3 
- data provided by the Inertial Measurement Unit through UART4
- data provided by wind sensor through analog inputs

Then, the system stores these data on Sd card and sends them throught UART1 on a computer. My work is divided is several main tasks (Acquisition Task, Compute Task, Store Task and Send Task) and two others task to recept the GPS and IMU data.

But I think, I have an error in my interrupt initialization because there is crash which often occurs when receiving data throught UART after few minutes or hours running. In the UART ISR, I give a semaphore to unblock an other task (_when the frame is completed _). I think I have similary problem describ on the other post (http://sourceforge.net/projects/freertos/forums/forum/382005/topic/4059693) but I don’t find my error.

Here is my NVIC configuration :

/*------------------------------------------------------------------------
 * Peripheral		NVIC - Nested Vectored Interrupt Controller
 * -----------------------------------------------------------------------
 * function			Enable Interrupt and Configure the Priority
 * -----------------------------------------------------------------------*/
void NVIC_Config(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
	
	/* Selectionne la priorite du group */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	
	/* Enable the DMA2 Stream0 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn ;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	  /* Enable the TIM1 global Interrupt - FreqMHU*/
  NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  /* Enable the TIM1 Interrupt - Overflow TIM1*/
  NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_TIM10_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  /* Enable the TIM2 Interrupt - Overflow TIM2 */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure); 
	
	/* Enable the UART4 Interrupt IMU */
  NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
  /* Enable the USART3 Interrupt GPS */
  NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

Here is my NVIC configuration :

/*------------------------------------------------
* INT.GLO UART3
* -----------------------------------------------
* Int. USART3 - USART_IT_RXNE
* When Each byte come from GPS is received
* -----------------------------------------------*/

Here is the ISR code for USART3 :

/* Public variables ------------------------------------------------------*/
extern xSemaphoreHandle xBinarySemaphoreGPS;
extern char GPSPacket[MAX_GPS_PACKET_SIZE];		// Used in USART3 Interrup (Receipt Frame)
extern unsigned char StateBufGps;;						// Used in USART3 Interrup (Receipt State)
extern uint16_t RxCounterGps;									// Used in USART3 Interrup (byte counter)
/* Function ------------------------------------------------------------------*/
void USART3_IRQHandler(void)
{
	unsigned char RxBufGps;
	portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
	/* Reception GPS - USART3 */
	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
	{
		/*	Lecture de l'octet transmit */
		RxBufGps = (USART_ReceiveData(USART3) & 0xFF);
				
		/* Test si il n'y a pas de depassement du compteur du buffer -------------*/
		if(RxCounterGps<=(MAX_GPS_PACKET_SIZE-2))
		{				
			/*	Lecture de l'octet transmit */
			GPSPacket[RxCounterGps++] = RxBufGps;
			/* Si il y a plus de 2 caracteres lu */
			if(RxCounterGps>2)
			{
				/* Verifie que l'on a pas le caractere de fin de trame Cr Lf */
				if((GPSPacket[RxCounterGps-2]==0x0D) & (GPSPacket[RxCounterGps-1]==0x0A))
				{
					/* Donne le semaphore */
					xSemaphoreGiveFromISR(xBinarySemaphoreGPS,&xHigherPriorityTaskWoken);
					/* Force à changer de tache */
					portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
						
					/* Reset du compteur  */
					RxCounterGps = 0;
				}
			}
		}
		
		/* Si il y a depassement du buffer, reinitialise la compteur Buffer GPS --*/
		else
		{
			#ifdef USE_DEBUG_INT_USART	
					printf("Overflow RxCounterGPS : %d \n",RxCounterGps);
			#endif
			RxCounterGps = 0;
		}
	}
}
[code]
Here is the code at the task associated to this interrupt:
[code]
/*------------------------------------------------------------------------
 * Task			GPS
 * -----------------------------------------------------------------------
 * Descr			Parse GPS Frame
 * Priority		tskIDLE_PRIORITY + 5
 * Size				configMINIMAL_STACK_SIZE*2
 * -----------------------------------------------------------------------*/
void TaskGps(void * pvParameters)
{
	/* The parameters are not used. */
	( void ) pvParameters;
	
	/* If Use Log Tick Counter, enable TIM2 counter */
	#ifdef USE_CNT_TASKGPS
		TIM_Cmd(TIM2,ENABLE);
	#endif
		
	/* Prend le semaphoreGPS 1 fois au depart */
	xSemaphoreTake(xBinarySemaphoreGPS, portMAX_DELAY);
	
	for(;;)
	{
		/* Prend le semaphoreGPS */
		xSemaphoreTake(xBinarySemaphoreGPS, portMAX_DELAY);
		
		/* Disable Interrupts */
		#ifdef USE_NOPREMP
			DisableInterrupts();
			taskDISABLE_INTERRUPTS();						
		#endif
		
		/* Debug Task GPS*/
		#ifdef USE_DEBUG_TASK
			//printf("\nTASK GPS\t");
			strcpy(SecondLastDebugTask,LastDebugTask);
			sprintf(LastDebugTask,"TASK GPS");
		#endif
		
		/* Get Cnt Tm2 */
		#ifdef USE_CNT_TASKGPS
			CntStart = TIM_GetCounter(TIM2);
		#endif
		/* Analyse la trame GPS */
		parseGPSPacket(GPSPacket,&GPSData);
		/* Mise à jour de l'horloge temps reel avec l'heure GPS (une fois au depart) */
		if((GPSData.UTC_time != 0)&&(FirstUpdateTime == 1))
		{
			/* Mise à jour de l'heure */
			UpdateTime(GPSData.UTC_time);
	
			/* Reset FirstUpdateTime*/
			FirstUpdateTime=0;
			
		}
		if((GPSData.date != 0)&&(FirstUpdateDate == 1))
		{
				/* Mise à jour de la date */
				UpdateDate(GPSData.date);
			
				/* Reset FirstUpdateTime*/
				FirstUpdateDate=0;
		}
						
		/* Get Cnt Tm2 and computime task tick execute */
		#ifdef USE_CNT_TASKGPS
			CntStop = TIM_GetCounter(TIM2);
			if(CntStop>CntStart) TickTask = CntStop - CntStart;
			else TickTask = (65535-CntStart) + CntStop  ;
		#endif
		
		/* Enable Interrupts */
		#ifdef USE_NOPREMP
			EnableInterrupts();
			taskENABLE_INTERRUPTS();						// Reactive les interruptions
		#endif	
		
		/* Enable the USART3 Receive interrupt */
		//USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
	}
}
[code]
Many thanks in advance for your assistance.

kronanberg wrote on Wednesday, April 03, 2013:

Sorry for the bad layout

Here is the ISR code for USART3 :

/*------------------------------------------------------------------------
 * INT.GLO		UART3
 * -----------------------------------------------------------------------
 * Int.				USART3 - USART_IT_RXNE
 * When				Each byte come from GPS is received
 * -----------------------------------------------------------------------*/
/* Public variables ------------------------------------------------------*/
extern xSemaphoreHandle xBinarySemaphoreGPS;
extern char GPSPacket[MAX_GPS_PACKET_SIZE];	// Used in USART3 Interrup (Receipt Frame)
extern unsigned char StateBufGps;;		// Used in USART3 Interrup (Receipt State)
extern uint16_t RxCounterGps;			// Used in USART3 Interrup (byte counter)
/* Function ------------------------------------------------------------------*/
void USART3_IRQHandler(void)
{
	unsigned char RxBufGps;
	portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
	/* Reception GPS - USART3 */
	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
	{
		/*	Lecture de l'octet transmit */
		RxBufGps = (USART_ReceiveData(USART3) & 0xFF);
				
		/* Test si il n'y a pas de depassement du compteur du buffer ---------*/
		if(RxCounterGps<=(MAX_GPS_PACKET_SIZE-2))
		{				
			/*	Lecture de l'octet transmit */
			GPSPacket[RxCounterGps++] = RxBufGps;
			/* Si il y a plus de 2 caracteres lu */
			if(RxCounterGps>2)
			{
			 /* Verifie que l'on a pas le caractere de fin de trame Cr Lf */
			 if((GPSPacket[RxCounterGps-2]==0x0D) & (GPSPacket[RxCounterGps-1]==0x0A))
			 {
			  /* Donne le semaphore */
			  xSemaphoreGiveFromISR(xBinarySemaphoreGPS,&xHigherPriorityTaskWoken);
			  /* Force à changer de tache */
			  portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
					
			  /* Reset du compteur  */
			  RxCounterGps = 0;
			 }
			}
		}
		
		/* Si il y a depassement du buffer, reinitialise la compteur Buffer GPS --*/
		else
		{
			#ifdef USE_DEBUG_INT_USART	
					printf("Overflow RxCounterGPS : %d \n",RxCounterGps);
			#endif
			RxCounterGps = 0;
		}
	}
}

Here is the code at the task associated to this interrupt:

/*------------------------------------------------------------------------
 * Task			GPS
 * -----------------------------------------------------------------------
 * Descr			Parse GPS Frame
 * Priority		tskIDLE_PRIORITY + 5
 * Size				configMINIMAL_STACK_SIZE*2
 * -----------------------------------------------------------------------*/
void TaskGps(void * pvParameters)
{
	/* The parameters are not used. */
	( void ) pvParameters;
	
	/* If Use Log Tick Counter, enable TIM2 counter */
	#ifdef USE_CNT_TASKGPS
		TIM_Cmd(TIM2,ENABLE);
	#endif
		
	/* Prend le semaphoreGPS 1 fois au depart */
	xSemaphoreTake(xBinarySemaphoreGPS, portMAX_DELAY);
	
	for(;;)
	{
		/* Prend le semaphoreGPS */
		xSemaphoreTake(xBinarySemaphoreGPS, portMAX_DELAY);
		
		/* Disable Interrupts */
		#ifdef USE_NOPREMP
			DisableInterrupts();
			taskDISABLE_INTERRUPTS();						
		#endif
		
		/* Debug Task GPS*/
		#ifdef USE_DEBUG_TASK
			//printf("\nTASK GPS\t");
			strcpy(SecondLastDebugTask,LastDebugTask);
			sprintf(LastDebugTask,"TASK GPS");
		#endif
		
		/* Get Cnt Tm2 */
		#ifdef USE_CNT_TASKGPS
			CntStart = TIM_GetCounter(TIM2);
		#endif
		/* Analyse la trame GPS */
		parseGPSPacket(GPSPacket,&GPSData);
		/* Mise à jour de l'horloge temps reel avec l'heure GPS (une fois au depart) */
		if((GPSData.UTC_time != 0)&&(FirstUpdateTime == 1))
		{
			/* Mise à jour de l'heure */
			UpdateTime(GPSData.UTC_time);
	
			/* Reset FirstUpdateTime*/
			FirstUpdateTime=0;
			
		}
		if((GPSData.date != 0)&&(FirstUpdateDate == 1))
		{
				/* Mise à jour de la date */
				UpdateDate(GPSData.date);
			
				/* Reset FirstUpdateTime*/
				FirstUpdateDate=0;
		}
						
		/* Get Cnt Tm2 and computime task tick execute */
		#ifdef USE_CNT_TASKGPS
			CntStop = TIM_GetCounter(TIM2);
			if(CntStop>CntStart) TickTask = CntStop - CntStart;
			else TickTask = (65535-CntStart) + CntStop  ;
		#endif
		
		/* Enable Interrupts */
		#ifdef USE_NOPREMP
			EnableInterrupts();
			taskENABLE_INTERRUPTS();	// Reactive les interruptions
		#endif	
		
		/* Enable the USART3 Receive interrupt */
		//USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
	}
}

Many thanks in advance for your assistance.

rtel wrote on Wednesday, April 03, 2013:

/* Enable the USART3 Interrupt GPS */
  NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

This interrupt priority is being set to 5 - is configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY also set to 5?  So something like this in FreeRTOSConfig.h:

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
#define configKERNEL_INTERRUPT_PRIORITY 	\
        ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY      \ 	
        ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

Is USE_DEBUG_INT_USART defined?  printf’ing from an interrupt could cause you problems.

Do you have stack overflow detection turned on?

Is the interrupt stack large enough?  Stack overflow detection will only detect stack overflows in the tasks.  The stack used by interrupts is the same stack used by main() - so the stack set up by the linker script/project configuration.

Regards.

kronanberg wrote on Wednesday, April 03, 2013:

Thank for your response.

In my projet, The configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY set to 15

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			0xf
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	15
#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

Otherwise for the moment, the stack overflown detection is turn off (for the tasks).

I think the interrupt stack is large enough because I increased the stack size and heap size in the  “startup_stm32f4xx.s” file.

I 'll configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY set to 5 and try if it works. If it doen’t work I add  stack overflow detection.

rtel wrote on Wednesday, April 03, 2013:

configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY set to 15

That is definitely an error then, and will lead to intermittent crashes if you have an interrupt that uses the interrupt safe FreeRTOS API (those functions that end in FromISR) from an interrupt of priority 5.  Remember that on a Cortex-M priority 5 will preempt priority 15.

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

Regards.

kronanberg wrote on Wednesday, April 03, 2013:

Thank you Richard,

But I have one more questions because I still have crashes with this configuration :

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	15
#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

NVIC configuration :

/*------------------------------------------------------------------------
 * Peripheral		NVIC - Nested Vectored Interrupt Controller
 * -----------------------------------------------------------------------
 * function			Enable Interrupt and Configure the Priority
 * -----------------------------------------------------------------------*/
void NVIC_Config(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
	
	/* Selectionne la priorite du group */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	
	/* Enable the DMA2 Stream0 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn ;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_LOWEST_INTERRUPT_PRIORITY - 5;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	  /* Enable the TIM1 global Interrupt - FreqMHU */
  NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_LOWEST_INTERRUPT_PRIORITY - 4;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  /* Enable the TIM1 Interrupt - Overflow TIM1 */
  NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_TIM10_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_LOWEST_INTERRUPT_PRIORITY - 3;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  /* Enable the TIM2 Interrupt - Overflow TIM2 */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_LOWEST_INTERRUPT_PRIORITY - 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure); 
	
	/* Enable the UART4 Interrupt IMU */
  NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_LOWEST_INTERRUPT_PRIORITY - 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
  /* Enable the USART3 Interrupt GPS */
  NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_LOWEST_INTERRUPT_PRIORITY;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  }

So what are the interrupts used by FreeRTOS and what are their priority level ? because I don’t see where they are configured.

Thank you very much for your help.

Regards,

Ronan.

rtel wrote on Wednesday, April 03, 2013:

The handlers used by FreeRTOS are listed as part of the answer to FAQ item 1 on this page: http://www.freertos.org/FAQHelp.html - they run at the priority set by configKERNEL_INTERRUPT_PRIORITY, which should always be the lowest priority available.

Regards.