In this example, we will protect a part of the code while 2 tasks run with the same periodicity. This application is designed to turn on progressively a series of LEDs using Task1, the second task Task2 makes the same, this time turning off the LEDs.

Function LED_Controll_Function(), has the code to be protected with the mutex. This function is called by the 2 Tasks, each one with the corresponding option that differences the behavior of the output. When the first task uses the function the second task cannot access it until the first task gives the mutex semaphore so the function is now unlocked to the second task.

Code Example:

#include "bsp.h"

#define DECREMENT 0     /* Option to decrement LEDs ON */
#define INCREMENT 1     /* Option to increment LEDs ON */

SemaphoreHandle_t  xMutex;  /* Mutex semaphore */
uint8_t LEDpin[8] = { GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_2, GPIO_PIN_3, GPIO_PIN_4, GPIO_PIN_5, GPIO_PIN_6, GPIO_PIN_7 }; /* Array of LED pins */

typedef struct LEDcontrol
{
    uint16_t pin;
    uint16_t status;
}LEDcontrol;

LEDcontrol LEDstatus; 

void Task1( void *pvParameters );   /* Task1 To turn on LEDs */
void Task2( void *pvParameters );   /* Task2 to turn off LEDs */

/* Function where the code is protected */
void LED_Control_Function( uint8_t option );   /* Logic to turn on or off LEDs */

int main( void )
{
    HAL_Init();

    SEGGER_SYSVIEW_Conf( );
    SEGGER_SYSVIEW_Start( );

    xMutex = xSemaphoreCreateMutex();       /* Create a Mutex Semaphore */
    
    xTaskCreate( Task1, "Task1", 240, NULL, 2, NULL );  /* Register Task1 to turn on LEDs */
    xTaskCreate( Task2, "Task2", 240, NULL, 1, NULL );  /* Register Task2 to turn off LEDs */
    
    vTaskStartScheduler();      /* Init the Kernel */
}

void Task1( void *pvParameters )
{
    for(;;)
    {
        LED_Control_Function( INCREMENT ); /* Call the function of the logic to increment LEDs on*/
        vTaskDelay(500);                    /* Periodic of the task */
    }
}

void Task2( void *pvParameters )
{
    for(;;)
    {
        LED_Control_Function( DECREMENT ); /* Call the function of the logic to increment LEDs off*/
        vTaskDelay(500);                    /* Period of the task */
    }   
}

/* Function where the mutex works, the code will be blocked when a task is using it */
void LED_Control_Function( uint8_t option )
{
        if( xSemaphoreTake(xMutex, 0) == pdTRUE )   /* Check if the Mutex can be taked */
        {
            if(option)                              /* option to turn on or off LEDS */
            {
                for(uint8_t iter=0; iter < 8; iter++)                               /* Increments the number of LEDs ON */
                {
                    LEDstatus.pin = LEDpin[ iter ];                                 /* Pin of LED */
                    LEDstatus.status = GPIO_PIN_SET;                                /* Put the pin in a high state */
                    HAL_GPIO_WritePin( GPIOC, LEDstatus.pin, LEDstatus.status );    /* Write the pin state in high */
                    SEGGER_SYSVIEW_PrintfHost( "LED_ON %d", iter );                 /* Print on terminal the current LED and State */
                    vTaskDelay(200);                                                /* Delay */
                }
            }
            else
            {
                for(uint8_t iter=8; iter > 0; iter--)                               /* Decrement the numbers of LEDs ON */
                {
                    LEDstatus.pin = LEDpin[ iter-1 ];                               /* Pin of LED */
                    LEDstatus.status = GPIO_PIN_RESET;                              /* Put the Pin in Low state */
                    HAL_GPIO_WritePin( GPIOC, LEDstatus.pin, LEDstatus.status );    /* Write the pin state in Low */
                    SEGGER_SYSVIEW_PrintfHost( "LED_OFF %d", iter-1 );              /* Print on terminal the current LED and State */
                    vTaskDelay(200);                                                /* Delay */
                }
            }

            xSemaphoreGive( xMutex );   /* Give the mutex, Unlock the code */
        }
}

SystemView output

Terminal shows the execution of the task, first observe that task1 has the access to function to turn on the LEDs, while task2 is waiting to access.

When task1 finishes, task2 now has access to the function tuning off the LEDs, task1 executes yet but can not access the code of the function.

Document

Timeline:

Document

First, we can observe that Task1 has the control of blocked code, and task2 can not do anything.

The next image shows only task1 works in the internal delay of the function of blocked code

When Task1 finishes, the code is unlocked and Task2 can take control now blocking the code for Task1.