EEPROM and IMU connected on same I2C line there are two tasks one for handling EEPROM activity and other one for IMU. I2C reading part runs through DMA (direct memory access), after receiving the specified buffer of memory it generates interrupt. So If I am using mutex I need to take mutex from the task and I need to give the mutex from the ISR, Can I do like that or is there any alternate way, Can you please suggest something on this?
no, you can not give a mutex from an isr. Use a binary semaphore or a task notification.
Using an I2C-bus mutex on task level should be sufficient. Take it before starting the transfer and release it from the owning task after it got notified from ISR and maybe completed transfer post-processing.
I use a mutex in the driver, that takes the mutex as part of the initial processing of the I2C transaction, and then the driver doesn’t return to the task until the ISR signals the operation is done, and then the driver can give the mutex back.
If you want to use an asynchronous operation where the driver copies the data to an internal buffer to let the task continue, then you can have the driver take the mutex, and if the driver is busy, wait for it to finish, and then queue up the next operations, start it, and then release the mutex.
So, for either method there is a mutex that lets only one task at a time use the driver, and a semaphore (or the like) to signal from the ISR level part of the driver to the task level of the driver that the operation was completed.
Thank you for the reply I will try that you have suggested.
And one more thing Can I take and give mutex from RTOS Software Timer ISR?
yes, as long as you follow the mutex rules.
Be aware though that blocking in software timers should be avoided regardless of the object type to wait on; if unavoidable, make sure that you block only for a short time, and look out for deadlock potential.
To be technically correct, FreeRTOS Software Timer callback is not an ISR but it is called in the context of timer task. It is therefore important to not anything blocking in the timer callback.
And one thing to add, there is a corner case, when a timer callback is run as a result of a timer overflow and the callback was supposed to run before that overflow, when the callbacks are called with the scheduler disabled, which means blocking isn’t just not advised, but actually improper and can lock the system.
This is a small enough corner, I sometimes wonder if that result is a bug or if timer callbacks are really supposed to be specified as CAN NOT BLOCK, not just SHOULD NOT BLOCK.
Hi @richard-damon ,
How it is possible if scheduler is not running means context switch will not happen right?
then how can the timer deamonTask will run to call the timer handler?
Timer call backs are done in the context of the timer deamon Task, and that is the task that is suspending the scheduler currently to let it drain the expired timer queue and then possibly block to get future commands while waiting for the next timer to expire. No need for a context switch.
Okay, If timer deamon task is suspending the scheduler means, If I am writing while(1) in timer handler means it will struck there context switch will not happens right? Then no other task will run after that? And what if I am accessing UART,I2C hardware resources from Software timers?
Hi @richard-damon , One more thing what if I am taking mutex before starting the scheduler?
If the timer task has the highest prio using a while(true);
loop in a timer callback will starve all other tasks and livelocks.
The common use case of timer callbacks triggering HW access is to just notify a HW access task doing the I/O operations, which in turn can block etc.
Hi @hs2 Can I send data on uart from timer handler?
you can’t. Muteces can only be used from FreeRTOS tasks, and before the scheduler is started, there is no such context.
So it is not possible taking mutex before starting the scheduler right? okay if I am sending data over UART from timer handler without using mutex, is that okay?
Probably not, but you better present some code before asking rather generic questions. The rules change dramatically between before and after the scheduler is started, so interoperability between the two system states is extremly limited at best.
I would need to double check the details of the code, but I think it works, as long as some task has been created, as before the scheduler starts, teh “current task” will be defined as the highest priority task that has been created. You may need to make sure you call with a 0 block time, as some parts of the code check for the possiblity of blocking when the scheduler isn’t running.
This all puts you into the case that it “might work” but you are doing things not how they should be done.
Hi @richard-damon,
You are telling if I am taking the mutex before starting the scheduler with the zero wait time it won’t cause any issue right? Can I use like I mentioned a code below?
#include "FreeRTOS.h"
#include "task.h"
#include "stm32f4xx_hal.h"
#include "semphr.h"
void MX_GPIO_Init(void);
void Task1_BlinkLED1(void *pvParameters);
void Task2_BlinkLED2(void *pvParameters);
SemaphoreHandle_t mutex_handle;
int main(void)
{
HAL_Init();
MX_GPIO_Init();
mutex_handle = xSemaphoreCreateMutex();
// Create tasks
xTaskCreate(Task1_BlinkLED1, "LED1", 128, NULL, 1, NULL);
xTaskCreate(Task2_BlinkLED2, "LED2", 128, NULL, 1, NULL);
// Start the scheduler
send_char('A',0);
vTaskStartScheduler();
while (1) {}
}
void Task1(void *pvParameters)
{
while (1)
{
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void Task2(void *pvParameters)
{
while (1)
{
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void send_char(uint8_t data,uint8_t wait_time)
{
if(NULL != mutex_handle)
{
xSemaphoreTake(mutex_handle,pdMS_TO_TICKS(wait_time));
}
else
{
return;
}
send_uart(data,1);
xSemaphoreGive(mutex_handle);
}
That may or may not work, but as Richard pointed out, it relies on some undocumented behavoir and thus may likely break with future versions of FreeRTOS.
Why not use this mechanism here
so your sendchar routine uses the mutex only after the scheduler has started?
Also note that this code assumes that the USART is fully functional before the scheduler has started. That is normally not the case, in particular is it is interrupt driven.