From 760a171903e0fe314b6795669893850bf46cad78 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 11 Aug 2020 09:14:13 -0500 Subject: [PATCH 01/19] nrf: Make port build with -Werror=undef .. build-tested on particle_xenon --- ports/nrf/Makefile | 16 +++++++++------- ports/nrf/common-hal/busio/SPI.c | 16 ++++++++++++++++ ports/nrf/supervisor/qspi_flash.c | 2 +- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 13a148df3b..d1745a70ef 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -73,11 +73,11 @@ INC += -I$(BUILD) INC += -I$(BUILD)/genhdr INC += -I./../../lib/cmsis/inc INC += -I./boards/$(BOARD) -INC += -I./nrfx -INC += -I./nrfx/hal -INC += -I./nrfx/mdk -INC += -I./nrfx/drivers/include -INC += -I./nrfx/drivers/src +INC += -isystem ./nrfx +INC += -isystem ./nrfx/hal +INC += -isystem ./nrfx/mdk +INC += -isystem ./nrfx/drivers/include +INC += -isystem ./nrfx/drivers/src INC += -I./bluetooth INC += -I./peripherals INC += -I../../lib/mp-readline @@ -100,8 +100,8 @@ CFLAGS += $(OPTIMIZATION_FLAGS) CFLAGS += $(INC) -Wall -Werror -std=gnu11 -nostdlib -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) # Undo some warnings. -# nrfx uses undefined preprocessor variables quite casually, so we can't do warning checks for these. -CFLAGS += -Wno-undef +## nrfx uses undefined preprocessor variables quite casually, so we can't do warning checks for these. +#CFLAGS += -Wno-undef # nrfx does casts that increase alignment requirements. CFLAGS += -Wno-cast-align @@ -240,6 +240,8 @@ endif OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) +$(addprefix $(BUILD)/, $(SRC_NRFX:.c=.o)): CFLAGS += -Wno-undef + $(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os $(filter $(PY_BUILD)/../extmod/vfs_fat_%.o, $(PY_O)): COPT += -Os diff --git a/ports/nrf/common-hal/busio/SPI.c b/ports/nrf/common-hal/busio/SPI.c index f27f0e267b..fdfe61811b 100644 --- a/ports/nrf/common-hal/busio/SPI.c +++ b/ports/nrf/common-hal/busio/SPI.c @@ -34,6 +34,22 @@ #include "nrfx_spim.h" #include "nrf_gpio.h" +#ifndef NRFX_SPIM3_ENABLED +#define NRFX_SPIM3_ENABLED (0) +#endif + +#ifndef NRFX_SPIM2_ENABLED +#define NRFX_SPIM2_ENABLED (0) +#endif + +#ifndef NRFX_SPIM1_ENABLED +#define NRFX_SPIM1_ENABLED (0) +#endif + +#ifndef NRFX_SPIM0_ENABLED +#define NRFX_SPIM0_ENABLED (0) +#endif + // These are in order from highest available frequency to lowest (32MHz first, then 8MHz). STATIC spim_peripheral_t spim_peripherals[] = { #if NRFX_CHECK(NRFX_SPIM3_ENABLED) diff --git a/ports/nrf/supervisor/qspi_flash.c b/ports/nrf/supervisor/qspi_flash.c index 5ab56c6bc4..7ca27d56c4 100644 --- a/ports/nrf/supervisor/qspi_flash.c +++ b/ports/nrf/supervisor/qspi_flash.c @@ -201,7 +201,7 @@ void spi_flash_init(void) { .irq_priority = 7, }; -#if EXTERNAL_FLASH_QSPI_DUAL +#if defined(EXTERNAL_FLASH_QSPI_DUAL) qspi_cfg.pins.io1_pin = MICROPY_QSPI_DATA1; qspi_cfg.prot_if.readoc = NRF_QSPI_READOC_READ2O; qspi_cfg.prot_if.writeoc = NRF_QSPI_WRITEOC_PP2O; From 32fc8b0676eac575a184f529aae6848f189ea71a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 11 Aug 2020 14:16:05 -0500 Subject: [PATCH 02/19] nrf: reset_pin_number: reset pin clears never-reset, mirroring samd --- ports/nrf/common-hal/microcontroller/Pin.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/nrf/common-hal/microcontroller/Pin.c b/ports/nrf/common-hal/microcontroller/Pin.c index 3132c76318..d294c1dd5d 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.c +++ b/ports/nrf/common-hal/microcontroller/Pin.c @@ -93,6 +93,7 @@ void reset_pin_number(uint8_t pin_number) { // Clear claimed bit. claimed_pins[nrf_pin_port(pin_number)] &= ~(1 << nrf_relative_pin_number(pin_number)); + never_reset_pins[nrf_pin_port(pin_number)] &= ~(1 << nrf_relative_pin_number(pin_number)); #ifdef MICROPY_HW_NEOPIXEL if (pin_number == MICROPY_HW_NEOPIXEL->number) { From ffc488e748890976fe1923c5503300f66064d904 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 31 Jul 2020 14:34:24 -0500 Subject: [PATCH 03/19] framebufferio: Fix crash calling unimplemented get_brightness If set_brightness was implemented but get_brightness wasn't, this would hard fault --- shared-module/framebufferio/FramebufferDisplay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 2a90fa0d4a..73917b1a32 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -109,7 +109,7 @@ bool common_hal_framebufferio_framebufferdisplay_set_auto_brightness(framebuffer } mp_float_t common_hal_framebufferio_framebufferdisplay_get_brightness(framebufferio_framebufferdisplay_obj_t* self) { - if (self->framebuffer_protocol->set_brightness) { + if (self->framebuffer_protocol->get_brightness) { return self->framebuffer_protocol->get_brightness(self->framebuffer); } return -1; From 5a7b2a20381513797b4e548684f8af5af46be0fa Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 31 Jul 2020 14:35:00 -0500 Subject: [PATCH 04/19] framebufferio: Don't call swapbuffers unnecessarily --- shared-module/framebufferio/FramebufferDisplay.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 73917b1a32..fed3352aa0 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -219,12 +219,14 @@ STATIC void _refresh_display(framebufferio_framebufferdisplay_obj_t* self) { displayio_display_core_start_refresh(&self->core); self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); const displayio_area_t* current_area = _get_refresh_areas(self); - while (current_area != NULL) { - _refresh_area(self, current_area); - current_area = current_area->next; + if (current_area) { + while (current_area != NULL) { + _refresh_area(self, current_area); + current_area = current_area->next; + } + self->framebuffer_protocol->swapbuffers(self->framebuffer); } displayio_display_core_finish_refresh(&self->core); - self->framebuffer_protocol->swapbuffers(self->framebuffer); } void common_hal_framebufferio_framebufferdisplay_set_rotation(framebufferio_framebufferdisplay_obj_t* self, int rotation){ From 6d19a098888236c7442e563bae90b09630fbefe2 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 31 Jul 2020 14:35:50 -0500 Subject: [PATCH 05/19] framebufferio: Set type to none when releasing This avoids the message "Too many displays in use" when they are released directly, rather than via release_displays(). --- shared-module/framebufferio/FramebufferDisplay.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index fed3352aa0..d21a103e2a 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -309,6 +309,7 @@ void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, false); release_display_core(&self->core); self->framebuffer_protocol->deinit(self->framebuffer); + self->base.type = &mp_type_NoneType; } void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { From a84cc19499e1cb71387cb5be379676d0c8b84f9a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 31 Jul 2020 15:46:07 -0500 Subject: [PATCH 06/19] framebufferio: Handle 1 (tested), 2, and 4 bpp displays --- .../framebufferio/FramebufferDisplay.c | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index d21a103e2a..b007975377 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -147,6 +147,14 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di return true; } uint16_t subrectangles = 1; + + // If pixels are packed by row then rows are on byte boundaries + if (self->core.colorspace.depth < 8 && self->core.colorspace.pixels_in_byte_share_row) { + int div = 8 / self->core.colorspace.depth; + clipped.x1 = (clipped.x1 / div) * div; + clipped.x2 = ((clipped.x2 + div - 1) / div) * div; + } + uint16_t rows_per_buffer = displayio_area_height(&clipped); uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; uint16_t pixels_per_buffer = displayio_area_size(&clipped); @@ -187,6 +195,7 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di .x2 = clipped.x2, .y2 = clipped.y1 + rows_per_buffer * (j + 1) }; + if (remaining_rows < rows_per_buffer) { subrectangle.y2 = subrectangle.y1 + remaining_rows; } @@ -197,12 +206,15 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); - // COULDDO: this arithmetic only supports multiple-of-8 bpp - uint8_t *dest = self->bufinfo.buf + (subrectangle.y1 * self->core.width + subrectangle.x1) * (self->core.colorspace.depth / 8); + uint8_t *buf = (uint8_t *)self->bufinfo.buf, *endbuf = buf + self->bufinfo.len; + (void)endbuf; // Hint to compiler that endbuf is "used" even if NDEBUG + + uint8_t *dest = self->bufinfo.buf + (subrectangle.y1 * self->core.width + subrectangle.x1) * self->core.colorspace.depth / 8; uint8_t *src = (uint8_t*)buffer; - size_t rowsize = (subrectangle.x2 - subrectangle.x1) * (self->core.colorspace.depth / 8); - size_t rowstride = self->core.width * (self->core.colorspace.depth/8); + size_t rowsize = (subrectangle.x2 - subrectangle.x1) * self->core.colorspace.depth / 8; + size_t rowstride = self->core.width * self->core.colorspace.depth/8; for (uint16_t i = subrectangle.y1; i < subrectangle.y2; i++) { + assert(dest >= buf && dest < endbuf && dest+rowsize <= endbuf); memcpy(dest, src, rowsize); dest += rowstride; src += rowsize; From 8021f3b4cbb96e0edaf139fa88ea7273c92a5493 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 31 Jul 2020 15:46:39 -0500 Subject: [PATCH 07/19] framebufferio: handle sharp memory displays A bit of cheating; we need to add a protocol getter for reverse_bytes_in_word --- shared-module/framebufferio/FramebufferDisplay.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index b007975377..190d3cb9dc 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -51,7 +51,7 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu uint16_t ram_width = 0x100; uint16_t ram_height = 0x100; - + uint16_t depth = self->framebuffer_protocol->get_color_depth(self->framebuffer); displayio_display_core_construct( &self->core, NULL, @@ -62,12 +62,13 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu 0, 0, rotation, - self->framebuffer_protocol->get_color_depth(self->framebuffer), - false, - false, + depth, + (depth < 12), // grayscale + true, // pixels_in_byte_share_row self->framebuffer_protocol->get_bytes_per_cell(self->framebuffer), - false, - false); + true, // reverse_pixels_in_byte + false // reverse_bytes_in_word + ); self->first_manual_refresh = !auto_refresh; From a33e48c065093212729e620bb22da5ca327fabe4 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 6 Aug 2020 14:28:10 -0500 Subject: [PATCH 08/19] framebufferio: add "first pixel offset" and "row stride" --- .../framebufferio/FramebufferDisplay.c | 17 ++++++++++++++--- .../framebufferio/FramebufferDisplay.h | 5 +++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 190d3cb9dc..e16777b83b 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -70,6 +70,15 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu false // reverse_bytes_in_word ); + self->first_pixel_offset = self->framebuffer_protocol->get_first_pixel_offset + ? self->framebuffer_protocol->get_first_pixel_offset(self->framebuffer) + : 0; + self->row_stride = self->framebuffer_protocol->get_row_stride + ? self->framebuffer_protocol->get_row_stride(self->framebuffer) + : 0; + if (self->row_stride == 0) { + self->row_stride = self->core.width * self->core.colorspace.depth/8; + } self->first_manual_refresh = !auto_refresh; self->native_frames_per_second = self->framebuffer_protocol->get_native_frames_per_second(self->framebuffer); @@ -209,11 +218,13 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di uint8_t *buf = (uint8_t *)self->bufinfo.buf, *endbuf = buf + self->bufinfo.len; (void)endbuf; // Hint to compiler that endbuf is "used" even if NDEBUG + buf += self->first_pixel_offset; - uint8_t *dest = self->bufinfo.buf + (subrectangle.y1 * self->core.width + subrectangle.x1) * self->core.colorspace.depth / 8; + size_t rowstride = self->row_stride; + uint8_t *dest = buf + subrectangle.y1 * rowstride + subrectangle.x1 * self->core.colorspace.depth / 8; uint8_t *src = (uint8_t*)buffer; size_t rowsize = (subrectangle.x2 - subrectangle.x1) * self->core.colorspace.depth / 8; - size_t rowstride = self->core.width * self->core.colorspace.depth/8; + for (uint16_t i = subrectangle.y1; i < subrectangle.y2; i++) { assert(dest >= buf && dest < endbuf && dest+rowsize <= endbuf); memcpy(dest, src, rowsize); @@ -230,9 +241,9 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di STATIC void _refresh_display(framebufferio_framebufferdisplay_obj_t* self) { displayio_display_core_start_refresh(&self->core); - self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); const displayio_area_t* current_area = _get_refresh_areas(self); if (current_area) { + self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); while (current_area != NULL) { _refresh_area(self, current_area); current_area = current_area->next; diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h index ca1ab984a3..1d207039ac 100644 --- a/shared-module/framebufferio/FramebufferDisplay.h +++ b/shared-module/framebufferio/FramebufferDisplay.h @@ -48,6 +48,7 @@ typedef struct { uint64_t last_refresh_call; uint16_t native_frames_per_second; uint16_t native_ms_per_frame; + uint16_t first_pixel_offset, row_stride; bool auto_refresh; bool first_manual_refresh; } framebufferio_framebufferdisplay_obj_t; @@ -70,6 +71,8 @@ typedef bool (*framebuffer_set_auto_brightness_fun)(mp_obj_t, bool); typedef bool (*framebuffer_get_auto_brightness_fun)(mp_obj_t); typedef int (*framebuffer_get_width_fun)(mp_obj_t); typedef int (*framebuffer_get_height_fun)(mp_obj_t); +typedef int (*framebuffer_get_row_stride_fun)(mp_obj_t); +typedef int (*framebuffer_get_first_pixel_offset_fun)(mp_obj_t); typedef int (*framebuffer_get_color_depth_fun)(mp_obj_t); typedef int (*framebuffer_get_bytes_per_cell_fun)(mp_obj_t); typedef int (*framebuffer_get_native_frames_per_second_fun)(mp_obj_t); @@ -86,6 +89,8 @@ typedef struct _framebuffer_p_t { framebuffer_get_native_frames_per_second_fun get_native_frames_per_second; framebuffer_get_brightness_fun get_brightness; framebuffer_set_brightness_fun set_brightness; + framebuffer_get_row_stride_fun get_row_stride; + framebuffer_get_first_pixel_offset_fun get_first_pixel_offset; framebuffer_get_auto_brightness_fun get_auto_brightness; framebuffer_set_auto_brightness_fun set_auto_brightness; } framebuffer_p_t; From 1ee2062c1b64ecfda0af49cb0f721573aad7dea4 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 6 Aug 2020 14:28:22 -0500 Subject: [PATCH 09/19] framebufferio: Check early if framebuffer is big enough --- shared-module/framebufferio/FramebufferDisplay.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index e16777b83b..230dd6991d 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -79,6 +79,13 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu if (self->row_stride == 0) { self->row_stride = self->core.width * self->core.colorspace.depth/8; } + + self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); + size_t framebuffer_size = self->first_pixel_offset + self->row_stride * self->core.height; + if (self->bufinfo.len < framebuffer_size) { + mp_raise_IndexError_varg(translate("Framebuffer requires %d bytes"), framebuffer_size); + } + self->first_manual_refresh = !auto_refresh; self->native_frames_per_second = self->framebuffer_protocol->get_native_frames_per_second(self->framebuffer); From 5e4ed9341586c3444409feeb61237e86a5c74c6f Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 6 Aug 2020 14:46:54 -0500 Subject: [PATCH 10/19] framebufferio: Add getters for remaining displayio_display_core_construct arguments .. and introduce a convenience macro that helps many of them be required (if their values match defaults or are inapplicable) --- .../framebufferio/FramebufferDisplay.c | 27 +++++----- .../framebufferio/FramebufferDisplay.h | 50 ++++++++++++------- 2 files changed, 47 insertions(+), 30 deletions(-) diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 230dd6991d..37989c29f7 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -40,6 +40,11 @@ #include #include +#define fb_getter_default(method, default_value) \ + (self->framebuffer_protocol->method \ + ? self->framebuffer_protocol->method(self->framebuffer) \ + : (default_value)) + void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebufferdisplay_obj_t* self, mp_obj_t framebuffer, uint16_t rotation, @@ -51,7 +56,7 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu uint16_t ram_width = 0x100; uint16_t ram_height = 0x100; - uint16_t depth = self->framebuffer_protocol->get_color_depth(self->framebuffer); + uint16_t depth = fb_getter_default(get_color_depth, 16); displayio_display_core_construct( &self->core, NULL, @@ -63,19 +68,15 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu 0, rotation, depth, - (depth < 12), // grayscale - true, // pixels_in_byte_share_row - self->framebuffer_protocol->get_bytes_per_cell(self->framebuffer), - true, // reverse_pixels_in_byte - false // reverse_bytes_in_word + fb_getter_default(get_grayscale, (depth < 8)), + fb_getter_default(get_pixels_in_byte_share_row, false), + fb_getter_default(get_bytes_per_cell, 2), + fb_getter_default(get_reverse_pixels_in_byte, false), + fb_getter_default(get_reverse_pixels_in_word, false) ); - self->first_pixel_offset = self->framebuffer_protocol->get_first_pixel_offset - ? self->framebuffer_protocol->get_first_pixel_offset(self->framebuffer) - : 0; - self->row_stride = self->framebuffer_protocol->get_row_stride - ? self->framebuffer_protocol->get_row_stride(self->framebuffer) - : 0; + self->first_pixel_offset = fb_getter_default(get_first_pixel_offset, 0); + self->row_stride = fb_getter_default(get_row_stride, 0); if (self->row_stride == 0) { self->row_stride = self->core.width * self->core.colorspace.depth/8; } @@ -88,7 +89,7 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu self->first_manual_refresh = !auto_refresh; - self->native_frames_per_second = self->framebuffer_protocol->get_native_frames_per_second(self->framebuffer); + self->native_frames_per_second = fb_getter_default(get_native_frames_per_second, 60); self->native_ms_per_frame = 1000 / self->native_frames_per_second; supervisor_start_terminal(self->core.width, self->core.height); diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h index 1d207039ac..93ad0118af 100644 --- a/shared-module/framebufferio/FramebufferDisplay.h +++ b/shared-module/framebufferio/FramebufferDisplay.h @@ -62,35 +62,51 @@ void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisp mp_obj_t common_hal_framebufferio_framebufferdisplay_get_framebuffer(framebufferio_framebufferdisplay_obj_t* self); +typedef bool (*framebuffer_get_auto_brightness_fun)(mp_obj_t); +typedef bool (*framebuffer_get_reverse_pixels_in_byte_fun)(mp_obj_t); +typedef bool (*framebuffer_get_reverse_pixels_in_word_fun)(mp_obj_t); +typedef bool (*framebuffer_set_auto_brightness_fun)(mp_obj_t, bool); +typedef bool (*framebuffer_set_brightness_fun)(mp_obj_t, mp_float_t); +typedef int (*framebuffer_get_bytes_per_cell_fun)(mp_obj_t); +typedef int (*framebuffer_get_color_depth_fun)(mp_obj_t); +typedef int (*framebuffer_get_first_pixel_offset_fun)(mp_obj_t); +typedef int (*framebuffer_get_grayscale_fun)(mp_obj_t); +typedef int (*framebuffer_get_height_fun)(mp_obj_t); +typedef int (*framebuffer_get_native_frames_per_second_fun)(mp_obj_t); +typedef int (*framebuffer_get_pixels_in_byte_share_row_fun)(mp_obj_t); +typedef int (*framebuffer_get_row_stride_fun)(mp_obj_t); +typedef int (*framebuffer_get_width_fun)(mp_obj_t); +typedef mp_float_t (*framebuffer_get_brightness_fun)(mp_obj_t); +typedef void (*framebuffer_deinit_fun)(mp_obj_t); typedef void (*framebuffer_get_bufinfo_fun)(mp_obj_t, mp_buffer_info_t *bufinfo); typedef void (*framebuffer_swapbuffers_fun)(mp_obj_t); -typedef void (*framebuffer_deinit_fun)(mp_obj_t); -typedef bool (*framebuffer_set_brightness_fun)(mp_obj_t, mp_float_t); -typedef mp_float_t (*framebuffer_get_brightness_fun)(mp_obj_t); -typedef bool (*framebuffer_set_auto_brightness_fun)(mp_obj_t, bool); -typedef bool (*framebuffer_get_auto_brightness_fun)(mp_obj_t); -typedef int (*framebuffer_get_width_fun)(mp_obj_t); -typedef int (*framebuffer_get_height_fun)(mp_obj_t); -typedef int (*framebuffer_get_row_stride_fun)(mp_obj_t); -typedef int (*framebuffer_get_first_pixel_offset_fun)(mp_obj_t); -typedef int (*framebuffer_get_color_depth_fun)(mp_obj_t); -typedef int (*framebuffer_get_bytes_per_cell_fun)(mp_obj_t); -typedef int (*framebuffer_get_native_frames_per_second_fun)(mp_obj_t); typedef struct _framebuffer_p_t { MP_PROTOCOL_HEAD // MP_QSTR_protocol_framebuffer + + // Mandatory framebuffer_get_bufinfo_fun get_bufinfo; framebuffer_swapbuffers_fun swapbuffers; framebuffer_deinit_fun deinit; framebuffer_get_width_fun get_width; framebuffer_get_height_fun get_height; - framebuffer_get_color_depth_fun get_color_depth; - framebuffer_get_bytes_per_cell_fun get_bytes_per_cell; - framebuffer_get_native_frames_per_second_fun get_native_frames_per_second; + + // Optional getters + framebuffer_get_bytes_per_cell_fun get_bytes_per_cell; // default: 2 + framebuffer_get_color_depth_fun get_color_depth; // default: 16 + framebuffer_get_first_pixel_offset_fun get_first_pixel_offset; // default: 0 + framebuffer_get_grayscale_fun get_grayscale; // default: grayscale if depth < 8 + framebuffer_get_native_frames_per_second_fun get_native_frames_per_second; // default: 60 + framebuffer_get_pixels_in_byte_share_row_fun get_pixels_in_byte_share_row; // default: false + framebuffer_get_reverse_pixels_in_byte_fun get_reverse_pixels_in_byte; // default: false + framebuffer_get_reverse_pixels_in_word_fun get_reverse_pixels_in_word; // default: false + framebuffer_get_row_stride_fun get_row_stride; // default: 0 (no extra row padding) + + // Optional -- default is no brightness control framebuffer_get_brightness_fun get_brightness; framebuffer_set_brightness_fun set_brightness; - framebuffer_get_row_stride_fun get_row_stride; - framebuffer_get_first_pixel_offset_fun get_first_pixel_offset; + + // Optional -- default is no automatic brightness control framebuffer_get_auto_brightness_fun get_auto_brightness; framebuffer_set_auto_brightness_fun set_auto_brightness; } framebuffer_p_t; From 9c4f644641400c7b7eea37ace73782bc1cec2691 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 6 Aug 2020 14:51:52 -0500 Subject: [PATCH 11/19] framebufferio: add dirty row tracking --- shared-bindings/rgbmatrix/RGBMatrix.c | 3 ++- shared-module/framebufferio/FramebufferDisplay.c | 10 +++++++--- shared-module/framebufferio/FramebufferDisplay.h | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/shared-bindings/rgbmatrix/RGBMatrix.c b/shared-bindings/rgbmatrix/RGBMatrix.c index d6b79f5ebb..9cfc0d4095 100644 --- a/shared-bindings/rgbmatrix/RGBMatrix.c +++ b/shared-bindings/rgbmatrix/RGBMatrix.c @@ -352,7 +352,8 @@ STATIC void rgbmatrix_rgbmatrix_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t * // These version exists so that the prototype matches the protocol, // avoiding a type cast that can hide errors -STATIC void rgbmatrix_rgbmatrix_swapbuffers(mp_obj_t self_in) { +STATIC void rgbmatrix_rgbmatrix_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) { + (void)dirty_row_bitmap; common_hal_rgbmatrix_rgbmatrix_refresh(self_in); } diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 37989c29f7..9a6797cd8c 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -156,7 +156,8 @@ STATIC const displayio_area_t* _get_refresh_areas(framebufferio_framebufferdispl return NULL; } -STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const displayio_area_t* area) { +#define MARK_ROW_DIRTY(r) (dirty_row_bitmask[r/8] = (1 << (r & 7))) +STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const displayio_area_t* area, uint8_t *dirty_row_bitmask) { uint16_t buffer_size = 128; // In uint32_ts displayio_area_t clipped; @@ -235,6 +236,7 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di for (uint16_t i = subrectangle.y1; i < subrectangle.y2; i++) { assert(dest >= buf && dest < endbuf && dest+rowsize <= endbuf); + MARK_ROW_DIRTY(i); memcpy(dest, src, rowsize); dest += rowstride; src += rowsize; @@ -251,12 +253,14 @@ STATIC void _refresh_display(framebufferio_framebufferdisplay_obj_t* self) { displayio_display_core_start_refresh(&self->core); const displayio_area_t* current_area = _get_refresh_areas(self); if (current_area) { + uint8_t dirty_row_bitmask[(self->core.height + 7) / 8]; + memset(dirty_row_bitmask, 0, sizeof(dirty_row_bitmask)); self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); while (current_area != NULL) { - _refresh_area(self, current_area); + _refresh_area(self, current_area, dirty_row_bitmask); current_area = current_area->next; } - self->framebuffer_protocol->swapbuffers(self->framebuffer); + self->framebuffer_protocol->swapbuffers(self->framebuffer, dirty_row_bitmask); } displayio_display_core_finish_refresh(&self->core); } diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h index 93ad0118af..027086b5a1 100644 --- a/shared-module/framebufferio/FramebufferDisplay.h +++ b/shared-module/framebufferio/FramebufferDisplay.h @@ -79,7 +79,7 @@ typedef int (*framebuffer_get_width_fun)(mp_obj_t); typedef mp_float_t (*framebuffer_get_brightness_fun)(mp_obj_t); typedef void (*framebuffer_deinit_fun)(mp_obj_t); typedef void (*framebuffer_get_bufinfo_fun)(mp_obj_t, mp_buffer_info_t *bufinfo); -typedef void (*framebuffer_swapbuffers_fun)(mp_obj_t); +typedef void (*framebuffer_swapbuffers_fun)(mp_obj_t, uint8_t *dirty_row_bitmask); typedef struct _framebuffer_p_t { MP_PROTOCOL_HEAD // MP_QSTR_protocol_framebuffer From c1400bae9bbdd55f650ddfe24edf6778f08c35b8 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 6 Aug 2020 16:03:31 -0500 Subject: [PATCH 12/19] sharpmemory: Implement support for Sharp Memory Displays in framebufferio --- py/circuitpy_defns.mk | 5 + py/circuitpy_mpconfig.h | 22 +- py/circuitpy_mpconfig.mk | 6 +- py/qstr.c | 1 + .../sharpdisplay/SharpMemoryFramebuffer.c | 92 ++++++ .../sharpdisplay/SharpMemoryFramebuffer.h | 34 +++ shared-bindings/sharpdisplay/__init__.c | 47 +++ shared-bindings/sharpdisplay/__init__.h | 0 shared-module/displayio/__init__.c | 33 +- shared-module/displayio/__init__.h | 10 + .../framebufferio/FramebufferDisplay.c | 21 +- .../framebufferio/FramebufferDisplay.h | 3 +- .../sharpdisplay/SharpMemoryFramebuffer.c | 282 ++++++++++++++++++ .../sharpdisplay/SharpMemoryFramebuffer.h | 60 ++++ shared-module/sharpdisplay/__init__.c | 0 shared-module/sharpdisplay/__init__.h | 0 supervisor/shared/display.c | 21 +- 17 files changed, 608 insertions(+), 29 deletions(-) create mode 100644 shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c create mode 100644 shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h create mode 100644 shared-bindings/sharpdisplay/__init__.c create mode 100644 shared-bindings/sharpdisplay/__init__.h create mode 100644 shared-module/sharpdisplay/SharpMemoryFramebuffer.c create mode 100644 shared-module/sharpdisplay/SharpMemoryFramebuffer.h create mode 100644 shared-module/sharpdisplay/__init__.c create mode 100644 shared-module/sharpdisplay/__init__.h diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index a39e0c9ddf..515b386f9e 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -222,6 +222,9 @@ endif ifeq ($(CIRCUITPY_SDIOIO),1) SRC_PATTERNS += sdioio/% endif +ifeq ($(CIRCUITPY_SHARPDISPLAY),1) +SRC_PATTERNS += sharpdisplay/% +endif ifeq ($(CIRCUITPY_STAGE),1) SRC_PATTERNS += _stage/% endif @@ -409,6 +412,8 @@ SRC_SHARED_MODULE_ALL = \ random/__init__.c \ rgbmatrix/RGBMatrix.c \ rgbmatrix/__init__.c \ + sharpdisplay/SharpMemoryFramebuffer.c \ + sharpdisplay/__init__.c \ socket/__init__.c \ storage/__init__.c \ struct/__init__.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 255ab99b93..f0e8adffa1 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -499,13 +499,6 @@ extern const struct _mp_obj_module_t pixelbuf_module; #define PIXELBUF_MODULE #endif -#if CIRCUITPY_RGBMATRIX -extern const struct _mp_obj_module_t rgbmatrix_module; -#define RGBMATRIX_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_rgbmatrix),(mp_obj_t)&rgbmatrix_module }, -#else -#define RGBMATRIX_MODULE -#endif - #if CIRCUITPY_PULSEIO extern const struct _mp_obj_module_t pulseio_module; #define PULSEIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_pulseio), (mp_obj_t)&pulseio_module }, @@ -520,6 +513,13 @@ extern const struct _mp_obj_module_t ps2io_module; #define PS2IO_MODULE #endif +#if CIRCUITPY_RGBMATRIX +extern const struct _mp_obj_module_t rgbmatrix_module; +#define RGBMATRIX_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_rgbmatrix),(mp_obj_t)&rgbmatrix_module }, +#else +#define RGBMATRIX_MODULE +#endif + #if CIRCUITPY_RANDOM extern const struct _mp_obj_module_t random_module; #define RANDOM_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&random_module }, @@ -562,6 +562,13 @@ extern const struct _mp_obj_module_t sdioio_module; #define SDIOIO_MODULE #endif +#if CIRCUITPY_SHARPDISPLAY +extern const struct _mp_obj_module_t sharpdisplay_module; +#define SHARPDISPLAY_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_sharpdisplay),(mp_obj_t)&sharpdisplay_module }, +#else +#define SHARPDISPLAY_MODULE +#endif + #if CIRCUITPY_STAGE extern const struct _mp_obj_module_t stage_module; #define STAGE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__stage), (mp_obj_t)&stage_module }, @@ -737,6 +744,7 @@ extern const struct _mp_obj_module_t watchdog_module; SAMD_MODULE \ SDCARDIO_MODULE \ SDIOIO_MODULE \ + SHARPDISPLAY_MODULE \ STAGE_MODULE \ STORAGE_MODULE \ STRUCT_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 2cf8426e5f..1ba71fa023 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -95,7 +95,7 @@ CFLAGS += -DCIRCUITPY_COUNTIO=$(CIRCUITPY_COUNTIO) CIRCUITPY_DISPLAYIO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_DISPLAYIO=$(CIRCUITPY_DISPLAYIO) -CIRCUITPY_FRAMEBUFFERIO ?= 0 +CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_FRAMEBUFFERIO=$(CIRCUITPY_FRAMEBUFFERIO) CIRCUITPY_VECTORIO ?= $(CIRCUITPY_DISPLAYIO) @@ -144,7 +144,6 @@ CFLAGS += -DCIRCUITPY_OS=$(CIRCUITPY_OS) CIRCUITPY_PIXELBUF ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_PIXELBUF=$(CIRCUITPY_PIXELBUF) -# Only for SAMD boards for the moment CIRCUITPY_RGBMATRIX ?= 0 CFLAGS += -DCIRCUITPY_RGBMATRIX=$(CIRCUITPY_RGBMATRIX) @@ -176,6 +175,9 @@ CFLAGS += -DCIRCUITPY_SDCARDIO=$(CIRCUITPY_SDCARDIO) CIRCUITPY_SDIOIO ?= 0 CFLAGS += -DCIRCUITPY_SDIOIO=$(CIRCUITPY_SDIOIO) +CIRCUITPY_SHARPDISPLAY ?= $(CIRCUITPY_FRAMEBUFFERIO) +CFLAGS += -DCIRCUITPY_SHARPDISPLAY=$(CIRCUITPY_SHARPDISPLAY) + # Currently always off. CIRCUITPY_STAGE ?= 0 CFLAGS += -DCIRCUITPY_STAGE=$(CIRCUITPY_STAGE) diff --git a/py/qstr.c b/py/qstr.c index 17d8517c93..c9ba298fb7 100755 --- a/py/qstr.c +++ b/py/qstr.c @@ -137,6 +137,7 @@ STATIC const byte *find_qstr(qstr q) { while (q < pool->total_prev_len) { pool = pool->prev; } + assert(q - pool->total_prev_len < pool->len); return pool->qstrs[q - pool->total_prev_len]; } diff --git a/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c new file mode 100644 index 0000000000..e8f4e970a2 --- /dev/null +++ b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c @@ -0,0 +1,92 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/objarray.h" +#include "py/runtime.h" + +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" + +STATIC mp_obj_t sharpdisplay_framebuffer_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_spi_bus, ARG_chip_select, ARG_width, ARG_height, ARG_baudrate, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_spi_bus, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} }, + { MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 2000000} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj); + busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi_bus].u_obj); + + sharpdisplay_framebuffer_obj_t* self = &allocate_display_bus_or_raise()->sharpdisplay; + self->base.type = &sharpdisplay_framebuffer_type; + + common_hal_sharpdisplay_framebuffer_construct(self, spi, chip_select, args[ARG_baudrate].u_int, args[ARG_width].u_int, args[ARG_height].u_int); + + return MP_OBJ_FROM_PTR(self); +} + + +STATIC mp_int_t sharpdisplay_framebuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + sharpdisplay_framebuffer_obj_t *self = (sharpdisplay_framebuffer_obj_t*)self_in; + // a readonly framebuffer would be unusual but not impossible + if ((flags & MP_BUFFER_WRITE) && !(self->bufinfo.typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) { + return 1; + } + *bufinfo = self->bufinfo; + return 0; +} + +STATIC mp_obj_t sharpdisplay_framebuffer_deinit(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = (sharpdisplay_framebuffer_obj_t*)self_in; + common_hal_sharpdisplay_framebuffer_deinit(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(sharpdisplay_framebuffer_deinit_obj, sharpdisplay_framebuffer_deinit); + +STATIC const mp_rom_map_elem_t sharpdisplay_framebuffer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sharpdisplay_framebuffer_deinit_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(sharpdisplay_framebuffer_locals_dict, sharpdisplay_framebuffer_locals_dict_table); + +const mp_obj_type_t sharpdisplay_framebuffer_type = { + { &mp_type_type }, + .name = MP_QSTR_SharpMemoryFramebuffer, + .buffer_p = { .get_buffer = sharpdisplay_framebuffer_get_buffer, }, + .make_new = sharpdisplay_framebuffer_make_new, + .protocol = &sharpdisplay_framebuffer_proto, + .locals_dict = (mp_obj_dict_t*)&sharpdisplay_framebuffer_locals_dict, +}; diff --git a/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h new file mode 100644 index 0000000000..30f1b867b1 --- /dev/null +++ b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +// #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" +// #include "shared-module/framebufferio/FramebufferDisplay.h" + +#include "py/objtype.h" + +extern const mp_obj_type_t sharpdisplay_framebuffer_type; diff --git a/shared-bindings/sharpdisplay/__init__.c b/shared-bindings/sharpdisplay/__init__.c new file mode 100644 index 0000000000..d1f728c61b --- /dev/null +++ b/shared-bindings/sharpdisplay/__init__.c @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" + +//| """Support for Sharp Memory Display framebuffers""" +//| + +STATIC const mp_rom_map_elem_t sharpdisplay_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sharpdisplay) }, + { MP_ROM_QSTR(MP_QSTR_SharpMemoryFramebuffer), MP_ROM_PTR(&sharpdisplay_framebuffer_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(sharpdisplay_module_globals, sharpdisplay_module_globals_table); + +const mp_obj_module_t sharpdisplay_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&sharpdisplay_module_globals, +}; diff --git a/shared-bindings/sharpdisplay/__init__.h b/shared-bindings/sharpdisplay/__init__.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index efc28470fb..e52ec5b9e3 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -19,14 +19,19 @@ #include "supervisor/spi_flash_api.h" #include "py/mpconfig.h" +#if CIRCUITPY_SHARPDISPLAY +#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" +#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" +#endif + primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; -#if CIRCUITPY_RGBMATRIX -STATIC bool any_display_uses_this_rgbmatrix(rgbmatrix_rgbmatrix_obj_t* pm) { +#if CIRCUITPY_RGBMATRIX || CIRCUITPY_SHARPDISPLAY +STATIC bool any_display_uses_this_framebuffer(mp_obj_base_t *obj) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - if (displays[i].framebuffer_display.base.type == &framebufferio_framebufferdisplay_type) { + if (displays[i].display_base.type == &framebufferio_framebufferdisplay_type) { framebufferio_framebufferdisplay_obj_t* display = &displays[i].framebuffer_display; - if (display->framebuffer == pm) { + if (display->framebuffer == obj) { return true; } } @@ -105,6 +110,10 @@ void common_hal_displayio_release_displays(void) { #if CIRCUITPY_FRAMEBUFFERIO } else if (bus_type == &rgbmatrix_RGBMatrix_type) { common_hal_rgbmatrix_rgbmatrix_deinit(&displays[i].rgbmatrix); +#endif +#if CIRCUITPY_SHARPDISPLAY + } else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { + common_hal_sharpdisplay_framebuffer_deinit(&displays[i].sharpdisplay); #endif } displays[i].fourwire_bus.base.type = &mp_type_NoneType; @@ -170,9 +179,18 @@ void reset_displays(void) { #if CIRCUITPY_RGBMATRIX } else if (displays[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) { rgbmatrix_rgbmatrix_obj_t * pm = &displays[i].rgbmatrix; - if(!any_display_uses_this_rgbmatrix(pm)) { + if(!any_display_uses_this_framebuffer(&pm->base)) { common_hal_rgbmatrix_rgbmatrix_deinit(pm); } +#endif +#if CIRCUITPY_SHARPDISPLAY + } else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { + sharpdisplay_framebuffer_obj_t * sharp = &displays[i].sharpdisplay; + if(any_display_uses_this_framebuffer(&sharp->base)) { + common_hal_sharpdisplay_framebuffer_reset(sharp); + } else { + common_hal_sharpdisplay_framebuffer_deinit(sharp); + } #endif } else { // Not an active display bus. @@ -203,6 +221,11 @@ void displayio_gc_collect(void) { rgbmatrix_rgbmatrix_collect_ptrs(&displays[i].rgbmatrix); } #endif +#if CIRCUITPY_SHARPDISPLAY + if (displays[i].rgbmatrix.base.type == &sharpdisplay_framebuffer_type) { + common_hal_sharpdisplay_framebuffer_collect_ptrs(&displays[i].sharpdisplay); + } +#endif if (displays[i].display.base.type == NULL) { continue; diff --git a/shared-module/displayio/__init__.h b/shared-module/displayio/__init__.h index 9eb10c28b2..44ad5a9a98 100644 --- a/shared-module/displayio/__init__.h +++ b/shared-module/displayio/__init__.h @@ -36,18 +36,28 @@ #include "shared-bindings/displayio/Group.h" #include "shared-bindings/displayio/I2CDisplay.h" #include "shared-bindings/displayio/ParallelBus.h" +#if CIRCUITPY_RGBMATRIX #include "shared-bindings/rgbmatrix/RGBMatrix.h" +#endif +#if CIRCUITPY_SHARPDISPLAY +#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" +#endif typedef struct { union { + mp_obj_base_t bus_base; displayio_fourwire_obj_t fourwire_bus; displayio_i2cdisplay_obj_t i2cdisplay_bus; displayio_parallelbus_obj_t parallel_bus; #if CIRCUITPY_RGBMATRIX rgbmatrix_rgbmatrix_obj_t rgbmatrix; +#endif +#if CIRCUITPY_SHARPDISPLAY + sharpdisplay_framebuffer_obj_t sharpdisplay; #endif }; union { + mp_obj_base_t display_base; displayio_display_obj_t display; displayio_epaperdisplay_obj_t epaper_display; #if CIRCUITPY_FRAMEBUFFERIO diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 9a6797cd8c..6b5346877c 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -156,7 +156,7 @@ STATIC const displayio_area_t* _get_refresh_areas(framebufferio_framebufferdispl return NULL; } -#define MARK_ROW_DIRTY(r) (dirty_row_bitmask[r/8] = (1 << (r & 7))) +#define MARK_ROW_DIRTY(r) (dirty_row_bitmask[r/8] |= (1 << (r & 7))) STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const displayio_area_t* area, uint8_t *dirty_row_bitmask) { uint16_t buffer_size = 128; // In uint32_ts @@ -250,6 +250,10 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di } STATIC void _refresh_display(framebufferio_framebufferdisplay_obj_t* self) { + self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); + if(!self->bufinfo.buf) { + return; + } displayio_display_core_start_refresh(&self->core); const displayio_area_t* current_area = _get_refresh_areas(self); if (current_area) { @@ -348,17 +352,18 @@ void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { self->base.type = &mp_type_NoneType; } -void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { - common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, true); - common_hal_framebufferio_framebufferdisplay_show(self, NULL); -} - void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisplay_obj_t* self) { gc_collect_ptr(self->framebuffer); displayio_display_core_collect_ptrs(&self->core); } void framebufferio_framebufferdisplay_reset(framebufferio_framebufferdisplay_obj_t* self) { - common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, true); - common_hal_framebufferio_framebufferdisplay_show(self, NULL); + mp_obj_type_t *fb_type = mp_obj_get_type(self->framebuffer); + if(fb_type != NULL && fb_type != &mp_type_NoneType) { + common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, true); + common_hal_framebufferio_framebufferdisplay_show(self, NULL); + self->core.full_refresh = true; + } else { + release_framebufferdisplay(self); + } } diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h index 027086b5a1..111c9f670d 100644 --- a/shared-module/framebufferio/FramebufferDisplay.h +++ b/shared-module/framebufferio/FramebufferDisplay.h @@ -55,7 +55,6 @@ typedef struct { void framebufferio_framebufferdisplay_background(framebufferio_framebufferdisplay_obj_t* self); void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self); -void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self); void framebufferio_framebufferdisplay_reset(framebufferio_framebufferdisplay_obj_t* self); void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisplay_obj_t* self); @@ -73,7 +72,7 @@ typedef int (*framebuffer_get_first_pixel_offset_fun)(mp_obj_t); typedef int (*framebuffer_get_grayscale_fun)(mp_obj_t); typedef int (*framebuffer_get_height_fun)(mp_obj_t); typedef int (*framebuffer_get_native_frames_per_second_fun)(mp_obj_t); -typedef int (*framebuffer_get_pixels_in_byte_share_row_fun)(mp_obj_t); +typedef bool (*framebuffer_get_pixels_in_byte_share_row_fun)(mp_obj_t); typedef int (*framebuffer_get_row_stride_fun)(mp_obj_t); typedef int (*framebuffer_get_width_fun)(mp_obj_t); typedef mp_float_t (*framebuffer_get_brightness_fun)(mp_obj_t); diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c new file mode 100644 index 0000000000..ac9c225729 --- /dev/null +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c @@ -0,0 +1,282 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/gc.h" + +#include "shared-bindings/board/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" +#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" + +#include "supervisor/memory.h" + +#define SHARPMEM_BIT_WRITECMD_LSB (0x80) +#define SHARPMEM_BIT_VCOM_LSB (0x40) + +static inline void *hybrid_alloc(size_t sz) { + if (gc_alloc_possible()) { + return m_malloc(sz + sizeof(void*), true); + } else { + supervisor_allocation *allocation = allocate_memory(align32_size(sz), false); + if (!allocation) { + return NULL; + } + memset(allocation->ptr, 0, sz); + return allocation->ptr; + } +} + +static inline void hybrid_free(void *ptr_in) { + supervisor_allocation *allocation = allocation_from_ptr(ptr_in); + + if (allocation) { + free_memory(allocation); + } +} + +STATIC uint8_t bitrev(uint8_t n) { + uint8_t r = 0; + for(int i=0;i<8;i++) r |= ((n>>i) & 1)<<(7-i); + return r; +} + +int common_hal_sharpdisplay_framebuffer_get_width(sharpdisplay_framebuffer_obj_t *self) { + return self->width; +} + +int common_hal_sharpdisplay_framebuffer_get_height(sharpdisplay_framebuffer_obj_t *self) { + return self->height; +} + +int common_hal_sharpdisplay_framebuffer_get_row_stride(sharpdisplay_framebuffer_obj_t *self) { + return (self->width + 7) / 8 + 2; +} + +int common_hal_sharpdisplay_framebuffer_get_first_pixel_offset(sharpdisplay_framebuffer_obj_t *self) { + return 2; +} + +bool common_hal_sharpdisplay_framebuffer_get_reverse_pixels_in_byte(sharpdisplay_framebuffer_obj_t *self) { + return true; +} + +bool common_hal_sharpdisplay_framebuffer_get_pixels_in_byte_share_row(sharpdisplay_framebuffer_obj_t *self) { + return true; +} + +void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *self) { + if (!allocation_from_ptr(self->bufinfo.buf)) { + self->bufinfo.buf = NULL; + } + + if (self->bus != &self->inline_bus +#if BOARD_SPI + && self->bus != common_hal_board_get_spi() +#endif + ) { + memcpy(&self->inline_bus, self->bus, sizeof(busio_spi_obj_t)); + self->bus = &self->inline_bus; + } +} + +void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self) { + +} + +void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo) { + if (!self->bufinfo.buf) { + int row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self); + int height = common_hal_sharpdisplay_framebuffer_get_height(self); + self->bufinfo.len = row_stride * height + 2; + self->bufinfo.buf = hybrid_alloc(self->bufinfo.len); + + uint8_t *data = self->bufinfo.buf; + *data++ = SHARPMEM_BIT_WRITECMD_LSB; + + for(int y=0; yfull_refresh = true; + } + *bufinfo = self->bufinfo; +} + +void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *self) { + if (self->base.type != &sharpdisplay_framebuffer_type) { + return; + } + + if (self->bus == &self->inline_bus) { + common_hal_busio_spi_deinit(self->bus); + } + + common_hal_reset_pin(self->chip_select.pin); + + hybrid_free(self->bufinfo.buf); + + memset(self, 0, sizeof(*self)); +} + +void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_t *self, busio_spi_obj_t *spi, mcu_pin_obj_t *chip_select, int baudrate, int width, int height) { + common_hal_digitalio_digitalinout_construct(&self->chip_select, chip_select); + common_hal_digitalio_digitalinout_switch_to_output(&self->chip_select, true, DRIVE_MODE_PUSH_PULL); + common_hal_never_reset_pin(chip_select); + + self->bus = spi; + common_hal_busio_spi_never_reset(self->bus); + + self->width = width; + self->height = height; + self->baudrate = baudrate; + + int row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self); + self->bufinfo.len = row_stride * height + 2; + self->bufinfo.buf = gc_alloc(self->bufinfo.len, false, true); + + uint8_t *data = self->bufinfo.buf; + *data++ = SHARPMEM_BIT_WRITECMD_LSB; + + for(int y=0; yheight; y++) { + *data = bitrev(y+1); + data += row_stride; + } + self->full_refresh = true; +} + +void common_hal_sharpdisplay_framebuffer_swapbuffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask) { + // claim SPI bus + if (!common_hal_busio_spi_try_lock(self->bus)) { + return; + } + common_hal_busio_spi_configure(self->bus, self->baudrate, 0, 0, 8); + + // set chip select high + common_hal_digitalio_digitalinout_set_value(&self->chip_select, true); + + // output the toggling signal + uint8_t *data = self->bufinfo.buf; + data[0] ^= SHARPMEM_BIT_VCOM_LSB; + +#define PARTIAL_UPDATES (1) +#if PARTIAL_UPDATES + common_hal_busio_spi_write(self->bus, data++, 1); + + // output each changed row + size_t row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self); + for(int y=0; yheight; y++) { + if(self->full_refresh || (dirty_row_bitmask[y/8] & (1 << (y & 7)))) { + common_hal_busio_spi_write(self->bus, data, row_stride); + } + data += row_stride; + } + + // output a trailing zero + common_hal_busio_spi_write(self->bus, data, 1); +#else + common_hal_busio_spi_write(self->bus, data, self->bufinfo.len); +#endif + + // set chip select low + common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); + + // release SPI bus + common_hal_busio_spi_unlock(self->bus); + + self->full_refresh = false; +} + +STATIC void sharpdisplay_framebuffer_deinit(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + common_hal_sharpdisplay_framebuffer_deinit(self); +} + +STATIC void sharpdisplay_framebuffer_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) { + sharpdisplay_framebuffer_obj_t *self = self_in; + common_hal_sharpdisplay_framebuffer_get_bufinfo(self, bufinfo); +} + +STATIC int sharpdisplay_framebuffer_get_color_depth(mp_obj_t self_in) { + return 1; +} + +STATIC int sharpdisplay_framebuffer_get_height(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + return common_hal_sharpdisplay_framebuffer_get_height(self); +} + +STATIC int sharpdisplay_framebuffer_get_width(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + return common_hal_sharpdisplay_framebuffer_get_width(self); +} + +STATIC int sharpdisplay_framebuffer_get_first_pixel_offset(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + return common_hal_sharpdisplay_framebuffer_get_first_pixel_offset(self); +} + +STATIC bool sharpdisplay_framebuffer_get_pixels_in_byte_share_row(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + return common_hal_sharpdisplay_framebuffer_get_pixels_in_byte_share_row(self); +} + +STATIC bool sharpdisplay_framebuffer_get_reverse_pixels_in_byte(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + return common_hal_sharpdisplay_framebuffer_get_reverse_pixels_in_byte(self); +} + +STATIC int sharpdisplay_framebuffer_get_row_stride(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + return common_hal_sharpdisplay_framebuffer_get_row_stride(self); +} + +STATIC void sharpdisplay_framebuffer_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmask) { + sharpdisplay_framebuffer_obj_t *self = self_in; + common_hal_sharpdisplay_framebuffer_swapbuffers(self, dirty_row_bitmask); +} + +const framebuffer_p_t sharpdisplay_framebuffer_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer) + .deinit = sharpdisplay_framebuffer_deinit, + .get_bufinfo = sharpdisplay_framebuffer_get_bufinfo, + .get_color_depth = sharpdisplay_framebuffer_get_color_depth, + .get_height = sharpdisplay_framebuffer_get_height, + .get_width = sharpdisplay_framebuffer_get_width, + .swapbuffers = sharpdisplay_framebuffer_swapbuffers, + + .get_first_pixel_offset = sharpdisplay_framebuffer_get_first_pixel_offset, + .get_pixels_in_byte_share_row = sharpdisplay_framebuffer_get_pixels_in_byte_share_row, + .get_reverse_pixels_in_byte = sharpdisplay_framebuffer_get_reverse_pixels_in_byte, + .get_row_stride = sharpdisplay_framebuffer_get_row_stride, +}; + +void common_hal_sharpdisplay_framebuffer_collect_ptrs(sharpdisplay_framebuffer_obj_t *self) { + gc_collect_ptr(self->framebuffer); + gc_collect_ptr(self->bus); + gc_collect_ptr(self->bufinfo.buf); +} diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.h b/shared-module/sharpdisplay/SharpMemoryFramebuffer.h new file mode 100644 index 0000000000..8acacc94e1 --- /dev/null +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.h @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-module/framebufferio/FramebufferDisplay.h" + +typedef struct { + mp_obj_base_t base; + mp_obj_t framebuffer; + busio_spi_obj_t* bus; + busio_spi_obj_t inline_bus; + digitalio_digitalinout_obj_t chip_select; + mp_buffer_info_t bufinfo; + + uint16_t width, height; + uint32_t baudrate; + + bool full_refresh:1; +} sharpdisplay_framebuffer_obj_t; + +void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_t *self, busio_spi_obj_t *spi, mcu_pin_obj_t *chip_select, int baudrate, int width, int height); +void common_hal_sharpdisplay_framebuffer_swap_buffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask); +void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *self); +void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo); +int common_hal_sharpdisplay_framebuffer_get_height(sharpdisplay_framebuffer_obj_t *self); +int common_hal_sharpdisplay_framebuffer_get_width(sharpdisplay_framebuffer_obj_t *self); +void common_hal_sharpdisplay_framebuffer_swap_buffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask); +void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *self); +void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self); + +extern const framebuffer_p_t sharpdisplay_framebuffer_proto; + +void common_hal_sharpdisplay_framebuffer_collect_ptrs(sharpdisplay_framebuffer_obj_t*); diff --git a/shared-module/sharpdisplay/__init__.c b/shared-module/sharpdisplay/__init__.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared-module/sharpdisplay/__init__.h b/shared-module/sharpdisplay/__init__.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index 9c074209b8..a86ef6396f 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -38,6 +38,11 @@ #include "shared-module/displayio/__init__.h" #endif +#if CIRCUITPY_SHARPDISPLAY +#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" +#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" +#endif + extern size_t blinka_bitmap_data[]; extern displayio_bitmap_t blinka_bitmap; extern displayio_group_t circuitpython_splash; @@ -116,15 +121,21 @@ void supervisor_display_move_memory(void) { grid->inline_tiles = false; } MP_STATE_VM(terminal_tilegrid_tiles) = NULL; - #if CIRCUITPY_RGBMATRIX for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - if (displays[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) { - rgbmatrix_rgbmatrix_obj_t * pm = &displays[i].rgbmatrix; + #if CIRCUITPY_RGBMATRIX + if (displays[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) { + rgbmatrix_rgbmatrix_obj_t * pm = &displays[i].rgbmatrix; common_hal_rgbmatrix_rgbmatrix_reconstruct(pm, NULL); - } + } + #endif + #if CIRCUITPY_SHARPDISPLAY + if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { + sharpdisplay_framebuffer_obj_t * sharp = &displays[i].sharpdisplay; + common_hal_sharpdisplay_framebuffer_reconstruct(sharp); + } + #endif } #endif - #endif } size_t blinka_bitmap_data[32] = { From 65f91f69ccdb3489f5ba649c939b8e3e96cc74e4 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 11 Aug 2020 15:37:10 -0500 Subject: [PATCH 13/19] make translate --- locale/circuitpython.pot | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 510facece6..32b5df5ee3 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-10 12:54-0500\n" +"POT-Creation-Date: 2020-08-11 15:37-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -823,6 +823,11 @@ msgstr "" msgid "File exists" msgstr "" +#: shared-module/framebufferio/FramebufferDisplay.c +#, c-format +msgid "Framebuffer requires %d bytes" +msgstr "" + #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c msgid "Frequency captured is above capability. Capture Paused." msgstr "" From 759ded9c38390c6d4328bd34aa211499b7e9f4f6 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 12 Aug 2020 07:39:12 -0500 Subject: [PATCH 14/19] Fix build errors when SHARPDISPLAY && !RGBMATRIX --- shared-module/displayio/__init__.c | 4 ++-- supervisor/shared/display.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index e52ec5b9e3..5afcba35ec 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -107,7 +107,7 @@ void common_hal_displayio_release_displays(void) { common_hal_displayio_i2cdisplay_deinit(&displays[i].i2cdisplay_bus); } else if (bus_type == &displayio_parallelbus_type) { common_hal_displayio_parallelbus_deinit(&displays[i].parallel_bus); -#if CIRCUITPY_FRAMEBUFFERIO +#if CIRCUITPY_RGBMATRIX } else if (bus_type == &rgbmatrix_RGBMatrix_type) { common_hal_rgbmatrix_rgbmatrix_deinit(&displays[i].rgbmatrix); #endif @@ -222,7 +222,7 @@ void displayio_gc_collect(void) { } #endif #if CIRCUITPY_SHARPDISPLAY - if (displays[i].rgbmatrix.base.type == &sharpdisplay_framebuffer_type) { + if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { common_hal_sharpdisplay_framebuffer_collect_ptrs(&displays[i].sharpdisplay); } #endif diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index a86ef6396f..08dd71404b 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -39,6 +39,7 @@ #endif #if CIRCUITPY_SHARPDISPLAY +#include "shared-module/displayio/__init__.h" #include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" #endif From cff448205f165dfd5ec40cc5b336decff045d4cd Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 12 Aug 2020 07:39:28 -0500 Subject: [PATCH 15/19] Don't define SHARPDISPLAY when !DISPLAYIO .. even if FULL_BUILD --- py/circuitpy_mpconfig.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 1ba71fa023..56060fa594 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -95,7 +95,11 @@ CFLAGS += -DCIRCUITPY_COUNTIO=$(CIRCUITPY_COUNTIO) CIRCUITPY_DISPLAYIO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_DISPLAYIO=$(CIRCUITPY_DISPLAYIO) +ifeq ($(CIRCUITPY_DISPLAYIO),1) CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_FULL_BUILD) +else +CIRCUITPY_FRAMEBUFFERIO ?= 0 +endif CFLAGS += -DCIRCUITPY_FRAMEBUFFERIO=$(CIRCUITPY_FRAMEBUFFERIO) CIRCUITPY_VECTORIO ?= $(CIRCUITPY_DISPLAYIO) From 454e616d13e6db762271b9e1ea8191407228e0ae Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 12 Aug 2020 10:46:56 -0500 Subject: [PATCH 16/19] atmel-samd: disable FRAMEBUFFERIO on samd21 .. this disables SHARPMEMORY as well. --- ports/atmel-samd/mpconfigport.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk index e4cf9ca833..5788a160b1 100644 --- a/ports/atmel-samd/mpconfigport.mk +++ b/ports/atmel-samd/mpconfigport.mk @@ -39,6 +39,9 @@ endif CIRCUITPY_SDCARDIO ?= 0 +# Not enough RAM for framebuffers +CIRCUITPY_FRAMEBUFFERIO ?= 0 + # SAMD21 needs separate endpoint pairs for MSC BULK IN and BULK OUT, otherwise it's erratic. USB_MSC_EP_NUM_OUT = 1 From d61f66d173c956b10679e83b93d7f84fbc6f0bb4 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 12 Aug 2020 12:50:08 -0500 Subject: [PATCH 17/19] Update shared-module/framebufferio/FramebufferDisplay.h Co-authored-by: Scott Shawcroft --- shared-module/framebufferio/FramebufferDisplay.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h index 111c9f670d..89df0d27c1 100644 --- a/shared-module/framebufferio/FramebufferDisplay.h +++ b/shared-module/framebufferio/FramebufferDisplay.h @@ -48,7 +48,8 @@ typedef struct { uint64_t last_refresh_call; uint16_t native_frames_per_second; uint16_t native_ms_per_frame; - uint16_t first_pixel_offset, row_stride; + uint16_t first_pixel_offset; + uint16_t row_stride; bool auto_refresh; bool first_manual_refresh; } framebufferio_framebufferdisplay_obj_t; From 06f6cd067dbf3c3f01d6f85445a190ee18e58b01 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 12 Aug 2020 12:51:35 -0500 Subject: [PATCH 18/19] nrf: Improve commenting about disabled warnings --- ports/nrf/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index d1745a70ef..3fef68e88e 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -100,8 +100,6 @@ CFLAGS += $(OPTIMIZATION_FLAGS) CFLAGS += $(INC) -Wall -Werror -std=gnu11 -nostdlib -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) # Undo some warnings. -## nrfx uses undefined preprocessor variables quite casually, so we can't do warning checks for these. -#CFLAGS += -Wno-undef # nrfx does casts that increase alignment requirements. CFLAGS += -Wno-cast-align @@ -240,6 +238,9 @@ endif OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) +# nrfx uses undefined preprocessor variables quite casually, so we can't do +# warning checks for these. Happily, we've confined the offenders to the NRFX +# source files themselves. $(addprefix $(BUILD)/, $(SRC_NRFX:.c=.o)): CFLAGS += -Wno-undef $(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os From 195c0ea986fd44f3b56cc57f23e8259df1e18202 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 12 Aug 2020 13:01:43 -0500 Subject: [PATCH 19/19] sharpdisplay: Make PARTIAL_UPDATES unconditional --- shared-module/sharpdisplay/SharpMemoryFramebuffer.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c index ac9c225729..71e00d7f01 100644 --- a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c @@ -183,8 +183,6 @@ void common_hal_sharpdisplay_framebuffer_swapbuffers(sharpdisplay_framebuffer_ob uint8_t *data = self->bufinfo.buf; data[0] ^= SHARPMEM_BIT_VCOM_LSB; -#define PARTIAL_UPDATES (1) -#if PARTIAL_UPDATES common_hal_busio_spi_write(self->bus, data++, 1); // output each changed row @@ -198,9 +196,6 @@ void common_hal_sharpdisplay_framebuffer_swapbuffers(sharpdisplay_framebuffer_ob // output a trailing zero common_hal_busio_spi_write(self->bus, data, 1); -#else - common_hal_busio_spi_write(self->bus, data, self->bufinfo.len); -#endif // set chip select low common_hal_digitalio_digitalinout_set_value(&self->chip_select, false);