diff --git a/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk index ce46d7000a..b23a8b76e8 100644 --- a/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk @@ -13,6 +13,8 @@ LONGINT_IMPL = MPZ CHIP_VARIANT = SAMD21G18A CHIP_FAMILY = samd21 +CFLAGS_INLINE_LIMIT = 70 + CIRCUITPY_NETWORK = 1 MICROPY_PY_WIZNET5K = 5500 diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index ee9106f778..7d6444a2d4 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -48,13 +48,15 @@ void common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_ void common_hal_displayio_display_refresh_soon(displayio_display_obj_t* self); -void displayio_display_start_region_update(displayio_display_obj_t* self, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); -void displayio_display_finish_region_update(displayio_display_obj_t* self); +bool displayio_display_begin_transaction(displayio_display_obj_t* self); +void displayio_display_end_transaction(displayio_display_obj_t* self); + +void displayio_display_set_region_to_update(displayio_display_obj_t* self, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); bool displayio_display_frame_queued(displayio_display_obj_t* self); bool displayio_display_refresh_queued(displayio_display_obj_t* self); void displayio_display_finish_refresh(displayio_display_obj_t* self); -bool displayio_display_send_pixels(displayio_display_obj_t* self, uint32_t* pixels, uint32_t length); +void displayio_display_send_pixels(displayio_display_obj_t* self, uint32_t* pixels, uint32_t length); bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self); void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness); diff --git a/shared-bindings/displayio/FourWire.c b/shared-bindings/displayio/FourWire.c index 56baa534b7..70cd427471 100644 --- a/shared-bindings/displayio/FourWire.c +++ b/shared-bindings/displayio/FourWire.c @@ -110,7 +110,12 @@ STATIC mp_obj_t displayio_fourwire_obj_send(mp_obj_t self, mp_obj_t command_obj, mp_buffer_info_t bufinfo; mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ); - common_hal_displayio_fourwire_begin_transaction(self); + // Wait for display bus to be available. + while (!common_hal_displayio_fourwire_begin_transaction(self)) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP ; +#endif + } common_hal_displayio_fourwire_send(self, true, &command, 1); common_hal_displayio_fourwire_send(self, false, ((uint8_t*) bufinfo.buf), bufinfo.len); common_hal_displayio_fourwire_end_transaction(self); diff --git a/shared-bindings/displayio/ParallelBus.c b/shared-bindings/displayio/ParallelBus.c index a54a844719..6a499ed069 100644 --- a/shared-bindings/displayio/ParallelBus.c +++ b/shared-bindings/displayio/ParallelBus.c @@ -114,7 +114,12 @@ STATIC mp_obj_t displayio_parallelbus_obj_send(mp_obj_t self, mp_obj_t command_o mp_buffer_info_t bufinfo; mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ); - common_hal_displayio_parallelbus_begin_transaction(self); + // Wait for display bus to be available. + while (!common_hal_displayio_parallelbus_begin_transaction(self)) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP ; +#endif + } common_hal_displayio_parallelbus_send(self, true, &command, 1); common_hal_displayio_parallelbus_send(self, false, ((uint8_t*) bufinfo.buf), bufinfo.len); common_hal_displayio_parallelbus_end_transaction(self); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 95c5cdfeca..0e76a868f5 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -69,7 +69,11 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->bus = bus; uint32_t i = 0; - self->begin_transaction(self->bus); + while (!self->begin_transaction(self->bus)) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP ; +#endif + } while (i < init_sequence_len) { uint8_t *cmd = init_sequence + i; uint8_t data_size = *(cmd + 1); @@ -198,9 +202,16 @@ bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, return ok; } -void displayio_display_start_region_update(displayio_display_obj_t* self, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { +bool displayio_display_begin_transaction(displayio_display_obj_t* self) { + return self->begin_transaction(self->bus); +} + +void displayio_display_end_transaction(displayio_display_obj_t* self) { + self->end_transaction(self->bus); +} + +void displayio_display_set_region_to_update(displayio_display_obj_t* self, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { // TODO(tannewt): Handle displays with single byte bounds. - self->begin_transaction(self->bus); uint16_t data[2]; self->send(self->bus, true, &self->set_column_command, 1); data[0] = __builtin_bswap16(x0 + self->colstart); @@ -213,10 +224,6 @@ void displayio_display_start_region_update(displayio_display_obj_t* self, uint16 self->send(self->bus, true, &self->write_ram_command, 1); } -void displayio_display_finish_region_update(displayio_display_obj_t* self) { - self->end_transaction(self->bus); -} - bool displayio_display_frame_queued(displayio_display_obj_t* self) { // Refresh at ~30 fps. return (ticks_ms - self->last_refresh) > 32; @@ -234,9 +241,8 @@ void displayio_display_finish_refresh(displayio_display_obj_t* self) { self->last_refresh = ticks_ms; } -bool displayio_display_send_pixels(displayio_display_obj_t* self, uint32_t* pixels, uint32_t length) { +void displayio_display_send_pixels(displayio_display_obj_t* self, uint32_t* pixels, uint32_t length) { self->send(self->bus, false, (uint8_t*) pixels, length * 4); - return true; } void displayio_display_update_backlight(displayio_display_obj_t* self) { diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 79014fb5af..546a46b1eb 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -22,7 +22,8 @@ static inline void swap(uint16_t* a, uint16_t* b) { *b = temp; } -bool refreshing_displays = false; +// Check for recursive calls to displayio_refresh_displays. +bool refresh_displays_in_progress = false; void displayio_refresh_displays(void) { if (mp_hal_is_interrupted()) { @@ -35,20 +36,25 @@ void displayio_refresh_displays(void) { return; } - if (refreshing_displays) { + if (refresh_displays_in_progress) { + // Don't allow recursive calls to this routine. return; } - refreshing_displays = true; + + refresh_displays_in_progress = true; + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { if (displays[i].display.base.type == NULL || displays[i].display.base.type == &mp_type_NoneType) { + // Skip null display. continue; } displayio_display_obj_t* display = &displays[i].display; displayio_display_update_backlight(display); + // Time to refresh at specified frame rate? if (!displayio_display_frame_queued(display)) { - refreshing_displays = false; - return; + // Too soon. Try next display. + continue; } if (displayio_display_refresh_queued(display)) { // We compute the pixels. r and c are row and column to match the display memory @@ -60,7 +66,13 @@ void displayio_refresh_displays(void) { if (display->transpose_xy) { swap(&c1, &r1); } - displayio_display_start_region_update(display, c0, r0, c1, r1); + + if (!displayio_display_begin_transaction(display)) { + // Can't acquire display bus; skip updating this display. Try next display. + continue; + } + displayio_display_set_region_to_update(display, c0, r0, c1, r1); + displayio_display_end_transaction(display); uint16_t x0 = 0; uint16_t x1 = display->width - 1; @@ -94,6 +106,8 @@ void displayio_refresh_displays(void) { size_t index = 0; uint16_t buffer_size = 256; uint32_t buffer[buffer_size / 2]; + bool skip_this_display = false; + for (uint16_t y = starty; y0 <= y && y <= y1; y += dy) { for (uint16_t x = startx; x0 <= x && x <= x1; x += dx) { uint16_t* pixel = &(((uint16_t*)buffer)[index]); @@ -110,11 +124,14 @@ void displayio_refresh_displays(void) { index += 1; // The buffer is full, send it. if (index >= buffer_size) { - if (!displayio_display_send_pixels(display, buffer, buffer_size / 2) || reload_requested) { - displayio_display_finish_region_update(display); - refreshing_displays = false; - return; + if (!displayio_display_begin_transaction(display)) { + // Can't acquire display bus; skip the rest of the data. Try next display. + index = 0; + skip_this_display = true; + break; } + displayio_display_send_pixels(display, buffer, buffer_size / 2); + displayio_display_end_transaction(display); // TODO(tannewt): Make refresh displays faster so we don't starve other // background tasks. usb_background(); @@ -122,17 +139,26 @@ void displayio_refresh_displays(void) { } } } - // Send the remaining data. - if (index && !displayio_display_send_pixels(display, buffer, index * 2)) { - displayio_display_finish_region_update(display); - refreshing_displays = false; - return; + + if (skip_this_display) { + // Go on to next display. + continue; } - displayio_display_finish_region_update(display); + // Send the remaining data. + if (index) { + if (!displayio_display_begin_transaction(display)) { + // Can't get display bus. Skip the rest of the data. Try next display. + continue; + } + displayio_display_send_pixels(display, buffer, index * 2); + } + displayio_display_end_transaction(display); } displayio_display_finish_refresh(display); } - refreshing_displays = false; + + // All done. + refresh_displays_in_progress = false; } void common_hal_displayio_release_displays(void) {