How to use mutex and semaphores in a FreeRTOS and SDK2.0 Project

Document created by soledad Employee on Jun 26, 2016Last modified by soledad Employee on Oct 19, 2016
Version 2Show Document
  • View in full screen mode

This document shows how to use a mutex and semaphores in order to synchronize two tasks in a FreeRTOS and SDK 2.0 project. For this example it is used SDK 2.0, TWR-K64F120M, and FreeRTOS.

If you want to know how to create a new SDK 2.0 with FreeRTOS project please check the below link: https://community.freescale.com/docs/DOC-330183

 

MUTEX EXAMPLE:

 

Introduction

A mutex provides mutual exclusion among tasks, when they access a shared resource.

When used for mutual exclusion the mutex acts like a token that is used to guard a resource. When a task wishes to access the resource it must first obtain ('take') the token. When it has finished with the resource it must 'give' the token back - allowing other tasks the opportunity to access the same resource. Mutexes cannot be used in interrupt service routines.

Mutexes use the same semaphore access API functions.

 

Writing a Mutex example code

The mutex example code is used to demonstrate how to use a mutex to synchronize two tasks. It creates a mutex and two tasks. Both tasks use PRINTF to print out messages. Each task will lock the mutex before printing and unlock it after printing to ensure that the outputs from tasks are not mixed together. According with this proposal it is necessary to follow the below steps.

 

  1. In main function, create a mutex using the xSemaphoreCreateMutex() API. This API creates a mutex, and returns a handle by which the created mutex can be referenced. Mutexes cannot be used in interrupt service routines.

 

xMutex = xSemaphoreCreateMutex();

 

  1. Create two tasks with the same priority, these tasks will use PRINTF to print out messages.

 

       xTaskCreate(write_task_1,"write_task_1",configMINIMAL_STACK_SIZE,NULL,

                     task_PRIORITY, NULL);

       xTaskCreate(write_task_2,"write_task_2",configMINIMAL_STACK_SIZE,NULL,

                     task_PRIORITY, NULL);

 

  1. The two print tasks both use the PRINTF. If they used it in the same time, there would be conflicts, so a mutex is used to synchronize the two tasks. Each print task will try to lock the mutex before printing the message, using the macro xSemaphoreTake (SemaphoreHandle_t xSemaphore,TickType_t xTicksToWait); it will wait for the mutex as long as needed. Once the mutex is locked it prints the message and then unlocks the mutex  with the macro xSemaphoreGive (SemaphoreHandle_t xSemaphore) so that the other task can lock it. This process is repeated indefinitely.

 

static void write_task_1(void *pvParameters)

{

    while (1)

    {

xSemaphoreTake(xMutex, portMAX_DELAY);

        PRINTF("Hello, this is the |");

        taskYIELD();

        PRINTF("first task \r\n");

xSemaphoreGive(xMutex);

        taskYIELD();

    }

}

static void write_task_2(void *pvParameters)

{

while (1)

{

xSemaphoreTake(xMutex, portMAX_DELAY);

PRINTF("And now this is the |");

taskYIELD();

PRINTF(" second task\r\n");

xSemaphoreGive(xMutex);

taskYIELD();

}

}

  1. At this point you can build and debug the example.

 

Complete Code

 

/* Kernel includes. */

#include "FreeRTOS.h"

#include "task.h"

#include "queue.h"

#include "timers.h"

#include "semphr.h"

 

/* Freescale includes. */

#include "fsl_device_registers.h"

#include "fsl_debug_console.h"

#include "board.h"

 

#include "pin_mux.h"

#include "clock_config.h"

/*******************************************************************************

* Definitions

******************************************************************************/

 

SemaphoreHandle_t xMutex;

 

/*******************************************************************************

* Prototypes

******************************************************************************/

static void write_task_1(void *pvParameters);

static void write_task_2(void *pvParameters);

 

/*******************************************************************************

* Code

******************************************************************************/

/*!

* @brief Main function

*/

int main(void)

{

xMutex = xSemaphoreCreateMutex();

 

BOARD_InitPins();

BOARD_BootClockRUN();

BOARD_InitDebugConsole();

xTaskCreate(write_task_1, "WRITE_TASK_1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);

xTaskCreate(write_task_2, "WRITE_TASK_2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);

/* Start scheduling. */

vTaskStartScheduler();

for (;;)

;

}

 

/*!

* @brief Write Task 1 function

*/

static void write_task_1(void *pvParameters)

{

while (1)

{

xSemaphoreTake(xMutex, portMAX_DELAY);

PRINTF("Hello, this is the ");

taskYIELD();

PRINTF("first task \r\n");

xSemaphoreGive(xMutex);

taskYIELD();

}

}

 

/*!

* @brief Write Task 2 function

*/

static void write_task_2(void *pvParameters)

{

while (1)

{

xSemaphoreTake(xMutex, portMAX_DELAY);

PRINTF("And now this is the ");

taskYIELD();

PRINTF(" second task\r\n");

xSemaphoreGive(xMutex);

taskYIELD();

}

}

 

SEMAPHORE EXAMPLE:

 

Introduction

Binary semaphores and mutexes are very similar but have some subtle differences: Mutexes include a priority inheritance mechanism, binary semaphores do not. This makes binary semaphores the better choice for implementing synchronisation (between tasks or between tasks and an interrupt), and mutexes the better choice for implementing simple mutual exclusion.

A semaphore can be used in order to control the access to a particular resource that consists of a finite number of instances.

 

Writing a Semaphore example code

After install SDK 2.0 you can find a semaphore example at the path: <SDK_install_path>\SDK_2.0_xxx\boards\<your_name>\rtos_examples\freertos_sem

The example uses four tasks. One producer_task and three consumer_tasks. The producer_task starts by creating of two semaphores (xSemaphore_producer and xSemaphore_consumer). These semaphores control access to virtual item. The synchronization is based on bilateral rendezvous pattern. Both of consumer and producer must be prepared to enable transaction.

 

Here’s the API (copied from the FreeRTOS website):

 

MODULES

xSemaphoreCreateBinary

SemaphoreHandle_t xSemaphoreCreateBinary( void );

Creates a binary semaphore, and returns a handle by which the semaphore can be referenced.

xSemaphoreCreateBinaryStatic

SemaphoreHandle_t xSemaphoreCreateBinaryStatic(

                          StaticSemaphore_t *pxSemaphoreBuffer );

Creates a binary semaphore, and returns a handle by which the semaphore can be referenced.

xSemaphoreCreateCounting

SemaphoreHandle_t xSemaphoreCreateCounting(

                                            UBaseType_t uxMaxCount,

UBaseType_t uxInitialCount);

Creates a counting semaphore and returns a handle by which the newly created semaphore can be referenced.

xSemaphoreCreateCountingStatic

SemaphoreHandle_t xSemaphoreCreateCountingStatic(

                                 UBaseType_t uxMaxCount,

                                 UBaseType_t uxInitialCount

StaticSemaphore_t pxSempahoreBuffer );

Creates a counting semaphore and returns a handle by which the newly created semaphore can be referenced.

xSemaphoreCreateMutex

SemaphoreHandle_t xSemaphoreCreateMutex( void )

Creates a mutex, and returns a handle by which the created mutex can be referenced. Mutexes cannot be used in interrupt service routines.

xSemaphoreCreateMutexStatic

SemaphoreHandle_t xSemaphoreCreateMutexStatic(

                            StaticSemaphore_t *pxMutexBuffer );

Creates a mutex, and returns a handle by which the created mutex can be referenced. Mutexes cannot be used in interrupt service routines.

xSemaphoreCreateRecursiveMutex

SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )

Creates a recursive mutex, and returns a handle by which the mutex can be referenced. Recursive mutexes cannot be used in interrupt service routines. configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for xSemaphoreCreateRecursiveMutex() to be available.

xSemaphoreCreateRecursiveMutexStatic

SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic(

StaticSemaphore_t *pxMutexBuffer )

Creates a recursive mutex, and returns a handle by which the mutex can be referenced. Recursive mutexes cannot be used in interrupt service routines. configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for xSemaphoreCreateRecursiveMutexStatic() to be available.

vSemaphoreDelete

void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

Deletes a semaphore, including mutex type semaphores and recursive semaphores.

Do not delete a semaphore that has tasks blocked on it (tasks that are in the Blocked state waiting for the semaphore to become available).

xSemaphoreGetMutexHolder

TaskHandle_t xSemaphoreGetMutexHolder( SemaphoreHandle_t xMutex );

Return the handle of the task that holds the mutex specified by the function parameter, if any.

xSemaphoreGetMutexHolder() can be used reliably to determine if the calling task is the mutex holder, but cannot be used reliably if the mutex is held by any task other than the calling task.

xSemaphoreTake

xSemaphoreTake( SemaphoreHandle_t xSemaphore,

                 TickType_t xTicksToWait );

Macro to obtain a semaphore. The semaphore must have previously been created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or xSemaphoreCreateCounting().

xSemaphoreTakeFromISR

xSemaphoreTakeFromISR(

        SemaphoreHandle_t xSemaphore,

        signed BaseType_t *pxHigherPriorityTaskWoken )

A version of xSemaphoreTake() that can be called from an ISR. Unlike xSemaphoreTake(), xSemaphoreTakeFromISR() does not permit a block time to be specified.

xSemaphoreTakeRecursive

xSemaphoreTakeRecursive( SemaphoreHandle_t xMutex,

                         TickType_t xTicksToWait );

Macro to recursively obtain, or 'take', a mutex type semaphore. The mutex must have previously been created using a call to xSemaphoreCreateRecursiveMutex();

configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this macro to be available.

xSemaphoreGive

xSemaphoreGive( SemaphoreHandle_t xSemaphore );

Macro to release a semaphore. The semaphore must have previously been created with a call to xSemaphoreCreateBinary(), xSemaphoreCreateMutex() or xSemaphoreCreateCounting(), and obtained using sSemaphoreTake().

xSemaphoreGiveRecursive

xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex )

Macro to recursively release, or 'give', a mutex type semaphore. The mutex must have previously been created using a call to xSemaphoreCreateRecursiveMutex();

configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h for this macro to be available.

xSemaphoreGiveFromISR

xSemaphoreGiveFromISR(

        SemaphoreHandle_t xSemaphore,

        signed BaseType_t *pxHigherPriorityTaskWoken)

Macro to release a semaphore. The semaphore must have previously been created with a call to xSemaphoreCreateBinary() or xSemaphoreCreateCounting().

Mutex type semaphores (those created using a call to xSemaphoreCreateMutex()) must not be used with this macro.

uxSemaphoreGetCount

UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );

Returns the count of a semaphore.

 

 

Enjoy!!!

1 person found this helpful

Attachments

    Outcomes