Синхронизация двух задач с Mutex в FreeRTOS - PullRequest
3 голосов
/ 05 марта 2020

Я пытаюсь включить и выключить светодиод с помощью FreeRTOS на микроконтроллере STM32 F401RE в IAR Workbench IDE.

Светодиод относится к плате ядра STM32. Есть две задачи: один светодиод включается, а другой - тот же светодиод.

Вот код:

Основной код:

SemaphoreHandle_t xMutex;
int main()
{  

  if ( xMutex == NULL )  
  {
      xMutex = xSemaphoreCreateMutex();  

      if ( ( xMutex ) != NULL )
        xSemaphoreGive( ( xMutex ) ); 

   }

   xTaskCreate(LedOn, "Led On", 100, NULL,  1, NULL);
   xTaskCreate(LedOff, "Led Off", 100, NULL, 1, NULL);
   vTaskStartScheduler();
   while(1){}

}

Задачи:

void LedOn(void *argument)
{
   for(;;)
   {  
      xSemaphoreTake( xMutex, ( TickType_t )5000 ) ;     
      HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
      vTaskDelay(5000); 
      xSemaphoreGive(xMutex);
    }
}

void LedOff(void *argument)
{
   for(;;)
   {  
      xSemaphoreTake( xMutex, ( TickType_t )5000 ) ;     
      HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
      vTaskDelay(5000); 
      xSemaphoreGive(xMutex);
    }
}

Мое намерение здесь таково:

Задача Led отвечает за включение Led на 5 с

Задача Led off отвечает за включение Led на 5 с

Так что это будет продолжаться до выключения питания

Моя проблема здесь:

В первоначальном случае светодиод остается включенным на 5 с после того, как светодиод выключен на 5 с, он работает только переключение двух контекстов после двух переключений светодиод остается включенным.

Когда после отладки после двух переключений точка останова не попадает в задачи

После небольшой попытки, я думаю, я нашел ответ:

Каждое задание должно иметь время задержки, поэтому нам нужно добавить время задержки, чтобы задача продолжила свою работу, но я добавил, что было добавлено время задержки между xTakeSemaphore и xGiveSemaphore методами, которые являются временем задержки мьютексов где указано, как должен быть заблокирован ресурс, а не время задержки задачи. * 103 1 *

Решение:

void LedOn(void *argument)
{
   for(;;)
   {  
       if(xSemaphoreTake(xMutex, portMAX_DELAY)== pdTRUE)
       {
          HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET); 
          vTaskDelay(pdMS_TO_TICKS(5000));
          xSemaphoreGive(xMutex);
          vTaskDelay(pdMS_TO_TICKS(5000));
       }    
    }
}

void LedOff(void *argument)
{
   for(;;)
   {
       if( xSemaphoreTake( xMutex, portMAX_DELAY)== pdTRUE)
       {
          HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET); 
          vTaskDelay(pdMS_TO_TICKS(5000));
          xSemaphoreGive(xMutex);  
          vTaskDelay(pdMS_TO_TICKS(5000));
       }  
   }

}

Ответы [ 4 ]

2 голосов
/ 06 марта 2020

просто ждать вечно мьютекса

xSemaphoreTake( xMutex, portMAX_DELAY);

в обеих задачах.

2 голосов
/ 06 марта 2020

Учтите, что «задача A» равна LedOn, а «задача B» равна LedOff. Или наоборот, поскольку это не имеет значения для проблемы.

Предположим, что задача B получила мьютекс.

Ваша проблема в том, что xSemaphoreTake задачи A [вероятно] истекает, без получения мьютекса.

Вы должны проверить код возврата.

Причина в том, что он имеет значение тайм-аута 5000 тиков. Но задача B выполняет vTaskDelay(5000). И, пока он делает это, у него заблокирован мьютекс заблокированный

Так что, наиболее вероятно, задача xSemaphoreTake будет задержана на раньше, чем задача B освободит мьютекс.

И затем вы переключаете значение светодиода и делаете задержку. Но затем вы делаете xSemaphoreGive на мьютексе, который задача A не заблокировала.

Другими словами, у вас есть состояние гонки.

Либо установите бесконечное время ожидания в вызовах take, либо, по крайней мере, установите большее значение, чем значение, которое вы задаете функции задержки.

Попробуйте значение take (например, 10000

)
1 голос
/ 06 марта 2020

Обычная предпосылка приоритетной запланированной ОСРВ заключается в том, что задача / поток с наивысшим приоритетом, готовые к запуску, опережают ту, которая выполняется с более низким приоритетом.

И LedOff, и LedOn задачи создаются с тем же приоритетом , и поэтому переключение контекста происходит не сразу, когда семафор сигнализируется.

Переключение контекста потенциально происходит, когда он обходит l oop и пытается снова взять семафор. В настоящее время с ним борются две задачи.

Кто выигрывает, по сути, является деталью реализации FreeRTOS - и, в частности, происходит ли выполнение операций с семафорами над семафором в строгом порядке FIFO или нет - ISTR, что VxWorks (что FreeRTOS кажется в значительной степени по образцу) при желании сделать это.

Альтернативный подход, который наблюдается с POSIX-потоками (который также поддерживает FreeRTOS), состоит в том, чтобы разбудить ожидающий поток, и семафор, который должен быть взят тем, который запланирован первым, - который наверняка будет одним уже работает.

В более общем плане вы сильно усложнили конечный автомат с двумя состояниями. Очень надежный способ достичь этого будет:

void LedFlasher(void *argument)
{
   for(;;)
   {      
      HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
      vTaskDelay(5000); 
      HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
      vTaskDelay(5000); 
   }
}
0 голосов
/ 12 апреля 2020

Немного поздно ..;) но я думаю, что есть ошибка в вашей программе. Первоначальный выпуск мьютекса (xSemaphoreGive в основном) нарушает его. Мьютекс создан готовым к использованию, т.е. в освобожденном состоянии.

...