Hi!
I wonder what is the best way to implement FreeRtos thread that can be interrupted and after interrupt handler it is resumed from the begining, not from the place where it has been interrupted. For an example imagine I use thread_1 to display images that loading takes 10 seconds each, and ISR is triggered when switch is pressed (which indicates image switch). I don’t want to wait 10 seconds before image is switched so I guess the best option is to restart thread_1 which will check again which image to display and then do it. Should I be changing return pointer or is it somehow easier to do?
Greetings
You don’t want to do that, because ‘aborting’ a thread at an arbitrary point in the middle is apt to leave stuff in bad states.
What you need to do is have the ISR set a flag that the task looks at frequently, and when it sees that flag set, it does a ‘controlled abort’ of the task and restarts.
Thank you for your reply. Could you confirm that my example is acceptable?
Now I create 1 ISR and 3 tasks. ISR detects key pressed and starts first task (with the highest priority from all 3 tasks) which is responsible for key behaviour. If that is the only task working it starts DisplayTasks with normal priority. If key was pressed during DisplayTasks run, StartTask02 sets flag which execudes algorithm during which DisplayTasks kills itself and is being created again inside TaskRestart (which has lowest priority).
void StartTask02(void *argument)
{
/* USER CODE BEGIN StartTask02 */
uint32_t thread_state;
/* Infinite loop */
for (;;)
{
osThreadFlagsWait(0x0001U, osFlagsWaitAll, osWaitForever);
thread_state = osThreadGetState(SecondTaskHandle);
if (thread_state == osThreadBlocked)
{
/*Start StartTask03*/
osEventFlagsSet(event_id, FLAG_START);
}
else if (thread_state == osThreadReady)
{
/*Execute restart procedure by setting flag*/
osEventFlagsSet(event_id, FLAG_END);
}
}
/* USER CODE END StartTask02 */
}
void DisplayTask(void *argument)
{
/* USER CODE BEGIN StartTask03 */
/* Infinite loop */
for (;;)
{
osEventFlagsWait(event_id, FLAG_START, osFlagsWaitAny, osWaitForever);
/*Displaying data*/
for (uint32_t x = 0; x < 15000; x++)
{
/*Interrupt during displaying*/
if (osEventFlagsGet(event_id) == FLAG_END)
{
/*
* Clear data
*/
/*Execute restart by starting a task*/
osEventFlagsSet(event_display, FLAG_RESTART);
osThreadExit();
}
}
}
/* USER CODE END StartTask03 */
}
void TaskRestart(void *argument)
{
/* USER CODE BEGIN TaskRestart */
/* Infinite loop */
for (;;)
{
osEventFlagsWait(event_display, FLAG_RESTART, osFlagsNoClear, osWaitForever);
osDelay(2);
if (osThreadGetState(SecondTaskHandle) == osThreadTerminated)
{
/*Block this thread and create new*/
osEventFlagsClear(event_display,FLAG_RESTART);
osEventFlagsSet(event_id, FLAG_START);
osThreadNew(StartTask03, NULL, &SecondTask_attributes);
}
}
/* USER CODE END TaskRestart */
}
It works but I am not sure how it is going to perform in more advanced design, since I am new to Rtos. Also system without osDelay(2) creates thread in TaskRestart (I guess) before thread was fully cleared and error occured cousing DisplayTask to never restart.
Why not just checking a restart or better repaint flag set by the key press ISR/key processing task in the display task and restart painting (loop) on key press ?
I don’t get the benefit of killing and recreating the display task. It’s overly complex and a waste of resources.
I’d create both tasks and let them do their job forever.
Hm, I guess that is more reliable way for this task. I was just learning FreeRtos and lead myself into wrong path. Thanks