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…
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.
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
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.