adafruit / circuitpython

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

displayio won't refresh (certain circumstances) on 3-Color il0373 EPD FeatherWing #2144

Open anecdata opened 4 years ago

anecdata commented 4 years ago

Environment: Adafruit Feather M4 Express with samd51j19 5.0.0-alpha.2 on 2019-09-04 CP Lib Bundle 20190907

The code below attempts to implement the Sprite Sheet example from: https://learn.adafruit.com/circuitpython-display-support-using-displayio/sprite-sheet ...by adapting it to the timing requirements of EPD displays (e.g., time.sleep(display.time_to_refresh))

This code works on the 2-color EPD FeatherWing (switch the True/False on the board flags below).

Can't completely characterize the failure and recovery modes here, but if your 3-coolor EPD is like mine... if you load this code onto the 3-color EPD (might need t power-cycle too), it will never refresh. Seems related to the imageload - some kind of init-deinit issue? The code runs, loops, and prints fine, just no refreshes.

You'll see two commented out blocks in the code. One tries to show/refresh to None (terminal). The other uses a solid red bitmap instead of the imageload. The only surefire way I've found to unfreeze the refreshes once it happens is to comment out the imageload, uncomment the red bitmap, and usually power-cycle).

I know this is convoluted. Hopefully it's reproducible by others, and maybe someone has some insights.

Interestingly perhaps, once the refresh is kicked back on, uncommenting the imageload code and commenting out the red bitmap, with a simple save or reload, will then allow the imageload sprites to refresh properly.

You can shorten the iterations from 180 seconds by adding the seconds_per_frame KW arg when you create the display.

This issue was moved from https://github.com/adafruit/Adafruit_CircuitPython_SSD1675/issues/2 (which has been closed).

import os
import time
import board
import terminalio
import displayio
import adafruit_imageload
from adafruit_display_text.label import Label
from adafruit_ssd1675 import SSD1675
from adafruit_il0373 import IL0373

# CicruitPython 5.0.0-alpha.2

# Feather M4 Express + choose your own EPD adventure...
ssd1675 = False  # 2C FeatherWing
il0373 = True    # 3C FeatherWing

def show_none():
    # Wait, then display default CircuitPython terminal
    time.sleep(display.time_to_refresh + 1)
    try:
        print("None    ", display.time_to_refresh)
        display.show(None)
        display.refresh()
    except RuntimeError as e:  # Refresh too soon
        print("None    ", display.time_to_refresh, e)

displayio.release_displays()
cs = board.D9
dc = board.D10

if ssd1675:
    display_bus = displayio.FourWire(board.SPI(), command=dc, chip_select=cs, baudrate=1000000)
    time.sleep(1)
    display = SSD1675(display_bus, width=250, height=122, rotation=90)
    epd_type = 'ssd1675_2C'
elif il0373:
    display_bus = displayio.FourWire(board.SPI(), command=dc, chip_select=cs, baudrate=1000000)
    time.sleep(1)
    display = IL0373(display_bus, width=212, height=104, rotation=90, highlight_color=0xff0000)
    epd_type = 'il0373_3C'

# sometimes this kicks refresh back on (sometimes power-cycle is needed too)...
# comment out the imageload to be sure
# show_none()

# Load the sprite sheet (bitmap) "/cp_sprite_sheet.bmp" (48x32) from:
# https://learn.adafruit.com/circuitpython-display-support-using-displayio/sprite-sheet
sprite_sheet, palette = adafruit_imageload.load("/cp_sprite_sheet.bmp",
                                                bitmap=displayio.Bitmap,
                                                palette=displayio.Palette)

# this usually kicks refresh back on (sometimes power-cycle is needed too)...
# comment out the imageload to be sure
# red bitmap
# prite_sheet = displayio.Bitmap(48, 32, 1)
# palette = displayio.Palette(1)
# palette[0] = 0xff0000

# Create a sprite (tilegrid)
sprite = displayio.TileGrid(sprite_sheet, pixel_shader=palette,
                            width = 1,
                            height = 1,
                            tile_width = 16,
                            tile_height = 16)

# Create a Group to hold the sprite
group = displayio.Group(scale=1)

# Add the sprite to the Group
group.append(sprite)

# Add the Group to the Display
# display.show(group)

# Set sprite location
group.x = 60  # was 120
group.y = 20  # was 80

# Loop through each sprite in the sprite sheet
source_index = 0
while True:
    sprite[0] = source_index % 6

    # Wait, then refresh display Sprite
    time.sleep(display.time_to_refresh + 1)  # +1 b/c occasional "Refresh too soon 0.001"
    try:
        print("Sprite  ", display.time_to_refresh, source_index)
        display.show(group)
        display.refresh()
    except RuntimeError as e:  # Refresh too soon
        print("Sprite  ", display.time_to_refresh, source_index, e)

    source_index += 1
anecdata commented 4 years ago

Reloading with a with open... OnDiskBitmap construct inserted early into the code (and a power cycle) also seems to kick refresh back on after it's frozen, and allow subsequent imageload to refresh properly.

with open("/display-ruler.bmp", "rb") as bitmap_file:
    g = displayio.Group(max_size=1)
    odb = displayio.OnDiskBitmap(bitmap_file)
    tg = displayio.TileGrid(odb, pixel_shader=displayio.ColorConverter())
    g.append(tg)
    try:
        time.sleep(display.time_to_refresh + 1)
        display.show(g)
        display.refresh()
        print("Ruler   ", display.time_to_refresh)
    except RuntimeError as e:  # Refresh too soon
        print("Ruler   ", display.time_to_refresh, e)
dhalbert commented 4 years ago

Hi @anecdata, could you retest on 5.0.0-alpha.4? Thanks!

anecdata commented 4 years ago

Appears to have the same quirky behavior on 5.0.0-alpha.4 on 2019-09-15 with CP Lib Bundle 20191029.

tannewt commented 1 year ago

I think this is fixed by https://github.com/adafruit/Adafruit_CircuitPython_SSD1675/pull/16

anecdata commented 1 year ago

This 3-color issue is with adafruit_il0373. The 2-color adafruit_ssd1675 was for comparison. But maybe the fix is the same?

tannewt commented 1 year ago

Ah, I didn't look close enough. I don't think the IL0373 is little endian. It is worth testing again though.