Skip to content

board.SPI lost after being used by display #3581

Closed
@cwalther

Description

@cwalther

While playing around with creating and destroying displays to exercise the supervisor heap, I came across some strange behavior: When a board.SPI() object has ever been used by a FourWire or a SharpMemoryFramebuffer that has since been deinitialized, subsequent sessions can never reconstruct it, because its pins are still in use.

Steps to reproduce:

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.

Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 6.0.0-rc.0-61-g1a677406b-dirty on 2020-10-21; CWtest with samd51G19
>>> import board, displayio
>>> displayio.FourWire(board.SPI(), command=board.RX, chip_select=board.TX)
<FourWire>
>>> displayio.release_displays()
>>> 
soft reboot

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Hello World!

Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 6.0.0-rc.0-61-g1a677406b-dirty on 2020-10-21; CWtest with samd51G19
>>> import board
>>> board.SPI()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: SCK in use
>>> 

or

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.

Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 6.0.0-rc.0-61-g1a677406b-dirty on 2020-10-21; CWtest with samd51G19
>>> import board, displayio, sharpdisplay
>>> sharpdisplay.SharpMemoryFramebuffer(board.SPI(), board.RX, 400, 240)
<SharpMemoryFramebuffer>
>>> displayio.release_displays()
>>> 
soft reboot

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Hello World!

Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 6.0.0-rc.0-61-g1a677406b-dirty on 2020-10-21; CWtest with samd51G19
>>> import board
>>> board.SPI()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: SCK in use
>>> 

What happens is:

  • common_hal_displayio_fourwire_construct() and common_hal_sharpdisplay_framebuffer_construct() call common_hal_busio_spi_never_reset(self->bus).
  • release_displays() doesn’t do anything with the SPI bus.
  • When the session ends, cleanup_after_vm()reset_port()reset_all_pins() does not reset the pins because they were marked as never_reset.
  • cleanup_after_vm()reset_board_busses() sets spi_singleton = NULL; so that the next call to board.SPI() needs to recreate it, but it can’t because the pins are still in use.

I’m not sure how this is supposed to work, but there seems to be a hole in the logic somewhere. I suppose someone should call common_hal_busio_spi_deinit() at some point so that the pins are made resettable again? Maybe reset_board_busses() before it effectively leaks the resources used by the spi_singleton, but then reset_port() and reset_board_busses() come in the wrong order?

Some of the observations made by @hatchman in #3508 (comment) seem related (but probably unrelated to the actual issue of #3508, so I’m opening a new one).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions