Timer gets stuck when thread is running - RP2040

RP2040 based microcontroller boards running MicroPython.
Target audience: MicroPython users with an RP2040 boards.
This does not include conventional Linux-based Raspberry Pi boards.
Post Reply
User avatar
EliAaron
Posts: 6
Joined: Thu Feb 24, 2022 1:35 pm
Location: Jerusalem, Israel
Contact:

Timer gets stuck when thread is running - RP2040

Post by EliAaron » Mon Jul 04, 2022 3:27 pm

There seems to be a problem using the Timer and a thread simultaneously. The timer randomly gets stuck after a few seconds. The higher the frequency of the timer, the quicker it gets stuck.

Note: I am using MicroPython v1.19.1 where rp2 memory corruption bug in thread was fixed.

I came across these two links which seem to be about the same issue, with no solution:
Timer callback stops with uart thread
Problem with machine.Timer() and _thread on Raspberry Pi Pico (RP2040)

I wrote a simple example that demonstrates the problem and is easy to reproduce with any Pico board.

In the example, the Pico LED is toggled in a thread and a timer runs with a callback that prints an incrementing counter.

Code: Select all

import time
import _thread
from machine import Pin, Timer

led = Pin(25, Pin.OUT)
counter = 0

def blink_func():
    led.toggle()

def print_func():
    global counter
    print(f"counter = {counter}")
    counter += 1
        
def thread_loop(freq, func):
    delay = 1/freq
    while True:
        func()
        time.sleep(delay)

def start_timer(freq, func):
    tim = Timer()
    tim.init(freq=freq, mode=Timer.PERIODIC, callback=lambda t:func())
    
def start_thread(freq, func):
    _thread.start_new_thread(thread_loop, (freq, func))


start_timer(3000, print_func)
start_thread(50, blink_func)

# This avoids an error from Thonny that probably has to do with the REPL and the printing
try:
    while True:
        pass
finally:
    pass

Details about my specific problem:

In my project, I am trying to do the following things simultaneously:
- Play a wave file from an SD card using I2S (the builtin MicroPython I2S)
- Light an RGB LED strip (8 WS2812B LEDS) with a sequence of RGB values using a Timer. The LEDS are controlled using the PIO.

The first thing I found out was that the LED must use a state machine with ID 1-7. If I used ID 0, the I2S would stop the LEDS immediately, probably some config is overwritten by the I2S object.

Still, the code did not work correctly. The LEDS would randomly stop after a few seconds. I tried to narrow down the problem. I found that if I use the I2S on the main thread (no second thread) or use a loop for controlling the LEDS instead of a timer, there were no problems. I also found that the higher the frequency of the timer, the faster it would get stuck.

I assume there is some problem using the timer and a thread simultaneously.
Last edited by EliAaron on Wed Jul 06, 2022 9:48 am, edited 5 times in total.

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Timer gets stuck when thread is running

Post by jimmo » Mon Jul 04, 2022 3:35 pm

EliAaron wrote:
Mon Jul 04, 2022 3:27 pm
There seems to be a problem using the Timer and a thread simultaneously. The timer randomly gets stuck after a few seconds. The higher the frequency of the timer, the quicker it gets stuck.
Thanks for the really detailed repro and background. I have been working on rp2040 concurrency-related issues this week, and will add this to the list.

I think it's possible that https://github.com/micropython/micropython/pull/8846 might fix this (the rp2 timer uses the scheduler, and the scheduler was not correctly thread-safe on rp2). I will test it tomorrow.

User avatar
EliAaron
Posts: 6
Joined: Thu Feb 24, 2022 1:35 pm
Location: Jerusalem, Israel
Contact:

Re: Timer gets stuck when thread is running

Post by EliAaron » Tue Jul 05, 2022 12:17 pm

Thank for replying!
jimmo wrote:
Mon Jul 04, 2022 3:35 pm
I think it's possible that https://github.com/micropython/micropython/pull/8846 might fix this (the rp2 timer uses the scheduler, and the scheduler was not correctly thread-safe on rp2). I will test it tomorrow.
I built and uploaded the MicroPython commit that you recommended but it did not solve the problem. It seems the timer gets stuck faster with that commit.

User avatar
Mike Teachman
Posts: 155
Joined: Mon Jun 13, 2016 3:19 pm
Location: Victoria, BC, Canada

Re: Timer gets stuck when thread is running - RP2040

Post by Mike Teachman » Tue Jul 05, 2022 5:41 pm

EliAaron wrote:
Mon Jul 04, 2022 3:27 pm
The first thing I found out was that the LED must use a state machine with ID 4-7. If I used ID 0-3, the I2S would stop the LEDS immediately, probably the PIO program or some other config was overwritten.
This can definitely happen. Here is a technical description on the problem you observe. The RP2.StateMachine class implementation does not mark the requested state machine as "used". By not marking the state machine as used, other module classes (such as I2S) can inadvertently select a state machine used by RP2.StateMachine, thereby overwriting it. This should likely be considered a bug in the RP2.StateMachine class implementation. The Pico SDK provides a rich set of functions to claim state machines and check that a given state machine is claimed by another entity. The RP2.StateMachine class implementation could be updated to use these SDK functions, thereby removing the problem you see. I should likely raise an Issue on this problem.

For now, your solution is a good workaround to this problem.

User avatar
Mike Teachman
Posts: 155
Joined: Mon Jun 13, 2016 3:19 pm
Location: Victoria, BC, Canada

Re: Timer gets stuck when thread is running - RP2040

Post by Mike Teachman » Tue Jul 05, 2022 7:59 pm

Mike Teachman wrote:
Tue Jul 05, 2022 5:41 pm
I should likely raise an Issue on this problem
I submitted an Issue:
https://github.com/micropython/micropython/issues/8866

Post Reply