我是FreeRTOS的新手,一直在阅读FreeRTOS文档,并在STM32F767 Nucleo板上使用FreeRTOS编写简单代码。在我编写的简单程序中,我使用二进制信号量仅在LPTIM和GPIO中断通过xSemaphoreGiveFromISR()
发生时向某些任务发出信号,并通过xSemaphoreGive()
向不同的任务发出信号以执行来自另一个任务的某些操作。
假设我有一个I2C1外围设备连接到两个不同的设备:
- 一种加速度计,每当发生活动/移动时,它就会触发微控制器的GPIO中断。该GPIO中断向微控制器发出信号,表示必须读取其中断事件寄存器内的一段数据,以便可以再次发出下一个活动/移动事件的信号
- 必须定期从中读取的设备,该设备将通过LPTIM或TIM外围设备触发
在上述情况下,我可以使用互斥和二进制信号量吗
二进制信号量将向任务指示需要根据触发的各个中断执行操作,但互斥将在这两个任务之间共享,其中Task1将负责从加速度计读取数据,Task2将负责从其他设备读取数据。我认为将使用Mutex,因为这两个操作永远不应该一起发生,这样总线上就不会发生可能锁定任何I2C设备的重叠I2C事务。
代码如下所示:
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 */
}
}
互斥是经常用于避免优先级反转场景,还是(更经常(广泛用于防止两个操作可能同时发生我想不出一个简单的场景,如果优先级反转发生,它可能对软件至关重要。
谢谢!
总的来说,我认为您的设计是可行的。信号量是两个任务工作的信号。互斥锁保护共享的I2C资源。
但是,与互斥体共享资源可能会导致复杂性。首先,您的操作任务在等待I2C资源互斥时不会对新的信号量信号/事件做出响应。其次,如果应用程序变得更加复杂,并且添加了更多的阻塞调用,那么设计可能会陷入阻塞、饥饿、竞争条件和死锁的恶性循环。你的简单设计还没有实现,但你正在沿着一条道路前进。
作为一种替代方案,可以考虑让第三个任务负责处理所有I2C通信。I2C任务将等待消息(在队列或邮箱中(。当消息到达时,I2C任务将执行相关联的I2C通信。操作任务将像现在一样等待信号量信号/事件。但是,现在操作任务将向I2C任务发送/发布消息,而不是等待I2C互斥变得可用。使用这种设计,您不需要互斥体来序列化对I2C资源的访问,因为I2C任务的队列/邮箱负责序列化来自其他任务的消息通信请求。此外,在这种新的设计中,每个任务只在一个地方阻塞,这更清洁,并允许操作任务对信号/事件做出更大的响应。
IMO这是一个完全错误的设计。
如果您想通知任务新数据已存在,请使用队列并发布到队列。如果有多个任务想要获取数据,您可以向多个队列发布(您可以有一组队列要发送(。您甚至可以在运行时添加队列。