Page 1 of 2

Trivial code sometimes takes 5ms and interrupts are missed

Posted: Sat Jul 17, 2021 7:47 pm
by ArmyrAntSEC
Hi
So I was a huge fan of the Pico price-point and the fact that it seemed possible to program a microcontroller with Python.

But I ave found a blocker for me to use the Pico with Python in my project. The issue is that the main loop in my sample program below sometimes takes up to 5ms to run. And more specifically, it seems that the pico will miss interrupts during when that happens.

So can someone explain what it is that causes this code to sometimes take a lot longer to run? My obvious theory is that it is a garbage collector or similar, but no complex garbage collection should be needed here as only some very trivial variables are created in each loop.

The below code does not demonstrate the missed interrupts as these require some special hardware to detect, but if I can understand why the loop sometimes takes a long time, I think that might be enough.

Full disclosure: I have posted the identically same question on the Raspberry Pi Pico Micropythong forum as well.

Code: Select all

import utime

lastTime_ms = utime.ticks_ms()
nextTime_ms = utime.ticks_add( lastTime_ms, 100 )

lastTime_us = utime.ticks_us()
intervalMean = 0
intervalMeanSq = 0
callCount = 0

while ( True ):
    # This block of code is the problem. It sometimes takes more than 1ms, up to 5ms
    thisTime_us = utime.ticks_us()
    delta_us = utime.ticks_diff( thisTime_us, lastTime_us )
    intervalMean = (callCount*intervalMean + delta_us)/(callCount+1)
    intervalMeanSq = (callCount*intervalMeanSq + delta_us*delta_us)/(callCount+1)
    lastTime_us = thisTime_us
    callCount = callCount + 1
    # End of problem block

    thisTime_ms = utime.ticks_ms()

    if ( utime.ticks_diff( nextTime_ms, thisTime_ms ) < 0 ):
        timeDiff_ms = utime.ticks_diff( thisTime_ms, lastTime_ms)
        print ( "Time: ", thisTime_ms , " Time diff: ", timeDiff_ms, end='' )
        if ( timeDiff_ms != 100 ):
            print ( " Warning!" )
        else:
            print ()
        lastTime_ms = thisTime_ms
        nextTime_ms = utime.ticks_add( nextTime_ms, 100 )

Re: Trivial code sometimes takes 5ms and interrupts are missed

Posted: Sat Jul 17, 2021 8:03 pm
by Roberthh
Even a non-complex gabage collection will take some time, if many objects have to get collected. A common approach to make the timing more predictable would be to manually force garbage collection when there seems time to do some, like in the main loop. If there a only a few objects to collect, it will run much faster.

Re: Trivial code sometimes takes 5ms and interrupts are missed

Posted: Sun Jul 18, 2021 6:42 am
by pythoncoder
Yes. Though the code is simple it uses floating point maths, which implies allocation. Therefore GC will eventually occur. By periodically calling gc.collect(), collection occurs when most of the RAM is unallocated, so the GC runs much quicker - I'd expect ~1ms.

The radical approach is to rearrange the maths to use integer calculations only. With care, code can be written to be non-allocating.

Re: Trivial code sometimes takes 5ms and interrupts are missed

Posted: Sun Jul 18, 2021 8:27 pm
by ArmyrAntSEC
Hi
So the delay in the loop isn't the big problem (All algorithms I intend to use can be written to compensate for that). But the issue is that interrupt handling seems to be unrelible when these delays happen.

So my question to those with kore experience than me is: Does the garbage collector halt the interupt handlers? Are there some known details on how that works?

Re: Trivial code sometimes takes 5ms and interrupts are missed

Posted: Mon Jul 19, 2021 1:48 am
by jimmo
ArmyrAntSEC wrote:
Sun Jul 18, 2021 8:27 pm
So my question to those with kore experience than me is: Does the garbage collector halt the interupt handlers? Are there some known details on how that works?
It's important to clarify the two types of interrupt handlers -- hard and soft. The GC will halt soft interrupts (which are executed via the scheduler), but not hard ones (which are true hardware IRQ). This is the reason why hard IRQs are not allowed to allocate memory (as they could be interrupting the GC).

See https://docs.micropython.org/en/latest/ ... ne.Pin.irq -- the default is soft.

For more information https://docs.micropython.org/en/latest/ ... #isr-rules

Re: Trivial code sometimes takes 5ms and interrupts are missed

Posted: Sat Jul 24, 2021 5:05 pm
by ArmyrAntSEC
Interesting choice not to set the "hard" as the default on a low-level system such as this. I am not convinced that this was the right choice.

Either way, this seems to be a solution, so I will try it and hope for the best.

Re: Trivial code sometimes takes 5ms and interrupts are missed

Posted: Sat Jul 24, 2021 5:13 pm
by ArmyrAntSEC
Thanks for a clear answer!

Re: Trivial code sometimes takes 5ms and interrupts are missed

Posted: Sat Jul 24, 2021 6:18 pm
by pythoncoder
ArmyrAntSEC wrote:
Sat Jul 24, 2021 5:05 pm
Interesting choice not to set the "hard" as the default on a low-level system such as this. I am not convinced that this was the right choice...
The point of the machine module is that it is cross-platform: it should be possible to run code reliant on the module on any platform (subject to trivial changes like changing pin names). Given that some platforms don't support hard IRQ's, the default therefore has to be soft. If you write code using hard IRQ's then - inevitably - you either accept that it won't run on some platforms or figure out a solution.

Re: Trivial code sometimes takes 5ms and interrupts are missed

Posted: Sat Jul 24, 2021 8:03 pm
by ArmyrAntSEC
Looking back at the docs, I see a potential reason for the fact that I missed this:
https://docs.micropython.org/en/latest/ ... interrupts

"All pins except number 16 can be configured to trigger a hard interrupt if their input changes. You can set code (a callback function) to be executed on the trigger."

This section then has no mentione about setting a flag to make the interrups actually be "hard".

Should I submit a suggestion that the word "hard" either be removed, or that the text elaborate a bit about the fact that "hard" is not the default?

Re: Trivial code sometimes takes 5ms and interrupts are missed

Posted: Sat Jul 24, 2021 9:50 pm
by scruss
note that you're linking to the ESP8266-specific instructions, so what applies to them doesn't apply to the Pico.

It's as reasonable to assume that interrupts are soft rather than hard, so to me the docs appear to be clear and adequate