adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.09k stars 1.21k forks source link

RP2040 hang when running specific code.py with an exception #5418

Closed DavePutz closed 2 years ago

DavePutz commented 3 years ago

CircuitPython version

Adafruit CircuitPython 7.0.0 on 2021-09-20; Raspberry Pi Pico with rp2040

Code/REPL

import time
from math import sin
import board
import displayio
import rgbmatrix
import framebufferio
import adafruit_imageload
import terminalio
from adafruit_display_text.label import Label

displayio.release_displays()
matrix = rgbmatrix.RGBMatrix(
    width=64, bit_depth=6,
    rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12],
    addr_pins=[board.D25, board.D24, board.A3, board.A2],
    clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1,
    doublebuffer=True)
xxxxx
display = framebufferio.FramebufferDisplay(matrix, auto_refresh=False)

g = displayio.Group()
b, p = adafruit_imageload.load("pi-logo32b.bmp")
t = displayio.TileGrid(b, pixel_shader=p)
t.x = 20
g.append(t)

l = Label(text="Feather\nRP2040", font=terminalio.FONT, color=0xffffff, line_spacing=.7)
g.append(l)

display.show(g)

target_fps = 50
ft = 1/target_fps
now = t0 = time.monotonic_ns()
deadline = t0 + ft

p = 1
q = 17
while True:
    tm = (now - t0) * 1e-9
    x = l.x - 1
    if x < -40:
        x = 63
    y =  round(12 + sin(tm / p) * 6)
    l.x = x
    l.y = y
    display.refresh(target_frames_per_second=target_fps, minimum_frames_per_second=0)
    while True:
        now = time.monotonic_ns()
        if now > deadline:
            break
        time.sleep((deadline - now) * 1e-9)
    deadline += ft

Behavior

Note that an intentional syntax error has been put in line 18. If the code is manually executed, the output is as expected:

>>> exec(open('bcode.py').read())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 18, in <module>
NameError: name 'xxxx' is not defined

However, if it is saved as code.py and automatically executed no messages are sent to the REPL device. The RP2040 is hung - CTRL-C, etc. have no effect. Compiling in DEBUG mode, the following stack was captured:

#0  _PM_row_handler (core=0x200038a4 <displays+20>) at ../../lib/protomatter/src/core.c:467
#1  0x100702b4 in _PM_PWM_ISR () at ../../lib/protomatter/src/arch/rp2040.h:194
#2  <signal handler called>
#3  0x1006fb22 in _PM_begin (core=core@entry=0x200038a4 <displays+20>) at ../../lib/protomatter/src/core.c:175
#4  0x10049920 in common_hal_rgbmatrix_rgbmatrix_reconstruct (self=self@entry=0x20003890 <displays>,
    framebuffer=framebuffer@entry=0x20008be0) at ../../shared-module/rgbmatrix/RGBMatrix.c:108
#5  0x10049a2c in common_hal_rgbmatrix_rgbmatrix_construct (self=self@entry=0x20003890 <displays>,
    width=<optimized out>, bit_depth=bit_depth@entry=6, rgb_count=<optimized out>,
    rgb_pins=rgb_pins@entry=0x20041da8 "\006\005\t\v\n\f", addr_count=4 '\004',
    addr_pins=addr_pins@entry=0x20041d9c "\031\030\035\034\025", clock_pin=clock_pin@entry=13 '\r',
    latch_pin=latch_pin@entry=0 '\000', oe_pin=oe_pin@entry=1 '\001', doublebuffer=true, framebuffer=0x20008be0,
    tile=tile@entry=1 '\001', serpentine=true, timer=timer@entry=0x0) at ../../shared-module/rgbmatrix/RGBMatrix.c:67
#6  0x1003d46e in rgbmatrix_rgbmatrix_make_new (type=<optimized out>, n_args=<optimized out>,
    pos_args=<optimized out>, kw_args=<optimized out>) at ../../shared-bindings/rgbmatrix/RGBMatrix.c:243
#7  0x10016888 in type_call (self_in=0x1008f0b0 <rgbmatrix_RGBMatrix_type>, n_args=0, n_kw=<optimized out>,
    args=0x200030d0 <_pystack+28>) at ../../py/objtype.c:1048
#8  0x1000bf94 in mp_call_function_n_kw (fun_in=0x1008f0b0 <rgbmatrix_RGBMatrix_type>, n_args=0, n_kw=n_kw@entry=8,
    args=0x200030d0 <_pystack+28>) at ../../py/runtime.c:652
#9  0x1000c072 in mp_call_method_n_kw (n_args=<optimized out>, n_kw=8, args=args@entry=0x200030c8 <_pystack+20>)
    at ../../py/runtime.c:667
#10 0x200015b2 in mp_execute_bytecode (code_state=code_state@entry=0x200030b4 <_pystack>,
    inject_exc=inject_exc@entry=0x0) at ../../py/vm.c:1102
#11 0x200011d8 in fun_bc_call (self_in=0x2003b590, n_args=0, n_kw=0, args=0x0) at ../../py/objfun.c:296
#12 0x1000bf94 in mp_call_function_n_kw (fun_in=fun_in@entry=0x2003b590, n_args=n_args@entry=0, n_kw=n_kw@entry=0,
    args=args@entry=0x0) at ../../py/runtime.c:652
#13 0x1000bfc0 in mp_call_function_0 (fun=fun@entry=0x2003b590) at ../../py/runtime.c:625
#14 0x10052fa0 in parse_compile_execute (source=source@entry=0x1007f8bc,
    input_kind=input_kind@entry=MP_PARSE_FILE_INPUT, exec_flags=exec_flags@entry=32, result=result@entry=0x20041fcc)
    at ../../lib/utils/pyexec.c:146
#15 0x100533a4 in pyexec_file (filename=filename@entry=0x1007f8bc "code.py", result=result@entry=0x20041fcc)
    at ../../lib/utils/pyexec.c:743
#16 0x1001cc62 in maybe_run_list (filenames=filenames@entry=0x1007f91c <supported_filenames>,
    exec_result=exec_result@entry=0x20041fcc) at ../../main.c:221
#17 0x1001d0e8 in run_code_py (safe_mode=NO_SAFE_MODE) at ../../main.c:374
#18 main () at ../../main.c:884

Description

The issue seems to be related to the use of rgbmatrix.RGBMatrix; as other code.py scripts with syntax errors behave as expected.

Additional information

No response

fivdi commented 3 years ago
Adafruit CircuitPython 7.0.0 on 2021-09-20; Raspberry Pi Pico with rp2040

This is the message that is printed by CircuitPython on a Raspberry Pi Pico but the code posted above appears to be for an Adafruit Feather RP2040. For example, board.D6 doesn't exist on a Raspberry Pi Pico but does exit on an Adafruit Feather RP2040.

On a Adafruit Feather RP2040 I'd expect the following message to be displayed:

Adafruit CircuitPython 7.0.0 on 2021-09-20; Adafruit Feather RP2040 with rp2040

What type of board is being used and was the correct version of CircuitPython flashed onto the board?

cjsieh commented 3 years ago

It fails on both, Easier to get traceback on pico board since it has easy to access debug pins. Feather 2040 need SMD headers soldered.

Yes the traceback was from a pico with pico circuitpython flashed to it.

On Sat, Oct 2, 2021 at 5:08 PM Brian Cooke @.***> wrote:

Adafruit CircuitPython 7.0.0 on 2021-09-20; Raspberry Pi Pico with rp2040

This is the message that is printed by CircuitPython on a Raspberry Pi Pico but the code posted above appears to be for an Adafruit Feather RP2040. For example, board.D6 doesn't exist on a Raspberry Pi Pico but does exit on an Adafruit Feather RP2040.

On a Adafruit Feather RP2040 I'd expect the following message to be displayed:

Adafruit CircuitPython 7.0.0 on 2021-09-20; Adafruit Feather RP2040 with rp2040

What type of board is being used and was the correct version of CircuitPython flashed onto the board?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/adafruit/circuitpython/issues/5418#issuecomment-932826796, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFM7PVIKJ7WIOZJZGW7SECLUE57G3ANCNFSM5FDFHKYA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

jepler commented 3 years ago

It seems most likely that the problem arises when an RGBMatrix has been created, but not its associated FramebufferDisplay. We have to do "strange things" across a soft restart when these displayio-related objects exist. I recommend exploring this possibility, especially if that is the ONLY line where placing the exception-causing code leads to the problem.

The problem would not occur in quite the same way in the repl, because the soft reset would not occur until exiting the repl.

DavePutz commented 2 years ago

The issue looks to be that it is getting into the protomatter PWM interrupt handler when things are not set up yet. Note that a similar hang can be generated when running the script from https://learn.adafruit.com/rgb-led-matrices-matrix-panels-with-circuitpython/connecting-with-feather-rp2040-featherwing by hitting CTRL-C during startup. @jepler - I am not clear on why common_hal_rgbmatrix_rgbmatrix_construct is being called to create a PM object when things are in the process of shutting down. Can you clarify? I have been able to correct the problem by turning off the PWM interrupt; putting a irq_set_enabled(PWM_IRQ_WRAP, false); near the beginning of _PM_begin in lib/protomatter/src/core.c; but I'm not sure that is a great solution.

jepler commented 2 years ago

When an RGBMatrix is initially constructed, its framebuffer (as well as other data used to do the low level "scan the matrix out" activity) is placed in the GC heap. Because displays are 'kept' over soft resets, there is a moment when it is necessary to destroy the RGBMatrix and construct a fresh one, placing the framebuffer in supervisor storage instead. This is what the common_hal_rgbmatrix_rgbmatrix_reconstruct function does when it's called during the interpreter teardown process. (there may be another way to do it, but this is the way I chose to do it. I welcome improvements to how this handover during reset is handled)

However, common_hal_rgbmatrix_rgbmatrix_construct should NOT be called during this time. (your traceback shows it being called during the run of your code.py)

To work as a displayio display, an RGBMatrix and a FramebufferDisplay object are both required to exist and work in concert. But in your example code, an RGBMatrix object is created but a FramebufferDisplay is not. This may have been an untested case and might not work properly.