FatFs, freertos, interrupt

molnardavid wrote on Wednesday, October 07, 2015:

Hi,

I am new at freertos and I need some help. I am using STM32F429 with CubeMx 1.7.0. FreeRTOS and STemWin and fatFs included. I have 2 tasks

blinky task - blinking a led on the board interval = 100ms

main task - read a bmp from sd card and draw it on LCD then clears LCD and start again

until this point everything works fine. Now I would like to detect touch screen from EXTI interrupt. interrupt works fine if I touch the screen almost ~10 interrupts triggered. There is only on thing in the interrupt handler -> print “ISR\r\n” to serial port. This also works fine. BUT!

After some touch (randomy changes but surely happens) my fatFs file systems responds that there is a timeout with the semaphor at f_open. And after this happened once then no more picture drawed on LCD bacause f_open reports this error.

My drawing function looks like this

void guiFile_drawBmp(char* path)
{
	FIL file;       /* File object */
	FRESULT result;    /* FatFs return code */
	result = f_open(&file, path, FA_READ);
	if (result != FR_OK)
	{
		printf("no file");
		return;
	}
	GUI_DrawStreamedBitmapExAuto(Stream_GetData, &file, 0, 0);

	f_close(&file);
}

Everything works fine until I press the touch screen and generate some interrups.

Interrupt handler:

/**
* @brief This function handles EXTI Line[15:10] interrupts.
*/
void EXTI15_10_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI15_10_IRQn 0 */
	printf("ISR!!\r\n");
  /* USER CODE END EXTI15_10_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);

  /* USER CODE BEGIN EXTI15_10_IRQn 1 */
  //CTP_INT_Callback();

  /* USER CODE END EXTI15_10_IRQn 1 */
}

Any help would be appreciated, thank you in advance
Dave

richard_damon wrote on Wednesday, October 07, 2015:

Is the printf routine in you system safe to use from interrupts?

molnardavid wrote on Wednesday, October 07, 2015:

Thank you for fast answer
Good point but!

if I blink my system LED it works

void EXTI15_10_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI15_10_IRQn 0 */
	HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_3);
  /* USER CODE END EXTI15_10_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);

  /* USER CODE BEGIN EXTI15_10_IRQn 1 */
  //CTP_INT_Callback();

  /* USER CODE END EXTI15_10_IRQn 1 */
}

but if I am doing this

void EXTI15_10_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI15_10_IRQn 0 */

	for (int i=0;i<1000;i++)
	{
		HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_3);
	}
  /* USER CODE END EXTI15_10_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);

  /* USER CODE BEGIN EXTI15_10_IRQn 1 */
  //CTP_INT_Callback();

  /* USER CODE END EXTI15_10_IRQn 1 */
}

maybe the problem has something to do with timing? If the routine in ISR takes too long then fatFs semaphore corrupted somehow?

molnardavid wrote on Wednesday, October 07, 2015:

of course my final goal is to get touch event parameters from screen and add it to a queue than later process them in a task. I have just simlify the problem example where the problem still exists.

molnardavid wrote on Wednesday, October 07, 2015:

I made another test. Completely removed the ISR just two tasks.

blinkyTask

  for(;;)
  {
        HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_3);
        osDelay(100);
  }

drawBmpTask

  for(;;)
  {
        FIL file;       /* File object */
        FRESULT result;    /* FatFs return code */
        result = f_open(&file, path, FA_READ);
        if (result != FR_OK)
        {
            printf("no file");
            return;
        }
        GUI_DrawStreamedBitmapExAuto(Stream_GetData, &file, 0, 0);

        f_close(&file);
    }

if I made a small modification on blinkyTask like this

  for(;;)
  {
	  for (int i=0;i<1000;i++)
	  {
		  HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_3);
	  }
	  osDelay(100);
  }

Then the problem occurs again: f_open gives me FR_DISK_ERR

HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks) returns MSD_ERROR;

heinbali01 wrote on Wednesday, October 07, 2015:

Hi Dávid,

of course my final goal is to get touch event parameters from screen
and add it to a queue than later process them in a task. I have just
simlify the problem example where the problem still exists.

It surprises me that fatFS is suffering from an interrupt that is taking too much time.
I would think it is related to the (hardware) disk driver, but I don’t know for sure.

What I do know (and you most probably also) is that all hw interrupts are to be kept as short as possible :slight_smile:

If your ISR is triggered by a touch event, let it use one of these calls:

	xTaskNotifyFromISR();
	xQueueSendFromISR();
	xSemaphoreGiveFromISR();

… in order to wake up a task which will handle the touch event(s).

I wouldn’t even bother to fetch the actual touch event data from within the ISR, just let the task do that.

Regards.

molnardavid wrote on Friday, October 09, 2015:

Hi Hein,

Thank you for your answer. I choosen the solution you suggested. Unfortunately the continous picture update gives me the same result (FR_DISK_ERR). Keep digging … until that I will turn off that feaure.

Here is what I did

/**
* @brief This function handles EXTI Line[15:10] interrupts.
*/
void EXTI15_10_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI15_10_IRQn 0 */
	long lHigherPriorityTaskWoken = pdFALSE;

	/* USER CODE END EXTI15_10_IRQn 0 */
	HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);

	/* This interrupt does nothing more than demonstrate how to synchronise a
	task with an interrupt.  First the handler releases a semaphore.
	lHigherPriorityTaskWoken has been initialised to zero. */
	xSemaphoreGiveFromISR( touchBinarySemHandle, &lHigherPriorityTaskWoken );

	/* If there was a task that was blocked on the semaphore, and giving the
	semaphore caused the task to unblock, and the unblocked task has a priority
	higher than the currently executing task (the task that this interrupt
	interrupted), then lHigherPriorityTaskWoken will have been set to pdTRUE.
	Passing pdTRUE into the following macro call will cause this interrupt to
	return directly to the unblocked, higher priority, task. */
	portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );


}
/* StartTouchTask function */
void StartTouchTask(void const * argument)
{
	/* USER CODE BEGIN StartTouchTask */
	I2C_Init();
	FT5206_Init();
	FT5206_Wake(1);
	xSemaphoreTake(touchBinarySemHandle,100);
	HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
	/* Infinite loop */
	for(;;)
	{

	  if (xSemaphoreTake(touchBinarySemHandle,portMAX_DELAY ) == pdTRUE)
	  {
		  CTP_INT_Callback(); 

	  }
	}
	/* USER CODE END StartTouchTask */
}
/** Interrupt Handlers -------------------------------------------------------*/
void CTP_INT_Callback()
{
  uint8_t reg = prvBaseRegisterForPoint[FT5206Point_1 - 1];
  I2C_Transmit(FT5206_ADDRESS, &reg, 1);
  uint8_t storage[4] = {0x00};
  I2C_Receive(FT5206_ADDRESS, storage, 4);

  LCDEventMessage message;
  message.event = LCDEvent_TouchEvent;
  message.data[0] = ((storage[0] & 0x0F) << 8) | storage[1];
  message.data[1] = ((storage[2] & 0x0F) << 8) | storage[3];
  message.data[2] = (storage[0] & 0xC0) >> 6;
  message.data[3] = FT5206Point_1;

  xQueueSendToBack(xLCDEventQueue, &message, NULL);
}

Main taks

	/* USER CODE BEGIN 5 */
	/* Infinite loop */
	for(;;)
	{
	  //graphicsTest_RGB565BMPStreamed();


		  if( xLCDEventQueue != 0 )
		  {
			  LCDEventMessage receivedMessage;
			  // Peek a message on the created queue.  Block for 10 ticks if a
			  // message is not immediately available.

			  if( xQueueReceive( xLCDEventQueue, & (receivedMessage), ( TickType_t ) 10 ) )
			  {

		          if (receivedMessage.data[3] == FT5206Point_1 )
		          {
		        	  printf("%lu: %lu %lu\r\n",receivedMessage.data[2],receivedMessage.data[0],receivedMessage.data[1]);
		        	  if (receivedMessage.data[2] ==1)
		        	  {
			        	  uint32_t result;
			        	  HAL_RNG_GenerateRandomNumber(&hrng,&result);
			        	  uint32_t color = result &0xFFFFFF;
			        	  GUI_SetColor(color);

		        	  }
		        	  else if (receivedMessage.data[2]==2)
		        	  {
		        		  GUI_FillCircle(480-receivedMessage.data[1],receivedMessage.data[0],10);
		        	  }
		          }
				  // pcRxedMessage now points to the struct AMessage variable posted
				  // by vATask, but the item still remains on the queue.
			  }
		  }
	}

Thank you for your help. If I will find the error I will post again.

Regards,
Dave

molnardavid wrote on Friday, October 09, 2015:

solution on the way…

if I am doing this the problem solved

there is a function which continously draws bmp onto the picture. If I disable interrupt before f_read and then reenable file system stays consistent

static int Stream_GetData(void * p, U8 ** ppData, unsigned NumBytesReq, U32 Off)
{


	FRESULT result;    /* FatFs return code */
	static int FileAddress = 0;
	UINT NumBytesRead;
	FIL *PicFile;
	PicFile = (FIL *)p;
	/*
	* Check buffer size
	*/

	/*
	* Set file pointer to the required position
	*/
	if(Off == 1) FileAddress = 0;
	else FileAddress = Off;
	result = f_lseek(PicFile, FileAddress);
	if (result != FR_OK) return -1;
	/*
	* Read data into buffer (directly to gui buffer)
	*/
	__disable_irq();
	result = f_read(PicFile, *ppData, NumBytesReq, &NumBytesRead);
	__enable_irq();
	//printf("f_read: %d read:%d\r\n ",result,NumBytesRead);
	/*
	* Return number of available bytes
	*/

	return NumBytesRead;
}

molnardavid wrote on Friday, October 09, 2015:

I am getting closer

/**
  * @brief  Reads block(s) from a specified address in an SD card, in polling mode. 
  * @param  pData: Pointer to the buffer that will contain the data to transmit
  * @param  ReadAddr: Address from where data is to be read  
  * @param  BlockSize: SD card data block size, that should be 512
  * @param  NumOfBlocks: Number of SD blocks to read 
  * @retval SD status
  */
uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumOfBlocks)
{
	HAL_SD_ErrorTypedef status=HAL_SD_ReadBlocks(&hsd, pData, ReadAddr, BlockSize, NumOfBlocks);
	if( status != SD_OK)
	{
		return MSD_ERROR;
	}
	else
	{
		return MSD_OK;
	}
}

gives me SD_RX_OVERRUN

molnardavid wrote on Thursday, October 15, 2015:

Hi

My final solution is in bsp_driver_sd.c. Need to disable OS during readblocks. It is somehow correlated with a timeout. Until I had short tasks for example led blink the problem not occurs.

regards,
Dave

/**
  * @brief  Reads block(s) from a specified address in an SD card, in polling mode. 
  * @param  pData: Pointer to the buffer that will contain the data to transmit
  * @param  ReadAddr: Address from where data is to be read  
  * @param  BlockSize: SD card data block size, that should be 512
  * @param  NumOfBlocks: Number of SD blocks to read 
  * @retval SD status
  */
uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumOfBlocks)
{
	vPortEnterCritical();	//context switch cause SD_RX_OVERRUN (maybe takes too much time)
	HAL_SD_ErrorTypedef status=HAL_SD_ReadBlocks(&hsd, pData, ReadAddr, BlockSize, NumOfBlocks);
	vPortExitCritical();
	if( status != SD_OK)
	{
		return MSD_ERROR;
	}
	else
	{
		return MSD_OK;
	}
}