STM32-Cube IDE-FreeRTOS Intertask Communication Part – 2

STM32-Cube IDE-FreeRTOS Intertask Communication Part – 2

Inter Process Communication
Figure 1: Inter Process Communication

Queues Allows to pass more information between the tasks. Suspend task if tries to “put” to full queue or “get” from empty one.

Semaphores are used to communication between the tasks without specifying the ID of the thread who can accept it. It allows counting multiple events and can be accepted by many threads.

Direct to task notifications are used to precise communication between the tasks. It is necessary to specify within signal thread id.

Mutexes are used to guard the shared resources. It must be taken and released always in that order by each task that uses the shared resource.

Event Groups are used to synchronize task with multiple events (OR-ed together). There could be 8 or 24 bit value used here (depends on configUSE_16_BIT_TICKS settings) – not implemented in CMSIS_OS API

Mutex

Mutex is a binary semaphore that include a priority inheritance mechanism.

  • binary semaphore is the better choice for implementing synchronization (between tasks or between tasks and an interrupt),
  • mutex is the better choice for implementing simple mutual exclusion (hence ‘MUT’ual ‘EX’clusion)

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.
  • In case of recursive mutex it should be given as many times as it was successfully taken (like counting semaphores) to release it for another task.
  • Mutexes use the same access API functions as semaphores – this permits a block time to be specified.
  • The block time indicates the maximum number of ‘ticks’ that a task should enter the Blocked state when attempting to ‘take’ a mutex if the mutex is not available immediately.
  • Unlike binary semaphores however – mutexes employ priority inheritance. This means that if a high priority task is blocked while attempting to obtain a mutex (token) that is currently held by a lower priority task, then the priority of the task holding the token is temporarily raised to that of the blocked task.
  • Mutex Management functions cannot be called from interrupt service routines (ISR).
  • A task must not be deleted while it is controlling a Mutex. Otherwise, the Mutex resource will be locked out to all other tasks

Priority inversion

This is the situation where a higher priority task is waiting for a lower priority task to give a control of the mutex and low priority task is not able to execute.

Priority inheritance

  • It is temporary raise of the priority of the mutex holder to that of the highest priority task that is attempting to obtain the same mutex. The low priority task that holds the mutex inherits the priority of the task waiting for the mutex. The priority of the mutex holder is reset automatically to its original value when it gives the mutex back.
  • It is a mechanism that minimizes the negative effects of priority inversion
  • It is complicating system timing analysis and it is not a good practice to rely on it for correct system operation

Deadlock (Deadly Embrace)

  • It occurs when two tasks cannot work because they are both waiting for a resource held by each other
  • The best way to avoid deadlock is to consider them at design time and design the system to be sure that the deadlock cannot occur.
Mutual exclusion implemented using a mutex
Mutual exclusion implemented using a mutex
Mutual exclusion implemented using a mutex
Mutual exclusion implemented using a mutex
Mutual exclusion implemented using a mutex
Mutual exclusion implemented using a mutex
Mutual exclusion implemented using a mutex
Source : FreeRTOS
Mutexes Function Documentation

a) osMutexId_t osMutexNew

osMutexId_t osMutexNew	(	const osMutexAttr_t * 	attr	)	

Parameters

[in]attrmutex attributes; NULL: default values.

Returns

mutex ID for reference by other functions or NULL in case of error.

The function osMutexNew creates and initializes a new mutex object and returns the pointer to the mutex object identifier or NULL in case of an error. It can be safely called before the RTOS is started (call to osKernelStart), but not before it is initialized (call to osKernelInitialize).

b) osStatus_t osMutexAcquire

osStatus_t osMutexAcquire	(	osMutexId_t 	mutex_id, uint32_t 	timeout )	

Parameters

[in]mutex_idmutex ID obtained by osMutexNew.
[in]timeoutTimeout Value or 0 in case of no time-out.

Returns

status code that indicates the execution status of the function.

The blocking function osMutexAcquire waits until a mutex object specified by parameter mutex_id becomes available. If no other thread has obtained the mutex, the function instantly returns and blocks the mutex object.

c) osStatus_t osMutexRelease

osStatus_t osMutexRelease	(	osMutexId_t 	mutex_id	)	

Parameters

[in]mutex_idmutex ID obtained by osMutexNew.

Return

sstatus code that indicates the execution status of the function.

The function osMutexRelease releases a mutex specified by parameter mutex_id. Other threads that currently wait for this mutex will be put into the READY state.

Step by step procedure to create FreeRTOS Mutexes using STM32CubeIDE

Step 1: Go to Pinout & Configurations Tab > FreeRTOS > Mutexes Tab > Mutexes > Add

Step 2:

step 3: for different task creation go to this page STM32-Cube IDE-FreeRTOS Tasks

Below code will be generated by STM32CubeIDE

/* Definitions for myMutex01 */
osMutexId_t myMutex01Handle;
const osMutexAttr_t myMutex01_attributes = {
  .name = "myMutex01"
};

  /* Create the mutex(es) */
  /* creation of myMutex01 */
  myMutex01Handle = osMutexNew(&myMutex01_attributes);

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

/* USER CODE BEGIN Header_ProducerTask */
/**
* @brief Function implementing the Producer thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_ProducerTask */
void ProducerTask(void *argument)
{
  /* USER CODE BEGIN ProducerTask */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1000);
    osMutexAcquire(myMutex01Handle, 1000);
    // do stuff
    osMutexRelease(myMutex01Handle);
  }
  /* USER CODE END ProducerTask */
}
Mutex Graphical Representation (www.st.com)

Event flags

The event flags management functions in CMSIS-RTOS allow you to control or wait for event flags. Each signal has up to 31 event flags.

A thread

  • can wait for event flags to be set (using osEventFlagsWait). Using this function, it enters the BLOCKED state.
  • may set one or more flags in any other given thread (using osEventFlagsSet).
  • may clear its own signals or the signals of other threads (using osEventFlagsClear).

When a thread wakes up and resumes execution, its signal flags are automatically cleared (unless event flags option osFlagsNoClear is specified).

Working with Events

Working with Events (Events)

Simple event communication

In the thread that is supposed to send a event with id sig1_id, call the set function:

osDelay(1000U);                                           // wait for 1 second
osEventFlagsSet(sig1_id, 0x0001U);                        // set the flag 0x0001U for event sig1_id

In another thread (or threads) that are supposed to wait for the event, call the wait function:

osEventFlagsWait(sig1_id, 0x0001U, NULL, osWaitForever); // wait forever for any flag

Event flags Function Documentation

a) osEventFlagsId_t osEventFlagsNew

osEventFlagsId_t osEventFlagsNew	(	const osEventFlagsAttr_t * 	attr	)	

Parameters

[in]attrevent flags attributes; NULL: default values.

Returns

event flags ID for reference by other functions or NULL in case of error.

b) uint32_t osEventFlagsSet

uint32_t osEventFlagsSet	(	osEventFlagsId_t 	ef_id, uint32_t 	flags )

Parameters

[in]ef_idevent flags ID obtained by osEventFlagsNew.
[in]flagsspecifies the flags that shall be set.

Returns

The threads with highest priority waiting for the flag(s) set will be notified to resume from BLOCKED state. The function returns the event flags stored in the event control block or an error code (highest bit is set, refer to Flags Functions Error Codes). Further threads may be wakened in priority order when the option osFlagsNoClear is given to the osEventFlagsWait call.

event flags after setting or error code if highest bit set.

The function osEventFlagsSet sets the event flags specified by the parameter flags in an event flags object specified by parameter ef_id.

c) uint32_t osEventFlagsWait

uint32_t osEventFlagsWait	(	osEventFlagsId_t 	ef_id,uint32_t 	flags,
                             uint32_t 	options,uint32_t 	timeout )	

Parameters

[in]ef_idevent flags ID obtained by osEventFlagsNew.
[in]flagsspecifies the flags to wait for.
[in]optionsspecifies flags options (osFlagsXxxx).
[in]timeoutTimeout Value or 0 in case of no time-out.

Returnsevent flags before clearing or error code if highest bit set.

The function osEventFlagsWait suspends the execution of the currently RUNNING thread until any or all event flags specified by the parameter flags in the event object specified by parameter ef_id are set. When these event flags are already set, the function returns instantly. Otherwise, the thread is put into the state BLOCKED.

Step by step procedure to create FreeRTOS Event flags using STM32CubeIDE

Step 1: Go to Pinout & Configurations Tab > FreeRTOS > Events Tab > Events > Add

STM32CubeIDE event flags generation
STM32CubeIDE

step 3: for different task creation go to this page STM32-Cube IDE-FreeRTOS Tasks

Below code will be generated by STM32CubeIDE

#define FLAGS_MSK1 0x00000001U

/* Definitions for myEvent01 */
osEventFlagsId_t myEvent01Handle;
const osEventFlagsAttr_t myEvent01_attributes = {
  .name = "myEvent01"
};

 /* creation of myEvent01 */
 myEvent01Handle = osEventFlagsNew(&myEvent01_attributes);

void Thread_EventSender (void *argument) {
 
  while (1) {    
    osEventFlagsSet( myEvent01Handle, FLAGS_MSK1);
    osThreadYield();                            // suspend thread
  }
}
 
void Thread_EventReceiver (void *argument) {
  uint32_t flags;
 
  while (1) {
    flags = osEventFlagsWait( myEvent01Handle, FLAGS_MSK1, osFlagsWaitAny, osWaitForever);
    //handle event
  }
}

References:

https://www.st.com/content/st_com/en/support/learning/stm32-education/stm32-moocs/FreeRTOS_on_STM32_MOOC.html

https://www.freertos.org/fr-content-src/uploads/2018/07/161204_Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf

https://www.keil.com/pack/doc/cmsis/RTOS2/html/modules.html

Leave a Reply

Your email address will not be published. Required fields are marked *

%d bloggers like this: