xEventGroupSetBitsFromISR() return pdFAIL from the ISR sometimes

unknowcoder wrote on Thursday, July 05, 2018:

I am using xEventGroupSetBitsFromISR() from an ISR which trigger when ever the timer expires. The timer is a 1 shot interrupt timer. It is not periodic.

I have noticed that sometimes xEventGroupSetBitsFromISR() return failure and the bit I am trying to set does not get set.

I can’t use task notifcation because I am using streambuffer which seem to use this. I’ve ran into multiple problems using streambuffer and task notifcation in the past.

My only other solution is to use a semaphore.

I am running FreeRTOSv10.0.0

On another note most these timer are setup on order of a few 100microseconds. A tick for the RTOS is 5ms. The timer task is set to the highest prioirty in the system.

static inline void Timer_Handler(const IRQn_Type irq_number, const pit_chnl_t channel, const uint32_t trigger_bit)
{
    if( NULL != events )
    {
        BaseType_t is_awoken = pdFALSE;

        Timer_Disable(irq_number,channel);

        if( pdFAIL != xEventGroupSetBitsFromISR(events, trigger_bit, &is_awoken) )
        {
            portYIELD_FROM_ISR(is_awoken);
        }
        else
        {
            ASSERT_DEBUG_MODE(0);
        }
    }
    else
    {
        ASSERT_DEBUG_MODE(0);
    }
}

unknowcoder wrote on Thursday, July 05, 2018:

It looks like after further investigation that xEventGroupSetBitsFromISR() is actually successing on every calls but the task pending on the bit (xEventGroupWaitBits()) never gets the bit.
Testing this with only 1 task created.

unknowcoder wrote on Thursday, July 05, 2018:

Ok, just to follow up on this I was completely mislead by what is occuring.
The problem had nothing to do with ISR. It has to do with xEventGroupWaitBits() in the task is not blocking for 1 tick which is 5ms. It’s blocking for only 436us.

The task calls xEventGroupWaitBits() with 1 tick timeout. But a single tick is 5ms while I had setup the ISR to run for 650us. Which means my ISR will run before that tick has elapsed. But that does not seem to occour. I used a scope and timed everything.
xEventGroupWaitBits() when called with 1 tick is only delaying about 436us. I completed timed this.

The expected calls are

  1. Setup timer interrupt with 650us
  2. Wait in the task for the event bit (xEventGroupWaitBits()) to be set by the ISR. With a max block time of 1 tick which equal to 5ms.
  3. ISR runs and sets the event bit

What I am finding is that xEventGroupWaitBits() returns before the ISR runs and when I time it using a GPIO pin and a scope the block time is only around 436us.

What I found is if I set xEventGroupWaitBits() to block for 2 ticks which is 10ms everything works great!
Any thoughts on why this may be occuring.

rtel wrote on Thursday, July 05, 2018:

There is no sub-tick resolution - if there is a tick every 5ms and you
ask for a block time of 1 tick, then the actual block time can be
anything from 0.000001ms to 4.999999ms, depending on where within the
time slice the request to block for 1 tick was made.

unknowcoder wrote on Friday, July 06, 2018:

Hi Richard,

I did a bad job at explaining what was occuring lets try this again. See the code reference below.

The RTOS is setup for 200Hz which is 5ms per tick.
I am setting up a hardware timer (lets call is PIT0) to interrupt once with a counter value equivalent to 650us. This is a different timer than the systick timer.

Before I block on xEventGroupWaitBits() for 1 tick (i.e 5ms) I toggle a GPIO line which i connected to a scope. I do this so I can measure the real time external to the MCU.

What I am finding is that occassionally xEventGroupWaitBits() does not wait anywhere close to 5ms. The PIT0 timer is setup correctly because I can measure that timing using another IO pin also connected to the scope.

I have cases where xEventGroupWaitBits() returns before the PIT0 interrupt runs. When I check the timing on GPIO0 which measure the time xEventGroupWaitBits() is in the blocked state it was around 436us. This is very far off from 5ms.

What I have found that works is if I set the timeout on xEventGroupWaitBits() to 2 ticks, everything works fine. That xEventGroupWaitBits() blocks for about 650us as expected.

Additonally

  1. I have been testing with only 1 task created.
  2. trigger_bit variable is only 1 bit that is the 4th bit only.
    xEventGroupClearBits(events, trigger_bit); /*Clear the trigger bit which will be given from the ISR*/
    Setup_Interrupt_Timer0();

    Toggle_GPIO0();

    const EventBits_t bit_taken = xEventGroupWaitBits(events, trigger_bit, pdTRUE, pdTRUE, 1);

    Toggle_GPIO0();

tlafleur wrote on Friday, July 06, 2018:

What Richard is trying to explain to you is that a tick is NOT deterministic, if a task yield in the middle of a tick caused by an interrupted or another mechanism, the scheduler will run and launch the next available tasks of the highest priority it does not wait 5 ms to launch the next task… doing so would be very inefficient use of the CPUs resources…most all Operating systems work like this. If you need more accurate timing use a hardware timer or change the tick to something faster like 1 ms… but setting the tick faster, cause the OS to spend more time in the scheduler so, it become a system design trade off…

rtel wrote on Friday, July 06, 2018:

To elaborate further: The tick interrupt occurs at a fixed frequency. If you ask to block for 1 tick you are effectively saying unblock the task at the next tick interrupt. If there is a tick interrupt every five milliseconds, and you block a task four milliseconds after the last tick interrupt, then the next tick interrupt will occur one milllisecond after that task entered the blocked state - and the task will therefore only block for one millisecond. This is what I mean by there is only (in your case) five millisecond resolution - you cannot block with any more accuracy than five milliseconds.