Preemption

Hi, I am using stm32f401re and I need to create two tasks that operate differently. I made the communication between an interrupt and the task through a queue. Everything seems to work but once the task that reads correctly from the queue is executed, the other task does not start running anymore. I was advised to use a preemption mechanism, can you tell me how I can implement it?

A preemption mechanism is implemented by a multi-tasking OS like FreeRTOS.
You can enable it by configUSE_PREEMPTION in FreeRTOSConfig.h.
Your description is a bit unclear. Have both tasks the same priority ?
What is the queue reading task doing after it received a queue item ?
Is the ISR firing and enqueuing data extremely often that the CPU gets overloaded ?
What is the other task doing and what exactly do you mean by does not not start running anymore ?

The task A that reads from the queue has a lower priority than the other task B.

After that the task A reads from the queue, executes the function referred to the command read from the queue and than releases the mutex.

L’ISR enqueuing data only when a key is pressed on the keyboard (not every time).

The other task B reads data from a gyroscope and when you press a key on the keyboard, the task A that read data correctly from the queue, executes the function correctly but the task B doesn’t restart and everything is blocked.

What’s the purpose of the mutex ?

Edit:
Did you define configASSERT and also enable stack overflow checking for development/debugging to catch possible fatal errors or data corruptions ?
Are the stack sizes of your tasks large enough ?
I’d also not poll the queue using the 1 tick timeout with an additional, probably useless osDelay(1) and aquiring/releasing the mutex all the time if there is nothing to do ?
Why not simply waiting for an key press being signalled and perform the desired action ?

PS: Please enclose code blocks in 3 tildes ‘~’ or backticks ‘`’ for better readabilty.
Or use the </> button for intraline code.

Yes, I defined configASSERT and stack overflow checking but I don’t catch any fatal errors.

The stack size of my task is defined by default (128 words).

I don’t understand what you mean with the last two questions. If you can please give me a possible solution to implement the preemption.

This is the code of the tasks

/* USER CODE BEGIN Header */
/**
  **************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  **************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  **************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "liquidcrystal_i2c.h"
#include "mpu6050.h"
#include "ds3231.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <math.h>
#include "handleSD.h"
#include "queue.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

extern void myprintf(const char *fmt, ...);

extern DS3231Time ds3231time;
extern int displayState;
extern I2C_HandleTypeDef hi2c1;
extern I2C_HandleTypeDef hi2c2;
extern UART_HandleTypeDef huart2;

extern float weight;
extern float height;
extern uint8_t input_cmd;

extern float user_weight;
extern float user_height;


MPU6050_t gyroscopeW;
MPU6050_t gyroscopeL;
MPU6050_t gyroscopeR;

int steps = 0;
int stepsL = 0;
int stepsR = 0;
float runned = 0;
float walked = 0;
float calories = 0;

float length;

TickType_t lastTimeL = 0;
TickType_t timeL = 0;
TickType_t diffL=0;
TickType_t lastTimeR = 0;
TickType_t timeR = 0;
TickType_t diffR=0;

/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
  .name = "defaultTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for readInputs */
osThreadId_t readInputsHandle;
const osThreadAttr_t readInputs_attributes = {
  .name = "readInputs",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityRealtime7,
};
/* Definitions for printDisplay */
osThreadId_t printDisplayHandle;
const osThreadAttr_t printDisplay_attributes = {
  .name = "printDisplay",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityRealtime7,
};
/* Definitions for userCommand */
osThreadId_t userCommandHandle;
const osThreadAttr_t userCommand_attributes = {
  .name = "userCommand",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityRealtime7,
};
/* Definitions for taskInputQueue */
osMessageQueueId_t taskInputQueueHandle;
const osMessageQueueAttr_t taskInputQueue_attributes = {
  .name = "taskInputQueue"
};
/* Definitions for simple_Mutex */
osMutexId_t simple_MutexHandle;
const osMutexAttr_t simple_Mutex_attributes = {
  .name = "simple_Mutex"
};

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void StartDefaultTask(void *argument);
void read_Inputs(void *argument);
void print_Display(void *argument);
void user_Command(void *argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */
  /* Create the mutex(es) */
  /* creation of simple_Mutex */
  simple_MutexHandle = osMutexNew(&simple_Mutex_attributes);

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* Create the queue(s) */
  /* creation of taskInputQueue */
  taskInputQueueHandle = osMessageQueueNew (16, sizeof(uint16_t), &taskInputQueue_attributes);

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* creation of defaultTask */
  defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);

  /* creation of readInputs */
  readInputsHandle = osThreadNew(read_Inputs, NULL, &readInputs_attributes);

  /* creation of printDisplay */
  printDisplayHandle = osThreadNew(print_Display, NULL, &printDisplay_attributes);

  /* creation of userCommand */
  userCommandHandle = osThreadNew(user_Command, NULL, &userCommand_attributes);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_EVENTS */
  /* add events, ... */
  /* USER CODE END RTOS_EVENTS */

}

/* USER CODE BEGIN Header_StartDefaultTask */
/**
  * @brief  Function implementing the defaultTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

/* USER CODE BEGIN Header_read_Inputs */
/**
* @brief Function implementing the readInputs thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_read_Inputs */
void read_Inputs(void *argument)
{
  /* USER CODE BEGIN read_Inputs */
  /* Infinite loop */
  for(;;)
  {
	  osMutexAcquire(simple_MutexHandle, osWaitForever);

	  MPU6050_Read_Accel(&hi2c2,&gyroscopeR);
	  MPU6050_Read_Accel_A0(&hi2c2,&gyroscopeL);
	  MPU6050_Read_Accel_A0(&hi2c1,&gyroscopeW);

	  if(gyroscopeW.Accel_X_RAW<0){
		  write_log_fall();
		  HD44780_Clear();
		  HD44780_SetCursor(0,0);
		  HD44780_PrintStr("Fall detected!");
		  osDelay(1);
	  }

	  length = sqrt(gyroscopeR.Ax * gyroscopeR.Ax + gyroscopeR.Ay * gyroscopeR.Ay + gyroscopeR.Az * gyroscopeR.Az);

	  if(length>=2){
		   lastTimeR = timeR;
		   timeR = xTaskGetTickCount() * portTICK_RATE_MS;
		   diffR = timeR-lastTimeR;

		  if(diffR>=200){
			  steps+=1;
			  stepsR+=1;
			  if(diffR>=500){
				walked+=((float)1/6)*height;
			  }
			  else{
				  runned+=((float)1/3)*height;
			  }
		  }
	  }

	  length = sqrt(gyroscopeL.Ax * gyroscopeL.Ax + gyroscopeL.Ay * gyroscopeL.Ay + gyroscopeL.Az * gyroscopeL.Az);
	  	 if(length>=2){
	  		  lastTimeL = timeL;
	  		  timeL = xTaskGetTickCount() * portTICK_RATE_MS;
	  	      diffL = timeL-lastTimeL;

	  		 if(diffL>=200){
				  steps+=1;
				  stepsL+=1;
				  if(diffL>=500){
					walked+=((float)1/6)*height;
				  }
				  else{
					  runned+=((float)1/3)*height;
				  }
	  		 }
	  }


	 osMutexRelease(simple_MutexHandle);
    osDelay(1);
  }
  /* USER CODE END read_Inputs */
}

/* USER CODE BEGIN Header_print_Display */
/**
* @brief Function implementing the printDisplay thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_print_Display */
void print_Display(void *argument)
{
  /* USER CODE BEGIN print_Display */
  /* Infinite loop */
  for(;;)
  {
	  osMutexAcquire(simple_MutexHandle, osWaitForever);
	  char displayr1_num[50];
	  char displayr2_num[50];

	  if(displayState==0){
	  					HD44780_Clear();
	  					HD44780_SetCursor(0,0);
	  					HD44780_PrintStr("Steps=");
	  					memset(displayr1_num, 0, 50);
	  					snprintf(displayr1_num, 50, "%d", steps);
	  					HD44780_PrintStr(displayr1_num);
	  	  	  }
	  else if(displayState==1){
	  	  	  			HD44780_Clear();
	  	  	  			HD44780_SetCursor(0,0);
	  	  	  			HD44780_PrintStr("StLeft=");
	  	  	  			memset(displayr1_num, 0, 15);
	  	  	  			snprintf(displayr1_num, 50, "%d", stepsL);
	  	  	  			HD44780_PrintStr(displayr1_num);

	  	  	  			HD44780_SetCursor(0,1);
	  	  	  			HD44780_PrintStr("StRight=");
	  	  	  			memset(displayr2_num, 1, 15);
	  	  	  			snprintf(displayr2_num, 50, "%d", stepsR);
	  	  	  			HD44780_PrintStr(displayr2_num);
	  	  	  	}
	  	  else if(displayState==2){
	  	  	  			HD44780_Clear();
	  	  	  			HD44780_SetCursor(0,0);
	  	  	  			HD44780_PrintStr("Walk=");
	  	  	  			memset(displayr1_num, 0, 50);
	  	  	  			snprintf(displayr1_num, 50, "%d m", (int)walked);
	  	  	  			HD44780_PrintStr(displayr1_num);
	  	  	  	  }
	  	  else if(displayState==3){
	  	  	  			HD44780_Clear();
	  	  	  			HD44780_SetCursor(0,0);
	  	  	  			HD44780_PrintStr("Run=");
	  	  	  			memset(displayr1_num, 0, 50);
	  	  	  			snprintf(displayr1_num, 50, "%d m", (int)runned);
	  	  	  			HD44780_PrintStr(displayr1_num);
	  	  	  	  }
	  	else if(displayState==4){
						HD44780_Clear();
						HD44780_SetCursor(0,0);
						HD44780_PrintStr("Cal=");
						memset(displayr1_num, 0, 50);
						calories=0.9*((walked+runned)/1000)*weight;
						snprintf(displayr1_num, 50, "%d KCal", (int)calories);
						HD44780_PrintStr(displayr1_num);
	  		  	  	  	  }
	  osMutexRelease(simple_MutexHandle);
	  osDelay(100);
  }
  /* USER CODE END print_Display */
}

/* USER CODE BEGIN Header_user_Command */
/**
* @brief Function implementing the userCommand thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_user_Command */
void user_Command(void *argument)
{
  /* USER CODE BEGIN user_Command */
  /* Infinite loop */
  for(;;)
  {
	  //osMutexAcquire(simple_MutexHandle, osWaitForever);

	  uint16_t character=0;

	  if(xQueueReceive(taskInputQueueHandle,&character,(( TickType_t ) 1 )) == pdTRUE){
		  if(character == 'l'){
			  read_log();
		  }
		  if(character == 'r'){
			  read_info();
		  }
		  if(character == 's'){
			read_info();

   		 char altezza[10];
   		 snprintf(altezza,10,"A=%.2f",weight);
   		 myprintf(altezza);
			write_info(height,weight);
			read_info();
		  }

	  }


	  //osMutexRelease(simple_MutexHandle);

	  osDelay(1);
	    }
  /* USER CODE END user_Command */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

This is the code of the callback

void HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart) {
    if (huart == &huart2) {
    	BaseType_t xHigherPriorityTaskWoken = pdFALSE;

        		  if(input_cmd == 'l'){
        			  if(xQueueSendFromISR(taskInputQueueHandle,&input_cmd,(( TickType_t ) 10 )) == pdPASS){
        				  myprintf("Request done\r\n");
        				  portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
        			  }
        		  }
        		  else if(input_cmd == 'r'){
        			  if(xQueueSendFromISR(taskInputQueueHandle,&input_cmd,(( TickType_t ) 10 )) == pdPASS){
        				  myprintf("Request done\r\n");
        				  portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
        			  }

        		  }
        		  else if(input_cmd == 's'){

        		 char read_buffer_height[50];
        		 char read_buffer_weight[50];
        		 uint8_t cmd = 0;
        		 uint8_t i = 0;

        		 myprintf("\r\nInsert height\r\n");

        		 HAL_UART_Receive(&huart2, &cmd, 1, HAL_MAX_DELAY);
        		 while (cmd != 13 && i < 50) {
        			 if ((cmd >= 48 && cmd <= 57) || cmd == '.') {
        				 HAL_UART_Transmit(&huart2, &cmd, 1, 1000);
        				 read_buffer_height[i] = cmd;
        				 i++;
        			 }
        			 HAL_UART_Receive(&huart2, &cmd, 1, 1000);
        		 }

        		 read_buffer_height[i] = '\0';
        		 cmd = 0;
        		 i = 0;

        		myprintf("\r\nInsert weight\r\n");

        		 HAL_UART_Receive(&huart2, &cmd, 1, HAL_MAX_DELAY);
        		 while (cmd != 13 && i < 50) {
        			 if ((cmd >= 48 && cmd <= 57) || cmd == '.') {
        				 HAL_UART_Transmit(&huart2, &cmd, 1, 1000);
        				 read_buffer_weight[i] = cmd;
        				 i++;
        			 }
        			 HAL_UART_Receive(&huart2, &cmd, 1, 1000);
        		 }

        		 read_buffer_weight[i] = '\0';

        		 height=atof(read_buffer_height);
        		 weight=atof(read_buffer_weight);

        		 if(xQueueSendFromISR(taskInputQueueHandle,&input_cmd,(( TickType_t ) 10 )) == pdPASS){
        			 myprintf("Request done\r\n");
        			 portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
        		 }

        		  }
        		  else{
        			  myprintf("\r\nWrong choice\r\n");
        		  }
        }


    HAL_UART_Receive_IT(&huart2, &input_cmd, 1);
}

I was referring to the original task code… :wink:
However, I afraid you’re doing much too much processing in the ISR callback.
Also is your myprintf function a custom printf-function which can be really called in ISRs ? Usually printf can’t be used in ISRs.
Also since your’re using atof do you use the FreeRTOS port with FPU support with proper FPU configuration ?
The recommended and widely used approach is doing the bare minimum amount of processing in ISRs and offload the heavy work to a task e.g. just signalling the key press events to the task queue and process them there.
Note that the ISR context has some restrictions and also other interrupts/ISRs might be delayed way too long when doing long lasting processing in an ISR.
Oh … using configMINIMAL_STACK_SIZE (I guess) for your application tasks is often too small. But of course it depends on the task code.
Note that FreeRTOS stack checking is a very big help but might not catch 100% of all stack overflows. Except the MCU provides hardware support for stack checking like Cortex-M33 and later.

1 Like

Hi, thanks to your suggests, I solved my problem, but I have one last question:
I have three different functions in a task A that were called when a specific key is pressed. The function f1 reads from a file file1, the function f2, reads from a file file2, and a function f3 that writes in the file file1. The functions f1 and f3 works well, while f2, reads only a part of the file file2 and blocks the whole program.

Sorry - I can’t help with file system / handling issues. But it should be possible to debug it.
Would be nice if you post the solution of the original problem to help the community :slight_smile:

This question does not seem related to FreeRTOS but to the file system you are using. I’d recommend checking with the maintainers of your file system. Also, as @hs2 mentioned, would be helpful for others if you can post your solution.

Thanks.