STM32 Not resuming other tasks after IRQ

moamind wrote on Tuesday, September 02, 2014:

I am writing an application using FreeRTOS V8.0.1 and the STM32F4 discovery board (Cortex-M4) in keil.

When powering and running a GPS reciever on USART2 after the IRQ is run no other tasks will resume. It was my understanding that with the Cortex-M4 processors no state saving functions need to be called during the ISR to preserve the system state and ISRs can be written as normal ensuring any rtos functions are *FromISR

In the code below I have an LCD initialise and display the some SD card information with another task updating the display with clock information. As soon as the gps_task runs and the chip recieves power (therefore transmitting NMEA strings) the IRQ will fire, the task run and then according to the debugger the application never leaves the gps_tasks infinite while loop (even sleeping the task doesnt help).

I do not understand what could cause the other tasks (LED flag, Update time, etc) to no longer be scheduled.

MAIN.C

:::c++
int main(void)
{
	prvSetupHardware();
	
	usartGate = xSemaphoreCreateMutex();
	lcdGate = xSemaphoreCreateMutex();
	sdCardGate = xSemaphoreCreateMutex();
	
	gpsMSG = xSemaphoreCreateMutex();
	supremaMSG = xSemaphoreCreateMutex();
	
	xTaskCreate(lcd_demo, (signed char*)"lcd", 512, NULL, 2, NULL);
	xTaskCreate(alert_flash, (signed char*)"lcd", 512, NULL, 1, NULL);
	xTaskCreate(update_time, (signed char*)"time", 512, NULL, 1, NULL);
	xTaskCreate(gps_task, (signed char*)"gps", 512, NULL,1,NULL);
	
	/* Start the scheduler. */
	vTaskStartScheduler();


	for( ;; );
}
/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
void lcd_demo(void){
	
	char buffer[40];
	int row = 4;
	
	if(xSemaphoreTake(lcdGate, 500)){
		lcd_init();	
		GLCD_Clear();
		GLCD_TextGoTo(0,row);
		row++;
		GLCD_WriteText("Power On");
		
		//Begin Boot Message
		GLCD_TextGoTo(0,row);
		row++;
		GLCD_WriteText("BETR V3.1 ");
		GLCD_TextGoTo(0,row);
		row++;
		row++;
		GLCD_WriteText("Acme PTY LTD");
		GLCD_TextGoTo(0,row);
		row++;
		row++;
		GLCD_WriteText("  Greetings Earthlings");
		GLCD_TextGoTo(0,row);
		row++;
		if(xSemaphoreTake (sdCardGate, 500)){
			GLCD_WriteText("Read SD Card Contents");
			if(!disk_initialize(0)){
				GLCD_TextGoTo(0,row);
				row++;
				GLCD_WriteText("Disc Initialised");
				if(!f_mount(0, &FatFs)){
					GLCD_TextGoTo(0,row);
					row++;
					GLCD_WriteText("Drive Mounted");
					fResult = f_opendir(&workDir, "");
					if(fResult == FR_OK){
						GLCD_TextGoTo(0,row);
						row++;
						GLCD_WriteText("Opened Directory");
						fResult = f_readdir(&workDir, &info);
						while(fResult == FR_OK && info.fname[0] != NULL){
							snprintf(buffer, 40, "Name: %s Size: %d Bytes",info.fname, info.fsize);
							row++;
							GLCD_TextGoTo(0,row);
							GLCD_WriteText(buffer);
							fResult = f_readdir(&workDir, &info);
		}}}}}
		xSemaphoreGive(lcdGate);
	}
	vTaskDelete(NULL);
	
	while(1){
		vTaskDelay(200);
	}
}


/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
void alert_flash(void){
	
	while(1){
		//alert_red(ON);
		alert_green(OFF);
		vTaskDelay(50);
		//alert_red(OFF);
		alert_green(ON);
		vTaskDelay(20);
	}
}

/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
void update_time(void){
	char dateString[40];
	char timeString[40];
	RTC_DateTypeDef  RTC_DateStructure;
	RTC_TimeTypeDef  RTC_TimeStruct;
	
	while(1){
		RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure); //retrieve date information, consider shifting to low priority task with higher interval
		RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);    //retrieve time information
			//Build display strings in preperation
		snprintf(dateString, 40, "Date 20%02d/%02d/%02d", RTC_DateStructure.RTC_Year, RTC_DateStructure.RTC_Month, RTC_DateStructure.RTC_Date);
		snprintf(timeString, 40, "Time %02d:%02d:%02d", RTC_TimeStruct.RTC_Hours, RTC_TimeStruct.RTC_Minutes, RTC_TimeStruct.RTC_Seconds);
		if(xSemaphoreTake(lcdGate, 500)){
			GLCD_TextGoTo(0,1);
			GLCD_WriteText("                              ");
			GLCD_TextGoTo(0,2);
			GLCD_WriteText("                              ");
			GLCD_TextGoTo(0,1);
			GLCD_WriteText(dateString);
			GLCD_TextGoTo(0,2);
			GLCD_WriteText(timeString);
			xSemaphoreGive(lcdGate);
		}
		vTaskDelay(500);
	}
}			

/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/

void USART2_IRQHandler(void){
    alert_red(ON);
}

void gps_task(void){
	
	gps_init();
	power_GPS(POWER_ON);
	
	while(1){
	vTaskDelay(1000);
}
	}

/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
static void prvSetupHardware( void )
{
	/* Setup STM32 system (clock, PLL and Flash configuration) */
	SystemInit();
		
	/* Ensure all priority bits are assigned as preemption priority bits. */
	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
	power_init();
	alert_init();
	power_LCD(POWER_ON);
	print_usart_init();
	App_RTC_Init();
}

gps_init

:::c++

void gps_init(void){
	USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
  
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

	USART_InitStructure.USART_BaudRate = 4800;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx;
  USART_Init(USART2, &USART_InitStructure);
	
  /* Enable the USART Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  
  /* Enable USART */
  USART_Cmd(USART2, ENABLE);
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);

// 	receiverState = waitForStart;
// 	parsedMsg.msg_valid = NOT_VALID;
// 	lastKnowGoodPos.msg_valid = NOT_VALID;
}

davedoors wrote on Tuesday, September 02, 2014:

I can’t see that you are clearing the uart interrupt. Perhaps you are just continuously exiting then reentering the interrupt.

moamind wrote on Tuesday, September 02, 2014:

Close Dave, thanks for the nudge.

It appears on this chipset the data buffer must be read to clear the interrupt.

modifying the IRQ handler to…

:::c++

void USART2_IRQHandler(void){
	uint8_t data;
	data = (uint8_t)USART_ReceiveData(USART2);

	alert_red(ON);
}


It is always fun starting with a new chip and a new OS at the same time.
Mods can delete as this is not a FreeRTOS issue if they wish.