GPIO Interrupt on STM32F4 causes FreeRTOS timer go haywire

rtel wrote on Tuesday, April 10, 2018:

Maybe a long shot, but what happens if you take out the calls to
printf()? Fist just from ‘other task’, which may get deleted before all
the output has been output (depending on how printf() is implemented),
and second removing printf() from all tasks.

aarbee wrote on Tuesday, April 10, 2018:

Disabling all Prints from all over the code didn’t help. I am using Segger RTT for prints. So I disabled it all together. It seems there is something special about deleting that first ever task.

If I kill that dummy task as well (along with other_task), I see the problem again. So it seems one of those tasks created in the beginning must stay in the task list.

rtel wrote on Tuesday, April 10, 2018:

I think RTT is just the output method. Did you actually comment out the
calls to printf()? Otherwise it will make little difference to the
libraries being called by printf(), and the stack used by printf(), in
order to prepare the string that will be output.

aarbee wrote on Tuesday, April 10, 2018:

In the printf function, I just returned without calling any functions thus effectively bypassing any calls to the functions. Individually commenting out each print statment would be a lot of statements to comment out…

Something like:

int p_printf(const char *format, ...)
{

    return 0;
    
    if (xSemaphoreTake(printf_mutex, 3000) == pdFALSE) {
        return -1;
    }

    va_list args;
    va_start(args, format);
    int loglen = vsnprintf(LOG_BUFFER, LOG_BUFFER_SIZE, format, args);
    va_end(args);

    int ret = SEGGER_RTT_Write(0, LOG_BUFFER, loglen);
    xSemaphoreGive(printf_mutex);
    return ret;
}

Also removed Segger initialization.

aarbee wrote on Tuesday, April 10, 2018:

If I kill the dummytask as well, I start seeing the problem again. Also the dummy task must be running for it to fix the issue…

aarbee wrote on Tuesday, April 10, 2018:

So here is what I have concluded till now.

**If dummy taks isblocked for more than twice the expiry time of the fastest timer, the GPIO interrupts will cause all timers to start expiring sooner than the scheduled expiry.
**

rtel wrote on Tuesday, April 10, 2018:

That seems to be good info. I can try and replicate but don’t have the
interrupt executing as you do.

Do I have this write:

  1. Create an app with multiple tasks and a timer.
  2. Make sure the tasks are blocking for more than twice the timer’s
    expire time.
  3. Have one of the tasks delete itself and watch what happens to the
    timer expiry time.

aarbee wrote on Tuesday, April 10, 2018:

Yes. That would work but interrupts coming on a GPIO is what triggers the issues. No interrupts = No issue.

aarbee wrote on Tuesday, April 10, 2018:

I am doing more debugging so if I find anything else I will post.

rtel wrote on Tuesday, April 10, 2018:

One thing to note that may help. If a timer is due to expire every
10ms, and it is blocked from running for 30ms, then it will execute 3
times in quick succession to ‘catch up’ with where it should have been.
That can make it look like all of a sudden it is running too quickly -
whereas in reality, once it is caught up with itself, it will return to
its proper frequency.

I don’t think that is what is happening in this case, so just something
to be aware of.

aarbee wrote on Tuesday, April 10, 2018:

Let me rephrase what I see:

There has to be atleast one task in the Running state. If all tasks are blocked, GPIO interrupts will cause timers to start expiring before the scheduled time

I removed the dummy task I created and I put a loop at the end of the inittask so that the init task never ends. This fixes the problem because now I have at least one task (inittask) which is in Runnign state while all others are in blocked state.

This is what changed at the end of the inittask:

// vTaskDelete(NULL);   <--- Commented this so this task doesn't end
while (1) {             <--- Kept it running for ever
    vTaskDelay(10);
     }
} /*end of inittask*/

I am testing it now to make sure it stands the test of time… I will let it run for a while.

aarbee wrote on Tuesday, April 10, 2018:

Interesting. So if it exectues three times in a succession, all the logic around it will execute three times as well. That would be a disaster for some applications.

Also, will a GPIO interrupt cause the timer to be blocked for the duration of the ISR execution causing the above behavior?

rtel wrote on Wednesday, April 11, 2018:

Interesting. So if it exectues three times in a succession, all the
logic around it will execute three times as well. That would be a
disaster for some applications.

Likewise it would be a disaster for some applications if it is supposed
to execute three times within a given period and in fact it only
executes once. Or if it missed its deadline by a single tick, so opted
not to execute. Executing exactly the required number of times seems
the best option.

Also, will a GPIO interrupt cause the timer to be blocked?

Only if the interrupt too a verrrrry long time to execute, or if the
interrupt was not cleared properly so was continuously being re-entered.
It looks like your interrupt is being cleared - assuming the code in
your post is correct - though.

richard_damon wrote on Wednesday, April 11, 2018:

Also, if you want non-catchup operation, just set the timer not to repeat and retrigger it as part of the timer callback.

richard_damon wrote on Wednesday, April 11, 2018:

There is ALWAYS a task in the ready to run state, as the Idle task that is automatically created will never block (and if you enable the idle hook, you must not block in it).

Your inittask above isn’t in the ‘Running’ state for most of its time, as it is blocked with vTaskDelay().

A task that deletes itself will have its final clean up defered to being done in the idle task.
Some thoughts that pop up:
Are you using the idle hook?
Are you using tickless idle? Having a task aways ready to wake up soon can block going into tickless idle, and if tickless idle isn’t setup right, it could throw off your time base.

aarbee wrote on Wednesday, April 11, 2018:

Richard,
You got it.
Thanks for the response.

I am using tickless idle and that was the culprit. I changed the configUSETICKLESSIDLE to 0 and problem goes away.

I am using idle hook too and I suspected that earlier. It uses ‘Wait for Interrupt’ in it. I commented it out but that didn’t help…

void vApplicationIdleHook(void) {
   asm("WFI");
}

What is this supposed to mean? Can’t use GPIO interrupts along with Tick less Idle? I am using default port implentation of the tick less idle.

richard_damon wrote on Wednesday, April 11, 2018:

WFI stopps the processor until an interrupt comes. This can save power. It shouldn’t normally cause issues, as if you are in the idle task, there isn’t anything else to do, but wait for some interrupt.

The possible issue with tickless idle is that something isn’t configured right. In tickless idle, if the kernal sees that nothing will be needed to be done for awhile, it reconfigures the system to stop interrupting every tick, but to go to sleep for a longer period of time, until an interrupt occurs or that long period of time expires. If it gets woken up by an interrupt, it then needs to figure out approximately how much time has expired by looking at the timer it setup and then advance time by that much. This process is NOT exact, and there can be some time slipage, and I think the tick hook may get called repeatedly (if you are using the tick hook, you may not want to use tickless idle). If you have some of the hardware configured differently than FreeRTOS is expecting, this time estimate could be off more signficantly.

aarbee wrote on Wednesday, April 11, 2018:

I have the tick hook enabled by
#define configUSE_TICK_HOOK 1

but the the function does nothing.

void vApplicationTickHook(void) {
}

What else to look at?

rtel wrote on Wednesday, April 11, 2018:

/I am using tickless idle and that was the culprit. I changed the
configUSETICKLESSIDLE to 0 and problem goes away./

I vital piece of information you omitted! ;o)

aarbee wrote on Wednesday, April 11, 2018:

If you have some of the hardware configured differently than FreeRTOS is expecting, this time estimate could be off more signficantly.

What does FreeRTOS expect?