Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hard fault with Feather RP2350 + ST7789 display after resizing terminal followed by running a REPL command #10084

Open
samblenny opened this issue Feb 21, 2025 · 17 comments

Comments

@samblenny
Copy link

CircuitPython version and board name

Adafruit CircuitPython 9.2.4 on 2025-01-28; Adafruit Feather RP2350 with rp2350a

Code/REPL

from board import SPI, D5, D6                                                   
import displayio                                                                
from fourwire import FourWire                                                   
import supervisor                                                               
                                                                                
from adafruit_st7789 import ST7789                                              
                                                                                
                                                                                
# Initialize 320x240 ST7789 IPS display with terminal at 2x scale.              
# The 2x zoom makes it easier to read the display.                              
displayio.release_displays()                                                    
bus = FourWire(SPI(), chip_select=D5, command=D6)                               
display = ST7789(bus, width=320, height=240, rotation=270)                      
supervisor.reset_terminal(160, 120)                                             
zoom_2x = displayio.Group(scale=2)                                              
display.root_group = None                                                       
zoom_2x.append(displayio.CIRCUITPYTHON_TERMINAL)                                
display.root_group = zoom_2x

# To trigger the hard fault, connect to serial REPL and run a command like `1+1` or `print()`

Behavior

  1. When the board boots from a hard reset, the boot messages look normal, and I can open the REPL and get a prompt
  2. Editing a line of text at the REPL prompt works fine. But, as soon as I press Enter to run a command like 1+1, print("hello world"), or import board, the board resets. The only exception I found is if I press Enter on a blank line. In that case, I get another >>> prompt. A single space, a #, or anything else I tried would trigger a reset.
  3. Upon reconnecting to the serial terminal, it shows a hard fault message:
Auto-reload is off.
Running in safe mode! Not running saved code.

You are in safe mode because:
CircuitPython core code crashed hard. Whoops!
Hard fault: memory access or instruction error.
Please file an issue with your program at github.com/adafruit/circuitpython/issues.
Press reset to exit safe mode.

Press any key to enter the REPL. Use CTRL-D to reload.

Description

Hardware setup:

Libraries:

Notes on Reproducer Code:

  • I tried reducing the reproducer to something smaller, but all of the included lines appear to be necessary to trigger the bug.
  • If I just do a supervisor.reset_terminal(160, 120) without changing anything about the root group, the display shows 4 tiled copies of the 160, 120 terminal. But, the characters look kinda glitched. It seems possible there might be some kind of buffer overflow thing going on.

Additional information

No response

@samblenny samblenny added the bug label Feb 21, 2025
@samblenny
Copy link
Author

I get the same hard fault with these additional firmware versions:

  • adafruit-circuitpython-adafruit_feather_rp2350-en_US-9.2.1.uf2
  • adafruit-circuitpython-adafruit_feather_rp2350-en_US-9.2.2.uf2
  • adafruit-circuitpython-adafruit_feather_rp2350-en_US-9.2.3.uf2

@samblenny
Copy link
Author

Also, it's not necessary to wire up the display just to reproduce the fault:

  1. I can get the same fault on the Feather RP2350 with the display disconnected
  2. I got the same hard fault result by running the reproducer above on a Metro RP2350 with no display connected
    (Adafruit CircuitPython 9.2.4 on 2025-01-28; Adafruit Metro RP2350 with rp2350b)

@samblenny
Copy link
Author

samblenny commented Feb 21, 2025

Another data point (thanks to @ Neradoc on discord for mentioning this):

If you register a release_displays atexit, like this:

import atexit
atexit.register(displayio.release_displays)

it stops the hard fault when you use the REPL. But, if your goal was to continue using the 2x zoom after code.py ends so you can have it for the REPL (perhaps with USB keyboard), then releasing the display doesn't help.

@tannewt
Copy link
Member

tannewt commented Feb 21, 2025

The zoom_2x = displayio.Group(scale=2) object will go away when the VM does. It is VM heap allocated. It should replace this with displayio.CIRCUITPYTHON_TERMINAL but I'm not sure why.

I think you want a settings.toml setting for terminal scale.

@samblenny
Copy link
Author

The zoom_2x = displayio.Group(scale=2) object will go away when the VM does.

Yeah... I figured something might be going out of scope, but the hard fault message said to file an issue, so I did.

I think you want a settings.toml setting for terminal scale.

Is that a thing that's possible? I didn't find any mention of such things in the docs.

@samblenny
Copy link
Author

I didn't find any mention of such things in the docs.

oh... actually... I just realized that the latest vs stable Environment variable docs are different, and I was looking at stable. Will CIRCUITPY_DISPLAY_WIDTH and CIRCUITPY_DISPLAY_HEIGHT work on something that's not a picodvi display? The latest docs page implies perhaps not?

@tannewt
Copy link
Member

tannewt commented Feb 24, 2025

Is that a thing that's possible?

Not yet but you could add it.

Yeah... I figured something might be going out of scope, but the hard fault message said to file an issue, so I did.

Issue is still good. It shouldn't crash regardless.

Will CIRCUITPY_DISPLAY_WIDTH and CIRCUITPY_DISPLAY_HEIGHT work on something that's not a picodvi display?

I don't think so. It depends on the board_init's display init code.

@RetiredWizard
Copy link

@samblenny Are you planning on working up a PR on this? If not, I think I have an update in mind that would work, although I don't know if it's optimal. If you're working on something, I'll wait and see what you come up with 😁

@samblenny
Copy link
Author

I don't have any plans for a PR on this any time soon. Just stumbled across the hard fault as I was using CircuitPython to check wiring for a thing I'm doing with Zephyr. Mostly I'm focused on the Zephyr stuff.

If you've got a plan for a way to make REPL text more legible on these little high res displays, or at minimum to just stop the hard fault, that sounds great. I'm curious to see what you come up with.

@RetiredWizard
Copy link

RetiredWizard commented Feb 25, 2025

I have to clean up the PR and properly document it, but if you want to give the attached firmware a try and let me know how it works that would be cool. Add a CIRCUITPY_TERMINAL_SCALE=2 to the settings.toml file. The setting won't take effect until a hard reset or power cycle.

firmware.zip (adafruit_feather_rp2350)

@samblenny
Copy link
Author

tannewt's opinion is probably more relevant than mine. I'm not super familiar with the core implementation. Looking at the code diff in your PR though, what you've done seems plausible.

@tannewt
Copy link
Member

tannewt commented Feb 25, 2025

The PR adds the functionality you want but doesn't fix the crash. We can leave the issue open until a separate crash fix.

@SamantazFox
Copy link

SamantazFox commented Feb 26, 2025

I can confirm that I have the same crash on a M4 express CAN board when CIRCUITPYTHON_TERMINAL is in a group, so I think it's neither board- nor scale-specific.

I somewhat circumvented the problem by removing the terminal from all groups before the program ends, but it's still crashing if I do a KeyboardInterrupt from the serial console (I've tried to use try/catch, but this doesn't seem to work with async code?)

PS: this is mentionned on this adafruit learning guide, for the record

@Neradoc
Copy link

Neradoc commented Feb 26, 2025

I somewhat circumvented the problem by removing the terminal from all groups before the program ends, but it's still crashing if I do a KeyboardInterrupt from the serial console (I've tried to use try/catch, but this doesn't seem to work with async code?)

You can use the atexit module to guarantee that some code will be called when the program ends (by exception or otherwise). You would register the call right after adding the terminal to the group.

import atexit
@atexit.register
def release():
    some_group.remove(displayio.CIRCUITPYTHON_TERMINAL)

@tannewt
Copy link
Member

tannewt commented Feb 27, 2025

Would someone like to try fixing it here:

if (!circuitpython_splash.in_group) {

It should set it as the root group even if it is in a group. (Maybe force it to false.) Or we need a finalizer for all group objects that remove the children from them.

@tannewt
Copy link
Member

tannewt commented Feb 27, 2025

Note that framebuffer displays always set it:

displayio_display_core_set_root_group(&self->core, &circuitpython_splash);

@RetiredWizard
Copy link

Would someone like to try fixing it here:

I can start poking at it, but my time is spread pretty thin at the moment so it may take a while. If anyone else has an interest don't wait for me 😁

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants