I am new to FreeRTOS and have been reading the FreeRTOS documentation and writing simple code using FreeRTOS on an STM32F767 Nucleo Board. In the simple program that I wrote, I used Binary Semaphores only to signal certain tasks when LPTIM and GPIO interrupts occur through xSemaphoreGiveFromISR()
, and to signal a different task to perform certain operations from another task through xSemaphoreGive()
.
Suppose that I have an I2C1 peripheral connected to two different equipments:
- An accelerometer that triggers a GPIO interrupt to the microcontroller whenever an activity/movement occurs. This GPIO interrupt signals the microcontroller that a piece of data inside its Interrupt Event registers must be read so that the next activity/movement event can be signalled again.
- An equipment that must be read from periodically, which will be triggered through an LPTIM or TIM peripheral
Can I use a Mutex and a Binary Semaphore in the situation above?
The Binary Semaphores will indicate to the task that an operation needs to be performed based on the respective interrupts that were triggered, but the Mutex will be shared between those two tasks, where Task1 will be responsible with reading data from the accelerometer, and Task2 will be responsible for reading data from the other equipment. I was thinking that a Mutex will be used since these two operations should never occur together, so that there are no overlapping I2C transactions that happen on the bus that could potentially lock up either of the I2C devices.
The code would look like the following:
void Task1_AccelerometerOperations(void *argument)
{
/* The Semaphore will be given from the GPIO Interrupt Handler, signalling that a piece of
data needs to be read from the accelerometer through I2C. */
if(xSemaphoreTake(xSemaphore_GPIOInterruptFlag, portMAX_DELAY) == pdTRUE)
{
/* This Mutex should ensure that only one I2C transaction can happen at a time */
if(xSemaphoreTakeRecursive(xMutex_I2CBus, 2000/portTICK_PERIOD_MS) == pdTRUE)
{
/* Perform I2C Transaction */
/* Perform operations with the data received */
/* Mutex will be given back, indicating that the shared I2C Bus is now available */
xSemaphoreGiveRecursive(xMutex_I2CBus);
}
else
{
/* Mutex was not available even after 2 seconds since the GPIO interrupt triggered.
Perform Error Handling for the event that the I2C bus was locked */
}
/* Piece of code that could take a few hundreds milliseconds to execute */
}
}
void Task2_OtherEquipmentOperations(void *argument)
{
/* The Semaphore will be given from the LPTIM Interrupt Handler, signalling that some maintenance
or periodic operation needs to be performed through I2C. */
if(xSemaphoreTake(xSemaphore_LPTIMInterruptFlag, portMAX_DELAY) == pdTRUE)
{
/* Only perform the I2C operations when the Mutex is available */
if(xSemaphoreTakeRecursive(xMutex_I2CBus, 2000/portTICK_PERIOD_MS) == pdTRUE)
{
/* Perform I2C Transaction */
/* Mutex will be given back, indicating that the shared I2C Bus is now available */
xSemaphoreGiveRecursive(xMutex_I2CBus);
}
else
{
/* Mutex was not available even after 2 seconds since the LPTIM interrupt triggered.
Perform Error Handling for the event that the I2C bus was locked */
}
/* Piece of code that could take a few seconds to execute */
}
}
Are Mutexes often used to avoid Priority Inversion scenarios, or are they (more often) widely used to prevent two operations from possibly happening together? I can't think of a simple scenario where if a Priority Inversion occurs, it could be critical for the software.
Thank you!