Sharing lock between ISR and application

michab66 wrote on Monday, May 28, 2018:

I want to setup the following high level structure: An application does periodic work in a loop. An ISR can set a boolean flag, e.g. to false, that stops the loop. Later-on, again from the ISR, the flag is reset to true and the loop continues.

So technically the ISR must be able to set and reset the flag without blocking. The application needs to be able to check the flag. If the flag is set, the application must continue. If the flag is not set, the application must block until the ISR sets the flag.

I think the FreeRTOS API that is part of my solution is ‘RTOS Task Notifications’.
My problem is in the application to (1) check the value AND (2) block if the wrong value is found until the value changes.

My intended code structure in the application is:

// In loop_task...

bool lock;

while ( true ) {
  taskENTER_CRITICAL
    while ( lock != true )
        xTaskNotifyWait(...)
  taskEXIT_CRITICAL
  
  // Do work.
}
// In the ISR...
...
taskENTER_CRITICAL_FROM_ISR
lock = new_lock_value;
xTakNotifyFromISR( loop_task... );
taskEXIT_CRITICAL_FROM_ISR
...

The xTaskNotifyWait() inside the critical section is bad. But if I start the wait after the critical section the ISR may switch and notify before the application waits.

So my question is: How can I sove that (seemingly simple) problem? Is there a better API I missed? I’m on FreeRTOS 10.

Best wishes,
Michael.

richard_damon wrote on Monday, May 28, 2018:

You don’t really need the critical section here. You do want the read access to the flag to be atomic, which on most processors a bool should be.

First, the critical section in the ISR doesn’t get you anything, as you only access these things in one ISR, so there is no need to block out the other ISRs during the action. Note, the ISR also should only send the notify if it just set the flag true.

The Critical section in the task doesn’t get you anything, as if it sees the flag true, it should run and no sequencing is important. If it sees the flag false, it will block until the notify, and you are gaurenteed that after the ISR transitions the flag from false to true that it will do a notify that will wake the task.

If you had a multi-core processor where coherance in memory views was an issue, you would need some memory barrier instrunctions, but FreeRTOS isn’t designed for that sorts of machines (critical sections via interuprt disabling doesn’t work there)

michab66 wrote on Tuesday, May 29, 2018:

That clarifies. One concern remains: What if

  • The application checks the flag and needs to block,
    … a context switch happens int the ISR …

  • The ISR modifies the flag and performs the …NotifyFromISR,
    … a context switch happens into the application task …

  • The application reaches the …Wait.

In this case the application task would miss the notify and wait forever?

Ah, in the documentation I found the description of ‘pending’ notifications. That’s the solution.
Thanks a lot.

richard_damon wrote on Tuesday, May 29, 2018:

A Notify remembers that it has been notified until the application waits, so the above isn’t a problem. This is why you don’t use suspend/resume, as if the ISR issued a resume from the task suspends it will be missed.

michab66 wrote on Wednesday, May 30, 2018:

Cool, I understand. One final question: Is the …NotifyFromISR cumulative? In other words, when called twice (and there’s no task waiting), are then two notifications pending or is ‘pending’ a binary flag?

rtel wrote on Wednesday, May 30, 2018:

https://www.freertos.org/RTOS_Task_Notification_As_Counting_Semaphore.html
https://www.freertos.org/xTaskNotifyGive.html