FreeRTOS column 14: priority flip and mutex semaphores

priority inversion

Introduction to priority flip:

It is the effect of high priority tasks running as if they are low priority tasks, and low priority tasks run before high priority tasks.

The priority flip is as follows:

Priority reversal process:

Why do priority reversals occur?

Because two tasks (L and H) use the same binary semaphore, and there is a medium priority task M between the two tasks, in this case, priority reversal is easy to occur. It is mainly because of the binary semaphore. The low priority task l occupies the semaphore and is not released, which makes the high priority task invalid when it requests the semaphore. At this time, the high priority task cannot run.

experimental design

The general idea is that both task L and task H request semaphores. When the semaphore is received, task H immediately releases the semaphore, while task l does the software delay for a period of time before releasing the semaphore to see the execution process of the program. The test code is as follows:

#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"

#include "bsp_led.h"
#include "bsp_key.h"
#include "bsp_usart.h"
#include "bsp_beep.h"

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

#include <string.h>

void start_task(void *pvParameters);
void low_task(void *pvParameters);
void middle_task(void *pvParameters);
void high_task(void *pvParameters);

/* Task related parameters */
#define START_TASK_SIZE     256
#define START_TASK_PRIO     1
TaskHandle_t start_Task_Handle;

#define LOW_TASK_SIZE       256
#define LOW_TASK_PRIO       2
TaskHandle_t low_task_Handle;

#define MIDDLE_TASK_SIZE    256
#define MIDDLE_TASK_PRIO    3
TaskHandle_t middle_task_Handle;

#define HIGH_TASK_SIZE      256
#define HIGH_TASK_PRIO      4
TaskHandle_t high_task_Handle;

SemaphoreHandle_t binary_semphr = NULL;   // Binary semaphore handle

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_I2C1_Init();
  MX_I2C2_Init();

  // Create start task
  xTaskCreate((TaskFunction_t )start_task,
              (char *         )"start_task",
              (uint16_t       )START_TASK_SIZE,
              (void *         )NULL,
              (UBaseType_t    )START_TASK_PRIO,
              (TaskHandle_t * )&start_Task_Handle);

  vTaskStartScheduler(); // Turn on scheduler
}

void start_task(void *pvParameters)
{
  taskENTER_CRITICAL();

  binary_semphr = xSemaphoreCreateBinary();  // Create semaphore
  if (binary_semphr != NULL)
  {
    printf("\n Binary semaphore created successfully");
    xSemaphoreGive(binary_semphr);    // Release semaphore
  }
  else
  {
    printf("\n Binary semaphore creation failed");
  }

  // Create low priority tasks
  xTaskCreate((TaskFunction_t )low_task,
              (char *         )"low_task",
              (uint16_t       )LOW_TASK_SIZE,
              (void *         )NULL,
              (UBaseType_t    )LOW_TASK_PRIO,
              (TaskHandle_t * )&low_task_Handle);
  // Create medium priority task
  xTaskCreate((TaskFunction_t )middle_task,
              (char *         )"middle_task",
              (uint16_t       )MIDDLE_TASK_SIZE,
              (void *         )NULL,
              (UBaseType_t    )MIDDLE_TASK_PRIO,
              (TaskHandle_t * )&middle_task_Handle);
  // Create high priority tasks
  xTaskCreate((TaskFunction_t )high_task,
              (char *         )"high_task",
              (uint16_t       )HIGH_TASK_SIZE,
              (void *         )NULL,
              (UBaseType_t    )HIGH_TASK_PRIO,
              (TaskHandle_t * )&high_task_Handle);
  taskEXIT_CRITICAL();
  // Delete start task
  vTaskDelete(start_Task_Handle);
}

void low_task(void *pvParameters)
{
  BaseType_t error_state;
  uint32_t limit;
  for (;;)
  {
    if (binary_semphr != NULL)
    {
      // Waiting for binary semaphore
      error_state = xSemaphoreTake(binary_semphr, portMAX_DELAY);   
      if (error_state == pdTRUE)
      {
        printf("\n Semaphore acquired by low priority task, occupying...");
      }
      else
      {
        printf("\n Low priority task failed to acquire semaphore");
      }
      #if 1
      // Analog low priority occupied semaphore
      for (limit = 0; limit < 5000000; limit++)
      {
        taskYIELD();      // Always call task switch 
      }
      #else
      HAL_Delay(8000);
      #endif
      // Release binary semaphore
      printf("\n Low priority task occupied semaphore end, about to release");
      xSemaphoreGive(binary_semphr);
    }
    vTaskDelay(500);
  }
}

void middle_task(void *pvParameters)
{
  for (;;)
  {
    printf("\n Medium priority task is running");
    vTaskDelay(1000);
  }
}

void high_task(void *pvParameters)
{
  for (;;)
  {
    if (binary_semphr != NULL)
    {
      printf("\n High priority task waiting for semaphore...");
      // Waiting for binary semaphore
      xSemaphoreTake(binary_semphr, portMAX_DELAY);   
      printf("\n Semaphore acquired by high priority task, about to be released...");
      xSemaphoreGive(binary_semphr);    // Release semaphore
    }
    vTaskDelay(1000);
  }
}

The running results of the program are as follows:

 

 

 

 

 

 

 

 

 

162 original articles published, 94 praised, 60000 visitors+
Private letter follow

Posted on Thu, 30 Jan 2020 02:53:08 -0800 by GetPutDelete