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));
}
}
}
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
just wait forever for the mutex
xSemaphoreTake( xMutex, portMAX_DELAY);
in both tasks.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With