micropython / micropython

MicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems
https://micropython.org
Other
19.5k stars 7.8k forks source link

rp2: Timer IRQ causes hang #6965

Open peterhinch opened 3 years ago

peterhinch commented 3 years ago

This has been discussed in a forum thread notably here where @marfis produced definitive evidence. The problem can also be demonstrated without using the PIO with this script:

from machine import Pin, Timer
from time import sleep_ms
import math

pin17 = Pin(17, Pin.OUT)
tim = Timer(freq=1000, mode=Timer.PERIODIC, callback=lambda _: pin17(not pin17()))
pin18 = Pin(18, Pin.OUT)

while True:
    pin18(1)  # Trigger
    pin18(0)
    y = 0
    for x in range(100):
        y += math.sin(x * 2 * math.pi/100)  # 6.2ms of busywork
    sleep_ms(100)

It doesn't run for more than a few minutes before the waveforms stop. It's not a complete crash: ctrl-c gets the REPL back.

Secondly the timer pulse duration varies, occasionally quite radically. It can take quite a few single shot readings to spot this. If you comment out the busywork, just leaving the sleep_ms(100) it runs forever.

The problem we were investigating proved to be entirely due to the timer code: replacing it with a PWM instance produced a solid fix.

hoihu commented 3 years ago

marfis here. One thing I noted was that the distorted waveform always occured after the sleep_ms(xx) call, right before the PIO was triggered. The PIO is not the source of the problem, as peter stated - I just wanted to point out that it happend in that timeslot.

@peterhinch did you observe this in your code above too, e.g. does the distortion happen around the time when pin18 is toggled?

Could it be that there is some blocking happening at that time (perhaps in a higher IRQ handler) - as @dhylands suggested in the form link above.

peterhinch commented 3 years ago

It's hard to be sure: you really need a way to trigger a single shot on an unusually long pulse. I definitely observed a trigger pulse followed by a very long delay on the timer, but if a long timer pulse occurred far from the trigger I would have missed it.

The fact that the code actually stops running would seem to imply something other than a higher priority IRQ.

One thing I noted was that the distorted waveform always occurred after the sleep_ms(xx) call, right before the PIO was triggered.

I spotted that too - which is why I concocted the above script with the PIO eliminated :) However time.sleep() is in the clear because if I remove the busywork leaving only

while True:
    pin18(1)  # Trigger
    pin18(0)
    sleep_ms(100)

it runs forever with clean pulses.