Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two Task Synchronisation With Mutex In FreeRTOS

I am trying to turn on and off a led using FreeRTOS on STM32 F401RE MCU in IAR Workbench IDE.

The led belongs the STM32 nucleo board. There are two task one turn on the Led, the other task turn off the same Led.

Here is the code:

The main Code:

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){}

}

The tasks:

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);
    }
}

My intension here is:

Led on task is responsible to turn on Led for 5s

Led off task is responsible to turn of Led for 5s

So this will continue till power off

My problem here is:

In the initial case, the Led stays 5s on after that led stays 5s off it works for only two context switching after two switching the led remains on.

When i debug after two switch the break point doesnt hit the tasks

After a little bit try I guess I found the answer:

Each task should have its delay time so we need to add a delay time in order to task proceed its operation, but i thougt i was add the delay time between xTakeSemaphore and xGiveSemaphore methods, are mutexes delay time which states how the resource should be locked not task delay time.

The Solution is:

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));
       }  
   }

}
like image 468
Nazim Avatar asked Aug 13 '26 00:08

Nazim


2 Answers

Consider that "task A" is LedOn and "task B" is LedOff. Or, the reverse as it doesn't matter for the problem.

Assume task B has acquired the mutex.

Your problem is that task A's xSemaphoreTake is [probably] timing out, without acquiring the mutex.

You should check the return code.

The reason is that it has a timeout value of 5000 ticks. But, task B does a vTaskDelay(5000). And, while it is doing this, it has the mutex locked

So, most probably, task A's xSemaphoreTake will timeout before task B releases the mutex.

And, then, you flip the LED value, and do a delay. But, then you're doing an xSemaphoreGive on a mutex that task A does not have locked.

In other words, you have a race condition.

Either set an infinite timeout in the take calls or at least set a larger value than the value you give to the delay function.

Try a take value of (e.g.) 10000

like image 74
Craig Estey Avatar answered Aug 15 '26 17:08

Craig Estey


just wait forever for the mutex

xSemaphoreTake( xMutex, portMAX_DELAY);

in both tasks.

like image 27
0___________ Avatar answered Aug 15 '26 17:08

0___________



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!