summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Shawcroft <scott@adafruit.com>2020-10-28 14:45:29 -0700
committerGitHub <noreply@github.com>2020-10-28 14:45:29 -0700
commit7cbc50962beac17f07162e75be7f041f1b11671f (patch)
treee33781989f89cc819faca2e1b6e0546fc353b9bd
parent557a58b244b19846472113fb90777303604f7f67 (diff)
parent54c0e98a37fc3c997d3a7a566a67e33d1636f46a (diff)
Merge pull request #3611 from tannewt/esp32s2_eink_portal
Add Adafruit ESP EInk Portal and grayscale EInk support
-rw-r--r--.github/workflows/build.yml1
-rw-r--r--ports/atmel-samd/boards/openbook_m4/board.c3
-rw-r--r--ports/esp32s2/boards/adafruit_esp32s2_eink_portal/board.c47
-rw-r--r--ports/esp32s2/boards/adafruit_esp32s2_eink_portal/mpconfigboard.h45
-rw-r--r--ports/esp32s2/boards/adafruit_esp32s2_eink_portal/mpconfigboard.mk17
-rw-r--r--ports/esp32s2/boards/adafruit_esp32s2_eink_portal/pins.c39
-rw-r--r--ports/esp32s2/boards/adafruit_esp32s2_eink_portal/sdkconfig33
-rw-r--r--ports/esp32s2/common-hal/busio/SPI.c3
-rw-r--r--shared-bindings/displayio/EPaperDisplay.c35
-rw-r--r--shared-bindings/displayio/EPaperDisplay.h2
-rw-r--r--shared-module/displayio/ColorConverter.c9
-rw-r--r--shared-module/displayio/EPaperDisplay.c15
-rw-r--r--shared-module/displayio/EPaperDisplay.h1
-rw-r--r--shared-module/displayio/Palette.h1
-rw-r--r--shared-module/displayio/display_core.c1
15 files changed, 235 insertions, 17 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index fa576bbf0..95bd2bfa4 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -418,6 +418,7 @@ jobs:
fail-fast: false
matrix:
board:
+ - "adafruit_esp32s2_eink_portal"
- "adafruit_metro_esp32s2"
- "electroniccats_bastwifi"
- "espressif_kaluga_1"
diff --git a/ports/atmel-samd/boards/openbook_m4/board.c b/ports/atmel-samd/boards/openbook_m4/board.c
index f0010f6d7..07dd1741a 100644
--- a/ports/atmel-samd/boards/openbook_m4/board.c
+++ b/ports/atmel-samd/boards/openbook_m4/board.c
@@ -97,7 +97,8 @@ void board_init(void) {
&pin_PA01, // busy_pin
false, // busy_state
5, // seconds_per_frame
- false); // chip_select (don't always toggle chip select)
+ false, // chip_select (don't always toggle chip select)
+ false); // grayscale
}
bool board_requests_safe_mode(void) {
diff --git a/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/board.c b/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/board.c
new file mode 100644
index 000000000..9f708874b
--- /dev/null
+++ b/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/board.c
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft 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 "boards/board.h"
+#include "mpconfigboard.h"
+#include "shared-bindings/microcontroller/Pin.h"
+
+void board_init(void) {
+ // USB
+ common_hal_never_reset_pin(&pin_GPIO19);
+ common_hal_never_reset_pin(&pin_GPIO20);
+
+ // Debug UART
+ common_hal_never_reset_pin(&pin_GPIO43);
+ common_hal_never_reset_pin(&pin_GPIO44);
+}
+
+bool board_requests_safe_mode(void) {
+ return false;
+}
+
+void reset_board(void) {
+
+}
diff --git a/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/mpconfigboard.h b/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/mpconfigboard.h
new file mode 100644
index 000000000..5a17a0cad
--- /dev/null
+++ b/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/mpconfigboard.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft 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.
+ */
+
+//Micropython setup
+
+#define MICROPY_HW_BOARD_NAME "EInk Portal"
+#define MICROPY_HW_MCU_NAME "ESP32S2"
+
+#define MICROPY_HW_NEOPIXEL (&pin_GPIO1)
+
+#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0)
+
+#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
+
+#define AUTORESET_DELAY_MS 500
+
+#define DEFAULT_I2C_BUS_SCL (&pin_GPIO34)
+#define DEFAULT_I2C_BUS_SDA (&pin_GPIO33)
+
+#define DEFAULT_SPI_BUS_SCK (&pin_GPIO36)
+#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO35)
+#define DEFAULT_SPI_BUS_MISO (&pin_GPIO37)
diff --git a/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/mpconfigboard.mk b/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/mpconfigboard.mk
new file mode 100644
index 000000000..31aff57da
--- /dev/null
+++ b/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/mpconfigboard.mk
@@ -0,0 +1,17 @@
+USB_VID = 0x239A
+USB_PID = 0x80E6
+USB_PRODUCT = "EInk Portal"
+USB_MANUFACTURER = "Adafruit"
+
+INTERNAL_FLASH_FILESYSTEM = 1
+LONGINT_IMPL = MPZ
+
+# The default queue depth of 16 overflows on release builds,
+# so increase it to 32.
+CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
+
+CIRCUITPY_ESP_FLASH_MODE=dio
+CIRCUITPY_ESP_FLASH_FREQ=40m
+CIRCUITPY_ESP_FLASH_SIZE=4MB
+
+CIRCUITPY_MODULE=wrover
diff --git a/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/pins.c b/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/pins.c
new file mode 100644
index 000000000..2cf3d2402
--- /dev/null
+++ b/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/pins.c
@@ -0,0 +1,39 @@
+#include "shared-bindings/board/__init__.h"
+
+STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) },
+ { MP_ROM_QSTR(MP_QSTR_AD1), MP_ROM_PTR(&pin_GPIO18) },
+ { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) },
+
+ { MP_ROM_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_GPIO17) },
+ { MP_ROM_QSTR(MP_QSTR_SPEAKER_ENABLE), MP_ROM_PTR(&pin_GPIO16) },
+
+ { MP_ROM_QSTR(MP_QSTR_EPD_BUSY), MP_ROM_PTR(&pin_GPIO5) },
+ { MP_ROM_QSTR(MP_QSTR_EPD_RESET), MP_ROM_PTR(&pin_GPIO6) },
+ { MP_ROM_QSTR(MP_QSTR_EPD_DC), MP_ROM_PTR(&pin_GPIO7) },
+ { MP_ROM_QSTR(MP_QSTR_EPD_CS), MP_ROM_PTR(&pin_GPIO8) },
+
+ { MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_PTR(&pin_GPIO15) },
+ { MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_PTR(&pin_GPIO14) },
+ { MP_ROM_QSTR(MP_QSTR_BUTTON_C), MP_ROM_PTR(&pin_GPIO12) },
+ { MP_ROM_QSTR(MP_QSTR_BUTTON_D), MP_ROM_PTR(&pin_GPIO11) },
+
+ { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO2) },
+ { MP_ROM_QSTR(MP_QSTR_BATTERY), MP_ROM_PTR(&pin_GPIO2) },
+
+ { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO33) },
+ { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO34) },
+
+ { MP_ROM_QSTR(MP_QSTR_CS), MP_ROM_PTR(&pin_GPIO8) },
+ { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) },
+ { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) },
+ { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) },
+
+ { MP_ROM_QSTR(MP_QSTR_NEOPIXEL_POWER), MP_ROM_PTR(&pin_GPIO21) },
+
+ { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO1) },
+
+ { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
+ { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
+};
+MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);
diff --git a/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/sdkconfig b/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/sdkconfig
new file mode 100644
index 000000000..9d8bbde96
--- /dev/null
+++ b/ports/esp32s2/boards/adafruit_esp32s2_eink_portal/sdkconfig
@@ -0,0 +1,33 @@
+CONFIG_ESP32S2_SPIRAM_SUPPORT=y
+
+#
+# SPI RAM config
+#
+# CONFIG_SPIRAM_TYPE_AUTO is not set
+CONFIG_SPIRAM_TYPE_ESPPSRAM16=y
+# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
+# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set
+CONFIG_SPIRAM_SIZE=2097152
+
+#
+# PSRAM clock and cs IO for ESP32S2
+#
+CONFIG_DEFAULT_PSRAM_CLK_IO=30
+CONFIG_DEFAULT_PSRAM_CS_IO=26
+# end of PSRAM clock and cs IO for ESP32S2
+
+# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set
+# CONFIG_SPIRAM_RODATA is not set
+# CONFIG_SPIRAM_SPEED_80M is not set
+CONFIG_SPIRAM_SPEED_40M=y
+# CONFIG_SPIRAM_SPEED_26M is not set
+# CONFIG_SPIRAM_SPEED_20M is not set
+CONFIG_SPIRAM=y
+CONFIG_SPIRAM_BOOT_INIT=y
+# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set
+CONFIG_SPIRAM_USE_MEMMAP=y
+# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
+# CONFIG_SPIRAM_USE_MALLOC is not set
+CONFIG_SPIRAM_MEMTEST=y
+# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
+# end of SPI RAM config
diff --git a/ports/esp32s2/common-hal/busio/SPI.c b/ports/esp32s2/common-hal/busio/SPI.c
index 1906ca6f0..490419f34 100644
--- a/ports/esp32s2/common-hal/busio/SPI.c
+++ b/ports/esp32s2/common-hal/busio/SPI.c
@@ -357,6 +357,9 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_ou
} else {
hal->dma_enabled = 0;
burst_length = sizeof(hal->hw->data_buf);
+ // When switching to non-DMA, we need to make sure DMA is off. Otherwise,
+ // the S2 will transmit zeroes instead of our data.
+ spi_ll_txdma_disable(hal->hw);
}
// This rounds up.
diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c
index 8be4ee4c4..e0326d9c8 100644
--- a/shared-bindings/displayio/EPaperDisplay.c
+++ b/shared-bindings/displayio/EPaperDisplay.c
@@ -49,7 +49,19 @@
//| Most people should not use this class directly. Use a specific display driver instead that will
//| contain the startup and shutdown sequences at minimum."""
//|
-//| def __init__(self, display_bus: _DisplayBus, start_sequence: ReadableBuffer, stop_sequence: ReadableBuffer, *, width: int, height: int, ram_width: int, ram_height: int, colstart: int = 0, rowstart: int = 0, rotation: int = 0, set_column_window_command: Optional[int] = None, set_row_window_command: Optional[int] = None, single_byte_bounds: bool = False, write_black_ram_command: int, black_bits_inverted: bool = False, write_color_ram_command: Optional[int] = None, color_bits_inverted: bool = False, highlight_color: int = 0x000000, refresh_display_command: int, refresh_time: float = 40, busy_pin: Optional[microcontroller.Pin] = None, busy_state: bool = True, seconds_per_frame: float = 180, always_toggle_chip_select: bool = False) -> None:
+//| def __init__(self, display_bus: _DisplayBus,
+//| start_sequence: ReadableBuffer, stop_sequence: ReadableBuffer, *,
+//| width: int, height: int, ram_width: int, ram_height: int,
+//| colstart: int = 0, rowstart: int = 0, rotation: int = 0,
+//| set_column_window_command: Optional[int] = None,
+//| set_row_window_command: Optional[int] = None, single_byte_bounds: bool = False,
+//| write_black_ram_command: int, black_bits_inverted: bool = False,
+//| write_color_ram_command: Optional[int] = None,
+//| color_bits_inverted: bool = False, highlight_color: int = 0x000000,
+//| refresh_display_command: int, refresh_time: float = 40,
+//| busy_pin: Optional[microcontroller.Pin] = None, busy_state: bool = True,
+//| seconds_per_frame: float = 180, always_toggle_chip_select: bool = False,
+//| grayscale: bool = False) -> None:
//| """Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`).
//|
//| The ``start_sequence`` and ``stop_sequence`` are bitpacked to minimize the ram impact. Every
@@ -84,11 +96,18 @@
//| :param microcontroller.Pin busy_pin: Pin used to signify the display is busy
//| :param bool busy_state: State of the busy pin when the display is busy
//| :param float seconds_per_frame: Minimum number of seconds between screen refreshes
-//| :param bool always_toggle_chip_select: When True, chip select is toggled every byte"""
+//| :param bool always_toggle_chip_select: When True, chip select is toggled every byte
+//| :param bool grayscale: When true, the color ram is the low bit of 2-bit grayscale"""
//| ...
//|
STATIC mp_obj_t displayio_epaperdisplay_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_display_bus, ARG_start_sequence, ARG_stop_sequence, ARG_width, ARG_height, ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command, ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted, ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color, ARG_refresh_display_command, ARG_refresh_time, ARG_busy_pin, ARG_busy_state, ARG_seconds_per_frame, ARG_always_toggle_chip_select };
+ enum { ARG_display_bus, ARG_start_sequence, ARG_stop_sequence, ARG_width, ARG_height,
+ ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation,
+ ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command,
+ ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted,
+ ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color,
+ ARG_refresh_display_command, ARG_refresh_time, ARG_busy_pin, ARG_busy_state,
+ ARG_seconds_per_frame, ARG_always_toggle_chip_select, ARG_grayscale };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_start_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ },
@@ -115,6 +134,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size
{ MP_QSTR_busy_state, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
{ MP_QSTR_seconds_per_frame, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(180)} },
{ MP_QSTR_always_toggle_chip_select, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -151,11 +171,14 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size
self,
display_bus,
start_bufinfo.buf, start_bufinfo.len, stop_bufinfo.buf, stop_bufinfo.len,
- args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_ram_width].u_int, args[ARG_ram_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation,
+ args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_ram_width].u_int, args[ARG_ram_height].u_int,
+ args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation,
args[ARG_set_column_window_command].u_int, args[ARG_set_row_window_command].u_int,
args[ARG_set_current_column_command].u_int, args[ARG_set_current_row_command].u_int,
- args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command, args[ARG_color_bits_inverted].u_bool, highlight_color, args[ARG_refresh_display_command].u_int, refresh_time,
- busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame, args[ARG_always_toggle_chip_select].u_bool
+ args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command,
+ args[ARG_color_bits_inverted].u_bool, highlight_color, args[ARG_refresh_display_command].u_int, refresh_time,
+ busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame,
+ args[ARG_always_toggle_chip_select].u_bool, args[ARG_grayscale].u_bool
);
return self;
diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h
index e4b81c883..352de899a 100644
--- a/shared-bindings/displayio/EPaperDisplay.h
+++ b/shared-bindings/displayio/EPaperDisplay.h
@@ -44,7 +44,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t*
uint16_t set_column_window_command, uint16_t set_row_window_command,
uint16_t set_current_column_command, uint16_t set_current_row_command,
uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, mp_float_t refresh_time,
- const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select);
+ const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select, bool grayscale);
bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self);
diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c
index dc64da03d..03ec99ceb 100644
--- a/shared-module/displayio/ColorConverter.c
+++ b/shared-module/displayio/ColorConverter.c
@@ -165,9 +165,9 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d
g8 = MIN(255,g8 + (randg&0x03));
} else {
int bitmask = 0xFF >> colorspace->depth;
- b8 = MIN(255,b8 + (randb&bitmask));
- r8 = MIN(255,r8 + (randr&bitmask));
- g8 = MIN(255,g8 + (randg&bitmask));
+ b8 = MIN(255,b8 + (randb & bitmask));
+ r8 = MIN(255,r8 + (randr & bitmask));
+ g8 = MIN(255,g8 + (randg & bitmask));
}
pixel = r8 << 16 | g8 << 8 | b8;
}
@@ -196,7 +196,8 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d
return;
} else if (colorspace->grayscale && colorspace->depth <= 8) {
uint8_t luma = displayio_colorconverter_compute_luma(pixel);
- output_color->pixel = luma >> (8 - colorspace->depth);
+ size_t bitmask = (1 << colorspace->depth) - 1;
+ output_color->pixel = (luma >> colorspace->grayscale_bit) & bitmask;
output_color->opaque = true;
return;
}
diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c
index 46c7ea82e..514b99a13 100644
--- a/shared-module/displayio/EPaperDisplay.c
+++ b/shared-module/displayio/EPaperDisplay.c
@@ -49,7 +49,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t*
uint16_t set_column_window_command, uint16_t set_row_window_command,
uint16_t set_current_column_command, uint16_t set_current_row_command,
uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, mp_float_t refresh_time,
- const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool chip_select) {
+ const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool chip_select, bool grayscale) {
if (highlight_color != 0x000000) {
self->core.colorspace.tricolor = true;
self->core.colorspace.tricolor_hue = displayio_colorconverter_compute_hue(highlight_color);
@@ -72,6 +72,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t*
self->refreshing = false;
self->milliseconds_per_frame = seconds_per_frame * 1000;
self->chip_select = chip_select ? CHIP_SELECT_TOGGLE_EVERY_BYTE : CHIP_SELECT_UNTOUCHED;
+ self->grayscale = grayscale;
self->start_sequence = start_sequence;
self->start_sequence_len = start_sequence_len;
@@ -230,17 +231,16 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c
uint32_t mask[mask_length];
uint8_t passes = 1;
- if (self->core.colorspace.tricolor) {
+ if (self->core.colorspace.tricolor || self->grayscale) {
passes = 2;
}
for (uint8_t pass = 0; pass < passes; pass++) {
uint16_t remaining_rows = displayio_area_height(&clipped);
- // added false parameter at end for SH1107_addressing quirk
if (self->set_row_window_command != NO_COMMAND) {
displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command,
self->set_row_window_command, self->set_current_column_command, self->set_current_row_command,
- false, self->chip_select, &clipped, false);
+ false, self->chip_select, &clipped, false /* SH1107_addressing */);
}
uint8_t write_command = self->write_black_ram_command;
@@ -270,8 +270,13 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c
memset(buffer, 0, buffer_size * sizeof(buffer[0]));
self->core.colorspace.grayscale = true;
+ self->core.colorspace.grayscale_bit = 7;
if (pass == 1) {
- self->core.colorspace.grayscale = false;
+ if (self->grayscale) { // 4-color grayscale
+ self->core.colorspace.grayscale_bit = 6;
+ } else { // Tri-color
+ self->core.colorspace.grayscale = false;
+ }
}
displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer);
diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h
index 3b9f6e368..4103fe5fc 100644
--- a/shared-module/displayio/EPaperDisplay.h
+++ b/shared-module/displayio/EPaperDisplay.h
@@ -55,6 +55,7 @@ typedef struct {
bool black_bits_inverted;
bool color_bits_inverted;
bool refreshing;
+ bool grayscale;
display_chip_select_behavior_t chip_select;
} displayio_epaperdisplay_obj_t;
diff --git a/shared-module/displayio/Palette.h b/shared-module/displayio/Palette.h
index da72f250f..993912cc5 100644
--- a/shared-module/displayio/Palette.h
+++ b/shared-module/displayio/Palette.h
@@ -37,6 +37,7 @@ typedef struct {
uint8_t bytes_per_cell;
uint8_t tricolor_hue;
uint8_t tricolor_luma;
+ uint8_t grayscale_bit; // The lowest grayscale bit. Normally 8 - depth.
bool grayscale;
bool tricolor;
bool pixels_in_byte_share_row;
diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c
index 411f9f373..57d33b565 100644
--- a/shared-module/displayio/display_core.c
+++ b/shared-module/displayio/display_core.c
@@ -48,6 +48,7 @@ void displayio_display_core_construct(displayio_display_core_t* self,
uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, bool reverse_bytes_in_word) {
self->colorspace.depth = color_depth;
self->colorspace.grayscale = grayscale;
+ self->colorspace.grayscale_bit = 8 - color_depth;
self->colorspace.pixels_in_byte_share_row = pixels_in_byte_share_row;
self->colorspace.bytes_per_cell = bytes_per_cell;
self->colorspace.reverse_pixels_in_byte = reverse_pixels_in_byte;