From 8fa87374650d6b67af4df82442120f7f2bf24238 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 30 Jul 2019 14:23:50 -0700 Subject: [PATCH 01/18] Initial ePaper work --- shared-bindings/displayio/Display.h | 6 +- shared-bindings/displayio/EPaperDisplay.c | 370 ++++++++++++++++++++++ shared-bindings/displayio/EPaperDisplay.h | 70 ++++ 3 files changed, 443 insertions(+), 3 deletions(-) create mode 100644 shared-bindings/displayio/EPaperDisplay.c create mode 100644 shared-bindings/displayio/EPaperDisplay.h diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index e871cfc5c..8df1adc08 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_DISPLAY_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_DISPLAY_H +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_DISPLAY_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_DISPLAY_H #include "common-hal/microcontroller/Pin.h" @@ -74,4 +74,4 @@ uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self); bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness); -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_DISPLAY_H +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_DISPLAY_H diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c new file mode 100644 index 000000000..d88b4c818 --- /dev/null +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -0,0 +1,370 @@ +/* + * This file is part of the Micro Python 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. + */ + +#include "shared-bindings/displayio/Display.h" + +#include + +#include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/objtype.h" +#include "py/runtime.h" +#include "shared-bindings/displayio/Group.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: displayio +//| +//| :class:`Display` -- Manage updating a display over a display bus +//| ========================================================================== +//| +//| This initializes a display and connects it into CircuitPython. Unlike other +//| objects in CircuitPython, Display objects live until `displayio.release_displays()` +//| is called. This is done so that CircuitPython can use the display itself. +//| +//| Most people should not use this class directly. Use a specific display driver instead that will +//| contain the initialization sequence at minimum. +//| +//| .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, grayscale=False, pixels_in_byte_share_row=True, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness_command=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False) +//| +//| Create a Display object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). +//| +//| The ``init_sequence`` is bitpacked to minimize the ram impact. Every command begins with a +//| command byte followed by a byte to determine the parameter count and if a delay is need after. +//| When the top bit of the second byte is 1, the next byte will be the delay time in milliseconds. +//| The remaining 7 bits are the parameter count excluding any delay byte. The third through final +//| bytes are the remaining command parameters. The next byte will begin a new command definition. +//| Here is a portion of ILI9341 init code: +//| +//| .. code-block:: python +//| +//| init_sequence = (b"\xe1\x0f\x00\x0E\x14\x03\x11\x07\x31\xC1\x48\x08\x0F\x0C\x31\x36\x0F" # Set Gamma +//| b"\x11\x80\x78"# Exit Sleep then delay 0x78 (120ms) +//| b"\x29\x80\x78"# Display on then delay 0x78 (120ms) +//| ) +//| display = displayio.Display(display_bus, init_sequence, width=320, height=240) +//| +//| The first command is 0xe1 with 15 (0xf) parameters following. The second and third are 0x11 and +//| 0x29 respectively with delays (0x80) of 120ms (0x78) and no parameters. Multiple byte literals +//| (b"") are merged together on load. The parens are needed to allow byte literals on subsequent +//| lines. +//| +//| The initialization sequence should always leave the display memory access inline with the scan +//| of the display to minimize tearing artifacts. +//| +//| :param display_bus: The bus that the display is connected to +//| :type display_bus: displayio.FourWire or displayio.ParallelBus +//| :param buffer init_sequence: Byte-packed initialization sequence. +//| :param int width: Width in pixels +//| :param int height: Height in pixels +//| :param int colstart: The index if the first visible column +//| :param int rowstart: The index if the first visible row +//| :param int rotation: The rotation of the display in degrees clockwise. Must be in 90 degree increments (0, 90, 180, 270) +//| :param int color_depth: The number of bits of color per pixel transmitted. (Some displays +//| support 18 bit but 16 is easier to transmit. The last bit is extrapolated.) +//| :param bool grayscale: True if the display only shows a single color. +//| :param bool pixels_in_byte_share_row: True when pixels are less than a byte and a byte includes pixels from the same row of the display. When False, pixels share a column. +//| :param int set_column_command: Command used to set the start and end columns to update +//| :param int set_row_command: Command used so set the start and end rows to update +//| :param int write_ram_command: Command used to write pixels values into the update region. Ignored if data_as_commands is set. +//| :param int set_vertical_scroll: Command used to set the first row to show +//| :param microcontroller.Pin backlight_pin: Pin connected to the display's backlight +//| :param int brightness_command: Command to set display brightness. Usually available in OLED controllers. +//| :param bool brightness: Initial display brightness. This value is ignored if auto_brightness is True. +//| :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism. +//| :param bool single_byte_bounds: Display column and row commands use single bytes +//| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this. +//| +STATIC mp_obj_t displayio_display_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_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_width, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, }, + { MP_QSTR_height, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, }, + { MP_QSTR_colstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_rowstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_rotation, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_color_depth, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, + { MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_pixels_in_byte_share_row, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_set_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2a} }, + { MP_QSTR_set_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2b} }, + { MP_QSTR_write_ram_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2c} }, + { MP_QSTR_set_vertical_scroll, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x0} }, + { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_brightness_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_BRIGHTNESS_COMMAND} }, + { MP_QSTR_brightness, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, + { MP_QSTR_auto_brightness, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_single_byte_bounds, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_data_as_commands, 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); + + mp_obj_t display_bus = args[ARG_display_bus].u_obj; + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_init_sequence].u_obj, &bufinfo, MP_BUFFER_READ); + + mp_obj_t backlight_pin_obj = args[ARG_backlight_pin].u_obj; + assert_pin(backlight_pin_obj, true); + const mcu_pin_obj_t* backlight_pin = NULL; + if (backlight_pin_obj != NULL && backlight_pin_obj != mp_const_none) { + backlight_pin = MP_OBJ_TO_PTR(backlight_pin_obj); + assert_pin_free(backlight_pin); + } + + mp_float_t brightness = mp_obj_get_float(args[ARG_brightness].u_obj); + + mp_int_t rotation = args[ARG_rotation].u_int; + if (rotation % 90 != 0) { + mp_raise_ValueError(translate("Display rotation must be in 90 degree increments")); + } + + displayio_display_obj_t *self = NULL; + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + if (displays[i].display.base.type == NULL || + displays[i].display.base.type == &mp_type_NoneType) { + self = &displays[i].display; + break; + } + } + if (self == NULL) { + mp_raise_RuntimeError(translate("Too many displays")); + } + self->base.type = &displayio_display_type; + common_hal_displayio_display_construct( + self, + display_bus, args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, + args[ARG_color_depth].u_int, args[ARG_grayscale].u_bool, args[ARG_pixels_in_byte_share_row].u_bool, + args[ARG_set_column_command].u_int, args[ARG_set_row_command].u_int, + args[ARG_write_ram_command].u_int, + args[ARG_set_vertical_scroll].u_int, + bufinfo.buf, bufinfo.len, + MP_OBJ_TO_PTR(backlight_pin), + args[ARG_brightness_command].u_int, + brightness, + args[ARG_auto_brightness].u_bool, + args[ARG_single_byte_bounds].u_bool, + args[ARG_data_as_commands].u_bool + ); + + return self; +} + +// Helper to ensure we have the native super class instead of a subclass. +static displayio_display_obj_t* native_display(mp_obj_t display_obj) { + mp_obj_t native_display = mp_instance_cast_to_native_base(display_obj, &displayio_display_type); + mp_obj_assert_native_inited(native_display); + return MP_OBJ_TO_PTR(native_display); +} + +//| .. method:: show(group) +//| +//| Switches to displaying the given group of layers. When group is None, the default +//| CircuitPython terminal will be shown. +//| +//| :param Group group: The group to show. +STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) { + displayio_display_obj_t *self = native_display(self_in); + displayio_group_t* group = NULL; + if (group_in != mp_const_none) { + group = MP_OBJ_TO_PTR(native_group(group_in)); + } + + common_hal_displayio_display_show(self, group); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show); + +//| .. method:: refresh_soon() +//| +//| Queues up a display refresh that happens in the background. +//| +STATIC mp_obj_t displayio_display_obj_refresh_soon(mp_obj_t self_in) { + displayio_display_obj_t *self = native_display(self_in); + common_hal_displayio_display_refresh_soon(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_refresh_soon_obj, displayio_display_obj_refresh_soon); + +//| .. method:: wait_for_frame() +//| +//| Waits until the next frame has been transmitted to the display unless the wait count is +//| behind the rendered frames. In that case, this will return immediately with the wait count. +//| +STATIC mp_obj_t displayio_display_obj_wait_for_frame(mp_obj_t self_in) { + displayio_display_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_wait_for_frame(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_wait_for_frame_obj, displayio_display_obj_wait_for_frame); + +//| .. attribute:: brightness +//| +//| The brightness of the display as a float. 0.0 is off and 1.0 is full brightness. When +//| `auto_brightness` is True, the value of `brightness` will change automatically. +//| If `brightness` is set, `auto_brightness` will be disabled and will be set to False. +//| +STATIC mp_obj_t displayio_display_obj_get_brightness(mp_obj_t self_in) { + displayio_display_obj_t *self = native_display(self_in); + mp_float_t brightness = common_hal_displayio_display_get_brightness(self); + if (brightness < 0) { + mp_raise_RuntimeError(translate("Brightness not adjustable")); + } + return mp_obj_new_float(brightness); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_brightness_obj, displayio_display_obj_get_brightness); + +STATIC mp_obj_t displayio_display_obj_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj) { + displayio_display_obj_t *self = native_display(self_in); + common_hal_displayio_display_set_auto_brightness(self, false); + mp_float_t brightness = mp_obj_get_float(brightness_obj); + if (brightness < 0 || brightness > 1.0) { + mp_raise_ValueError(translate("Brightness must be 0-1.0")); + } + bool ok = common_hal_displayio_display_set_brightness(self, brightness); + if (!ok) { + mp_raise_RuntimeError(translate("Brightness not adjustable")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_brightness_obj, displayio_display_obj_set_brightness); + +const mp_obj_property_t displayio_display_brightness_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_display_get_brightness_obj, + (mp_obj_t)&displayio_display_set_brightness_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: auto_brightness +//| +//| True when the display brightness is adjusted automatically, based on an ambient +//| light sensor or other method. Note that some displays may have this set to True by default, +//| but not actually implement automatic brightness adjustment. `auto_brightness` is set to False +//| if `brightness` is set manually. +//| +STATIC mp_obj_t displayio_display_obj_get_auto_brightness(mp_obj_t self_in) { + displayio_display_obj_t *self = native_display(self_in); + return mp_obj_new_bool(common_hal_displayio_display_get_auto_brightness(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_auto_brightness_obj, displayio_display_obj_get_auto_brightness); + +STATIC mp_obj_t displayio_display_obj_set_auto_brightness(mp_obj_t self_in, mp_obj_t auto_brightness) { + displayio_display_obj_t *self = native_display(self_in); + + common_hal_displayio_display_set_auto_brightness(self, mp_obj_is_true(auto_brightness)); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_auto_brightness_obj, displayio_display_obj_set_auto_brightness); + +const mp_obj_property_t displayio_display_auto_brightness_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_display_get_auto_brightness_obj, + (mp_obj_t)&displayio_display_set_auto_brightness_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: width +//| +//| Gets the width of the board +//| +//| +STATIC mp_obj_t displayio_display_obj_get_width(mp_obj_t self_in) { + displayio_display_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_width(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_width_obj, displayio_display_obj_get_width); + +const mp_obj_property_t displayio_display_width_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_display_get_width_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: height +//| +//| Gets the height of the board +//| +//| +STATIC mp_obj_t displayio_display_obj_get_height(mp_obj_t self_in) { + displayio_display_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_height(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_height_obj, displayio_display_obj_get_height); + +const mp_obj_property_t displayio_display_height_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_display_get_height_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: bus +//| +//| The bus being used by the display +//| +//| +STATIC mp_obj_t displayio_display_obj_get_bus(mp_obj_t self_in) { + displayio_display_obj_t *self = native_display(self_in); + return self->bus; +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_bus_obj, displayio_display_obj_get_bus); + +const mp_obj_property_t displayio_display_bus_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_display_get_bus_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_display_show_obj) }, + { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_display_refresh_soon_obj) }, + { MP_ROM_QSTR(MP_QSTR_wait_for_frame), MP_ROM_PTR(&displayio_display_wait_for_frame_obj) }, + + { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&displayio_display_brightness_obj) }, + { MP_ROM_QSTR(MP_QSTR_auto_brightness), MP_ROM_PTR(&displayio_display_auto_brightness_obj) }, + + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_display_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_display_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_display_bus_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(displayio_display_locals_dict, displayio_display_locals_dict_table); + +const mp_obj_type_t displayio_display_type = { + { &mp_type_type }, + .name = MP_QSTR_Display, + .make_new = displayio_display_make_new, + .locals_dict = (mp_obj_dict_t*)&displayio_display_locals_dict, +}; diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h new file mode 100644 index 000000000..6ffabedee --- /dev/null +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -0,0 +1,70 @@ +/* + * This file is part of the Micro Python 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_EPAPERDISPLAY_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_EPAPERDISPLAY_H + +#include "common-hal/microcontroller/Pin.h" + +#include "shared-module/displayio/Display.h" +#include "shared-module/displayio/Group.h" + +extern const mp_obj_type_t displayio_epaperdisplay_type; + +#define DELAY 0x80 + +void common_hal_displayio_display_construct(displayio_display_obj_t* self, + mp_obj_t bus, uint16_t width, uint16_t height, uint16_t seconds_per_frame, + uint16_t rotation, uint16_t color_depth, bool grayscale, + uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* busy_pin, uint16_t partial_command); + +int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* self); + +void common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); + +void common_hal_displayio_display_refresh_soon(displayio_display_obj_t* self); + +bool displayio_display_begin_transaction(displayio_display_obj_t* self); +void displayio_display_end_transaction(displayio_display_obj_t* self); + +// The second point of the region is exclusive. +void displayio_display_set_region_to_update(displayio_display_obj_t* self, displayio_area_t* area); +bool displayio_display_frame_queued(displayio_display_obj_t* self); + +bool displayio_display_refresh_queued(displayio_display_obj_t* self); +void displayio_display_finish_refresh(displayio_display_obj_t* self); +void displayio_display_send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length); + +bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self); +void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness); + +uint16_t common_hal_displayio_display_get_width(displayio_display_obj_t* self); +uint16_t common_hal_displayio_display_get_height(displayio_display_obj_t* self); + +mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self); +bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_EPAPERDISPLAY_H From 70680d5b22aa6cb797ccf26645d553a4c72b5100 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 2 Aug 2019 16:17:38 -0700 Subject: [PATCH 02/18] EPaper displays work mostly. --- .../common-hal/displayio/ParallelBus.c | 19 +- py/circuitpy_defns.mk | 1 + shared-bindings/displayio/EPaperDisplay.c | 331 +++++------ shared-bindings/displayio/EPaperDisplay.h | 53 +- shared-bindings/displayio/FourWire.c | 26 +- shared-bindings/displayio/FourWire.h | 5 +- shared-bindings/displayio/I2CDisplay.c | 2 +- shared-bindings/displayio/I2CDisplay.h | 5 +- shared-bindings/displayio/ParallelBus.c | 4 +- shared-bindings/displayio/ParallelBus.h | 5 +- shared-bindings/displayio/__init__.c | 3 + shared-module/displayio/ColorConverter.c | 90 +++ shared-module/displayio/ColorConverter.h | 3 + shared-module/displayio/Display.c | 30 +- shared-module/displayio/Display.h | 2 +- shared-module/displayio/EPaperDisplay.c | 531 ++++++++++++++++++ shared-module/displayio/EPaperDisplay.h | 92 +++ shared-module/displayio/FourWire.c | 27 +- shared-module/displayio/Group.c | 3 + shared-module/displayio/I2CDisplay.c | 23 +- shared-module/displayio/OnDiskBitmap.c | 49 +- shared-module/displayio/Palette.c | 18 +- shared-module/displayio/Palette.h | 8 +- shared-module/displayio/TileGrid.c | 1 + shared-module/displayio/__init__.c | 91 ++- shared-module/displayio/__init__.h | 6 +- supervisor/shared/display.c | 24 +- tools/gen_display_resources.py | 6 +- 28 files changed, 1123 insertions(+), 335 deletions(-) create mode 100644 shared-module/displayio/EPaperDisplay.c create mode 100644 shared-module/displayio/EPaperDisplay.h diff --git a/ports/atmel-samd/common-hal/displayio/ParallelBus.c b/ports/atmel-samd/common-hal/displayio/ParallelBus.c index c370f7e52..a43d20511 100644 --- a/ports/atmel-samd/common-hal/displayio/ParallelBus.c +++ b/ports/atmel-samd/common-hal/displayio/ParallelBus.c @@ -84,10 +84,7 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel common_hal_digitalio_digitalinout_construct(&self->reset, reset); common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); never_reset_pin_number(reset->number); - - common_hal_digitalio_digitalinout_set_value(&self->reset, false); - common_hal_mcu_delay_us(4); - common_hal_digitalio_digitalinout_set_value(&self->reset, true); + common_hal_displayio_parallelbus_reset(self); } never_reset_pin_number(command->number); @@ -111,13 +108,25 @@ void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self) reset_pin_number(self->reset.pin->number); } +void common_hal_displayio_parallelbus_reset(mp_obj_t obj) { + displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); + + common_hal_digitalio_digitalinout_set_value(&self->reset, false); + common_hal_mcu_delay_us(4); + common_hal_digitalio_digitalinout_set_value(&self->reset, true); +} + +bool common_hal_displayio_parallelbus_bus_free(mp_obj_t obj) { + return true; +} + bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t obj) { displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); return true; } -void common_hal_displayio_parallelbus_send(mp_obj_t obj, bool command, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_parallelbus_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); common_hal_digitalio_digitalinout_set_value(&self->command, !command); uint32_t* clear_write = (uint32_t*) &self->write_group->OUTCLR.reg; diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 95939de2b..d0f0cf7dc 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -320,6 +320,7 @@ SRC_SHARED_MODULE_ALL = \ displayio/Bitmap.c \ displayio/ColorConverter.c \ displayio/Display.c \ + displayio/EPaperDisplay.c \ displayio/FourWire.c \ displayio/Group.c \ displayio/I2CDisplay.c \ diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index d88b4c818..d13d07e4a 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "shared-bindings/displayio/Display.h" +#include "shared-bindings/displayio/EPaperDisplay.h" #include @@ -41,147 +41,143 @@ //| .. currentmodule:: displayio //| -//| :class:`Display` -- Manage updating a display over a display bus +//| :class:`EPaperDisplay` -- Manage updating an epaper display over a display bus //| ========================================================================== //| -//| This initializes a display and connects it into CircuitPython. Unlike other -//| objects in CircuitPython, Display objects live until `displayio.release_displays()` +//| This initializes an epaper display and connects it into CircuitPython. Unlike other +//| objects in CircuitPython, EPaperDisplay objects live until `displayio.release_displays()` //| is called. This is done so that CircuitPython can use the display itself. //| //| Most people should not use this class directly. Use a specific display driver instead that will -//| contain the initialization sequence at minimum. +//| contain the startup and shutdown sequences at minimum. //| -//| .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, grayscale=False, pixels_in_byte_share_row=True, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness_command=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False) +//| .. class:: EPaperDisplay(display_bus, start_sequence, stop_sequence, *, width, height, ram_width, ram_height, colstart=0, rowstart=0, rotation=0, set_column_window_command=None, set_row_window_command=None, single_byte_bounds=False, write_black_ram_command, black_bits_inverted=False, write_color_ram_command=None, color_bits_inverted=False, refresh_display_command, busy_pin=None, busy_state=True, seconds_per_frame=180, always_toggle_chip_select=False) //| -//| Create a Display object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). +//| Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| -//| The ``init_sequence`` is bitpacked to minimize the ram impact. Every command begins with a -//| command byte followed by a byte to determine the parameter count and if a delay is need after. -//| When the top bit of the second byte is 1, the next byte will be the delay time in milliseconds. -//| The remaining 7 bits are the parameter count excluding any delay byte. The third through final -//| bytes are the remaining command parameters. The next byte will begin a new command definition. -//| Here is a portion of ILI9341 init code: -//| -//| .. code-block:: python -//| -//| init_sequence = (b"\xe1\x0f\x00\x0E\x14\x03\x11\x07\x31\xC1\x48\x08\x0F\x0C\x31\x36\x0F" # Set Gamma -//| b"\x11\x80\x78"# Exit Sleep then delay 0x78 (120ms) -//| b"\x29\x80\x78"# Display on then delay 0x78 (120ms) -//| ) -//| display = displayio.Display(display_bus, init_sequence, width=320, height=240) -//| -//| The first command is 0xe1 with 15 (0xf) parameters following. The second and third are 0x11 and -//| 0x29 respectively with delays (0x80) of 120ms (0x78) and no parameters. Multiple byte literals -//| (b"") are merged together on load. The parens are needed to allow byte literals on subsequent -//| lines. -//| -//| The initialization sequence should always leave the display memory access inline with the scan -//| of the display to minimize tearing artifacts. +//| The ``start_sequence`` and ``stop_sequence`` bitpacked to minimize the ram impact. Every +//| command begins with a command byte followed by a byte to determine the parameter count and if +//| a delay is need after. When the top bit of the second byte is 1, the next byte will be the +//| delay time in milliseconds. The remaining 7 bits are the parameter count excluding any delay +//| byte. The third through final bytes are the remaining command parameters. The next byte will +//| begin a new command definition. //| //| :param display_bus: The bus that the display is connected to //| :type display_bus: displayio.FourWire or displayio.ParallelBus -//| :param buffer init_sequence: Byte-packed initialization sequence. +//| :param buffer start_sequence: Byte-packed initialization sequence. +//| :param buffer stop_sequence: Byte-packed initialization sequence. //| :param int width: Width in pixels //| :param int height: Height in pixels +//| :param int ram_width: RAM width in pixels +//| :param int ram_height: RAM height in pixels //| :param int colstart: The index if the first visible column //| :param int rowstart: The index if the first visible row //| :param int rotation: The rotation of the display in degrees clockwise. Must be in 90 degree increments (0, 90, 180, 270) -//| :param int color_depth: The number of bits of color per pixel transmitted. (Some displays -//| support 18 bit but 16 is easier to transmit. The last bit is extrapolated.) -//| :param bool grayscale: True if the display only shows a single color. -//| :param bool pixels_in_byte_share_row: True when pixels are less than a byte and a byte includes pixels from the same row of the display. When False, pixels share a column. -//| :param int set_column_command: Command used to set the start and end columns to update -//| :param int set_row_command: Command used so set the start and end rows to update -//| :param int write_ram_command: Command used to write pixels values into the update region. Ignored if data_as_commands is set. -//| :param int set_vertical_scroll: Command used to set the first row to show -//| :param microcontroller.Pin backlight_pin: Pin connected to the display's backlight -//| :param int brightness_command: Command to set display brightness. Usually available in OLED controllers. -//| :param bool brightness: Initial display brightness. This value is ignored if auto_brightness is True. -//| :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism. -//| :param bool single_byte_bounds: Display column and row commands use single bytes -//| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this. +//| :param int set_column_window_command: Command used to set the start and end columns to update +//| :param int set_row_window_command: Command used so set the start and end rows to update +//| :param int set_current_column_command: Command used to set the current column location +//| :param int set_current_row_command: Command used to set the current row location +//| :param int write_black_ram_command: Command used to write pixels values into the update region +//| :param bool black_bits_inverted: True if 0 bits are used to show black pixels. Otherwise, 1 means to show black. +//| :param int write_color_ram_command: Command used to write pixels values into the update region +//| :param bool color_bits_inverted: True if 0 bits are used to show the color. Otherwise, 1 means to show color. +//| :param int third_color: Color of third ePaper color in RGB888. +//| :param int refresh_display_command: Command used to start a display refresh +//| :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 int seconds_per_frame: Minimum number of seconds between screen refreshes +//| :param bool always_toggle_chip_select: When True, chip select is toggled every byte //| -STATIC mp_obj_t displayio_display_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_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands }; +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_third_color, ARG_refresh_display_command, ARG_busy_pin, ARG_busy_state, ARG_seconds_per_frame, ARG_always_toggle_chip_select }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_start_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_stop_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_width, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, }, { MP_QSTR_height, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, }, + { MP_QSTR_ram_width, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, }, + { MP_QSTR_ram_height, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, }, { MP_QSTR_colstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_rowstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_rotation, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, - { MP_QSTR_color_depth, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, - { MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - { MP_QSTR_pixels_in_byte_share_row, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, - { MP_QSTR_set_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2a} }, - { MP_QSTR_set_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2b} }, - { MP_QSTR_write_ram_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2c} }, - { MP_QSTR_set_vertical_scroll, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x0} }, - { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, - { MP_QSTR_brightness_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_BRIGHTNESS_COMMAND} }, - { MP_QSTR_brightness, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, - { MP_QSTR_auto_brightness, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - { MP_QSTR_single_byte_bounds, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - { MP_QSTR_data_as_commands, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_set_column_window_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} }, + { MP_QSTR_set_row_window_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} }, + { MP_QSTR_set_current_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} }, + { MP_QSTR_set_current_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} }, + { MP_QSTR_write_black_ram_command, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_black_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_write_color_ram_command, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_color_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_third_color, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x000000} }, + { MP_QSTR_refresh_display_command, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_busy_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { 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_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); mp_obj_t display_bus = args[ARG_display_bus].u_obj; - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_init_sequence].u_obj, &bufinfo, MP_BUFFER_READ); + mp_buffer_info_t start_bufinfo; + mp_get_buffer_raise(args[ARG_start_sequence].u_obj, &start_bufinfo, MP_BUFFER_READ); + mp_buffer_info_t stop_bufinfo; + mp_get_buffer_raise(args[ARG_stop_sequence].u_obj, &stop_bufinfo, MP_BUFFER_READ); - mp_obj_t backlight_pin_obj = args[ARG_backlight_pin].u_obj; - assert_pin(backlight_pin_obj, true); - const mcu_pin_obj_t* backlight_pin = NULL; - if (backlight_pin_obj != NULL && backlight_pin_obj != mp_const_none) { - backlight_pin = MP_OBJ_TO_PTR(backlight_pin_obj); - assert_pin_free(backlight_pin); - } - mp_float_t brightness = mp_obj_get_float(args[ARG_brightness].u_obj); + mp_obj_t busy_pin_obj = args[ARG_busy_pin].u_obj; + assert_pin(busy_pin_obj, true); + const mcu_pin_obj_t* busy_pin = NULL; + if (busy_pin_obj != NULL && busy_pin_obj != mp_const_none) { + busy_pin = MP_OBJ_TO_PTR(busy_pin_obj); + assert_pin_free(busy_pin); + } mp_int_t rotation = args[ARG_rotation].u_int; if (rotation % 90 != 0) { mp_raise_ValueError(translate("Display rotation must be in 90 degree increments")); } - displayio_display_obj_t *self = NULL; + displayio_epaperdisplay_obj_t *self = NULL; for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { if (displays[i].display.base.type == NULL || displays[i].display.base.type == &mp_type_NoneType) { - self = &displays[i].display; + self = &displays[i].epaper_display; break; } } if (self == NULL) { mp_raise_RuntimeError(translate("Too many displays")); } - self->base.type = &displayio_display_type; - common_hal_displayio_display_construct( + + mp_float_t seconds_per_frame = mp_obj_get_float(args[ARG_seconds_per_frame].u_obj); + + mp_int_t write_color_ram_command = NO_COMMAND; + mp_int_t third_color = args[ARG_third_color].u_int; + if (args[ARG_write_color_ram_command].u_obj != mp_const_none) { + write_color_ram_command = mp_obj_get_int(args[ARG_write_color_ram_command].u_obj); + } + + self->base.type = &displayio_epaperdisplay_type; + common_hal_displayio_epaperdisplay_construct( self, - display_bus, args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, - args[ARG_color_depth].u_int, args[ARG_grayscale].u_bool, args[ARG_pixels_in_byte_share_row].u_bool, - args[ARG_set_column_command].u_int, args[ARG_set_row_command].u_int, - args[ARG_write_ram_command].u_int, - args[ARG_set_vertical_scroll].u_int, - bufinfo.buf, bufinfo.len, - MP_OBJ_TO_PTR(backlight_pin), - args[ARG_brightness_command].u_int, - brightness, - args[ARG_auto_brightness].u_bool, - args[ARG_single_byte_bounds].u_bool, - args[ARG_data_as_commands].u_bool + 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_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, third_color, args[ARG_refresh_display_command].u_int, + busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame, args[ARG_always_toggle_chip_select].u_bool ); return self; } // Helper to ensure we have the native super class instead of a subclass. -static displayio_display_obj_t* native_display(mp_obj_t display_obj) { - mp_obj_t native_display = mp_instance_cast_to_native_base(display_obj, &displayio_display_type); +static displayio_epaperdisplay_obj_t* native_display(mp_obj_t display_obj) { + mp_obj_t native_display = mp_instance_cast_to_native_base(display_obj, &displayio_epaperdisplay_type); mp_obj_assert_native_inited(native_display); return MP_OBJ_TO_PTR(native_display); } @@ -192,139 +188,75 @@ static displayio_display_obj_t* native_display(mp_obj_t display_obj) { //| CircuitPython terminal will be shown. //| //| :param Group group: The group to show. -STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) { - displayio_display_obj_t *self = native_display(self_in); +STATIC mp_obj_t displayio_epaperdisplay_obj_show(mp_obj_t self_in, mp_obj_t group_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); displayio_group_t* group = NULL; if (group_in != mp_const_none) { group = MP_OBJ_TO_PTR(native_group(group_in)); } - common_hal_displayio_display_show(self, group); + bool ok = common_hal_displayio_epaperdisplay_show(self, group); + if (!ok) { + mp_raise_ValueError(translate("Group already used")); + } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show); +MP_DEFINE_CONST_FUN_OBJ_2(displayio_epaperdisplay_show_obj, displayio_epaperdisplay_obj_show); //| .. method:: refresh_soon() //| //| Queues up a display refresh that happens in the background. //| -STATIC mp_obj_t displayio_display_obj_refresh_soon(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - common_hal_displayio_display_refresh_soon(self); +STATIC mp_obj_t displayio_epaperdisplay_obj_refresh_soon(mp_obj_t self_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); + common_hal_displayio_epaperdisplay_refresh_soon(self); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_refresh_soon_obj, displayio_display_obj_refresh_soon); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_refresh_soon_obj, displayio_epaperdisplay_obj_refresh_soon); //| .. method:: wait_for_frame() //| //| Waits until the next frame has been transmitted to the display unless the wait count is //| behind the rendered frames. In that case, this will return immediately with the wait count. //| -STATIC mp_obj_t displayio_display_obj_wait_for_frame(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_wait_for_frame(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_wait_for_frame_obj, displayio_display_obj_wait_for_frame); - -//| .. attribute:: brightness -//| -//| The brightness of the display as a float. 0.0 is off and 1.0 is full brightness. When -//| `auto_brightness` is True, the value of `brightness` will change automatically. -//| If `brightness` is set, `auto_brightness` will be disabled and will be set to False. -//| -STATIC mp_obj_t displayio_display_obj_get_brightness(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - mp_float_t brightness = common_hal_displayio_display_get_brightness(self); - if (brightness < 0) { - mp_raise_RuntimeError(translate("Brightness not adjustable")); - } - return mp_obj_new_float(brightness); +STATIC mp_obj_t displayio_epaperdisplay_obj_wait_for_frame(mp_obj_t self_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_wait_for_frame(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_brightness_obj, displayio_display_obj_get_brightness); - -STATIC mp_obj_t displayio_display_obj_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj) { - displayio_display_obj_t *self = native_display(self_in); - common_hal_displayio_display_set_auto_brightness(self, false); - mp_float_t brightness = mp_obj_get_float(brightness_obj); - if (brightness < 0 || brightness > 1.0) { - mp_raise_ValueError(translate("Brightness must be 0-1.0")); - } - bool ok = common_hal_displayio_display_set_brightness(self, brightness); - if (!ok) { - mp_raise_RuntimeError(translate("Brightness not adjustable")); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_brightness_obj, displayio_display_obj_set_brightness); - -const mp_obj_property_t displayio_display_brightness_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&displayio_display_get_brightness_obj, - (mp_obj_t)&displayio_display_set_brightness_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: auto_brightness -//| -//| True when the display brightness is adjusted automatically, based on an ambient -//| light sensor or other method. Note that some displays may have this set to True by default, -//| but not actually implement automatic brightness adjustment. `auto_brightness` is set to False -//| if `brightness` is set manually. -//| -STATIC mp_obj_t displayio_display_obj_get_auto_brightness(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - return mp_obj_new_bool(common_hal_displayio_display_get_auto_brightness(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_auto_brightness_obj, displayio_display_obj_get_auto_brightness); - -STATIC mp_obj_t displayio_display_obj_set_auto_brightness(mp_obj_t self_in, mp_obj_t auto_brightness) { - displayio_display_obj_t *self = native_display(self_in); - - common_hal_displayio_display_set_auto_brightness(self, mp_obj_is_true(auto_brightness)); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_auto_brightness_obj, displayio_display_obj_set_auto_brightness); - -const mp_obj_property_t displayio_display_auto_brightness_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&displayio_display_get_auto_brightness_obj, - (mp_obj_t)&displayio_display_set_auto_brightness_obj, - (mp_obj_t)&mp_const_none_obj}, -}; +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_wait_for_frame_obj, displayio_epaperdisplay_obj_wait_for_frame); //| .. attribute:: width //| -//| Gets the width of the board +//| Gets the width of the display in pixels //| //| -STATIC mp_obj_t displayio_display_obj_get_width(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_width(self)); +STATIC mp_obj_t displayio_epaperdisplay_obj_get_width(mp_obj_t self_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_get_width(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_width_obj, displayio_display_obj_get_width); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_width_obj, displayio_epaperdisplay_obj_get_width); -const mp_obj_property_t displayio_display_width_obj = { +const mp_obj_property_t displayio_epaperdisplay_width_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&displayio_display_get_width_obj, + .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_width_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj}, }; //| .. attribute:: height //| -//| Gets the height of the board +//| Gets the height of the display in pixels //| //| -STATIC mp_obj_t displayio_display_obj_get_height(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_height(self)); +STATIC mp_obj_t displayio_epaperdisplay_obj_get_height(mp_obj_t self_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_get_height(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_height_obj, displayio_display_obj_get_height); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_height_obj, displayio_epaperdisplay_obj_get_height); -const mp_obj_property_t displayio_display_height_obj = { +const mp_obj_property_t displayio_epaperdisplay_height_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&displayio_display_get_height_obj, + .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_height_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj}, }; @@ -334,37 +266,34 @@ const mp_obj_property_t displayio_display_height_obj = { //| The bus being used by the display //| //| -STATIC mp_obj_t displayio_display_obj_get_bus(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); +STATIC mp_obj_t displayio_epaperdisplay_obj_get_bus(mp_obj_t self_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); return self->bus; } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_bus_obj, displayio_display_obj_get_bus); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_bus_obj, displayio_epaperdisplay_obj_get_bus); -const mp_obj_property_t displayio_display_bus_obj = { +const mp_obj_property_t displayio_epaperdisplay_bus_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&displayio_display_get_bus_obj, + .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_bus_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj}, }; -STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_display_show_obj) }, - { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_display_refresh_soon_obj) }, - { MP_ROM_QSTR(MP_QSTR_wait_for_frame), MP_ROM_PTR(&displayio_display_wait_for_frame_obj) }, - - { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&displayio_display_brightness_obj) }, - { MP_ROM_QSTR(MP_QSTR_auto_brightness), MP_ROM_PTR(&displayio_display_auto_brightness_obj) }, +STATIC const mp_rom_map_elem_t displayio_epaperdisplay_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_epaperdisplay_show_obj) }, + { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_epaperdisplay_refresh_soon_obj) }, + { MP_ROM_QSTR(MP_QSTR_wait_for_frame), MP_ROM_PTR(&displayio_epaperdisplay_wait_for_frame_obj) }, - { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_display_width_obj) }, - { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_display_height_obj) }, - { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_display_bus_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_epaperdisplay_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_epaperdisplay_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_epaperdisplay_bus_obj) }, }; -STATIC MP_DEFINE_CONST_DICT(displayio_display_locals_dict, displayio_display_locals_dict_table); +STATIC MP_DEFINE_CONST_DICT(displayio_epaperdisplay_locals_dict, displayio_epaperdisplay_locals_dict_table); -const mp_obj_type_t displayio_display_type = { +const mp_obj_type_t displayio_epaperdisplay_type = { { &mp_type_type }, - .name = MP_QSTR_Display, - .make_new = displayio_display_make_new, - .locals_dict = (mp_obj_dict_t*)&displayio_display_locals_dict, + .name = MP_QSTR_EPaperDisplay, + .make_new = displayio_epaperdisplay_make_new, + .locals_dict = (mp_obj_dict_t*)&displayio_epaperdisplay_locals_dict, }; diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index 6ffabedee..3deeef959 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -24,47 +24,52 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_EPAPERDISPLAY_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_EPAPERDISPLAY_H +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H #include "common-hal/microcontroller/Pin.h" -#include "shared-module/displayio/Display.h" +#include "shared-module/displayio/EPaperDisplay.h" #include "shared-module/displayio/Group.h" extern const mp_obj_type_t displayio_epaperdisplay_type; #define DELAY 0x80 -void common_hal_displayio_display_construct(displayio_display_obj_t* self, - mp_obj_t bus, uint16_t width, uint16_t height, uint16_t seconds_per_frame, - uint16_t rotation, uint16_t color_depth, bool grayscale, - uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* busy_pin, uint16_t partial_command); +#define NO_COMMAND 0x100 -int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* self); +void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self, + mp_obj_t bus, uint8_t* start_sequence, uint16_t start_sequence_len, uint8_t* stop_sequence, uint16_t stop_sequence_len, + uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, + 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 third_color, uint16_t refresh_display_command, + const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select); -void common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); +int32_t common_hal_displayio_epaperdisplay_wait_for_frame(displayio_epaperdisplay_obj_t* self); -void common_hal_displayio_display_refresh_soon(displayio_display_obj_t* self); +bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self, displayio_group_t* root_group); -bool displayio_display_begin_transaction(displayio_display_obj_t* self); -void displayio_display_end_transaction(displayio_display_obj_t* self); +void common_hal_displayio_epaperdisplay_refresh_soon(displayio_epaperdisplay_obj_t* self); + +bool displayio_epaperdisplay_begin_transaction(displayio_epaperdisplay_obj_t* self); +void displayio_epaperdisplay_end_transaction(displayio_epaperdisplay_obj_t* self); // The second point of the region is exclusive. -void displayio_display_set_region_to_update(displayio_display_obj_t* self, displayio_area_t* area); -bool displayio_display_frame_queued(displayio_display_obj_t* self); +void displayio_epaperdisplay_set_region_to_update(displayio_epaperdisplay_obj_t* self, displayio_area_t* area); +bool displayio_epaperdisplay_frame_queued(displayio_epaperdisplay_obj_t* self); -bool displayio_display_refresh_queued(displayio_display_obj_t* self); -void displayio_display_finish_refresh(displayio_display_obj_t* self); -void displayio_display_send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length); +bool displayio_epaperdisplay_refresh_queued(displayio_epaperdisplay_obj_t* self); +void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self); +void displayio_epaperdisplay_send_pixels(displayio_epaperdisplay_obj_t* self, uint8_t* pixels, uint32_t length); -bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self); -void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness); +bool common_hal_displayio_epaperdisplay_get_auto_brightness(displayio_epaperdisplay_obj_t* self); +void common_hal_displayio_epaperdisplay_set_auto_brightness(displayio_epaperdisplay_obj_t* self, bool auto_brightness); -uint16_t common_hal_displayio_display_get_width(displayio_display_obj_t* self); -uint16_t common_hal_displayio_display_get_height(displayio_display_obj_t* self); +uint16_t common_hal_displayio_epaperdisplay_get_width(displayio_epaperdisplay_obj_t* self); +uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_obj_t* self); -mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self); -bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness); +mp_float_t common_hal_displayio_epaperdisplay_get_brightness(displayio_epaperdisplay_obj_t* self); +bool common_hal_displayio_epaperdisplay_set_brightness(displayio_epaperdisplay_obj_t* self, mp_float_t brightness); -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_EPAPERDISPLAY_H +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H diff --git a/shared-bindings/displayio/FourWire.c b/shared-bindings/displayio/FourWire.c index 0d41359ee..efd553e2e 100644 --- a/shared-bindings/displayio/FourWire.c +++ b/shared-bindings/displayio/FourWire.c @@ -103,31 +103,41 @@ STATIC mp_obj_t displayio_fourwire_make_new(const mp_obj_type_t *type, size_t n_ return self; } -//| .. method:: send(command, data) +//| .. method:: send(command, data, *, toggle_every_byte=False) //| //| Sends the given command value followed by the full set of data. Display state, such as //| vertical scroll, set via ``send`` may or may not be reset once the code is done. //| -STATIC mp_obj_t displayio_fourwire_obj_send(mp_obj_t self, mp_obj_t command_obj, mp_obj_t data_obj) { - mp_int_t command_int = MP_OBJ_SMALL_INT_VALUE(command_obj); - if (!MP_OBJ_IS_SMALL_INT(command_obj) || command_int > 255 || command_int < 0) { +STATIC mp_obj_t displayio_fourwire_obj_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_command, ARG_data, ARG_toggle_every_byte }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_command, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_toggle_every_byte, 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 - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t command_int = args[ARG_command].u_int; + if (command_int > 255 || command_int < 0) { mp_raise_ValueError(translate("Command must be an int between 0 and 255")); } + displayio_fourwire_obj_t *self = pos_args[0]; uint8_t command = command_int; mp_buffer_info_t bufinfo; - mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ); + mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ); // Wait for display bus to be available. while (!common_hal_displayio_fourwire_begin_transaction(self)) { RUN_BACKGROUND_TASKS; } - common_hal_displayio_fourwire_send(self, true, &command, 1); - common_hal_displayio_fourwire_send(self, false, ((uint8_t*) bufinfo.buf), bufinfo.len); + common_hal_displayio_fourwire_send(self, true, args[ARG_toggle_every_byte].u_bool, &command, 1); + common_hal_displayio_fourwire_send(self, false, args[ARG_toggle_every_byte].u_bool, ((uint8_t*) bufinfo.buf), bufinfo.len); common_hal_displayio_fourwire_end_transaction(self); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_3(displayio_fourwire_send_obj, displayio_fourwire_obj_send); +MP_DEFINE_CONST_FUN_OBJ_KW(displayio_fourwire_send_obj, 3, displayio_fourwire_obj_send); STATIC const mp_rom_map_elem_t displayio_fourwire_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_fourwire_send_obj) }, diff --git a/shared-bindings/displayio/FourWire.h b/shared-bindings/displayio/FourWire.h index 5dbd60764..ee69a63ac 100644 --- a/shared-bindings/displayio/FourWire.h +++ b/shared-bindings/displayio/FourWire.h @@ -40,9 +40,12 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self, void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self); +void common_hal_displayio_fourwire_reset(mp_obj_t self); +bool common_hal_displayio_fourwire_bus_free(mp_obj_t self); + bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t self); -void common_hal_displayio_fourwire_send(mp_obj_t self, bool command, uint8_t *data, uint32_t data_length); +void common_hal_displayio_fourwire_send(mp_obj_t self, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); void common_hal_displayio_fourwire_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c index 9ef989d71..4428e8dbb 100644 --- a/shared-bindings/displayio/I2CDisplay.c +++ b/shared-bindings/displayio/I2CDisplay.c @@ -116,7 +116,7 @@ STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_ob uint8_t full_command[bufinfo.len + 1]; full_command[0] = command; memcpy(full_command + 1, ((uint8_t*) bufinfo.buf), bufinfo.len); - common_hal_displayio_i2cdisplay_send(self, true, full_command, bufinfo.len + 1); + common_hal_displayio_i2cdisplay_send(self, true, false, full_command, bufinfo.len + 1); common_hal_displayio_i2cdisplay_end_transaction(self); return mp_const_none; diff --git a/shared-bindings/displayio/I2CDisplay.h b/shared-bindings/displayio/I2CDisplay.h index cc4162800..6a75fc488 100644 --- a/shared-bindings/displayio/I2CDisplay.h +++ b/shared-bindings/displayio/I2CDisplay.h @@ -37,9 +37,12 @@ void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self, void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self); +void common_hal_displayio_i2cdisplay_reset(mp_obj_t self); +bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t self); + bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t self); -void common_hal_displayio_i2cdisplay_send(mp_obj_t self, bool command, uint8_t *data, uint32_t data_length); +void common_hal_displayio_i2cdisplay_send(mp_obj_t self, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); void common_hal_displayio_i2cdisplay_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/ParallelBus.c b/shared-bindings/displayio/ParallelBus.c index c29c79fff..e260f9b7e 100644 --- a/shared-bindings/displayio/ParallelBus.c +++ b/shared-bindings/displayio/ParallelBus.c @@ -124,8 +124,8 @@ STATIC mp_obj_t displayio_parallelbus_obj_send(mp_obj_t self, mp_obj_t command_o while (!common_hal_displayio_parallelbus_begin_transaction(self)) { RUN_BACKGROUND_TASKS; } - common_hal_displayio_parallelbus_send(self, true, &command, 1); - common_hal_displayio_parallelbus_send(self, false, ((uint8_t*) bufinfo.buf), bufinfo.len); + common_hal_displayio_parallelbus_send(self, true, false, &command, 1); + common_hal_displayio_parallelbus_send(self, false, false, ((uint8_t*) bufinfo.buf), bufinfo.len); common_hal_displayio_parallelbus_end_transaction(self); return mp_const_none; diff --git a/shared-bindings/displayio/ParallelBus.h b/shared-bindings/displayio/ParallelBus.h index c4cde5ff5..b8da91041 100644 --- a/shared-bindings/displayio/ParallelBus.h +++ b/shared-bindings/displayio/ParallelBus.h @@ -40,9 +40,12 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self); +void common_hal_displayio_parallelbus_reset(mp_obj_t self); +bool common_hal_displayio_parallelbus_bus_free(mp_obj_t self); + bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t self); -void common_hal_displayio_parallelbus_send(mp_obj_t self, bool command, uint8_t *data, uint32_t data_length); +void common_hal_displayio_parallelbus_send(mp_obj_t self, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); void common_hal_displayio_parallelbus_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/__init__.c b/shared-bindings/displayio/__init__.c index fd3dc4233..8c5d1f228 100644 --- a/shared-bindings/displayio/__init__.c +++ b/shared-bindings/displayio/__init__.c @@ -33,6 +33,7 @@ #include "shared-bindings/displayio/Bitmap.h" #include "shared-bindings/displayio/ColorConverter.h" #include "shared-bindings/displayio/Display.h" +#include "shared-bindings/displayio/EPaperDisplay.h" #include "shared-bindings/displayio/FourWire.h" #include "shared-bindings/displayio/Group.h" #include "shared-bindings/displayio/I2CDisplay.h" @@ -60,6 +61,7 @@ //| Bitmap //| ColorConverter //| Display +//| EPaperDisplay //| FourWire //| Group //| I2CDisplay @@ -91,6 +93,7 @@ STATIC const mp_rom_map_elem_t displayio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Bitmap), MP_ROM_PTR(&displayio_bitmap_type) }, { MP_ROM_QSTR(MP_QSTR_ColorConverter), MP_ROM_PTR(&displayio_colorconverter_type) }, { MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&displayio_display_type) }, + { MP_ROM_QSTR(MP_QSTR_EPaperDisplay), MP_ROM_PTR(&displayio_epaperdisplay_type) }, { MP_ROM_QSTR(MP_QSTR_Group), MP_ROM_PTR(&displayio_group_type) }, { MP_ROM_QSTR(MP_QSTR_OnDiskBitmap), MP_ROM_PTR(&displayio_ondiskbitmap_type) }, { MP_ROM_QSTR(MP_QSTR_Palette), MP_ROM_PTR(&displayio_palette_type) }, diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 6b9bd5840..0277c79f0 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -45,14 +45,104 @@ uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888) { return (r8 * 19) / 255 + (g8 * 182) / 255 + (b8 + 54) / 255; } +void compute_bounds(uint8_t r8, uint8_t g8, uint8_t b8, uint8_t* min, uint8_t* max) { + if (r8 > g8) { + if (b8 > r8) { + *max = b8; + } else { + *max = r8; + } + if (b8 < g8) { + *min = b8; + } else { + *min = g8; + } + } else { + if (b8 > g8) { + *max = b8; + } else { + *max = g8; + } + if (b8 < r8) { + *min = b8; + } else { + *min = r8; + } + } +} + +uint8_t displayio_colorconverter_compute_chroma(uint32_t color_rgb888) { + uint32_t r8 = (color_rgb888 >> 16); + uint32_t g8 = (color_rgb888 >> 8) & 0xff; + uint32_t b8 = color_rgb888 & 0xff; + uint8_t max; + uint8_t min; + compute_bounds(r8, g8, b8, &min, &max); + return max - min; +} + +uint8_t displayio_colorconverter_compute_hue(uint32_t color_rgb888) { + uint32_t r8 = (color_rgb888 >> 16); + uint32_t g8 = (color_rgb888 >> 8) & 0xff; + uint32_t b8 = color_rgb888 & 0xff; + uint8_t max; + uint8_t min; + compute_bounds(r8, g8, b8, &min, &max); + uint8_t c = max - min; + if (c == 0) { + return 0; + } + + int32_t hue = 0; + if (max == r8) { + hue = (((int32_t) (g8 - b8) * 40) / c) % 240; + } else if (max == g8) { + hue = (((int32_t) (b8 - r8) + (2 * c)) * 40) / c; + } else if (max == b8) { + hue = (((int32_t) (r8 - g8) + (4 * c)) * 40) / c; + } + if (hue < 0) { + hue += 240; + } + + return hue; +} + +void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t* colorspace, uint8_t pixel_hue, uint8_t pixel_luma, uint32_t* color) { + + int16_t hue_diff = colorspace->tricolor_hue - pixel_hue; + if ((-10 <= hue_diff && hue_diff <= 10) || hue_diff <= -220 || hue_diff >= 220) { + if (colorspace->grayscale) { + *color = 0; + } else { + *color = 1; + } + } else if (!colorspace->grayscale) { + *color = 0; + } +} + bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color) { if (colorspace->depth == 16) { *output_color = displayio_colorconverter_compute_rgb565(input_color); return true; + } else if (colorspace->tricolor) { + uint8_t luma = displayio_colorconverter_compute_luma(input_color); + *output_color = luma >> (8 - colorspace->depth); + if (displayio_colorconverter_compute_chroma(input_color) <= 16) { + if (!colorspace->grayscale) { + *output_color = 0; + } + return true; + } + uint8_t pixel_hue = displayio_colorconverter_compute_hue(input_color); + displayio_colorconverter_compute_tricolor(colorspace, pixel_hue, luma, output_color); + return true; } else if (colorspace->grayscale && colorspace->depth <= 8) { uint8_t luma = displayio_colorconverter_compute_luma(input_color); *output_color = luma >> (8 - colorspace->depth); return true; + } else if (!colorspace->grayscale && colorspace->depth == 1) { } return false; } diff --git a/shared-module/displayio/ColorConverter.h b/shared-module/displayio/ColorConverter.h index c48b98e6d..c79e6a2f7 100644 --- a/shared-module/displayio/ColorConverter.h +++ b/shared-module/displayio/ColorConverter.h @@ -42,5 +42,8 @@ void displayio_colorconverter_finish_refresh(displayio_colorconverter_t *self); bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color); uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888); uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888); +uint8_t displayio_colorconverter_compute_chroma(uint32_t color_rgb888); +uint8_t displayio_colorconverter_compute_hue(uint32_t color_rgb888); +void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t* colorspace, uint8_t pixel_hue, uint8_t pixel_luma, uint32_t* color); #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_COLORCONVERTER_H diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index d11813b8c..97a18740a 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -40,8 +40,6 @@ #include "tick.h" -#define DELAY 0x80 - void common_hal_displayio_display_construct(displayio_display_obj_t* self, mp_obj_t bus, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, @@ -97,10 +95,10 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t full_command[data_size + 1]; full_command[0] = cmd[0]; memcpy(full_command + 1, data, data_size); - self->send(self->bus, true, full_command, data_size + 1); + self->send(self->bus, true, true, full_command, data_size + 1); } else { - self->send(self->bus, true, cmd, 1); - self->send(self->bus, false, data, data_size); + self->send(self->bus, true, true, cmd, 1); + self->send(self->bus, false, false, data, data_size); } uint16_t delay_length_ms = 10; if (delay) { @@ -232,6 +230,9 @@ const displayio_area_t* displayio_display_get_refresh_areas(displayio_display_ob self->area.next = NULL; return &self->area; } else { + if (self->current_group == NULL || self->current_group->base.type != &displayio_group_type) { + asm("bkpt"); + } return displayio_group_get_refresh_areas(self->current_group, NULL); } } @@ -283,12 +284,12 @@ bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, if (ok) { if (self->data_as_commands) { uint8_t set_brightness[2] = {self->brightness_command, (uint8_t) (0xff * brightness)}; - self->send(self->bus, true, set_brightness, 2); + self->send(self->bus, true, true, set_brightness, 2); } else { uint8_t command = self->brightness_command; uint8_t hex_brightness = 0xff * brightness; - self->send(self->bus, true, &command, 1); - self->send(self->bus, false, &hex_brightness, 1); + self->send(self->bus, true, true, &command, 1); + self->send(self->bus, false, false, &hex_brightness, 1); } self->end_transaction(self->bus); } @@ -331,7 +332,7 @@ void displayio_display_set_region_to_update(displayio_display_obj_t* self, displ data[0] = self->set_column_command; uint8_t data_length = 1; if (!self->data_as_commands) { - self->send(self->bus, true, data, 1); + self->send(self->bus, true, true, data, 1); data_length = 0; } if (self->single_byte_bounds) { @@ -345,13 +346,13 @@ void displayio_display_set_region_to_update(displayio_display_obj_t* self, displ data[data_length++] = x2 >> 8; data[data_length++] = x2 & 0xff; } - self->send(self->bus, self->data_as_commands, data, data_length); + self->send(self->bus, self->data_as_commands, self->data_as_commands, data, data_length); // Set row. data[0] = self->set_row_command; data_length = 1; if (!self->data_as_commands) { - self->send(self->bus, true, data, 1); + self->send(self->bus, true, true, data, 1); data_length = 0; } if (self->single_byte_bounds) { @@ -365,7 +366,7 @@ void displayio_display_set_region_to_update(displayio_display_obj_t* self, displ data[data_length++] = y2 >> 8; data[data_length++] = y2 & 0xff; } - self->send(self->bus, self->data_as_commands, data, data_length); + self->send(self->bus, self->data_as_commands, self->data_as_commands, data, data_length); } void displayio_display_start_refresh(displayio_display_obj_t* self) { @@ -391,9 +392,9 @@ void displayio_display_finish_refresh(displayio_display_obj_t* self) { void displayio_display_send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length) { if (!self->data_as_commands) { - self->send(self->bus, true, &self->write_ram_command, 1); + self->send(self->bus, true, true, &self->write_ram_command, 1); } - self->send(self->bus, false, pixels, length); + self->send(self->bus, false, false, pixels, length); } void displayio_display_update_backlight(displayio_display_obj_t* self) { @@ -414,7 +415,6 @@ void release_display(displayio_display_obj_t* self) { if (self->current_group != NULL) { self->current_group->in_group = false; } - if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { common_hal_pulseio_pwmout_reset_ok(&self->backlight_pwm); common_hal_pulseio_pwmout_deinit(&self->backlight_pwm); diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index 74ae175b1..c85d69b0e 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -34,7 +34,7 @@ #include "shared-module/displayio/area.h" typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); -typedef void (*display_bus_send)(mp_obj_t bus, bool command, uint8_t *data, uint32_t data_length); +typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); typedef void (*display_bus_end_transaction)(mp_obj_t bus); typedef struct { diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c new file mode 100644 index 000000000..5e4bdc340 --- /dev/null +++ b/shared-module/displayio/EPaperDisplay.c @@ -0,0 +1,531 @@ +/* + * 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. + */ + +#include "shared-bindings/displayio/EPaperDisplay.h" + +#include "py/runtime.h" +#include "shared-bindings/displayio/ColorConverter.h" +#include "shared-bindings/displayio/FourWire.h" +#include "shared-bindings/displayio/I2CDisplay.h" +#include "shared-bindings/displayio/ParallelBus.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/time/__init__.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/display.h" +#include "supervisor/usb.h" + +#include +#include + +#include "tick.h" + +void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self, + mp_obj_t bus, uint8_t* start_sequence, uint16_t start_sequence_len, uint8_t* stop_sequence, uint16_t stop_sequence_len, + uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, + int16_t colstart, int16_t rowstart, uint16_t rotation, + 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 third_color, uint16_t refresh_display_command, + const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select) { + self->colorspace.depth = 1; + self->colorspace.grayscale = true; + self->colorspace.pixels_in_byte_share_row = true; + self->colorspace.bytes_per_cell = 1; + self->colorspace.reverse_pixels_in_byte = true; + + if (third_color != 0x000000) { + self->colorspace.tricolor = true; + self->colorspace.tricolor_hue = displayio_colorconverter_compute_hue(third_color); + self->colorspace.tricolor_luma = displayio_colorconverter_compute_luma(third_color); + } + + self->set_column_window_command = set_column_window_command; + self->set_row_window_command = set_row_window_command; + self->set_current_column_command = set_current_column_command; + self->set_current_row_command = set_current_row_command; + self->write_black_ram_command = write_black_ram_command; + self->black_bits_inverted = black_bits_inverted; + self->write_color_ram_command = write_color_ram_command; + self->color_bits_inverted = color_bits_inverted; + self->refresh_display_command = refresh_display_command; + self->busy_state = busy_state; + self->refresh = true; + self->current_group = NULL; + self->colstart = colstart; + self->rowstart = rowstart; + self->refreshing = false; + self->milliseconds_per_frame = seconds_per_frame * 1000; + self->always_toggle_chip_select = always_toggle_chip_select; + + self->start_sequence = start_sequence; + self->start_sequence_len = start_sequence_len; + self->stop_sequence = stop_sequence; + self->stop_sequence_len = stop_sequence_len; + + + if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { + self->bus_reset = common_hal_displayio_parallelbus_reset; + self->bus_free = common_hal_displayio_parallelbus_bus_free; + self->begin_transaction = common_hal_displayio_parallelbus_begin_transaction; + self->send = common_hal_displayio_parallelbus_send; + self->end_transaction = common_hal_displayio_parallelbus_end_transaction; + } else if (MP_OBJ_IS_TYPE(bus, &displayio_fourwire_type)) { + self->bus_reset = common_hal_displayio_fourwire_reset; + self->bus_free = common_hal_displayio_fourwire_bus_free; + self->begin_transaction = common_hal_displayio_fourwire_begin_transaction; + self->send = common_hal_displayio_fourwire_send; + self->end_transaction = common_hal_displayio_fourwire_end_transaction; + } else if (MP_OBJ_IS_TYPE(bus, &displayio_i2cdisplay_type)) { + self->bus_reset = common_hal_displayio_i2cdisplay_reset; + self->bus_free = common_hal_displayio_i2cdisplay_bus_free; + self->begin_transaction = common_hal_displayio_i2cdisplay_begin_transaction; + self->send = common_hal_displayio_i2cdisplay_send; + self->end_transaction = common_hal_displayio_i2cdisplay_end_transaction; + } else { + mp_raise_ValueError(translate("Unsupported display bus type")); + } + self->bus = bus; + + supervisor_start_terminal(width, height); + + self->width = width; + self->height = height; + rotation = rotation % 360; + self->transform.x = 0; + self->transform.y = 0; + self->transform.scale = 1; + self->transform.mirror_x = false; + self->transform.mirror_y = false; + self->transform.transpose_xy = false; + if (rotation == 0 || rotation == 180) { + if (rotation == 180) { + self->transform.mirror_x = true; + self->transform.mirror_y = true; + } + } else { + self->transform.transpose_xy = true; + if (rotation == 270) { + self->transform.mirror_y = true; + } else { + self->transform.mirror_x = true; + } + } + + self->ram_width = ram_width; + self->ram_height = ram_height; + + self->area.x1 = 0; + self->area.y1 = 0; + self->area.next = NULL; + + self->transform.dx = 1; + self->transform.dy = 1; + if (self->transform.transpose_xy) { + self->area.x2 = height; + self->area.y2 = width; + if (self->transform.mirror_x) { + self->transform.x = height; + self->transform.dx = -1; + } + if (self->transform.mirror_y) { + self->transform.y = width; + self->transform.dy = -1; + } + } else { + self->area.x2 = width; + self->area.y2 = height; + if (self->transform.mirror_x) { + self->transform.x = width; + self->transform.dx = -1; + } + if (self->transform.mirror_y) { + self->transform.y = height; + self->transform.dy = -1; + } + } + + self->busy.base.type = &mp_type_NoneType; + if (busy_pin != NULL) { + self->busy.base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(&self->busy, busy_pin); + never_reset_pin_number(busy_pin->number); + } + + // Set the group after initialization otherwise we may send pixels while we delay in + // initialization. + common_hal_displayio_epaperdisplay_show(self, &circuitpython_splash); +} + +bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self, displayio_group_t* root_group) { + if (root_group == NULL && !circuitpython_splash.in_group) { + root_group = &circuitpython_splash; + } + if (root_group == self->current_group) { + return true; + } + if (root_group != NULL && root_group->in_group) { + return false; + } + if (self->current_group != NULL) { + self->current_group->in_group = false; + } + if (root_group != NULL) { + displayio_group_update_transform(root_group, &self->transform); + root_group->in_group = true; + self->current_group = root_group; + } + self->full_refresh = true; + common_hal_displayio_epaperdisplay_refresh_soon(self); + return true; +} + +void common_hal_displayio_epaperdisplay_refresh_soon(displayio_epaperdisplay_obj_t* self) { + self->refresh = true; +} + +const displayio_area_t* displayio_epaperdisplay_get_refresh_areas(displayio_epaperdisplay_obj_t *self) { + const displayio_area_t* first_area; + if (self->current_group == NULL || self->current_group->base.type != &displayio_group_type) { + asm("bkpt"); + } + if (self->full_refresh) { + first_area = &self->area; + } else { + first_area = displayio_group_get_refresh_areas(self->current_group, NULL); + } + if (first_area != NULL && self->set_row_window_command == NO_COMMAND) { + self->area.next = NULL; + return &self->area; + } + return first_area; +} + +int32_t common_hal_displayio_epaperdisplay_wait_for_frame(displayio_epaperdisplay_obj_t* self) { + uint64_t last_refresh = self->last_refresh; + // Don't try to refresh if we got an exception. + while (last_refresh == self->last_refresh && MP_STATE_VM(mp_pending_exception) == NULL) { + MICROPY_VM_HOOK_LOOP + } + return 0; +} + +uint16_t common_hal_displayio_epaperdisplay_get_width(displayio_epaperdisplay_obj_t* self){ + return self->width; +} + +uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_obj_t* self){ + return self->height; +} + +bool displayio_epaperdisplay_bus_free(displayio_epaperdisplay_obj_t *self) { + return self->bus_free(self->bus); +} + +bool displayio_epaperdisplay_begin_transaction(displayio_epaperdisplay_obj_t* self) { + return self->begin_transaction(self->bus); +} + +void displayio_epaperdisplay_end_transaction(displayio_epaperdisplay_obj_t* self) { + self->end_transaction(self->bus); +} + +STATIC void wait_for_busy(displayio_epaperdisplay_obj_t* self) { + if (self->busy.base.type == &mp_type_NoneType) { + return; + } + while (common_hal_digitalio_digitalinout_get_value(&self->busy) == self->busy_state) { + #ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP + #endif + } +} + +STATIC void send_command_sequence(displayio_epaperdisplay_obj_t* self, bool should_wait_for_busy, uint8_t* sequence, uint32_t sequence_len) { + uint32_t i = 0; + while (i < sequence_len) { + uint8_t *cmd = sequence + i; + uint8_t data_size = *(cmd + 1); + bool delay = (data_size & DELAY) != 0; + data_size &= ~DELAY; + uint8_t *data = cmd + 2; + self->begin_transaction(self->bus); + self->send(self->bus, true, self->always_toggle_chip_select, cmd, 1); + self->send(self->bus, false, self->always_toggle_chip_select, data, data_size); + self->end_transaction(self->bus); + uint16_t delay_length_ms = 0; + if (delay) { + data_size++; + delay_length_ms = *(cmd + 1 + data_size); + if (delay_length_ms == 255) { + delay_length_ms = 500; + } + } + common_hal_time_delay_ms(delay_length_ms); + if (should_wait_for_busy) { + wait_for_busy(self); + } + i += 2 + data_size; + } +} + +void displayio_epaperdisplay_set_region_to_update(displayio_epaperdisplay_obj_t* self, displayio_area_t* area) { + if (self->set_row_window_command == NO_COMMAND) { + return; + } + uint16_t x1 = area->x1; + uint16_t x2 = area->x2; + uint16_t y1 = area->y1; + uint16_t y2 = area->y2; + // Collapse down the dimension where multiple pixels are in a byte. + uint8_t pixels_per_byte = 8 / self->colorspace.depth; + x1 /= pixels_per_byte * self->colorspace.bytes_per_cell; + x2 /= pixels_per_byte * self->colorspace.bytes_per_cell; + + + // Set column. + uint8_t data[5]; + data[0] = self->set_column_window_command; + self->send(self->bus, true, self->always_toggle_chip_select, data, 1); + uint8_t data_length = 0; + if (self->ram_width / pixels_per_byte < 0x100) { + data[data_length++] = x1 + self->colstart; + data[data_length++] = x2 - 1 + self->colstart; + } else { + x1 += self->colstart; + x2 += self->colstart - 1; + data[data_length++] = x1 >> 8; + data[data_length++] = x1 & 0xff; + data[data_length++] = x2 >> 8; + data[data_length++] = x2 & 0xff; + } + self->send(self->bus, false, self->always_toggle_chip_select, data, data_length); + if (self->set_current_column_command != NO_COMMAND) { + uint8_t command = self->set_current_column_command; + self->send(self->bus, true, self->always_toggle_chip_select, &command, 1); + self->send(self->bus, false, self->always_toggle_chip_select, data, data_length / 2); + } + + // Set row. + data[0] = self->set_row_window_command; + self->send(self->bus, true, self->always_toggle_chip_select, data, 1); + data_length = 0; + if (self->ram_height < 0x100) { + data[data_length++] = y1 + self->rowstart; + data[data_length++] = y2 - 1 + self->rowstart; + } else { + y1 += self->rowstart; + y2 += self->rowstart - 1; + data[data_length++] = y1 & 0xff; + data[data_length++] = y1 >> 8; + data[data_length++] = y2 & 0xff; + data[data_length++] = y2 >> 8; + } + self->send(self->bus, false, self->always_toggle_chip_select, data, data_length); + if (self->set_current_row_command != NO_COMMAND) { + uint8_t command = self->set_current_row_command; + self->send(self->bus, true, self->always_toggle_chip_select, &command, 1); + self->send(self->bus, false, self->always_toggle_chip_select, data, data_length / 2); + } +} + +void displayio_epaperdisplay_start_refresh(displayio_epaperdisplay_obj_t* self) { + // run start sequence + self->bus_reset(self->bus); + + send_command_sequence(self, true, self->start_sequence, self->start_sequence_len); + self->last_refresh = ticks_ms; +} + +bool displayio_epaperdisplay_frame_queued(displayio_epaperdisplay_obj_t* self) { + if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) { + if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) { + self->refreshing = false; + // Run stop sequence but don't wait for busy because busy is set when sleeping. + send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); + } else { + return false; + } + } + if (self->current_group == NULL) { + return false; + } + // Refresh at seconds per frame rate. + return (ticks_ms - self->last_refresh) > self->milliseconds_per_frame; +} + +void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self) { + // Actually refresh the display now that all pixel RAM has been updated. + displayio_epaperdisplay_begin_transaction(self); + self->send(self->bus, true, self->always_toggle_chip_select, &self->refresh_display_command, 1); + displayio_epaperdisplay_end_transaction(self); + self->refreshing = true; + + if (self->current_group != NULL) { + displayio_group_finish_refresh(self->current_group); + } + self->refresh = false; + self->full_refresh = false; + self->last_refresh = ticks_ms; +} + +void displayio_epaperdisplay_send_pixels(displayio_epaperdisplay_obj_t* self, uint8_t* pixels, uint32_t length) { +} + + +bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, const displayio_area_t* area) { + uint16_t buffer_size = 128; // In uint32_ts + + displayio_area_t clipped; + // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. + if (!displayio_epaperdisplay_clip_area(self, area, &clipped)) { + return true; + } + uint16_t subrectangles = 1; + uint16_t rows_per_buffer = displayio_area_height(&clipped); + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->colorspace.depth; + uint16_t pixels_per_buffer = displayio_area_size(&clipped); + if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { + rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); + if (rows_per_buffer == 0) { + rows_per_buffer = 1; + } + subrectangles = displayio_area_height(&clipped) / rows_per_buffer; + if (displayio_area_height(&clipped) % rows_per_buffer != 0) { + subrectangles++; + } + pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); + buffer_size = pixels_per_buffer / pixels_per_word; + if (pixels_per_buffer % pixels_per_word) { + buffer_size += 1; + } + } + + // Allocated and shared as a uint32_t array so the compiler knows the + // alignment everywhere. + uint32_t buffer[buffer_size]; + volatile uint32_t mask_length = (pixels_per_buffer / 32) + 1; + uint32_t mask[mask_length]; + + uint8_t passes = 1; + if (self->colorspace.tricolor) { + passes = 2; + } + for (uint8_t pass = 0; pass < passes; pass++) { + uint16_t remaining_rows = displayio_area_height(&clipped); + + displayio_epaperdisplay_begin_transaction(self); + displayio_epaperdisplay_set_region_to_update(self, &clipped); + displayio_epaperdisplay_end_transaction(self); + + uint8_t write_command = self->write_black_ram_command; + if (pass == 1) { + write_command = self->write_color_ram_command; + } + displayio_epaperdisplay_begin_transaction(self); + self->send(self->bus, true, self->always_toggle_chip_select, &write_command, 1); + displayio_epaperdisplay_end_transaction(self); + + for (uint16_t j = 0; j < subrectangles; j++) { + displayio_area_t subrectangle = { + .x1 = clipped.x1, + .y1 = clipped.y1 + rows_per_buffer * j, + .x2 = clipped.x2, + .y2 = clipped.y1 + rows_per_buffer * (j + 1) + }; + if (remaining_rows < rows_per_buffer) { + subrectangle.y2 = subrectangle.y1 + remaining_rows; + } + remaining_rows -= rows_per_buffer; + + + uint16_t subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->colorspace.depth); + + for (uint16_t k = 0; k < mask_length; k++) { + mask[k] = 0x00000000; + } + for (uint16_t k = 0; k < buffer_size; k++) { + buffer[k] = 0x00000000; + } + + self->colorspace.grayscale = true; + if (pass == 1) { + self->colorspace.grayscale = false; + } + displayio_group_fill_area(self->current_group, &self->colorspace, &subrectangle, mask, buffer); + + // Invert it all. + if ((pass == 1 && self->color_bits_inverted) || + (pass == 0 && self->black_bits_inverted)) { + for (uint16_t k = 0; k < buffer_size; k++) { + buffer[k] = ~buffer[k]; + } + } + + if (!displayio_epaperdisplay_begin_transaction(self)) { + // Can't acquire display bus; skip the rest of the data. Try next display. + return false; + } + self->send(self->bus, false, self->always_toggle_chip_select, (uint8_t*) buffer, subrectangle_size_bytes); + displayio_epaperdisplay_end_transaction(self); + + // TODO(tannewt): Make refresh displays faster so we don't starve other + // background tasks. + usb_background(); + } + } + + return true; +} + +void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { + if (self->current_group != NULL) { + self->current_group->in_group = false; + } + if (self->busy.base.type == &digitalio_digitalinout_type) { + common_hal_digitalio_digitalinout_deinit(&self->busy); + } +} + +bool displayio_epaperdisplay_fill_area(displayio_epaperdisplay_obj_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer) { + return displayio_group_fill_area(self->current_group, &self->colorspace, area, mask, buffer); +} + +bool displayio_epaperdisplay_clip_area(displayio_epaperdisplay_obj_t *self, const displayio_area_t* area, displayio_area_t* clipped) { + bool overlaps = displayio_area_compute_overlap(&self->area, area, clipped); + if (!overlaps) { + return false; + } + // Expand the area if we have multiple pixels per byte and we need to byte + // align the bounds. + uint8_t pixels_per_byte = 8; + if (clipped->x1 % pixels_per_byte != 0) { + clipped->x1 -= clipped->x1 % pixels_per_byte; + } + if (clipped->x2 % pixels_per_byte != 0) { + clipped->x2 += pixels_per_byte - clipped->x2 % pixels_per_byte; + } + return true; +} diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h new file mode 100644 index 000000000..737b5987a --- /dev/null +++ b/shared-module/displayio/EPaperDisplay.h @@ -0,0 +1,92 @@ +/* + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_EPAPERDISPLAY_H +#define MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_EPAPERDISPLAY_H + +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/displayio/Group.h" +#include "shared-bindings/pulseio/PWMOut.h" + +#include "shared-module/displayio/area.h" + +typedef void (*display_bus_bus_reset)(mp_obj_t bus); +typedef bool (*display_bus_bus_free)(mp_obj_t bus); +typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); +typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); +typedef void (*display_bus_end_transaction)(mp_obj_t bus); + +typedef struct { + mp_obj_base_t base; + mp_obj_t bus; + displayio_group_t *current_group; + uint64_t last_refresh; + display_bus_bus_reset bus_reset; + display_bus_bus_free bus_free; + display_bus_begin_transaction begin_transaction; + display_bus_send send; + display_bus_end_transaction end_transaction; + digitalio_digitalinout_obj_t busy; + uint32_t milliseconds_per_frame; + uint8_t* start_sequence; + uint32_t start_sequence_len; + uint8_t* stop_sequence; + uint32_t stop_sequence_len; + displayio_buffer_transform_t transform; + displayio_area_t area; + uint16_t width; + uint16_t height; + uint16_t ram_width; + uint16_t ram_height; + _displayio_colorspace_t colorspace; + int16_t colstart; + int16_t rowstart; + 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; + uint16_t write_color_ram_command; + uint8_t refresh_display_command; + uint8_t hue; + bool busy_state; + bool black_bits_inverted; + bool color_bits_inverted; + bool refresh; + bool refreshing; + bool full_refresh; // New group means we need to refresh the whole display. + bool always_toggle_chip_select; +} displayio_epaperdisplay_obj_t; + +bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* display, const displayio_area_t* area); +void displayio_epaperdisplay_start_refresh(displayio_epaperdisplay_obj_t* self); +const displayio_area_t* displayio_epaperdisplay_get_refresh_areas(displayio_epaperdisplay_obj_t *self); +bool displayio_epaperdisplay_fill_area(displayio_epaperdisplay_obj_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer); +bool displayio_epaperdisplay_clip_area(displayio_epaperdisplay_obj_t *self, const displayio_area_t* area, displayio_area_t* clipped); +bool displayio_epaperdisplay_bus_free(displayio_epaperdisplay_obj_t *self); +void release_epaperdisplay(displayio_epaperdisplay_obj_t* self); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_EPAPERDISPLAY_H diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c index 913635db8..64ad80665 100644 --- a/shared-module/displayio/FourWire.c +++ b/shared-module/displayio/FourWire.c @@ -59,11 +59,7 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self, common_hal_digitalio_digitalinout_construct(&self->reset, reset); common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); never_reset_pin_number(reset->number); - - common_hal_digitalio_digitalinout_set_value(&self->reset, false); - common_hal_mcu_delay_us(10); - common_hal_digitalio_digitalinout_set_value(&self->reset, true); - common_hal_mcu_delay_us(10); + common_hal_displayio_fourwire_reset(self); } never_reset_pin_number(command->number); @@ -80,6 +76,23 @@ void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self) { reset_pin_number(self->reset.pin->number); } +void common_hal_displayio_fourwire_reset(mp_obj_t obj) { + displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); + common_hal_digitalio_digitalinout_set_value(&self->reset, false); + common_hal_time_delay_ms(1); + common_hal_digitalio_digitalinout_set_value(&self->reset, true); + common_hal_time_delay_ms(1); +} + +bool common_hal_displayio_fourwire_bus_free(mp_obj_t obj) { + displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); + if (!common_hal_busio_spi_try_lock(self->bus)) { + return false; + } + common_hal_busio_spi_unlock(self->bus); + return true; +} + bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t obj) { displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); if (!common_hal_busio_spi_try_lock(self->bus)) { @@ -91,10 +104,10 @@ bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t obj) { return true; } -void common_hal_displayio_fourwire_send(mp_obj_t obj, bool command, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_fourwire_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); common_hal_digitalio_digitalinout_set_value(&self->command, !command); - if (command) { + if (toggle_every_byte) { // Toggle chip select after each command byte in case the display driver // IC latches commands based on it. for (size_t i = 0; i < data_length; i++) { diff --git a/shared-module/displayio/Group.c b/shared-module/displayio/Group.c index 38418a029..eb6e9a453 100644 --- a/shared-module/displayio/Group.c +++ b/shared-module/displayio/Group.c @@ -304,6 +304,9 @@ void displayio_group_finish_refresh(displayio_group_t *self) { } displayio_area_t* displayio_group_get_refresh_areas(displayio_group_t *self, displayio_area_t* tail) { + if (self->base.type != &displayio_group_type) { + asm("bkpt"); + } if (self->item_removed) { self->dirty_area.next = tail; tail = &self->dirty_area; diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c index 9d8949528..23ebc0889 100644 --- a/shared-module/displayio/I2CDisplay.c +++ b/shared-module/displayio/I2CDisplay.c @@ -59,10 +59,7 @@ void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self, common_hal_digitalio_digitalinout_construct(&self->reset, reset); common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); never_reset_pin_number(reset->number); - - common_hal_digitalio_digitalinout_set_value(&self->reset, false); - common_hal_mcu_delay_us(1); - common_hal_digitalio_digitalinout_set_value(&self->reset, true); + common_hal_displayio_i2cdisplay_reset(self); } } @@ -74,7 +71,17 @@ void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self) { reset_pin_number(self->reset.pin->number); } -bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t obj) { + +void common_hal_displayio_i2cdisplay_reset(mp_obj_t obj) { + displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); + + common_hal_digitalio_digitalinout_set_value(&self->reset, false); + common_hal_mcu_delay_us(1); + common_hal_digitalio_digitalinout_set_value(&self->reset, true); +} + + +bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t obj) { displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); if (!common_hal_busio_i2c_try_lock(self->bus)) { return false; @@ -82,7 +89,11 @@ bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t obj) { return true; } -void common_hal_displayio_i2cdisplay_send(mp_obj_t obj, bool command, uint8_t *data, uint32_t data_length) { +bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t obj) { + return common_hal_displayio_i2cdisplay_bus_free(obj); +} + +void common_hal_displayio_i2cdisplay_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); if (command) { uint8_t command_bytes[2 * data_length]; diff --git a/shared-module/displayio/OnDiskBitmap.c b/shared-module/displayio/OnDiskBitmap.c index 2b5642437..10fc0c4a2 100644 --- a/shared-module/displayio/OnDiskBitmap.c +++ b/shared-module/displayio/OnDiskBitmap.c @@ -74,7 +74,7 @@ void common_hal_displayio_ondiskbitmap_construct(displayio_ondiskbitmap_t *self, self->g_bitmask = 0x3e0; self->b_bitmask = 0x1f; } - } else if ((indexed) && (self->bits_per_pixel != 1)) { + } else if (indexed && self->bits_per_pixel != 1) { uint16_t palette_size = number_of_colors * sizeof(uint32_t); uint16_t palette_offset = 0xe + header_size; @@ -90,25 +90,24 @@ void common_hal_displayio_ondiskbitmap_construct(displayio_ondiskbitmap_t *self, if (palette_bytes_read != palette_size) { mp_raise_ValueError(translate("Unable to read color palette data")); } - - } else if (!(header_size == 12 || header_size == 40 || header_size == 108 || header_size == 124)) { mp_raise_ValueError_varg(translate("Only Windows format, uncompressed BMP supported: given header size is %d"), header_size); } - if ((bits_per_pixel == 4 ) || (( bits_per_pixel == 8) && (number_of_colors == 0))) { - mp_raise_ValueError_varg(translate("Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp given"), bits_per_pixel); + if (bits_per_pixel == 8 && number_of_colors == 0) { + mp_raise_ValueError_varg(translate("Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: %d bpp given"), bits_per_pixel); } - if (self->bits_per_pixel >=8){ - self->stride = (self->width * (bits_per_pixel / 8)); + uint8_t bytes_per_pixel = (self->bits_per_pixel / 8) ? (self->bits_per_pixel /8) : 1; + uint8_t pixels_per_byte = 8 / self->bits_per_pixel; + if (pixels_per_byte == 0){ + self->stride = (self->width * bytes_per_pixel); // Rows are word aligned. if (self->stride % 4 != 0) { self->stride += 4 - self->stride % 4; } - } else { - uint32_t bit_stride = self->width; + uint32_t bit_stride = self->width * self->bits_per_pixel; if (bit_stride % 32 != 0) { bit_stride += 32 - bit_stride % 32; } @@ -126,10 +125,11 @@ uint32_t common_hal_displayio_ondiskbitmap_get_pixel(displayio_ondiskbitmap_t *s uint32_t location; uint8_t bytes_per_pixel = (self->bits_per_pixel / 8) ? (self->bits_per_pixel /8) : 1; - if (self->bits_per_pixel >= 8){ + uint8_t pixels_per_byte = 8 / self->bits_per_pixel; + if (pixels_per_byte == 0){ location = self->data_offset + (self->height - y - 1) * self->stride + x * bytes_per_pixel; } else { - location = self->data_offset + (self->height - y - 1) * self->stride + x / 8; + location = self->data_offset + (self->height - y - 1) * self->stride + x / pixels_per_byte; } // We don't cache here because the underlying FS caches sectors. f_lseek(&self->file->fp, location); @@ -141,20 +141,21 @@ uint32_t common_hal_displayio_ondiskbitmap_get_pixel(displayio_ondiskbitmap_t *s uint8_t red; uint8_t green; uint8_t blue; - if (self->bits_per_pixel == 1) { - uint8_t bit_offset = x%8; - tmp = ( pixel_data & (0x80 >> (bit_offset))) >> (7 - bit_offset); - if (tmp == 1) { - return 0x00FFFFFF; - } else { - return 0x00000000; + if (bytes_per_pixel == 1) { + uint8_t offset = (x % pixels_per_byte) * self->bits_per_pixel; + uint8_t mask = (1 << self->bits_per_pixel) - 1; + + uint8_t index = (pixel_data >> ((8 - self->bits_per_pixel) - offset)) & mask; + if (self->bits_per_pixel == 1) { + if (index == 1) { + return 0xFFFFFF; + } else if (index == 0) { + return 0x000000; + } else { + asm("bkpt"); + } } - } else if (bytes_per_pixel == 1) { - blue = ((self->palette_data[pixel_data] & 0xFF) >> 0); - red = ((self->palette_data[pixel_data] & 0xFF0000) >> 16); - green = ((self->palette_data[pixel_data] & 0xFF00) >> 8); - tmp = (red << 16 | green << 8 | blue ); - return tmp; + return self->palette_data[index]; } else if (bytes_per_pixel == 2) { if (self->g_bitmask == 0x07e0) { // 565 red =((pixel_data & self->r_bitmask) >>11); diff --git a/shared-module/displayio/Palette.c b/shared-module/displayio/Palette.c index 444151b3c..3bce86f48 100644 --- a/shared-module/displayio/Palette.c +++ b/shared-module/displayio/Palette.c @@ -52,6 +52,10 @@ void common_hal_displayio_palette_set_color(displayio_palette_t* self, uint32_t self->colors[palette_index].rgb888 = color; self->colors[palette_index].luma = displayio_colorconverter_compute_luma(color); self->colors[palette_index].rgb565 = displayio_colorconverter_compute_rgb565(color); + + uint8_t chroma = displayio_colorconverter_compute_chroma(color); + self->colors[palette_index].chroma = chroma; + self->colors[palette_index].hue = displayio_colorconverter_compute_hue(color); self->needs_refresh = true; } @@ -64,7 +68,19 @@ bool displayio_palette_get_color(displayio_palette_t *self, const _displayio_col return false; // returns opaque } - if (colorspace->grayscale) { + if (colorspace->tricolor) { + uint8_t luma = self->colors[palette_index].luma; + *color = luma >> (8 - colorspace->depth); + // Chroma 0 means the color is a gray and has no hue so never color based on it. + if (self->colors[palette_index].chroma <= 16) { + if (!colorspace->grayscale) { + *color = 0; + } + return true; + } + uint8_t pixel_hue = self->colors[palette_index].hue; + displayio_colorconverter_compute_tricolor(colorspace, pixel_hue, luma, color); + } else if (colorspace->grayscale) { *color = self->colors[palette_index].luma >> (8 - colorspace->depth); } else { *color = self->colors[palette_index].rgb565; diff --git a/shared-module/displayio/Palette.h b/shared-module/displayio/Palette.h index a917e2432..1cfdd199a 100644 --- a/shared-module/displayio/Palette.h +++ b/shared-module/displayio/Palette.h @@ -34,17 +34,21 @@ typedef struct { uint8_t depth; + uint8_t bytes_per_cell; + uint8_t tricolor_hue; + uint8_t tricolor_luma; bool grayscale; + bool tricolor; bool pixels_in_byte_share_row; - uint8_t bytes_per_cell; bool reverse_pixels_in_byte; - uint8_t hue; } _displayio_colorspace_t; typedef struct { uint32_t rgb888; uint16_t rgb565; uint8_t luma; + uint8_t hue; + uint8_t chroma; bool transparent; // This may have additional bits added later for blending. } _displayio_color_t; diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index 6144f8f99..6553cf901 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -443,6 +443,7 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c } uint8_t shift = (offset % pixels_per_byte) * colorspace->depth; if (colorspace->reverse_pixels_in_byte) { + // Reverse the shift by subtracting it from the leftmost shift. shift = (pixels_per_byte - 1) * colorspace->depth - shift; } ((uint8_t*)buffer)[offset / pixels_per_byte] |= pixel << shift; diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 3e9c4aa2a..a8f888654 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -133,26 +133,50 @@ void displayio_refresh_displays(void) { // Skip null display. continue; } - displayio_display_obj_t* display = &displays[i].display; - displayio_display_update_backlight(display); - - // Time to refresh at specified frame rate? - if (!displayio_display_frame_queued(display)) { - // Too soon. Try next display. - continue; - } - if (!displayio_display_begin_transaction(display)) { - // Can't acquire display bus; skip updating this display. Try next display. - continue; - } - displayio_display_end_transaction(display); - displayio_display_start_refresh(display); - const displayio_area_t* current_area = displayio_display_get_refresh_areas(display); - while (current_area != NULL) { - refresh_area(display, current_area); - current_area = current_area->next; + if (displays[i].display.base.type == &displayio_display_type) { + displayio_display_obj_t* display = &displays[i].display; + displayio_display_update_backlight(display); + + // Time to refresh at specified frame rate? + if (!displayio_display_frame_queued(display)) { + // Too soon. Try next display. + continue; + } + if (!displayio_display_begin_transaction(display)) { + // Can't acquire display bus; skip updating this display. Try next display. + continue; + } + displayio_display_end_transaction(display); + displayio_display_start_refresh(display); + const displayio_area_t* current_area = displayio_display_get_refresh_areas(display); + while (current_area != NULL) { + refresh_area(display, current_area); + current_area = current_area->next; + } + displayio_display_finish_refresh(display); + } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { + displayio_epaperdisplay_obj_t* display = &displays[i].epaper_display; + // Time to refresh at specified frame rate? + if (!displayio_epaperdisplay_frame_queued(display)) { + // Too soon. Try next display. + continue; + } + if (!displayio_epaperdisplay_bus_free(display)) { + // Can't acquire display bus; skip updating this display. Try next display. + continue; + } + const displayio_area_t* current_area = displayio_epaperdisplay_get_refresh_areas(display); + if (current_area == NULL) { + continue; + } + displayio_epaperdisplay_start_refresh(display); + while (current_area != NULL) { + displayio_epaperdisplay_refresh_area(display, current_area); + current_area = current_area->next; + } + displayio_epaperdisplay_finish_refresh(display); } - displayio_display_finish_refresh(display); + frame_count++; } @@ -175,7 +199,14 @@ void common_hal_displayio_release_displays(void) { displays[i].fourwire_bus.base.type = &mp_type_NoneType; } for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - release_display(&displays[i].display); + mp_const_obj_t display_type = displays[i].display.base.type; + if (display_type == NULL || display_type == &mp_type_NoneType) { + continue; + } else if (display_type == &displayio_display_type) { + release_display(&displays[i].display); + } else if (display_type == &displayio_epaperdisplay_type) { + release_epaperdisplay(&displays[i].epaper_display); + } displays[i].display.base.type = &mp_type_NoneType; } @@ -232,7 +263,7 @@ void reset_displays(void) { } } } else { - // Not an active display. + // Not an active display bus. continue; } } @@ -240,9 +271,14 @@ void reset_displays(void) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { // Reset the displayed group. Only the first will get the terminal but // that's ok. - displayio_display_obj_t* display = &displays[i].display; - display->auto_brightness = true; - common_hal_displayio_display_show(display, NULL); + if (displays[i].display.base.type == &displayio_display_type) { + displayio_display_obj_t* display = &displays[i].display; + display->auto_brightness = true; + common_hal_displayio_display_show(display, NULL); + } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { + displayio_epaperdisplay_obj_t* display = &displays[i].epaper_display; + common_hal_displayio_epaperdisplay_show(display, NULL); + } } } @@ -254,8 +290,11 @@ void displayio_gc_collect(void) { // Alternatively, we could use gc_collect_root over the whole object, // but this is more precise, and is the only field that needs marking. - gc_collect_ptr(displays[i].display.current_group); - + if (displays[i].display.base.type == &displayio_display_type) { + gc_collect_ptr(displays[i].display.current_group); + } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { + gc_collect_ptr(displays[i].epaper_display.current_group); + } } } diff --git a/shared-module/displayio/__init__.h b/shared-module/displayio/__init__.h index caa5ce36d..95eefbdd9 100644 --- a/shared-module/displayio/__init__.h +++ b/shared-module/displayio/__init__.h @@ -28,6 +28,7 @@ #define MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO___INIT___H #include "shared-bindings/displayio/Display.h" +#include "shared-bindings/displayio/EPaperDisplay.h" #include "shared-bindings/displayio/FourWire.h" #include "shared-bindings/displayio/Group.h" #include "shared-bindings/displayio/I2CDisplay.h" @@ -39,7 +40,10 @@ typedef struct { displayio_i2cdisplay_obj_t i2cdisplay_bus; displayio_parallelbus_obj_t parallel_bus; }; - displayio_display_obj_t display; + union { + displayio_display_obj_t display; + displayio_epaperdisplay_obj_t epaper_display; + }; } primary_display_t; extern primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index fd51e2c07..586b6f8be 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -151,37 +151,49 @@ _displayio_color_t blinka_colors[7] = { .rgb888 = 0x000000, .rgb565 = 0x0000, .luma = 0x00, + .chroma = 0, .transparent = true }, { .rgb888 = 0x8428bc, .rgb565 = 0x7889, - .luma = 0xff // We cheat the luma here. It is actually 0x60 + .luma = 0xff, // We cheat the luma here. It is actually 0x60 + .hue = 184, + .chroma = 148 }, { .rgb888 = 0xff89bc, .rgb565 = 0xB8FC, - .luma = 0xb5 + .luma = 0xb5, + .hue = 222, + .chroma = 118 }, { .rgb888 = 0x7beffe, .rgb565 = 0x9F86, - .luma = 0xe0 + .luma = 0xe0, + .hue = 124, + .chroma = 131 }, { .rgb888 = 0x51395f, .rgb565 = 0x0D5A, - .luma = 0x47 + .luma = 0x47, + .hue = 185, + .chroma = 38 }, { .rgb888 = 0xffffff, .rgb565 = 0xffff, - .luma = 0xff + .luma = 0xff, + .chroma = 0 }, { .rgb888 = 0x0736a0, .rgb565 = 0xf501, - .luma = 0x44 + .luma = 0x44, + .hue = 147, + .chroma = 153 }, }; diff --git a/tools/gen_display_resources.py b/tools/gen_display_resources.py index 0f6b9014b..65600a195 100644 --- a/tools/gen_display_resources.py +++ b/tools/gen_display_resources.py @@ -102,12 +102,14 @@ _displayio_color_t terminal_colors[2] = { { .rgb888 = 0x000000, .rgb565 = 0x0000, - .luma = 0x00 + .luma = 0x00, + .chroma = 0 }, { .rgb888 = 0xffffff, .rgb565 = 0xffff, - .luma = 0xff + .luma = 0xff, + .chroma = 0 }, }; From d37dd4d758dd2d2a63fd4c9b7989d60560fd4a25 Mon Sep 17 00:00:00 2001 From: Benny Meisels Date: Tue, 6 Aug 2019 02:24:25 +0300 Subject: [PATCH 03/18] Updated ParallelBus implementation in nrf port --- ports/nrf/common-hal/displayio/ParallelBus.c | 28 +++++++++++++++----- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/ports/nrf/common-hal/displayio/ParallelBus.c b/ports/nrf/common-hal/displayio/ParallelBus.c index 42231be52..efb8c15b9 100644 --- a/ports/nrf/common-hal/displayio/ParallelBus.c +++ b/ports/nrf/common-hal/displayio/ParallelBus.c @@ -31,6 +31,7 @@ #include "common-hal/microcontroller/Pin.h" #include "py/runtime.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/microcontroller/__init__.h" #include "tick.h" @@ -70,10 +71,6 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel 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); - self->reset.base.type = &digitalio_digitalinout_type; - common_hal_digitalio_digitalinout_construct(&self->reset, reset); - common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); - self->write.base.type = &digitalio_digitalinout_type; common_hal_digitalio_digitalinout_construct(&self->write, write); common_hal_digitalio_digitalinout_switch_to_output(&self->write, true, DRIVE_MODE_PUSH_PULL); @@ -93,11 +90,18 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel } self->write_mask = 1 << (write->number % num_pins_in_write_port); + if (reset != NULL) { + self->reset.base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(&self->reset, reset); + common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); + never_reset_pin_number(reset->number); + common_hal_displayio_parallelbus_reset(self); + } + never_reset_pin_number(command->number); never_reset_pin_number(chip_select->number); never_reset_pin_number(write->number); never_reset_pin_number(read->number); - never_reset_pin_number(reset->number); for (uint8_t i = 0; i < 8; i++) { never_reset_pin_number(data_pin + i); } @@ -115,13 +119,25 @@ void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self) reset_pin_number(self->reset.pin->number); } +void common_hal_displayio_parallelbus_reset(mp_obj_t obj) { + displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); + + common_hal_digitalio_digitalinout_set_value(&self->reset, false); + common_hal_mcu_delay_us(4); + common_hal_digitalio_digitalinout_set_value(&self->reset, true); +} + +bool common_hal_displayio_parallelbus_bus_free(mp_obj_t obj) { + return true; +} + bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t obj) { displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); return true; } -void common_hal_displayio_parallelbus_send(mp_obj_t obj, bool command, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_parallelbus_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); common_hal_digitalio_digitalinout_set_value(&self->command, !command); uint32_t* clear_write = (uint32_t*) &self->write_group->OUTCLR; From c247e7df9c043dc6a452a6cabc7bf232c0e9e085 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 14 Aug 2019 14:17:35 -0700 Subject: [PATCH 04/18] Begin refresh rework. --- ports/atmel-samd/background.c | 2 +- ports/nrf/background.c | 2 +- ports/stm32f4/background.c | 2 +- py/circuitpy_mpconfig.h | 2 +- shared-bindings/displayio/Display.c | 37 ++++-- shared-bindings/displayio/Display.h | 14 +- shared-bindings/displayio/EPaperDisplay.c | 45 ++++--- shared-bindings/displayio/EPaperDisplay.h | 9 +- shared-module/displayio/Display.c | 124 +++++++++++++++++- shared-module/displayio/Display.h | 8 +- shared-module/displayio/EPaperDisplay.c | 71 ++++++++--- shared-module/displayio/EPaperDisplay.h | 8 +- shared-module/displayio/__init__.c | 149 ++-------------------- shared-module/displayio/__init__.h | 2 +- 14 files changed, 254 insertions(+), 221 deletions(-) diff --git a/ports/atmel-samd/background.c b/ports/atmel-samd/background.c index 694238070..386ba0715 100644 --- a/ports/atmel-samd/background.c +++ b/ports/atmel-samd/background.c @@ -60,7 +60,7 @@ void run_background_tasks(void) { audio_dma_background(); #endif #if CIRCUITPY_DISPLAYIO - displayio_refresh_displays(); + displayio_background(); #endif #if CIRCUITPY_NETWORK diff --git a/ports/nrf/background.c b/ports/nrf/background.c index 453bc96df..94411cbce 100644 --- a/ports/nrf/background.c +++ b/ports/nrf/background.c @@ -56,7 +56,7 @@ void run_background_tasks(void) { #endif #if CIRCUITPY_DISPLAYIO - displayio_refresh_displays(); + displayio_background(); #endif running_background_tasks = false; diff --git a/ports/stm32f4/background.c b/ports/stm32f4/background.c index e9872b045..b91c3793e 100644 --- a/ports/stm32f4/background.c +++ b/ports/stm32f4/background.c @@ -49,7 +49,7 @@ void run_background_tasks(void) { //usb_background(); #if CIRCUITPY_DISPLAYIO - displayio_refresh_displays(); + displayio_background(); #endif running_background_tasks = false; diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 393b7600c..c2e2e2d02 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -307,7 +307,7 @@ extern const struct _mp_obj_module_t terminalio_module; #define DISPLAYIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_displayio), (mp_obj_t)&displayio_module }, #define FONTIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_fontio), (mp_obj_t)&fontio_module }, #define TERMINALIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_terminalio), (mp_obj_t)&terminalio_module }, -#define CIRCUITPY_DISPLAY_LIMIT (3) +#define CIRCUITPY_DISPLAY_LIMIT (1) #else #define DISPLAYIO_MODULE #define FONTIO_MODULE diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 0c48b0cc5..fb9bfff85 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -212,27 +212,42 @@ STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) } MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show); -//| .. method:: refresh_soon() +//| .. method:: refresh(*, target_frames_per_second=None, minimum_frames_per_second=1) //| -//| Queues up a display refresh that happens in the background. +//| Waits for the target frame rate and then refreshes the display. If the call is too late for the given target frame rate, then the refresh returns immediately without updating the screen to hopefully help getting caught up. If the current frame rate is below the minimum frame rate, then an exception will be raised. //| -STATIC mp_obj_t displayio_display_obj_refresh_soon(mp_obj_t self_in) { +STATIC mp_obj_t displayio_display_obj_refresh(mp_obj_t self_in) { displayio_display_obj_t *self = native_display(self_in); - common_hal_displayio_display_refresh_soon(self); + common_hal_displayio_display_refresh(self); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_refresh_soon_obj, displayio_display_obj_refresh_soon); -//| .. method:: wait_for_frame() +//| .. attribute:: auto_refresh //| -//| Waits until the next frame has been transmitted to the display unless the wait count is -//| behind the rendered frames. In that case, this will return immediately with the wait count. +//| True when the display is refreshed automatically. //| -STATIC mp_obj_t displayio_display_obj_wait_for_frame(mp_obj_t self_in) { +STATIC mp_obj_t displayio_display_obj_get_auto_refresh(mp_obj_t self_in) { displayio_display_obj_t *self = native_display(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_wait_for_frame(self)); + return mp_obj_new_bool(common_hal_displayio_display_get_auto_refresh(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_wait_for_frame_obj, displayio_display_obj_wait_for_frame); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_auto_refresh_obj, displayio_display_obj_get_auto_refresh); + +STATIC mp_obj_t displayio_display_obj_set_auto_refresh(mp_obj_t self_in, mp_obj_t auto_refresh) { + displayio_display_obj_t *self = native_display(self_in); + + common_hal_displayio_display_set_auto_refresh(self, mp_obj_is_true(auto_refresh)); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_auto_refresh_obj, displayio_display_obj_set_auto_refresh); + +const mp_obj_property_t displayio_display_auto_refresh_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_display_get_auto_refresh_obj, + (mp_obj_t)&displayio_display_set_auto_refresh_obj, + (mp_obj_t)&mp_const_none_obj}, +}; //| .. attribute:: brightness //| @@ -442,6 +457,8 @@ STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_wait_for_frame), MP_ROM_PTR(&displayio_display_wait_for_frame_obj) }, { MP_ROM_QSTR(MP_QSTR_fill_row), MP_ROM_PTR(&displayio_display_fill_row_obj) }, + { MP_ROM_QSTR(MP_QSTR_auto_refresh), MP_ROM_PTR(&displayio_display_auto_refresh_obj) }, + { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&displayio_display_brightness_obj) }, { MP_ROM_QSTR(MP_QSTR_auto_brightness), MP_ROM_PTR(&displayio_display_auto_brightness_obj) }, diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index 8df1adc08..0d416b868 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -44,26 +44,16 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, - mp_float_t brightness, bool auto_brightness, + mp_float_t brightness, bool auto_brightness, bool auto_refresh, uint8_t frames_per_second, bool single_byte_bounds, bool data_as_commands); -int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* self); - bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); -void common_hal_displayio_display_refresh_soon(displayio_display_obj_t* self); +void common_hal_displayio_display_refresh(displayio_display_obj_t* self); bool displayio_display_begin_transaction(displayio_display_obj_t* self); void displayio_display_end_transaction(displayio_display_obj_t* self); -// The second point of the region is exclusive. -void displayio_display_set_region_to_update(displayio_display_obj_t* self, displayio_area_t* area); -bool displayio_display_frame_queued(displayio_display_obj_t* self); - -bool displayio_display_refresh_queued(displayio_display_obj_t* self); -void displayio_display_finish_refresh(displayio_display_obj_t* self); -void displayio_display_send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length); - bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self); void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness); diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index d13d07e4a..4b00240d1 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -51,7 +51,7 @@ //| Most people should not use this class directly. Use a specific display driver instead that will //| contain the startup and shutdown sequences at minimum. //| -//| .. class:: EPaperDisplay(display_bus, start_sequence, stop_sequence, *, width, height, ram_width, ram_height, colstart=0, rowstart=0, rotation=0, set_column_window_command=None, set_row_window_command=None, single_byte_bounds=False, write_black_ram_command, black_bits_inverted=False, write_color_ram_command=None, color_bits_inverted=False, refresh_display_command, busy_pin=None, busy_state=True, seconds_per_frame=180, always_toggle_chip_select=False) +//| .. class:: EPaperDisplay(display_bus, start_sequence, stop_sequence, *, width, height, ram_width, ram_height, colstart=0, rowstart=0, rotation=0, set_column_window_command=None, set_row_window_command=None, single_byte_bounds=False, write_black_ram_command, black_bits_inverted=False, write_color_ram_command=None, color_bits_inverted=False, highlight_color=0x000000, refresh_display_command, busy_pin=None, busy_state=True, seconds_per_frame=180, always_toggle_chip_select=False) //| //| Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| @@ -81,7 +81,7 @@ //| :param bool black_bits_inverted: True if 0 bits are used to show black pixels. Otherwise, 1 means to show black. //| :param int write_color_ram_command: Command used to write pixels values into the update region //| :param bool color_bits_inverted: True if 0 bits are used to show the color. Otherwise, 1 means to show color. -//| :param int third_color: Color of third ePaper color in RGB888. +//| :param int highlight_color: RGB888 of source color to highlight with third ePaper color. //| :param int refresh_display_command: Command used to start a display refresh //| :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 @@ -89,7 +89,7 @@ //| :param bool always_toggle_chip_select: When True, chip select is toggled every byte //| 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_third_color, ARG_refresh_display_command, 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_busy_pin, ARG_busy_state, ARG_seconds_per_frame, ARG_always_toggle_chip_select }; 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 }, @@ -109,7 +109,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size { MP_QSTR_black_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_write_color_ram_command, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, { MP_QSTR_color_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - { MP_QSTR_third_color, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x000000} }, + { MP_QSTR_highlight_color, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x000000} }, { MP_QSTR_refresh_display_command, MP_ARG_INT | MP_ARG_REQUIRED }, { MP_QSTR_busy_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, { MP_QSTR_busy_state, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, @@ -155,7 +155,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size mp_float_t seconds_per_frame = mp_obj_get_float(args[ARG_seconds_per_frame].u_obj); mp_int_t write_color_ram_command = NO_COMMAND; - mp_int_t third_color = args[ARG_third_color].u_int; + mp_int_t highlight_color = args[ARG_highlight_color].u_int; if (args[ARG_write_color_ram_command].u_obj != mp_const_none) { write_color_ram_command = mp_obj_get_int(args[ARG_write_color_ram_command].u_obj); } @@ -168,7 +168,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size 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, third_color, args[ARG_refresh_display_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, busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame, args[ARG_always_toggle_chip_select].u_bool ); @@ -203,27 +203,38 @@ STATIC mp_obj_t displayio_epaperdisplay_obj_show(mp_obj_t self_in, mp_obj_t grou } MP_DEFINE_CONST_FUN_OBJ_2(displayio_epaperdisplay_show_obj, displayio_epaperdisplay_obj_show); -//| .. method:: refresh_soon() +//| .. method:: refresh() //| -//| Queues up a display refresh that happens in the background. +//| Refreshes the display immediately or raises an exception if too soon. Use +//| ``time.sleep(display.time_to_refresh)`` to sleep until a refresh can occur. //| STATIC mp_obj_t displayio_epaperdisplay_obj_refresh_soon(mp_obj_t self_in) { displayio_epaperdisplay_obj_t *self = native_display(self_in); - common_hal_displayio_epaperdisplay_refresh_soon(self); + bool ok = common_hal_displayio_epaperdisplay_refresh(self); + if (!ok) { + mp_raise_RuntimeError(translate("Refresh too soon")); + } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_refresh_soon_obj, displayio_epaperdisplay_obj_refresh_soon); -//| .. method:: wait_for_frame() +//| .. attribute:: time_to_refresh //| -//| Waits until the next frame has been transmitted to the display unless the wait count is -//| behind the rendered frames. In that case, this will return immediately with the wait count. +//| Time, in fractional seconds, until the ePaper display can be refreshed. //| -STATIC mp_obj_t displayio_epaperdisplay_obj_wait_for_frame(mp_obj_t self_in) { +//| +STATIC mp_obj_t displayio_epaperdisplay_obj_get_time_to_refresh(mp_obj_t self_in) { displayio_epaperdisplay_obj_t *self = native_display(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_wait_for_frame(self)); + return mp_obj_new_float(common_hal_displayio_epaperdisplay_get_time_to_refresh(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_wait_for_frame_obj, displayio_epaperdisplay_obj_wait_for_frame); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_time_to_refresh_obj, displayio_epaperdisplay_obj_get_time_to_refresh); + +const mp_obj_property_t displayio_epaperdisplay_time_to_refresh_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_time_to_refresh_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; //| .. attribute:: width //| @@ -282,12 +293,12 @@ const mp_obj_property_t displayio_epaperdisplay_bus_obj = { STATIC const mp_rom_map_elem_t displayio_epaperdisplay_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_epaperdisplay_show_obj) }, - { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_epaperdisplay_refresh_soon_obj) }, - { MP_ROM_QSTR(MP_QSTR_wait_for_frame), MP_ROM_PTR(&displayio_epaperdisplay_wait_for_frame_obj) }, + { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_epaperdisplay_refresh_obj) }, { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_epaperdisplay_width_obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_epaperdisplay_height_obj) }, { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_epaperdisplay_bus_obj) }, + { MP_ROM_QSTR(MP_QSTR_time_to_refresh), MP_ROM_PTR(&displayio_epaperdisplay_time_to_refresh_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_epaperdisplay_locals_dict, displayio_epaperdisplay_locals_dict_table); diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index 3deeef959..87feb4da0 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -43,23 +43,24 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, 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 third_color, uint16_t refresh_display_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, const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select); int32_t common_hal_displayio_epaperdisplay_wait_for_frame(displayio_epaperdisplay_obj_t* self); bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self, displayio_group_t* root_group); -void common_hal_displayio_epaperdisplay_refresh_soon(displayio_epaperdisplay_obj_t* self); - bool displayio_epaperdisplay_begin_transaction(displayio_epaperdisplay_obj_t* self); void displayio_epaperdisplay_end_transaction(displayio_epaperdisplay_obj_t* self); +bool displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self); + +mp_float_t displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self); + // The second point of the region is exclusive. void displayio_epaperdisplay_set_region_to_update(displayio_epaperdisplay_obj_t* self, displayio_area_t* area); bool displayio_epaperdisplay_frame_queued(displayio_epaperdisplay_obj_t* self); -bool displayio_epaperdisplay_refresh_queued(displayio_epaperdisplay_obj_t* self); void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self); void displayio_epaperdisplay_send_pixels(displayio_epaperdisplay_obj_t* self, uint8_t* pixels, uint32_t length); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 97a18740a..fafb35f43 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -221,10 +221,6 @@ bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_ return true; } -void common_hal_displayio_display_refresh_soon(displayio_display_obj_t* self) { - self->refresh = true; -} - const displayio_area_t* displayio_display_get_refresh_areas(displayio_display_obj_t *self) { if (self->full_refresh) { self->area.next = NULL; @@ -246,6 +242,118 @@ int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* sel return 0; } +STATIC bool refresh_area(displayio_display_obj_t* display, const displayio_area_t* area) { + uint16_t buffer_size = 128; // In uint32_ts + + displayio_area_t clipped; + // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. + if (!displayio_display_clip_area(display, area, &clipped)) { + return true; + } + uint16_t subrectangles = 1; + uint16_t rows_per_buffer = displayio_area_height(&clipped); + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / display->colorspace.depth; + uint16_t pixels_per_buffer = displayio_area_size(&clipped); + if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { + rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); + if (rows_per_buffer == 0) { + rows_per_buffer = 1; + } + // If pixels are packed by column then ensure rows_per_buffer is on a byte boundary. + if (display->colorspace.depth < 8 && !display->colorspace.pixels_in_byte_share_row) { + uint8_t pixels_per_byte = 8 / display->colorspace.depth; + if (rows_per_buffer % pixels_per_byte != 0) { + rows_per_buffer -= rows_per_buffer % pixels_per_byte; + } + } + subrectangles = displayio_area_height(&clipped) / rows_per_buffer; + if (displayio_area_height(&clipped) % rows_per_buffer != 0) { + subrectangles++; + } + pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); + buffer_size = pixels_per_buffer / pixels_per_word; + if (pixels_per_buffer % pixels_per_word) { + buffer_size += 1; + } + } + + // Allocated and shared as a uint32_t array so the compiler knows the + // alignment everywhere. + uint32_t buffer[buffer_size]; + volatile uint32_t mask_length = (pixels_per_buffer / 32) + 1; + uint32_t mask[mask_length]; + uint16_t remaining_rows = displayio_area_height(&clipped); + + for (uint16_t j = 0; j < subrectangles; j++) { + displayio_area_t subrectangle = { + .x1 = clipped.x1, + .y1 = clipped.y1 + rows_per_buffer * j, + .x2 = clipped.x2, + .y2 = clipped.y1 + rows_per_buffer * (j + 1) + }; + if (remaining_rows < rows_per_buffer) { + subrectangle.y2 = subrectangle.y1 + remaining_rows; + } + remaining_rows -= rows_per_buffer; + + displayio_display_begin_transaction(display); + displayio_display_set_region_to_update(display, &subrectangle); + displayio_display_end_transaction(display); + + uint16_t subrectangle_size_bytes; + if (display->colorspace.depth >= 8) { + subrectangle_size_bytes = displayio_area_size(&subrectangle) * (display->colorspace.depth / 8); + } else { + subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / display->colorspace.depth); + } + + for (uint16_t k = 0; k < mask_length; k++) { + mask[k] = 0x00000000; + } + for (uint16_t k = 0; k < buffer_size; k++) { + buffer[k] = 0x00000000; + } + + displayio_display_fill_area(display, &subrectangle, mask, buffer); + + if (!displayio_display_begin_transaction(display)) { + // Can't acquire display bus; skip the rest of the data. Try next display. + return false; + } + displayio_display_send_pixels(display, (uint8_t*) buffer, subrectangle_size_bytes); + displayio_display_end_transaction(display); + + // TODO(tannewt): Make refresh displays faster so we don't starve other + // background tasks. + usb_background(); + } + return true; +} + +STATIC void refresh_display(displayio_display_obj_t* self) { + if (!displayio_display_begin_transaction(self)) { + // Can't acquire display bus; skip updating this display. Try next display. + continue; + } + displayio_display_end_transaction(self); + displayio_display_start_refresh(self); + const displayio_area_t* current_area = displayio_display_get_refresh_areas(self); + while (current_area != NULL) { + refresh_area(self, current_area); + current_area = current_area->next; + } + displayio_display_finish_refresh(self); +} + +void common_hal_displayio_display_refresh(displayio_display_obj_t* self) { + // Time to refresh at specified frame rate? + while (!displayio_display_frame_queued(self)) { + // Too soon. Try next display. + continue; + } + refresh_display(self); +} + bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self) { return self->auto_brightness; } @@ -411,6 +519,14 @@ void displayio_display_update_backlight(displayio_display_obj_t* self) { self->last_backlight_refresh = ticks_ms; } +void displayio_display_background(displayio_display_obj_t* self) { + displayio_display_update_backlight(self); + + if (self->auto_refresh && (ticks_ms - self->last_refresh) > 16) { + display_refresh(self); + } +} + void release_display(displayio_display_obj_t* self) { if (self->current_group != NULL) { self->current_group->in_group = false; diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index c85d69b0e..db0a23012 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -63,7 +63,7 @@ typedef struct { uint8_t set_column_command; uint8_t set_row_command; uint8_t write_ram_command; - bool refresh; + bool auto_refresh; bool single_byte_bounds; bool data_as_commands; bool auto_brightness; @@ -71,11 +71,7 @@ typedef struct { bool full_refresh; // New group means we need to refresh the whole display. } displayio_display_obj_t; -void displayio_display_start_refresh(displayio_display_obj_t* self); -const displayio_area_t* displayio_display_get_refresh_areas(displayio_display_obj_t *self); -bool displayio_display_fill_area(displayio_display_obj_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer); -void displayio_display_update_backlight(displayio_display_obj_t* self); -bool displayio_display_clip_area(displayio_display_obj_t *self, const displayio_area_t* area, displayio_area_t* clipped); +void displayio_display_background(displayio_display_obj_t* self); void release_display(displayio_display_obj_t* self); #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_H diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 5e4bdc340..434adbdf4 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -48,7 +48,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* int16_t colstart, int16_t rowstart, uint16_t rotation, 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 third_color, uint16_t refresh_display_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, const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select) { self->colorspace.depth = 1; self->colorspace.grayscale = true; @@ -56,10 +56,10 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->colorspace.bytes_per_cell = 1; self->colorspace.reverse_pixels_in_byte = true; - if (third_color != 0x000000) { + if (highlight_color != 0x000000) { self->colorspace.tricolor = true; - self->colorspace.tricolor_hue = displayio_colorconverter_compute_hue(third_color); - self->colorspace.tricolor_luma = displayio_colorconverter_compute_luma(third_color); + self->colorspace.tricolor_hue = displayio_colorconverter_compute_hue(highlight_color); + self->colorspace.tricolor_luma = displayio_colorconverter_compute_luma(highlight_color); } self->set_column_window_command = set_column_window_command; @@ -174,6 +174,11 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* never_reset_pin_number(busy_pin->number); } + // Clear the color memory if it isn't in use. + if (highlight_color == 0x00 && write_color_ram_command != NO_COMMAND) { + // TODO: Clear + } + // Set the group after initialization otherwise we may send pixels while we delay in // initialization. common_hal_displayio_epaperdisplay_show(self, &circuitpython_splash); @@ -198,14 +203,9 @@ bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self self->current_group = root_group; } self->full_refresh = true; - common_hal_displayio_epaperdisplay_refresh_soon(self); return true; } -void common_hal_displayio_epaperdisplay_refresh_soon(displayio_epaperdisplay_obj_t* self) { - self->refresh = true; -} - const displayio_area_t* displayio_epaperdisplay_get_refresh_areas(displayio_epaperdisplay_obj_t *self) { const displayio_area_t* first_area; if (self->current_group == NULL || self->current_group->base.type != &displayio_group_type) { @@ -359,21 +359,23 @@ void displayio_epaperdisplay_start_refresh(displayio_epaperdisplay_obj_t* self) self->last_refresh = ticks_ms; } -bool displayio_epaperdisplay_frame_queued(displayio_epaperdisplay_obj_t* self) { +void displayio_epaperdisplay_background_task(displayio_epaperdisplay_obj_t* self) { if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) { if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) { self->refreshing = false; // Run stop sequence but don't wait for busy because busy is set when sleeping. send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); - } else { - return false; } } - if (self->current_group == NULL) { - return false; - } +} + +uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self) { // Refresh at seconds per frame rate. - return (ticks_ms - self->last_refresh) > self->milliseconds_per_frame; + uint32_t elapsed_time = ticks_ms - self->last_refresh; + if (elapsed_time > self->milliseconds_per_frame) { + return 0; + } + return self->milliseconds_per_frame - elapsed_time; } void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self) { @@ -394,7 +396,6 @@ void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self) void displayio_epaperdisplay_send_pixels(displayio_epaperdisplay_obj_t* self, uint8_t* pixels, uint32_t length) { } - bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, const displayio_area_t* area) { uint16_t buffer_size = 128; // In uint32_ts @@ -500,6 +501,42 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c return true; } +bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self) { + + if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) { + if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) { + self->refreshing = false; + // Run stop sequence but don't wait for busy because busy is set when sleeping. + send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); + } else { + return false; + } + } + if (self->current_group == NULL) { + return false; + } + // Refresh at seconds per frame rate. + if (ticks_ms - self->last_refresh) > self->milliseconds_per_frame; + + if (displayio_epaperdisplay_get_time_to_refresh(display) > 0) { + return false; + } + if (!displayio_epaperdisplay_bus_free(display)) { + // Can't acquire display bus; skip updating this display. Try next display. + continue; + } + const displayio_area_t* current_area = displayio_epaperdisplay_get_refresh_areas(display); + if (current_area == NULL) { + continue; + } + displayio_epaperdisplay_start_refresh(display); + while (current_area != NULL) { + displayio_epaperdisplay_refresh_area(display, current_area); + current_area = current_area->next; + } + displayio_epaperdisplay_finish_refresh(display); +} + void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { if (self->current_group != NULL) { self->current_group->in_group = false; diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index 737b5987a..cc7db6f6d 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -75,18 +75,12 @@ typedef struct { bool busy_state; bool black_bits_inverted; bool color_bits_inverted; - bool refresh; bool refreshing; bool full_refresh; // New group means we need to refresh the whole display. bool always_toggle_chip_select; } displayio_epaperdisplay_obj_t; -bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* display, const displayio_area_t* area); -void displayio_epaperdisplay_start_refresh(displayio_epaperdisplay_obj_t* self); -const displayio_area_t* displayio_epaperdisplay_get_refresh_areas(displayio_epaperdisplay_obj_t *self); -bool displayio_epaperdisplay_fill_area(displayio_epaperdisplay_obj_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer); -bool displayio_epaperdisplay_clip_area(displayio_epaperdisplay_obj_t *self, const displayio_area_t* area, displayio_area_t* clipped); -bool displayio_epaperdisplay_bus_free(displayio_epaperdisplay_obj_t *self); +void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self); void release_epaperdisplay(displayio_epaperdisplay_obj_t* self); #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_EPAPERDISPLAY_H diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index a8f888654..0ebed58c2 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -19,100 +19,11 @@ #include "supervisor/usb.h" primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; -uint32_t frame_count = 0; -bool refresh_area(displayio_display_obj_t* display, const displayio_area_t* area) { - uint16_t buffer_size = 128; // In uint32_ts +// Check for recursive calls to displayio_background. +bool displayio_background_in_progress = false; - displayio_area_t clipped; - // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. - if (!displayio_display_clip_area(display, area, &clipped)) { - return true; - } - uint16_t subrectangles = 1; - uint16_t rows_per_buffer = displayio_area_height(&clipped); - uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / display->colorspace.depth; - uint16_t pixels_per_buffer = displayio_area_size(&clipped); - if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { - rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); - if (rows_per_buffer == 0) { - rows_per_buffer = 1; - } - // If pixels are packed by column then ensure rows_per_buffer is on a byte boundary. - if (display->colorspace.depth < 8 && !display->colorspace.pixels_in_byte_share_row) { - uint8_t pixels_per_byte = 8 / display->colorspace.depth; - if (rows_per_buffer % pixels_per_byte != 0) { - rows_per_buffer -= rows_per_buffer % pixels_per_byte; - } - } - subrectangles = displayio_area_height(&clipped) / rows_per_buffer; - if (displayio_area_height(&clipped) % rows_per_buffer != 0) { - subrectangles++; - } - pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); - buffer_size = pixels_per_buffer / pixels_per_word; - if (pixels_per_buffer % pixels_per_word) { - buffer_size += 1; - } - } - - // Allocated and shared as a uint32_t array so the compiler knows the - // alignment everywhere. - uint32_t buffer[buffer_size]; - volatile uint32_t mask_length = (pixels_per_buffer / 32) + 1; - uint32_t mask[mask_length]; - uint16_t remaining_rows = displayio_area_height(&clipped); - - for (uint16_t j = 0; j < subrectangles; j++) { - displayio_area_t subrectangle = { - .x1 = clipped.x1, - .y1 = clipped.y1 + rows_per_buffer * j, - .x2 = clipped.x2, - .y2 = clipped.y1 + rows_per_buffer * (j + 1) - }; - if (remaining_rows < rows_per_buffer) { - subrectangle.y2 = subrectangle.y1 + remaining_rows; - } - remaining_rows -= rows_per_buffer; - - displayio_display_begin_transaction(display); - displayio_display_set_region_to_update(display, &subrectangle); - displayio_display_end_transaction(display); - - uint16_t subrectangle_size_bytes; - if (display->colorspace.depth >= 8) { - subrectangle_size_bytes = displayio_area_size(&subrectangle) * (display->colorspace.depth / 8); - } else { - subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / display->colorspace.depth); - } - - for (uint16_t k = 0; k < mask_length; k++) { - mask[k] = 0x00000000; - } - for (uint16_t k = 0; k < buffer_size; k++) { - buffer[k] = 0x00000000; - } - - displayio_display_fill_area(display, &subrectangle, mask, buffer); - - if (!displayio_display_begin_transaction(display)) { - // Can't acquire display bus; skip the rest of the data. Try next display. - return false; - } - displayio_display_send_pixels(display, (uint8_t*) buffer, subrectangle_size_bytes); - displayio_display_end_transaction(display); - - // TODO(tannewt): Make refresh displays faster so we don't starve other - // background tasks. - usb_background(); - } - return true; -} - -// Check for recursive calls to displayio_refresh_displays. -bool refresh_displays_in_progress = false; - -void displayio_refresh_displays(void) { +void displayio_background(void) { if (mp_hal_is_interrupted()) { return; } @@ -121,12 +32,12 @@ void displayio_refresh_displays(void) { return; } - if (refresh_displays_in_progress) { + if (displayio_background_in_progress) { // Don't allow recursive calls to this routine. return; } - refresh_displays_in_progress = true; + displayio_background_in_progress = true; for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { if (displays[i].display.base.type == NULL || displays[i].display.base.type == &mp_type_NoneType) { @@ -134,54 +45,14 @@ void displayio_refresh_displays(void) { continue; } if (displays[i].display.base.type == &displayio_display_type) { - displayio_display_obj_t* display = &displays[i].display; - displayio_display_update_backlight(display); - - // Time to refresh at specified frame rate? - if (!displayio_display_frame_queued(display)) { - // Too soon. Try next display. - continue; - } - if (!displayio_display_begin_transaction(display)) { - // Can't acquire display bus; skip updating this display. Try next display. - continue; - } - displayio_display_end_transaction(display); - displayio_display_start_refresh(display); - const displayio_area_t* current_area = displayio_display_get_refresh_areas(display); - while (current_area != NULL) { - refresh_area(display, current_area); - current_area = current_area->next; - } - displayio_display_finish_refresh(display); - } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { - displayio_epaperdisplay_obj_t* display = &displays[i].epaper_display; - // Time to refresh at specified frame rate? - if (!displayio_epaperdisplay_frame_queued(display)) { - // Too soon. Try next display. - continue; - } - if (!displayio_epaperdisplay_bus_free(display)) { - // Can't acquire display bus; skip updating this display. Try next display. - continue; - } - const displayio_area_t* current_area = displayio_epaperdisplay_get_refresh_areas(display); - if (current_area == NULL) { - continue; - } - displayio_epaperdisplay_start_refresh(display); - while (current_area != NULL) { - displayio_epaperdisplay_refresh_area(display, current_area); - current_area = current_area->next; - } - displayio_epaperdisplay_finish_refresh(display); + displayio_display_background(&displays[i].display); + } else if (displays[i].epaperdisplay.base.type == &displayio_epaperdisplay_type) { + displayio_epaperdisplay_background(&displays[i].epaperdisplay); } - - frame_count++; } // All done. - refresh_displays_in_progress = false; + displayio_background_in_progress = false; } void common_hal_displayio_release_displays(void) { @@ -245,7 +116,7 @@ void reset_displays(void) { ((uint32_t) i2c->bus) > ((uint32_t) &displays + CIRCUITPY_DISPLAY_LIMIT)) { busio_i2c_obj_t* original_i2c = i2c->bus; #if BOARD_I2C - // We don't need to move original_i2c if it is the board.SPI object because it is + // We don't need to move original_i2c if it is the board.I2C object because it is // statically allocated already. (Doing so would also make it impossible to reference in // a subsequent VM run.) if (original_i2c == common_hal_board_get_i2c()) { diff --git a/shared-module/displayio/__init__.h b/shared-module/displayio/__init__.h index 95eefbdd9..e78bc61ce 100644 --- a/shared-module/displayio/__init__.h +++ b/shared-module/displayio/__init__.h @@ -50,7 +50,7 @@ extern primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; extern displayio_group_t circuitpython_splash; -void displayio_refresh_displays(void); +void displayio_background(void); void reset_displays(void); void displayio_gc_collect(void); From 36a23e0fe3914b43645e51bf23a4d8bfec2db2c9 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 16 Aug 2019 18:34:00 -0700 Subject: [PATCH 05/18] Rework refresh API and factor common display stuff out NOT TESTED! Just compiles Fixes #1691 --- ports/atmel-samd/Makefile | 3 +- .../boards/hallowing_m0_express/board.c | 4 +- ports/atmel-samd/boards/pybadge/board.c | 4 +- .../atmel-samd/boards/pybadge_airlift/board.c | 4 +- ports/atmel-samd/boards/pygamer/board.c | 4 +- .../atmel-samd/boards/pygamer_advance/board.c | 4 +- ports/atmel-samd/boards/pyportal/board.c | 4 +- .../atmel-samd/boards/pyportal_titano/board.c | 4 +- ports/nrf/Makefile | 3 +- ports/stm32f4/Makefile | 3 +- py/circuitpy_defns.mk | 6 + shared-bindings/_stage/__init__.c | 10 +- shared-bindings/displayio/Display.c | 54 +- shared-bindings/displayio/Display.h | 23 +- shared-bindings/displayio/EPaperDisplay.c | 10 +- shared-bindings/displayio/EPaperDisplay.h | 19 +- shared-module/_stage/__init__.c | 4 +- shared-module/displayio/Display.c | 479 ++++++------------ shared-module/displayio/Display.h | 27 +- shared-module/displayio/EPaperDisplay.c | 350 +++---------- shared-module/displayio/EPaperDisplay.h | 28 +- shared-module/displayio/__init__.c | 10 +- shared-module/displayio/display_core.c | 309 +++++++++++ shared-module/displayio/display_core.h | 90 ++++ 24 files changed, 726 insertions(+), 730 deletions(-) create mode 100644 shared-module/displayio/display_core.c create mode 100644 shared-module/displayio/display_core.h diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 8e3fe9460..11e6874ed 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -289,7 +289,8 @@ SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ $(addprefix common-hal/, $(SRC_COMMON_HAL)) SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE)) \ - $(addprefix shared-module/, $(SRC_SHARED_MODULE)) + $(addprefix shared-module/, $(SRC_SHARED_MODULE)) \ + $(addprefix shared-module/, $(SRC_SHARED_MODULE_INTERNAL)) SRC_S = supervisor/$(CHIP_FAMILY)_cpu.s diff --git a/ports/atmel-samd/boards/hallowing_m0_express/board.c b/ports/atmel-samd/boards/hallowing_m0_express/board.c index c12431f8b..b4c54062f 100644 --- a/ports/atmel-samd/boards/hallowing_m0_express/board.c +++ b/ports/atmel-samd/boards/hallowing_m0_express/board.c @@ -106,7 +106,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pybadge/board.c b/ports/atmel-samd/boards/pybadge/board.c index e30b901b0..37f7991d1 100644 --- a/ports/atmel-samd/boards/pybadge/board.c +++ b/ports/atmel-samd/boards/pybadge/board.c @@ -108,7 +108,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pybadge_airlift/board.c b/ports/atmel-samd/boards/pybadge_airlift/board.c index 38fb33886..7622de6f0 100644 --- a/ports/atmel-samd/boards/pybadge_airlift/board.c +++ b/ports/atmel-samd/boards/pybadge_airlift/board.c @@ -86,7 +86,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pygamer/board.c b/ports/atmel-samd/boards/pygamer/board.c index 5ccf3fc50..b33ae4fb0 100644 --- a/ports/atmel-samd/boards/pygamer/board.c +++ b/ports/atmel-samd/boards/pygamer/board.c @@ -108,7 +108,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pygamer_advance/board.c b/ports/atmel-samd/boards/pygamer_advance/board.c index 72d4dda8d..8eb501243 100644 --- a/ports/atmel-samd/boards/pygamer_advance/board.c +++ b/ports/atmel-samd/boards/pygamer_advance/board.c @@ -86,7 +86,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pyportal/board.c b/ports/atmel-samd/boards/pyportal/board.c index a5de1d145..2a7289778 100644 --- a/ports/atmel-samd/boards/pyportal/board.c +++ b/ports/atmel-samd/boards/pyportal/board.c @@ -98,7 +98,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pyportal_titano/board.c b/ports/atmel-samd/boards/pyportal_titano/board.c index 0ed1010a1..a18bb380b 100644 --- a/ports/atmel-samd/boards/pyportal_titano/board.c +++ b/ports/atmel-samd/boards/pyportal_titano/board.c @@ -118,7 +118,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 9a461f9d8..6ec160088 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -192,7 +192,8 @@ SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ $(addprefix common-hal/, $(SRC_COMMON_HAL)) SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE)) \ - $(addprefix shared-module/, $(SRC_SHARED_MODULE)) + $(addprefix shared-module/, $(SRC_SHARED_MODULE)) \ + $(addprefix shared-module/, $(SRC_SHARED_MODULE_INTERNAL)) SRC_S = supervisor/cpu.s diff --git a/ports/stm32f4/Makefile b/ports/stm32f4/Makefile index 7f0744443..c75a6c7ee 100755 --- a/ports/stm32f4/Makefile +++ b/ports/stm32f4/Makefile @@ -216,7 +216,8 @@ SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ $(addprefix common-hal/, $(SRC_COMMON_HAL)) SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE)) \ - $(addprefix shared-module/, $(SRC_SHARED_MODULE)) + $(addprefix shared-module/, $(SRC_SHARED_MODULE)) \ + $(addprefix shared-module/, $(SRC_SHARED_MODULE_INTERNAL)) diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index d0f0cf7dc..e7b917512 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -364,6 +364,12 @@ SRC_SHARED_MODULE_ALL += \ touchio/__init__.c endif +# All possible sources are listed here, and are filtered by SRC_PATTERNS. +SRC_SHARED_MODULE_INTERNAL = \ +$(filter $(SRC_PATTERNS), \ + displayio/display_core.c \ +) + ifeq ($(INTERNAL_LIBM),1) SRC_LIBM = \ $(addprefix lib/,\ diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c index 6096f6b6d..1d970cce4 100644 --- a/shared-bindings/_stage/__init__.c +++ b/shared-bindings/_stage/__init__.c @@ -30,6 +30,7 @@ #include "shared-bindings/busio/SPI.h" #include "shared-bindings/displayio/Display.h" #include "shared-module/_stage/__init__.h" +#include "shared-module/displayio/display_core.h" #include "Layer.h" #include "Text.h" @@ -95,7 +96,8 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { scale = mp_obj_get_int(args[7]); } - while (!displayio_display_begin_transaction(display)) { + // TODO: Everything below should be in shared-module because it's not argument parsing. + while (!displayio_display_core_begin_transaction(&display->core)) { RUN_BACKGROUND_TASKS; } displayio_area_t area; @@ -103,12 +105,12 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { area.y1 = y0; area.x2 = x1; area.y2 = y1; - displayio_display_set_region_to_update(display, &area); + displayio_display_core_set_region_to_update(&display->core, display->set_column_command, display->set_row_command, NO_COMMAND, NO_COMMAND, display->data_as_commands, false, &area); - display->send(display->bus, true, &display->write_ram_command, 1); + display->core.send(display->core.bus, true, true, &display->write_ram_command, 1); render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size, display, scale); - displayio_display_end_transaction(display); + displayio_display_core_end_transaction(&display->core); return mp_const_none; } diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index fb9bfff85..ded4119ca 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -51,7 +51,7 @@ //| Most people should not use this class directly. Use a specific display driver instead that will //| contain the initialization sequence at minimum. //| -//| .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, grayscale=False, pixels_in_byte_share_row=True, bytes_per_cell=1, reverse_pixels_in_byte=False, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness_command=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False) +//| .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, grayscale=False, pixels_in_byte_share_row=True, bytes_per_cell=1, reverse_pixels_in_byte=False, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness_command=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False, auto_refresh=True, native_frames_per_second=60) //| //| Create a Display object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| @@ -102,9 +102,11 @@ //| :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism. //| :param bool single_byte_bounds: Display column and row commands use single bytes //| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this. +//| :param bool auto_refresh: Automatically refresh the screen +//| :param int native_frames_per_second: Number of display refreshes per second that occur with the given init_sequence. //| STATIC mp_obj_t displayio_display_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_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands }; + enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, ARG_auto_refresh, ARG_native_frames_per_second }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -128,6 +130,8 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a { MP_QSTR_auto_brightness, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_single_byte_bounds, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_data_as_commands, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_auto_refresh, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_native_frames_per_second, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 60} }, }; 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); @@ -178,7 +182,9 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a brightness, args[ARG_auto_brightness].u_bool, args[ARG_single_byte_bounds].u_bool, - args[ARG_data_as_commands].u_bool + args[ARG_data_as_commands].u_bool, + args[ARG_auto_refresh].u_bool, + args[ARG_native_frames_per_second].u_int ); return self; @@ -214,14 +220,28 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| .. method:: refresh(*, target_frames_per_second=None, minimum_frames_per_second=1) //| -//| Waits for the target frame rate and then refreshes the display. If the call is too late for the given target frame rate, then the refresh returns immediately without updating the screen to hopefully help getting caught up. If the current frame rate is below the minimum frame rate, then an exception will be raised. +//| When auto refresh is off, waits for the target frame rate and then refreshes the display. If +//| the call is too late for the given target frame rate, then the refresh returns immediately +//| without updating the screen to hopefully help getting caught up. If the current frame rate +//| is below the minimum frame rate, then an exception will be raised. //| -STATIC mp_obj_t displayio_display_obj_refresh(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - common_hal_displayio_display_refresh(self); +//| When auto refresh is on, updates the display immediately. (The display will also update +//| without calls to this.) +//| +STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_target_frames_per_second, ARG_minimum_frames_per_second }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_target_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 60} }, + { MP_QSTR_minimum_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + displayio_display_obj_t *self = native_display(pos_args[0]); + common_hal_displayio_display_refresh(self, 1000 / args[ARG_target_frames_per_second].u_int, 1000 / args[ARG_minimum_frames_per_second].u_int); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_refresh_soon_obj, displayio_display_obj_refresh_soon); +MP_DEFINE_CONST_FUN_OBJ_KW(displayio_display_refresh_obj, 1, displayio_display_obj_refresh); //| .. attribute:: auto_refresh //| @@ -376,7 +396,7 @@ const mp_obj_property_t displayio_display_rotation_obj = { //| STATIC mp_obj_t displayio_display_obj_get_bus(mp_obj_t self_in) { displayio_display_obj_t *self = native_display(self_in); - return self->bus; + return common_hal_displayio_display_get_bus(self); } MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_bus_obj, displayio_display_obj_get_bus); @@ -412,18 +432,18 @@ STATIC mp_obj_t displayio_display_obj_fill_row(size_t n_args, const mp_obj_t *po if (bufinfo.typecode != BYTEARRAY_TYPECODE) { mp_raise_ValueError(translate("Buffer is not a bytearray.")); } - if (self->colorspace.depth != 16) { + if (self->core.colorspace.depth != 16) { mp_raise_ValueError(translate("Display must have a 16 bit colorspace.")); } displayio_area_t area = { .x1 = 0, .y1 = y, - .x2 = self->width, + .x2 = self->core.width, .y2 = y + 1 }; - uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->colorspace.depth; - uint16_t buffer_size = self->width / pixels_per_word; + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; + uint16_t buffer_size = self->core.width / pixels_per_word; uint16_t pixels_per_buffer = displayio_area_size(&area); if (pixels_per_buffer % pixels_per_word) { buffer_size += 1; @@ -440,7 +460,7 @@ STATIC mp_obj_t displayio_display_obj_fill_row(size_t n_args, const mp_obj_t *po mask[k] = 0x00000000; } - displayio_display_fill_area(self, &area, mask, result_buffer); + displayio_display_core_fill_area(&self->core, &area, mask, result_buffer); return result; } else { mp_raise_ValueError(translate("Buffer is too small")); @@ -448,13 +468,9 @@ STATIC mp_obj_t displayio_display_obj_fill_row(size_t n_args, const mp_obj_t *po } MP_DEFINE_CONST_FUN_OBJ_KW(displayio_display_fill_row_obj, 1, displayio_display_obj_fill_row); - - - STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_display_show_obj) }, - { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_display_refresh_soon_obj) }, - { MP_ROM_QSTR(MP_QSTR_wait_for_frame), MP_ROM_PTR(&displayio_display_wait_for_frame_obj) }, + { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&displayio_display_refresh_obj) }, { MP_ROM_QSTR(MP_QSTR_fill_row), MP_ROM_PTR(&displayio_display_fill_row_obj) }, { MP_ROM_QSTR(MP_QSTR_auto_refresh), MP_ROM_PTR(&displayio_display_auto_refresh_obj) }, diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index 0d416b868..06c848d0d 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -44,24 +44,29 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, - mp_float_t brightness, bool auto_brightness, bool auto_refresh, uint8_t frames_per_second, - bool single_byte_bounds, bool data_as_commands); + mp_float_t brightness, bool auto_brightness, + bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second); -bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); +bool common_hal_displayio_display_show(displayio_display_obj_t* self, + displayio_group_t* root_group); -void common_hal_displayio_display_refresh(displayio_display_obj_t* self); +// Times in ms. +void common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_frame_time, uint32_t maximum_frame_time); -bool displayio_display_begin_transaction(displayio_display_obj_t* self); -void displayio_display_end_transaction(displayio_display_obj_t* self); - -bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self); -void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness); +bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self); +void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t* self, bool auto_refresh); uint16_t common_hal_displayio_display_get_width(displayio_display_obj_t* self); uint16_t common_hal_displayio_display_get_height(displayio_display_obj_t* self); uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self); +bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self); +void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness); + mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self); bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness); +mp_obj_t common_hal_displayio_display_get_bus(displayio_display_obj_t* self); + + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_DISPLAY_H diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index 4b00240d1..8f3c16efd 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -208,7 +208,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_epaperdisplay_show_obj, displayio_epaperdisp //| Refreshes the display immediately or raises an exception if too soon. Use //| ``time.sleep(display.time_to_refresh)`` to sleep until a refresh can occur. //| -STATIC mp_obj_t displayio_epaperdisplay_obj_refresh_soon(mp_obj_t self_in) { +STATIC mp_obj_t displayio_epaperdisplay_obj_refresh(mp_obj_t self_in) { displayio_epaperdisplay_obj_t *self = native_display(self_in); bool ok = common_hal_displayio_epaperdisplay_refresh(self); if (!ok) { @@ -216,7 +216,7 @@ STATIC mp_obj_t displayio_epaperdisplay_obj_refresh_soon(mp_obj_t self_in) { } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_refresh_soon_obj, displayio_epaperdisplay_obj_refresh_soon); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_refresh_obj, displayio_epaperdisplay_obj_refresh); //| .. attribute:: time_to_refresh //| @@ -225,7 +225,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_refresh_soon_obj, displayio_ep //| STATIC mp_obj_t displayio_epaperdisplay_obj_get_time_to_refresh(mp_obj_t self_in) { displayio_epaperdisplay_obj_t *self = native_display(self_in); - return mp_obj_new_float(common_hal_displayio_epaperdisplay_get_time_to_refresh(self)); + return mp_obj_new_float(common_hal_displayio_epaperdisplay_get_time_to_refresh(self) / 1000.0); } MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_time_to_refresh_obj, displayio_epaperdisplay_obj_get_time_to_refresh); @@ -279,7 +279,7 @@ const mp_obj_property_t displayio_epaperdisplay_height_obj = { //| STATIC mp_obj_t displayio_epaperdisplay_obj_get_bus(mp_obj_t self_in) { displayio_epaperdisplay_obj_t *self = native_display(self_in); - return self->bus; + return common_hal_displayio_epaperdisplay_get_bus(self); } MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_bus_obj, displayio_epaperdisplay_obj_get_bus); @@ -293,7 +293,7 @@ const mp_obj_property_t displayio_epaperdisplay_bus_obj = { STATIC const mp_rom_map_elem_t displayio_epaperdisplay_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_epaperdisplay_show_obj) }, - { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_epaperdisplay_refresh_obj) }, + { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&displayio_epaperdisplay_refresh_obj) }, { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_epaperdisplay_width_obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_epaperdisplay_height_obj) }, diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index 87feb4da0..2a3cb921f 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -46,23 +46,12 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* 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, const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select); -int32_t common_hal_displayio_epaperdisplay_wait_for_frame(displayio_epaperdisplay_obj_t* self); +bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self); bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self, displayio_group_t* root_group); -bool displayio_epaperdisplay_begin_transaction(displayio_epaperdisplay_obj_t* self); -void displayio_epaperdisplay_end_transaction(displayio_epaperdisplay_obj_t* self); - -bool displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self); - -mp_float_t displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self); - -// The second point of the region is exclusive. -void displayio_epaperdisplay_set_region_to_update(displayio_epaperdisplay_obj_t* self, displayio_area_t* area); -bool displayio_epaperdisplay_frame_queued(displayio_epaperdisplay_obj_t* self); - -void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self); -void displayio_epaperdisplay_send_pixels(displayio_epaperdisplay_obj_t* self, uint8_t* pixels, uint32_t length); +// Returns time in milliseconds. +uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self); bool common_hal_displayio_epaperdisplay_get_auto_brightness(displayio_epaperdisplay_obj_t* self); void common_hal_displayio_epaperdisplay_set_auto_brightness(displayio_epaperdisplay_obj_t* self, bool auto_brightness); @@ -73,4 +62,6 @@ uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_o mp_float_t common_hal_displayio_epaperdisplay_get_brightness(displayio_epaperdisplay_obj_t* self); bool common_hal_displayio_epaperdisplay_set_brightness(displayio_epaperdisplay_obj_t* self, mp_float_t brightness); +mp_obj_t common_hal_displayio_epaperdisplay_get_bus(displayio_epaperdisplay_obj_t* self); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H diff --git a/shared-module/_stage/__init__.c b/shared-module/_stage/__init__.c index ca71b758e..bfef165e7 100644 --- a/shared-module/_stage/__init__.c +++ b/shared-module/_stage/__init__.c @@ -57,7 +57,7 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, index += 1; // The buffer is full, send it. if (index >= buffer_size) { - display->send(display->bus, false, ((uint8_t*)buffer), + display->core.send(display->core.bus, false, false, ((uint8_t*)buffer), buffer_size * 2); index = 0; } @@ -67,6 +67,6 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, } // Send the remaining data. if (index) { - display->send(display->bus, false, ((uint8_t*)buffer), index * 2); + display->core.send(display->core.bus, false, false, ((uint8_t*)buffer), index * 2); } } diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index fafb35f43..86800328f 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -33,7 +33,9 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/time/__init__.h" #include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/display_core.h" #include "supervisor/shared/display.h" +#include "supervisor/usb.h" #include #include @@ -41,48 +43,34 @@ #include "tick.h" void common_hal_displayio_display_construct(displayio_display_obj_t* self, - mp_obj_t bus, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart, uint16_t rotation, - uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, - uint8_t set_column_command, uint8_t set_row_command, - uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, - const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, - bool single_byte_bounds, bool data_as_commands) { - self->colorspace.depth = color_depth; - self->colorspace.grayscale = grayscale; - 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; + mp_obj_t bus, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart, + uint16_t rotation, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, + uint8_t bytes_per_cell, bool reverse_pixels_in_byte, uint8_t set_column_command, + uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, + uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, + uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, + bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second) { + uint16_t ram_width = 0x100; + uint16_t ram_height = 0x100; + if (single_byte_bounds) { + ram_width = 0xff; + ram_height = 0xff; + } + displayio_display_core_construct(&self->core, bus, width, height, ram_width, ram_height, colstart, rowstart, rotation, + color_depth, grayscale, pixels_in_byte_share_row, bytes_per_cell, reverse_pixels_in_byte); + self->set_column_command = set_column_command; self->set_row_command = set_row_command; self->write_ram_command = write_ram_command; - self->refresh = false; - self->current_group = NULL; - self->colstart = colstart; - self->rowstart = rowstart; self->brightness_command = brightness_command; self->auto_brightness = auto_brightness; self->data_as_commands = data_as_commands; - self->single_byte_bounds = single_byte_bounds; - - if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { - self->begin_transaction = common_hal_displayio_parallelbus_begin_transaction; - self->send = common_hal_displayio_parallelbus_send; - self->end_transaction = common_hal_displayio_parallelbus_end_transaction; - } else if (MP_OBJ_IS_TYPE(bus, &displayio_fourwire_type)) { - self->begin_transaction = common_hal_displayio_fourwire_begin_transaction; - self->send = common_hal_displayio_fourwire_send; - self->end_transaction = common_hal_displayio_fourwire_end_transaction; - } else if (MP_OBJ_IS_TYPE(bus, &displayio_i2cdisplay_type)) { - self->begin_transaction = common_hal_displayio_i2cdisplay_begin_transaction; - self->send = common_hal_displayio_i2cdisplay_send; - self->end_transaction = common_hal_displayio_i2cdisplay_end_transaction; - } else { - mp_raise_ValueError(translate("Unsupported display bus type")); - } - self->bus = bus; + + self->native_frames_per_second = native_frames_per_second; + self->native_frame_time = 1000 / native_frames_per_second; uint32_t i = 0; - while (!self->begin_transaction(self->bus)) { + while (!displayio_display_core_begin_transaction(&self->core)) { RUN_BACKGROUND_TASKS; } while (i < init_sequence_len) { @@ -95,10 +83,10 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t full_command[data_size + 1]; full_command[0] = cmd[0]; memcpy(full_command + 1, data, data_size); - self->send(self->bus, true, true, full_command, data_size + 1); + self->core.send(self->core.bus, true, true, full_command, data_size + 1); } else { - self->send(self->bus, true, true, cmd, 1); - self->send(self->bus, false, false, data, data_size); + self->core.send(self->core.bus, true, true, cmd, 1); + self->core.send(self->core.bus, false, false, data, data_size); } uint16_t delay_length_ms = 10; if (delay) { @@ -111,33 +99,10 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, common_hal_time_delay_ms(delay_length_ms); i += 2 + data_size; } - self->end_transaction(self->bus); + self->core.end_transaction(self->core.bus); supervisor_start_terminal(width, height); - self->width = width; - self->height = height; - self->rotation = rotation % 360; - self->transform.x = 0; - self->transform.y = 0; - self->transform.scale = 1; - self->transform.mirror_x = false; - self->transform.mirror_y = false; - self->transform.transpose_xy = false; - if (rotation == 0 || rotation == 180) { - if (rotation == 180) { - self->transform.mirror_x = true; - self->transform.mirror_y = true; - } - } else { - self->transform.transpose_xy = true; - if (rotation == 270) { - self->transform.mirror_y = true; - } else { - self->transform.mirror_x = true; - } - } - // Always set the backlight type in case we're reusing memory. self->backlight_inout.base.type = &mp_type_NoneType; if (backlight_pin != NULL && common_hal_mcu_pin_is_free(backlight_pin)) { @@ -158,101 +123,98 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->current_brightness = -1.0; } - self->area.x1 = 0; - self->area.y1 = 0; - self->area.next = NULL; - - self->transform.dx = 1; - self->transform.dy = 1; - if (self->transform.transpose_xy) { - self->area.x2 = height; - self->area.y2 = width; - if (self->transform.mirror_x) { - self->transform.x = height; - self->transform.dx = -1; - } - if (self->transform.mirror_y) { - self->transform.y = width; - self->transform.dy = -1; - } - } else { - self->area.x2 = width; - self->area.y2 = height; - if (self->transform.mirror_x) { - self->transform.x = width; - self->transform.dx = -1; - } - if (self->transform.mirror_y) { - self->transform.y = height; - self->transform.dy = -1; - } - } - // Set the group after initialization otherwise we may send pixels while we delay in // initialization. common_hal_displayio_display_show(self, &circuitpython_splash); } bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) { - if (root_group == NULL) { - if (!circuitpython_splash.in_group) { - root_group = &circuitpython_splash; - } else if (self->current_group == &circuitpython_splash) { - return false; + return displayio_display_core_show(&self->core, root_group); +} + +uint16_t common_hal_displayio_display_get_width(displayio_display_obj_t* self){ + return displayio_display_core_get_width(&self->core); +} + +uint16_t common_hal_displayio_display_get_height(displayio_display_obj_t* self){ + return displayio_display_core_get_height(&self->core); +} + +bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self) { + return self->auto_brightness; +} + +void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness) { + self->auto_brightness = auto_brightness; +} + +mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self) { + return self->current_brightness; +} + +bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness) { + self->updating_backlight = true; + bool ok = false; + if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { + common_hal_pulseio_pwmout_set_duty_cycle(&self->backlight_pwm, (uint16_t) (0xffff * brightness)); + ok = true; + } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { + common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, brightness > 0.99); + ok = true; + } else if (self->brightness_command != NO_BRIGHTNESS_COMMAND) { + ok = displayio_display_core_begin_transaction(&self->core); + if (ok) { + if (self->data_as_commands) { + uint8_t set_brightness[2] = {self->brightness_command, (uint8_t) (0xff * brightness)}; + self->core.send(self->core.bus, true, true, set_brightness, 2); + } else { + uint8_t command = self->brightness_command; + uint8_t hex_brightness = 0xff * brightness; + self->core.send(self->core.bus, true, true, &command, 1); + self->core.send(self->core.bus, false, false, &hex_brightness, 1); + } + displayio_display_core_end_transaction(&self->core); } + } - if (root_group == self->current_group) { - return true; - } - if (root_group != NULL && root_group->in_group) { - return false; - } - if (self->current_group != NULL) { - self->current_group->in_group = false; + self->updating_backlight = false; + if (ok) { + self->current_brightness = brightness; } + return ok; +} - if (root_group != NULL) { - displayio_group_update_transform(root_group, &self->transform); - root_group->in_group = true; - } - self->current_group = root_group; - self->full_refresh = true; - common_hal_displayio_display_refresh_soon(self); - return true; +mp_obj_t common_hal_displayio_display_get_bus(displayio_display_obj_t* self) { + return self->core.bus; } -const displayio_area_t* displayio_display_get_refresh_areas(displayio_display_obj_t *self) { - if (self->full_refresh) { - self->area.next = NULL; - return &self->area; +STATIC const displayio_area_t* _get_refresh_areas(displayio_display_obj_t *self) { + if (self->core.full_refresh) { + self->core.area.next = NULL; + return &self->core.area; } else { - if (self->current_group == NULL || self->current_group->base.type != &displayio_group_type) { - asm("bkpt"); - } - return displayio_group_get_refresh_areas(self->current_group, NULL); + return displayio_group_get_refresh_areas(self->core.current_group, NULL); } } -int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* self) { - uint64_t last_refresh = self->last_refresh; - // Don't try to refresh if we got an exception. - while (last_refresh == self->last_refresh && MP_STATE_VM(mp_pending_exception) == NULL) { - RUN_BACKGROUND_TASKS; +STATIC void _send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length) { + if (!self->data_as_commands) { + self->core.send(self->core.bus, true, true, &self->write_ram_command, 1); } - return 0; + self->core.send(self->core.bus, false, false, pixels, length); } -STATIC bool refresh_area(displayio_display_obj_t* display, const displayio_area_t* area) { +STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* area) { uint16_t buffer_size = 128; // In uint32_ts displayio_area_t clipped; // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. - if (!displayio_display_clip_area(display, area, &clipped)) { + if (!displayio_display_core_clip_area(&self->core, area, &clipped)) { return true; } uint16_t subrectangles = 1; uint16_t rows_per_buffer = displayio_area_height(&clipped); - uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / display->colorspace.depth; + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; uint16_t pixels_per_buffer = displayio_area_size(&clipped); if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); @@ -260,8 +222,8 @@ STATIC bool refresh_area(displayio_display_obj_t* display, const displayio_area_ rows_per_buffer = 1; } // If pixels are packed by column then ensure rows_per_buffer is on a byte boundary. - if (display->colorspace.depth < 8 && !display->colorspace.pixels_in_byte_share_row) { - uint8_t pixels_per_byte = 8 / display->colorspace.depth; + if (self->core.colorspace.depth < 8 && !self->core.colorspace.pixels_in_byte_share_row) { + uint8_t pixels_per_byte = 8 / self->core.colorspace.depth; if (rows_per_buffer % pixels_per_byte != 0) { rows_per_buffer -= rows_per_buffer % pixels_per_byte; } @@ -296,15 +258,13 @@ STATIC bool refresh_area(displayio_display_obj_t* display, const displayio_area_ } remaining_rows -= rows_per_buffer; - displayio_display_begin_transaction(display); - displayio_display_set_region_to_update(display, &subrectangle); - displayio_display_end_transaction(display); + displayio_display_core_set_region_to_update(&self->core, self->set_column_command, self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, &subrectangle); uint16_t subrectangle_size_bytes; - if (display->colorspace.depth >= 8) { - subrectangle_size_bytes = displayio_area_size(&subrectangle) * (display->colorspace.depth / 8); + if (self->core.colorspace.depth >= 8) { + subrectangle_size_bytes = displayio_area_size(&subrectangle) * (self->core.colorspace.depth / 8); } else { - subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / display->colorspace.depth); + subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); } for (uint16_t k = 0; k < mask_length; k++) { @@ -314,14 +274,16 @@ STATIC bool refresh_area(displayio_display_obj_t* display, const displayio_area_ buffer[k] = 0x00000000; } - displayio_display_fill_area(display, &subrectangle, mask, buffer); + displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); - if (!displayio_display_begin_transaction(display)) { - // Can't acquire display bus; skip the rest of the data. Try next display. + // Can't acquire display bus; skip the rest of the data. + if (!displayio_display_core_bus_free(&self->core)) { return false; } - displayio_display_send_pixels(display, (uint8_t*) buffer, subrectangle_size_bytes); - displayio_display_end_transaction(display); + + displayio_display_core_begin_transaction(&self->core); + _send_pixels(self, (uint8_t*) buffer, subrectangle_size_bytes); + displayio_display_core_end_transaction(&self->core); // TODO(tannewt): Make refresh displays faster so we don't starve other // background tasks. @@ -330,182 +292,59 @@ STATIC bool refresh_area(displayio_display_obj_t* display, const displayio_area_ return true; } -STATIC void refresh_display(displayio_display_obj_t* self) { - if (!displayio_display_begin_transaction(self)) { +STATIC void _refresh_display(displayio_display_obj_t* self) { + if (!displayio_display_core_bus_free(&self->core)) { // Can't acquire display bus; skip updating this display. Try next display. - continue; + return; } - displayio_display_end_transaction(self); - displayio_display_start_refresh(self); - const displayio_area_t* current_area = displayio_display_get_refresh_areas(self); + displayio_display_core_start_refresh(&self->core); + const displayio_area_t* current_area = _get_refresh_areas(self); while (current_area != NULL) { - refresh_area(self, current_area); + _refresh_area(self, current_area); current_area = current_area->next; } - displayio_display_finish_refresh(self); -} - -void common_hal_displayio_display_refresh(displayio_display_obj_t* self) { - // Time to refresh at specified frame rate? - while (!displayio_display_frame_queued(self)) { - // Too soon. Try next display. - continue; - } - refresh_display(self); -} - -bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self) { - return self->auto_brightness; -} - -uint16_t common_hal_displayio_display_get_width(displayio_display_obj_t* self){ - return self->width; -} - -uint16_t common_hal_displayio_display_get_height(displayio_display_obj_t* self){ - return self->height; + displayio_display_core_finish_refresh(&self->core); } uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self){ - return self->rotation; -} - -void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness) { - self->auto_brightness = auto_brightness; -} - -mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self) { - return self->current_brightness; + return self->core.rotation; } -bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness) { - self->updating_backlight = true; - bool ok = false; - if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { - common_hal_pulseio_pwmout_set_duty_cycle(&self->backlight_pwm, (uint16_t) (0xffff * brightness)); - ok = true; - } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { - common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, brightness > 0.99); - ok = true; - } else if (self->brightness_command != NO_BRIGHTNESS_COMMAND) { - ok = self->begin_transaction(self->bus); - if (ok) { - if (self->data_as_commands) { - uint8_t set_brightness[2] = {self->brightness_command, (uint8_t) (0xff * brightness)}; - self->send(self->bus, true, true, set_brightness, 2); - } else { - uint8_t command = self->brightness_command; - uint8_t hex_brightness = 0xff * brightness; - self->send(self->bus, true, true, &command, 1); - self->send(self->bus, false, false, &hex_brightness, 1); - } - self->end_transaction(self->bus); +void common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_frame_time, uint32_t maximum_frame_time) { + if (!self->auto_refresh) { + uint64_t current_time = ticks_ms; + uint32_t current_frame_time = current_time - self->core.last_refresh; + // Test to see if the real frame time is below our minimum. + if (current_frame_time > maximum_frame_time) { + mp_raise_RuntimeError(translate("Below minimum frame rate")); } - - } - self->updating_backlight = false; - if (ok) { - self->current_brightness = brightness; - } - return ok; -} - -bool displayio_display_begin_transaction(displayio_display_obj_t* self) { - return self->begin_transaction(self->bus); -} - -void displayio_display_end_transaction(displayio_display_obj_t* self) { - self->end_transaction(self->bus); -} - -void displayio_display_set_region_to_update(displayio_display_obj_t* self, displayio_area_t* area) { - uint16_t x1 = area->x1; - uint16_t x2 = area->x2; - uint16_t y1 = area->y1; - uint16_t y2 = area->y2; - // Collapse down the dimension where multiple pixels are in a byte. - if (self->colorspace.depth < 8) { - uint8_t pixels_per_byte = 8 / self->colorspace.depth; - if (self->colorspace.pixels_in_byte_share_row) { - x1 /= pixels_per_byte * self->colorspace.bytes_per_cell; - x2 /= pixels_per_byte * self->colorspace.bytes_per_cell; - } else { - y1 /= pixels_per_byte * self->colorspace.bytes_per_cell; - y2 /= pixels_per_byte * self->colorspace.bytes_per_cell; + uint32_t current_call_time = current_time - self->last_refresh_call; + self->last_refresh_call = current_time; + // Skip the actual refresh to help catch up. + if (current_call_time > target_frame_time) { + return; + } + uint32_t remaining_time = target_frame_time - (current_frame_time % target_frame_time); + // We're ahead of the game so wait until we align with the frame rate. + while (ticks_ms - self->last_refresh_call < remaining_time) { + #ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP ; + #endif } } - - // Set column. - uint8_t data[5]; - data[0] = self->set_column_command; - uint8_t data_length = 1; - if (!self->data_as_commands) { - self->send(self->bus, true, true, data, 1); - data_length = 0; - } - if (self->single_byte_bounds) { - data[data_length++] = x1 + self->colstart; - data[data_length++] = x2 - 1 + self->colstart; - } else { - x1 += self->colstart; - x2 += self->colstart - 1; - data[data_length++] = x1 >> 8; - data[data_length++] = x1 & 0xff; - data[data_length++] = x2 >> 8; - data[data_length++] = x2 & 0xff; - } - self->send(self->bus, self->data_as_commands, self->data_as_commands, data, data_length); - - // Set row. - data[0] = self->set_row_command; - data_length = 1; - if (!self->data_as_commands) { - self->send(self->bus, true, true, data, 1); - data_length = 0; - } - if (self->single_byte_bounds) { - data[data_length++] = y1 + self->rowstart; - data[data_length++] = y2 - 1 + self->rowstart; - } else { - y1 += self->rowstart; - y2 += self->rowstart - 1; - data[data_length++] = y1 >> 8; - data[data_length++] = y1 & 0xff; - data[data_length++] = y2 >> 8; - data[data_length++] = y2 & 0xff; - } - self->send(self->bus, self->data_as_commands, self->data_as_commands, data, data_length); -} - -void displayio_display_start_refresh(displayio_display_obj_t* self) { - self->last_refresh = ticks_ms; -} - -bool displayio_display_frame_queued(displayio_display_obj_t* self) { - if (self->current_group == NULL) { - return false; - } - // Refresh at ~60 fps. - return (ticks_ms - self->last_refresh) > 16; + _refresh_display(self); } -void displayio_display_finish_refresh(displayio_display_obj_t* self) { - if (self->current_group != NULL) { - displayio_group_finish_refresh(self->current_group); - } - self->refresh = false; - self->full_refresh = false; - self->last_refresh = ticks_ms; +bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self) { + return self->auto_refresh; } -void displayio_display_send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length) { - if (!self->data_as_commands) { - self->send(self->bus, true, true, &self->write_ram_command, 1); - } - self->send(self->bus, false, false, pixels, length); +void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t* self, + bool auto_refresh) { + self->auto_refresh = auto_refresh; } -void displayio_display_update_backlight(displayio_display_obj_t* self) { +STATIC void _update_backlight(displayio_display_obj_t* self) { if (!self->auto_brightness || self->updating_backlight) { return; } @@ -520,17 +359,15 @@ void displayio_display_update_backlight(displayio_display_obj_t* self) { } void displayio_display_background(displayio_display_obj_t* self) { - displayio_display_update_backlight(self); + _update_backlight(self); - if (self->auto_refresh && (ticks_ms - self->last_refresh) > 16) { - display_refresh(self); + if (self->auto_refresh && (ticks_ms - self->core.last_refresh) > self->native_frame_time) { + _refresh_display(self); } } void release_display(displayio_display_obj_t* self) { - if (self->current_group != NULL) { - self->current_group->in_group = false; - } + release_display_core(&self->core); if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { common_hal_pulseio_pwmout_reset_ok(&self->backlight_pwm); common_hal_pulseio_pwmout_deinit(&self->backlight_pwm); @@ -539,34 +376,6 @@ void release_display(displayio_display_obj_t* self) { } } -bool displayio_display_fill_area(displayio_display_obj_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer) { - return displayio_group_fill_area(self->current_group, &self->colorspace, area, mask, buffer); -} - -bool displayio_display_clip_area(displayio_display_obj_t *self, const displayio_area_t* area, displayio_area_t* clipped) { - bool overlaps = displayio_area_compute_overlap(&self->area, area, clipped); - if (!overlaps) { - return false; - } - // Expand the area if we have multiple pixels per byte and we need to byte - // align the bounds. - if (self->colorspace.depth < 8) { - uint8_t pixels_per_byte = 8 / self->colorspace.depth * self->colorspace.bytes_per_cell; - if (self->colorspace.pixels_in_byte_share_row) { - if (clipped->x1 % pixels_per_byte != 0) { - clipped->x1 -= clipped->x1 % pixels_per_byte; - } - if (clipped->x2 % pixels_per_byte != 0) { - clipped->x2 += pixels_per_byte - clipped->x2 % pixels_per_byte; - } - } else { - if (clipped->y1 % pixels_per_byte != 0) { - clipped->y1 -= clipped->y1 % pixels_per_byte; - } - if (clipped->y2 % pixels_per_byte != 0) { - clipped->y2 += pixels_per_byte - clipped->y2 % pixels_per_byte; - } - } - } - return true; +void displayio_display_collect_ptrs(displayio_display_obj_t* self) { + displayio_display_core_collect_ptrs(&self->core); } diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index db0a23012..cff566a61 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -32,46 +32,33 @@ #include "shared-bindings/pulseio/PWMOut.h" #include "shared-module/displayio/area.h" - -typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); -typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); -typedef void (*display_bus_end_transaction)(mp_obj_t bus); +#include "shared-module/displayio/display_core.h" typedef struct { mp_obj_base_t base; - mp_obj_t bus; - displayio_group_t *current_group; - uint64_t last_refresh; - display_bus_begin_transaction begin_transaction; - display_bus_send send; - display_bus_end_transaction end_transaction; + displayio_display_core_t core; union { digitalio_digitalinout_obj_t backlight_inout; pulseio_pwmout_obj_t backlight_pwm; }; uint64_t last_backlight_refresh; - displayio_buffer_transform_t transform; - displayio_area_t area; + uint64_t last_refresh_call; mp_float_t current_brightness; - uint16_t width; - uint16_t height; - uint16_t rotation; - _displayio_colorspace_t colorspace; - int16_t colstart; - int16_t rowstart; uint16_t brightness_command; + uint16_t native_frames_per_second; + uint16_t native_frame_time; uint8_t set_column_command; uint8_t set_row_command; uint8_t write_ram_command; bool auto_refresh; - bool single_byte_bounds; bool data_as_commands; bool auto_brightness; bool updating_backlight; - bool full_refresh; // New group means we need to refresh the whole display. } displayio_display_obj_t; void displayio_display_background(displayio_display_obj_t* self); void release_display(displayio_display_obj_t* self); +void displayio_display_collect_ptrs(displayio_display_obj_t* self); + #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_H diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 434adbdf4..6ff060a6a 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -50,18 +50,14 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* 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, const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select) { - self->colorspace.depth = 1; - self->colorspace.grayscale = true; - self->colorspace.pixels_in_byte_share_row = true; - self->colorspace.bytes_per_cell = 1; - self->colorspace.reverse_pixels_in_byte = true; - if (highlight_color != 0x000000) { - self->colorspace.tricolor = true; - self->colorspace.tricolor_hue = displayio_colorconverter_compute_hue(highlight_color); - self->colorspace.tricolor_luma = displayio_colorconverter_compute_luma(highlight_color); + self->core.colorspace.tricolor = true; + self->core.colorspace.tricolor_hue = displayio_colorconverter_compute_hue(highlight_color); + self->core.colorspace.tricolor_luma = displayio_colorconverter_compute_luma(highlight_color); } + displayio_display_core_construct(&self->core, bus, width, height, ram_width, ram_height, colstart, rowstart, rotation, 1, true, true, 1, true); + self->set_column_window_command = set_column_window_command; self->set_row_window_command = set_row_window_command; self->set_current_column_command = set_current_column_command; @@ -72,10 +68,6 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->color_bits_inverted = color_bits_inverted; self->refresh_display_command = refresh_display_command; self->busy_state = busy_state; - self->refresh = true; - self->current_group = NULL; - self->colstart = colstart; - self->rowstart = rowstart; self->refreshing = false; self->milliseconds_per_frame = seconds_per_frame * 1000; self->always_toggle_chip_select = always_toggle_chip_select; @@ -85,88 +77,6 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->stop_sequence = stop_sequence; self->stop_sequence_len = stop_sequence_len; - - if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { - self->bus_reset = common_hal_displayio_parallelbus_reset; - self->bus_free = common_hal_displayio_parallelbus_bus_free; - self->begin_transaction = common_hal_displayio_parallelbus_begin_transaction; - self->send = common_hal_displayio_parallelbus_send; - self->end_transaction = common_hal_displayio_parallelbus_end_transaction; - } else if (MP_OBJ_IS_TYPE(bus, &displayio_fourwire_type)) { - self->bus_reset = common_hal_displayio_fourwire_reset; - self->bus_free = common_hal_displayio_fourwire_bus_free; - self->begin_transaction = common_hal_displayio_fourwire_begin_transaction; - self->send = common_hal_displayio_fourwire_send; - self->end_transaction = common_hal_displayio_fourwire_end_transaction; - } else if (MP_OBJ_IS_TYPE(bus, &displayio_i2cdisplay_type)) { - self->bus_reset = common_hal_displayio_i2cdisplay_reset; - self->bus_free = common_hal_displayio_i2cdisplay_bus_free; - self->begin_transaction = common_hal_displayio_i2cdisplay_begin_transaction; - self->send = common_hal_displayio_i2cdisplay_send; - self->end_transaction = common_hal_displayio_i2cdisplay_end_transaction; - } else { - mp_raise_ValueError(translate("Unsupported display bus type")); - } - self->bus = bus; - - supervisor_start_terminal(width, height); - - self->width = width; - self->height = height; - rotation = rotation % 360; - self->transform.x = 0; - self->transform.y = 0; - self->transform.scale = 1; - self->transform.mirror_x = false; - self->transform.mirror_y = false; - self->transform.transpose_xy = false; - if (rotation == 0 || rotation == 180) { - if (rotation == 180) { - self->transform.mirror_x = true; - self->transform.mirror_y = true; - } - } else { - self->transform.transpose_xy = true; - if (rotation == 270) { - self->transform.mirror_y = true; - } else { - self->transform.mirror_x = true; - } - } - - self->ram_width = ram_width; - self->ram_height = ram_height; - - self->area.x1 = 0; - self->area.y1 = 0; - self->area.next = NULL; - - self->transform.dx = 1; - self->transform.dy = 1; - if (self->transform.transpose_xy) { - self->area.x2 = height; - self->area.y2 = width; - if (self->transform.mirror_x) { - self->transform.x = height; - self->transform.dx = -1; - } - if (self->transform.mirror_y) { - self->transform.y = width; - self->transform.dy = -1; - } - } else { - self->area.x2 = width; - self->area.y2 = height; - if (self->transform.mirror_x) { - self->transform.x = width; - self->transform.dx = -1; - } - if (self->transform.mirror_y) { - self->transform.y = height; - self->transform.dy = -1; - } - } - self->busy.base.type = &mp_type_NoneType; if (busy_pin != NULL) { self->busy.base.type = &digitalio_digitalinout_type; @@ -179,77 +89,37 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* // TODO: Clear } + supervisor_start_terminal(width, height); + // Set the group after initialization otherwise we may send pixels while we delay in // initialization. common_hal_displayio_epaperdisplay_show(self, &circuitpython_splash); } bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self, displayio_group_t* root_group) { - if (root_group == NULL && !circuitpython_splash.in_group) { - root_group = &circuitpython_splash; - } - if (root_group == self->current_group) { - return true; - } - if (root_group != NULL && root_group->in_group) { - return false; - } - if (self->current_group != NULL) { - self->current_group->in_group = false; - } - if (root_group != NULL) { - displayio_group_update_transform(root_group, &self->transform); - root_group->in_group = true; - self->current_group = root_group; - } - self->full_refresh = true; - return true; + return displayio_display_core_show(&self->core, root_group); } const displayio_area_t* displayio_epaperdisplay_get_refresh_areas(displayio_epaperdisplay_obj_t *self) { const displayio_area_t* first_area; - if (self->current_group == NULL || self->current_group->base.type != &displayio_group_type) { - asm("bkpt"); - } - if (self->full_refresh) { - first_area = &self->area; + if (self->core.full_refresh) { + first_area = &self->core.area; } else { - first_area = displayio_group_get_refresh_areas(self->current_group, NULL); + first_area = displayio_group_get_refresh_areas(self->core.current_group, NULL); } if (first_area != NULL && self->set_row_window_command == NO_COMMAND) { - self->area.next = NULL; - return &self->area; + self->core.area.next = NULL; + return &self->core.area; } return first_area; } -int32_t common_hal_displayio_epaperdisplay_wait_for_frame(displayio_epaperdisplay_obj_t* self) { - uint64_t last_refresh = self->last_refresh; - // Don't try to refresh if we got an exception. - while (last_refresh == self->last_refresh && MP_STATE_VM(mp_pending_exception) == NULL) { - MICROPY_VM_HOOK_LOOP - } - return 0; -} - uint16_t common_hal_displayio_epaperdisplay_get_width(displayio_epaperdisplay_obj_t* self){ - return self->width; + return displayio_display_core_get_width(&self->core); } uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_obj_t* self){ - return self->height; -} - -bool displayio_epaperdisplay_bus_free(displayio_epaperdisplay_obj_t *self) { - return self->bus_free(self->bus); -} - -bool displayio_epaperdisplay_begin_transaction(displayio_epaperdisplay_obj_t* self) { - return self->begin_transaction(self->bus); -} - -void displayio_epaperdisplay_end_transaction(displayio_epaperdisplay_obj_t* self) { - self->end_transaction(self->bus); + return displayio_display_core_get_height(&self->core); } STATIC void wait_for_busy(displayio_epaperdisplay_obj_t* self) { @@ -271,10 +141,10 @@ STATIC void send_command_sequence(displayio_epaperdisplay_obj_t* self, bool shou bool delay = (data_size & DELAY) != 0; data_size &= ~DELAY; uint8_t *data = cmd + 2; - self->begin_transaction(self->bus); - self->send(self->bus, true, self->always_toggle_chip_select, cmd, 1); - self->send(self->bus, false, self->always_toggle_chip_select, data, data_size); - self->end_transaction(self->bus); + displayio_display_core_begin_transaction(&self->core); + self->core.send(self->core.bus, true, self->always_toggle_chip_select, cmd, 1); + self->core.send(self->core.bus, false, self->always_toggle_chip_select, data, data_size); + displayio_display_core_end_transaction(&self->core); uint16_t delay_length_ms = 0; if (delay) { data_size++; @@ -291,87 +161,17 @@ STATIC void send_command_sequence(displayio_epaperdisplay_obj_t* self, bool shou } } -void displayio_epaperdisplay_set_region_to_update(displayio_epaperdisplay_obj_t* self, displayio_area_t* area) { - if (self->set_row_window_command == NO_COMMAND) { - return; - } - uint16_t x1 = area->x1; - uint16_t x2 = area->x2; - uint16_t y1 = area->y1; - uint16_t y2 = area->y2; - // Collapse down the dimension where multiple pixels are in a byte. - uint8_t pixels_per_byte = 8 / self->colorspace.depth; - x1 /= pixels_per_byte * self->colorspace.bytes_per_cell; - x2 /= pixels_per_byte * self->colorspace.bytes_per_cell; - - - // Set column. - uint8_t data[5]; - data[0] = self->set_column_window_command; - self->send(self->bus, true, self->always_toggle_chip_select, data, 1); - uint8_t data_length = 0; - if (self->ram_width / pixels_per_byte < 0x100) { - data[data_length++] = x1 + self->colstart; - data[data_length++] = x2 - 1 + self->colstart; - } else { - x1 += self->colstart; - x2 += self->colstart - 1; - data[data_length++] = x1 >> 8; - data[data_length++] = x1 & 0xff; - data[data_length++] = x2 >> 8; - data[data_length++] = x2 & 0xff; - } - self->send(self->bus, false, self->always_toggle_chip_select, data, data_length); - if (self->set_current_column_command != NO_COMMAND) { - uint8_t command = self->set_current_column_command; - self->send(self->bus, true, self->always_toggle_chip_select, &command, 1); - self->send(self->bus, false, self->always_toggle_chip_select, data, data_length / 2); - } - - // Set row. - data[0] = self->set_row_window_command; - self->send(self->bus, true, self->always_toggle_chip_select, data, 1); - data_length = 0; - if (self->ram_height < 0x100) { - data[data_length++] = y1 + self->rowstart; - data[data_length++] = y2 - 1 + self->rowstart; - } else { - y1 += self->rowstart; - y2 += self->rowstart - 1; - data[data_length++] = y1 & 0xff; - data[data_length++] = y1 >> 8; - data[data_length++] = y2 & 0xff; - data[data_length++] = y2 >> 8; - } - self->send(self->bus, false, self->always_toggle_chip_select, data, data_length); - if (self->set_current_row_command != NO_COMMAND) { - uint8_t command = self->set_current_row_command; - self->send(self->bus, true, self->always_toggle_chip_select, &command, 1); - self->send(self->bus, false, self->always_toggle_chip_select, data, data_length / 2); - } -} - void displayio_epaperdisplay_start_refresh(displayio_epaperdisplay_obj_t* self) { // run start sequence - self->bus_reset(self->bus); + self->core.bus_reset(self->core.bus); send_command_sequence(self, true, self->start_sequence, self->start_sequence_len); - self->last_refresh = ticks_ms; -} - -void displayio_epaperdisplay_background_task(displayio_epaperdisplay_obj_t* self) { - if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) { - if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) { - self->refreshing = false; - // Run stop sequence but don't wait for busy because busy is set when sleeping. - send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); - } - } + displayio_display_core_start_refresh(&self->core); } uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self) { // Refresh at seconds per frame rate. - uint32_t elapsed_time = ticks_ms - self->last_refresh; + uint32_t elapsed_time = ticks_ms - self->core.last_refresh; if (elapsed_time > self->milliseconds_per_frame) { return 0; } @@ -380,20 +180,16 @@ uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaper void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self) { // Actually refresh the display now that all pixel RAM has been updated. - displayio_epaperdisplay_begin_transaction(self); - self->send(self->bus, true, self->always_toggle_chip_select, &self->refresh_display_command, 1); - displayio_epaperdisplay_end_transaction(self); + displayio_display_core_begin_transaction(&self->core); + self->core.send(self->core.bus, true, self->always_toggle_chip_select, &self->refresh_display_command, 1); + displayio_display_core_end_transaction(&self->core); self->refreshing = true; - if (self->current_group != NULL) { - displayio_group_finish_refresh(self->current_group); - } - self->refresh = false; - self->full_refresh = false; - self->last_refresh = ticks_ms; + displayio_display_core_finish_refresh(&self->core); } -void displayio_epaperdisplay_send_pixels(displayio_epaperdisplay_obj_t* self, uint8_t* pixels, uint32_t length) { +mp_obj_t common_hal_displayio_epaperdisplay_get_bus(displayio_epaperdisplay_obj_t* self) { + return self->core.bus; } bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, const displayio_area_t* area) { @@ -401,12 +197,12 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c displayio_area_t clipped; // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. - if (!displayio_epaperdisplay_clip_area(self, area, &clipped)) { + if (!displayio_display_core_clip_area(&self->core, area, &clipped)) { return true; } uint16_t subrectangles = 1; uint16_t rows_per_buffer = displayio_area_height(&clipped); - uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->colorspace.depth; + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; uint16_t pixels_per_buffer = displayio_area_size(&clipped); if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); @@ -431,23 +227,23 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c uint32_t mask[mask_length]; uint8_t passes = 1; - if (self->colorspace.tricolor) { + if (self->core.colorspace.tricolor) { passes = 2; } for (uint8_t pass = 0; pass < passes; pass++) { uint16_t remaining_rows = displayio_area_height(&clipped); - displayio_epaperdisplay_begin_transaction(self); - displayio_epaperdisplay_set_region_to_update(self, &clipped); - displayio_epaperdisplay_end_transaction(self); + 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->always_toggle_chip_select, &clipped); + } uint8_t write_command = self->write_black_ram_command; if (pass == 1) { write_command = self->write_color_ram_command; } - displayio_epaperdisplay_begin_transaction(self); - self->send(self->bus, true, self->always_toggle_chip_select, &write_command, 1); - displayio_epaperdisplay_end_transaction(self); + displayio_display_core_begin_transaction(&self->core); + self->core.send(self->core.bus, true, self->always_toggle_chip_select, &write_command, 1); + displayio_display_core_end_transaction(&self->core); for (uint16_t j = 0; j < subrectangles; j++) { displayio_area_t subrectangle = { @@ -462,7 +258,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c remaining_rows -= rows_per_buffer; - uint16_t subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->colorspace.depth); + uint16_t subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); for (uint16_t k = 0; k < mask_length; k++) { mask[k] = 0x00000000; @@ -471,11 +267,11 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c buffer[k] = 0x00000000; } - self->colorspace.grayscale = true; + self->core.colorspace.grayscale = true; if (pass == 1) { - self->colorspace.grayscale = false; + self->core.colorspace.grayscale = false; } - displayio_group_fill_area(self->current_group, &self->colorspace, &subrectangle, mask, buffer); + displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); // Invert it all. if ((pass == 1 && self->color_bits_inverted) || @@ -485,12 +281,12 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c } } - if (!displayio_epaperdisplay_begin_transaction(self)) { + if (!displayio_display_core_begin_transaction(&self->core)) { // Can't acquire display bus; skip the rest of the data. Try next display. return false; } - self->send(self->bus, false, self->always_toggle_chip_select, (uint8_t*) buffer, subrectangle_size_bytes); - displayio_epaperdisplay_end_transaction(self); + self->core.send(self->core.bus, false, self->always_toggle_chip_select, (uint8_t*) buffer, subrectangle_size_bytes); + displayio_display_core_end_transaction(&self->core); // TODO(tannewt): Make refresh displays faster so we don't starve other // background tasks. @@ -512,57 +308,47 @@ bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* s return false; } } - if (self->current_group == NULL) { - return false; + if (self->core.current_group == NULL) { + return true; } // Refresh at seconds per frame rate. - if (ticks_ms - self->last_refresh) > self->milliseconds_per_frame; - - if (displayio_epaperdisplay_get_time_to_refresh(display) > 0) { + if (common_hal_displayio_epaperdisplay_get_time_to_refresh(self) > 0) { return false; } - if (!displayio_epaperdisplay_bus_free(display)) { + if (!displayio_display_core_bus_free(&self->core)) { // Can't acquire display bus; skip updating this display. Try next display. - continue; + return false; } - const displayio_area_t* current_area = displayio_epaperdisplay_get_refresh_areas(display); + const displayio_area_t* current_area = displayio_epaperdisplay_get_refresh_areas(self); if (current_area == NULL) { - continue; + return true; } - displayio_epaperdisplay_start_refresh(display); + displayio_epaperdisplay_start_refresh(self); while (current_area != NULL) { - displayio_epaperdisplay_refresh_area(display, current_area); + displayio_epaperdisplay_refresh_area(self, current_area); current_area = current_area->next; } - displayio_epaperdisplay_finish_refresh(display); + displayio_epaperdisplay_finish_refresh(self); + return true; } -void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { - if (self->current_group != NULL) { - self->current_group->in_group = false; +void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self) { + if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) { + if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) { + self->refreshing = false; + // Run stop sequence but don't wait for busy because busy is set when sleeping. + send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); + } } +} + +void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { + release_display_core(&self->core); if (self->busy.base.type == &digitalio_digitalinout_type) { common_hal_digitalio_digitalinout_deinit(&self->busy); } } -bool displayio_epaperdisplay_fill_area(displayio_epaperdisplay_obj_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer) { - return displayio_group_fill_area(self->current_group, &self->colorspace, area, mask, buffer); -} - -bool displayio_epaperdisplay_clip_area(displayio_epaperdisplay_obj_t *self, const displayio_area_t* area, displayio_area_t* clipped) { - bool overlaps = displayio_area_compute_overlap(&self->area, area, clipped); - if (!overlaps) { - return false; - } - // Expand the area if we have multiple pixels per byte and we need to byte - // align the bounds. - uint8_t pixels_per_byte = 8; - if (clipped->x1 % pixels_per_byte != 0) { - clipped->x1 -= clipped->x1 % pixels_per_byte; - } - if (clipped->x2 % pixels_per_byte != 0) { - clipped->x2 += pixels_per_byte - clipped->x2 % pixels_per_byte; - } - return true; +void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t* self) { + displayio_display_core_collect_ptrs(&self->core); } diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index cc7db6f6d..88b5ebfaf 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -32,38 +32,17 @@ #include "shared-bindings/pulseio/PWMOut.h" #include "shared-module/displayio/area.h" - -typedef void (*display_bus_bus_reset)(mp_obj_t bus); -typedef bool (*display_bus_bus_free)(mp_obj_t bus); -typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); -typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); -typedef void (*display_bus_end_transaction)(mp_obj_t bus); +#include "shared-module/displayio/display_core.h" typedef struct { mp_obj_base_t base; - mp_obj_t bus; - displayio_group_t *current_group; - uint64_t last_refresh; - display_bus_bus_reset bus_reset; - display_bus_bus_free bus_free; - display_bus_begin_transaction begin_transaction; - display_bus_send send; - display_bus_end_transaction end_transaction; + displayio_display_core_t core; digitalio_digitalinout_obj_t busy; uint32_t milliseconds_per_frame; uint8_t* start_sequence; uint32_t start_sequence_len; uint8_t* stop_sequence; uint32_t stop_sequence_len; - displayio_buffer_transform_t transform; - displayio_area_t area; - uint16_t width; - uint16_t height; - uint16_t ram_width; - uint16_t ram_height; - _displayio_colorspace_t colorspace; - int16_t colstart; - int16_t rowstart; uint16_t set_column_window_command; uint16_t set_row_window_command; uint16_t set_current_column_command; @@ -76,11 +55,12 @@ typedef struct { bool black_bits_inverted; bool color_bits_inverted; bool refreshing; - bool full_refresh; // New group means we need to refresh the whole display. bool always_toggle_chip_select; } displayio_epaperdisplay_obj_t; void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self); void release_epaperdisplay(displayio_epaperdisplay_obj_t* self); +void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t* self); + #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_EPAPERDISPLAY_H diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 0ebed58c2..0a3b1fd10 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -4,7 +4,6 @@ #include "shared-module/displayio/__init__.h" #include "lib/utils/interrupt_char.h" -#include "py/gc.h" #include "py/reload.h" #include "py/runtime.h" #include "shared-bindings/board/__init__.h" @@ -16,7 +15,6 @@ #include "supervisor/shared/autoreload.h" #include "supervisor/shared/display.h" #include "supervisor/memory.h" -#include "supervisor/usb.h" primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; @@ -46,8 +44,8 @@ void displayio_background(void) { } if (displays[i].display.base.type == &displayio_display_type) { displayio_display_background(&displays[i].display); - } else if (displays[i].epaperdisplay.base.type == &displayio_epaperdisplay_type) { - displayio_epaperdisplay_background(&displays[i].epaperdisplay); + } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { + displayio_epaperdisplay_background(&displays[i].epaper_display); } } @@ -162,9 +160,9 @@ void displayio_gc_collect(void) { // Alternatively, we could use gc_collect_root over the whole object, // but this is more precise, and is the only field that needs marking. if (displays[i].display.base.type == &displayio_display_type) { - gc_collect_ptr(displays[i].display.current_group); + displayio_display_collect_ptrs(&displays[i].display); } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { - gc_collect_ptr(displays[i].epaper_display.current_group); + displayio_epaperdisplay_collect_ptrs(&displays[i].epaper_display); } } } diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c new file mode 100644 index 000000000..f8a8d8fea --- /dev/null +++ b/shared-module/displayio/display_core.c @@ -0,0 +1,309 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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 "shared-bindings/displayio/Display.h" + +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/displayio/FourWire.h" +#include "shared-bindings/displayio/I2CDisplay.h" +#include "shared-bindings/displayio/ParallelBus.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/time/__init__.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/display.h" + +#include +#include + +#include "tick.h" + +void displayio_display_core_construct(displayio_display_core_t* self, + mp_obj_t bus, uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, + uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte) { + self->colorspace.depth = color_depth; + self->colorspace.grayscale = grayscale; + 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; + self->current_group = NULL; + self->colstart = colstart; + self->rowstart = rowstart; + + if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { + self->bus_reset = common_hal_displayio_parallelbus_reset; + self->bus_free = common_hal_displayio_parallelbus_bus_free; + self->begin_transaction = common_hal_displayio_parallelbus_begin_transaction; + self->send = common_hal_displayio_parallelbus_send; + self->end_transaction = common_hal_displayio_parallelbus_end_transaction; + } else if (MP_OBJ_IS_TYPE(bus, &displayio_fourwire_type)) { + self->bus_reset = common_hal_displayio_fourwire_reset; + self->bus_free = common_hal_displayio_fourwire_bus_free; + self->begin_transaction = common_hal_displayio_fourwire_begin_transaction; + self->send = common_hal_displayio_fourwire_send; + self->end_transaction = common_hal_displayio_fourwire_end_transaction; + } else if (MP_OBJ_IS_TYPE(bus, &displayio_i2cdisplay_type)) { + self->bus_reset = common_hal_displayio_i2cdisplay_reset; + self->bus_free = common_hal_displayio_i2cdisplay_bus_free; + self->begin_transaction = common_hal_displayio_i2cdisplay_begin_transaction; + self->send = common_hal_displayio_i2cdisplay_send; + self->end_transaction = common_hal_displayio_i2cdisplay_end_transaction; + } else { + mp_raise_ValueError(translate("Unsupported display bus type")); + } + self->bus = bus; + + + supervisor_start_terminal(width, height); + + self->width = width; + self->height = height; + self->ram_width = width; + self->ram_height = height; + rotation = rotation % 360; + self->transform.x = 0; + self->transform.y = 0; + self->transform.scale = 1; + self->transform.mirror_x = false; + self->transform.mirror_y = false; + self->transform.transpose_xy = false; + if (rotation == 0 || rotation == 180) { + if (rotation == 180) { + self->transform.mirror_x = true; + self->transform.mirror_y = true; + } + } else { + self->transform.transpose_xy = true; + if (rotation == 270) { + self->transform.mirror_y = true; + } else { + self->transform.mirror_x = true; + } + } + + self->area.x1 = 0; + self->area.y1 = 0; + self->area.next = NULL; + + self->transform.dx = 1; + self->transform.dy = 1; + if (self->transform.transpose_xy) { + self->area.x2 = height; + self->area.y2 = width; + if (self->transform.mirror_x) { + self->transform.x = height; + self->transform.dx = -1; + } + if (self->transform.mirror_y) { + self->transform.y = width; + self->transform.dy = -1; + } + } else { + self->area.x2 = width; + self->area.y2 = height; + if (self->transform.mirror_x) { + self->transform.x = width; + self->transform.dx = -1; + } + if (self->transform.mirror_y) { + self->transform.y = height; + self->transform.dy = -1; + } + } +} + +bool displayio_display_core_show(displayio_display_core_t* self, displayio_group_t* root_group) { + if (root_group == NULL) { + if (!circuitpython_splash.in_group) { + root_group = &circuitpython_splash; + } else if (self->current_group == &circuitpython_splash) { + return false; + } + } + if (root_group == self->current_group) { + return true; + } + if (root_group != NULL && root_group->in_group) { + return false; + } + if (self->current_group != NULL) { + self->current_group->in_group = false; + } + + if (root_group != NULL) { + displayio_group_update_transform(root_group, &self->transform); + root_group->in_group = true; + } + self->current_group = root_group; + self->full_refresh = true; + return true; +} + +uint16_t displayio_display_core_get_width(displayio_display_core_t* self){ + return self->width; +} + +uint16_t displayio_display_core_get_height(displayio_display_core_t* self){ + return self->height; +} + +bool displayio_display_core_bus_free(displayio_display_core_t *self) { + return self->bus_free(self->bus); +} + +bool displayio_display_core_begin_transaction(displayio_display_core_t* self) { + return self->begin_transaction(self->bus); +} + +void displayio_display_core_end_transaction(displayio_display_core_t* self) { + self->end_transaction(self->bus); +} + +void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area) { + displayio_display_core_begin_transaction(self); + uint16_t x1 = area->x1; + uint16_t x2 = area->x2; + uint16_t y1 = area->y1; + uint16_t y2 = area->y2; + // Collapse down the dimension where multiple pixels are in a byte. + if (self->colorspace.depth < 8) { + uint8_t pixels_per_byte = 8 / self->colorspace.depth; + if (self->colorspace.pixels_in_byte_share_row) { + x1 /= pixels_per_byte * self->colorspace.bytes_per_cell; + x2 /= pixels_per_byte * self->colorspace.bytes_per_cell; + } else { + y1 /= pixels_per_byte * self->colorspace.bytes_per_cell; + y2 /= pixels_per_byte * self->colorspace.bytes_per_cell; + } + } + + // Set column. + uint8_t data[5]; + data[0] = column_command; + uint8_t data_length = 1; + if (!data_as_commands) { + self->send(self->bus, true, true, data, 1); + data_length = 0; + } + if (self->ram_width < 0x100) { + data[data_length++] = x1 + self->colstart; + data[data_length++] = x2 - 1 + self->colstart; + } else { + x1 += self->colstart; + x2 += self->colstart - 1; + data[data_length++] = x1 >> 8; + data[data_length++] = x1 & 0xff; + data[data_length++] = x2 >> 8; + data[data_length++] = x2 & 0xff; + } + self->send(self->bus, data_as_commands, data_as_commands, data, data_length); + if (set_current_column_command != NO_COMMAND) { + uint8_t command = set_current_column_command; + self->send(self->bus, true, always_toggle_chip_select, &command, 1); + self->send(self->bus, false, always_toggle_chip_select, data, data_length / 2); + } + + // Set row. + data[0] = row_command; + data_length = 1; + if (!data_as_commands) { + self->send(self->bus, true, true, data, 1); + data_length = 0; + } + if (self->ram_height < 0x100) { + data[data_length++] = y1 + self->rowstart; + data[data_length++] = y2 - 1 + self->rowstart; + } else { + y1 += self->rowstart; + y2 += self->rowstart - 1; + data[data_length++] = y1 >> 8; + data[data_length++] = y1 & 0xff; + data[data_length++] = y2 >> 8; + data[data_length++] = y2 & 0xff; + } + self->send(self->bus, data_as_commands, data_as_commands, data, data_length); + if (set_current_row_command != NO_COMMAND) { + uint8_t command = set_current_row_command; + self->send(self->bus, true, always_toggle_chip_select, &command, 1); + self->send(self->bus, false, always_toggle_chip_select, data, data_length / 2); + } + + displayio_display_core_end_transaction(self); +} + +void displayio_display_core_start_refresh(displayio_display_core_t* self) { + self->last_refresh = ticks_ms; +} + +void displayio_display_core_finish_refresh(displayio_display_core_t* self) { + if (self->current_group != NULL) { + displayio_group_finish_refresh(self->current_group); + } + self->full_refresh = false; + self->last_refresh = ticks_ms; +} + +void release_display_core(displayio_display_core_t* self) { + if (self->current_group != NULL) { + self->current_group->in_group = false; + } +} + +void displayio_display_core_collect_ptrs(displayio_display_core_t* self) { + gc_collect_ptr(self->current_group); +} + +bool displayio_display_core_fill_area(displayio_display_core_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer) { + return displayio_group_fill_area(self->current_group, &self->colorspace, area, mask, buffer); +} + +bool displayio_display_core_clip_area(displayio_display_core_t *self, const displayio_area_t* area, displayio_area_t* clipped) { + bool overlaps = displayio_area_compute_overlap(&self->area, area, clipped); + if (!overlaps) { + return false; + } + // Expand the area if we have multiple pixels per byte and we need to byte + // align the bounds. + if (self->colorspace.depth < 8) { + uint8_t pixels_per_byte = 8 / self->colorspace.depth * self->colorspace.bytes_per_cell; + if (self->colorspace.pixels_in_byte_share_row) { + if (clipped->x1 % pixels_per_byte != 0) { + clipped->x1 -= clipped->x1 % pixels_per_byte; + } + if (clipped->x2 % pixels_per_byte != 0) { + clipped->x2 += pixels_per_byte - clipped->x2 % pixels_per_byte; + } + } else { + if (clipped->y1 % pixels_per_byte != 0) { + clipped->y1 -= clipped->y1 % pixels_per_byte; + } + if (clipped->y2 % pixels_per_byte != 0) { + clipped->y2 += pixels_per_byte - clipped->y2 % pixels_per_byte; + } + } + } + return true; +} diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h new file mode 100644 index 000000000..c837ce913 --- /dev/null +++ b/shared-module/displayio/display_core.h @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_CORE_H +#define MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_CORE_H + +#include "shared-bindings/displayio/Group.h" + +#include "shared-module/displayio/area.h" + +#define NO_COMMAND 0x100 + +typedef void (*display_bus_bus_reset)(mp_obj_t bus); +typedef bool (*display_bus_bus_free)(mp_obj_t bus); +typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); +typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); +typedef void (*display_bus_end_transaction)(mp_obj_t bus); + +typedef struct { + mp_obj_t bus; + displayio_group_t *current_group; + uint64_t last_refresh; + display_bus_bus_reset bus_reset; + display_bus_bus_free bus_free; + display_bus_begin_transaction begin_transaction; + display_bus_send send; + display_bus_end_transaction end_transaction; + displayio_buffer_transform_t transform; + displayio_area_t area; + uint16_t width; + uint16_t height; + uint16_t rotation; + uint16_t ram_width; + uint16_t ram_height; + _displayio_colorspace_t colorspace; + int16_t colstart; + int16_t rowstart; + bool full_refresh; // New group means we need to refresh the whole display. +} displayio_display_core_t; + +void displayio_display_core_construct(displayio_display_core_t* self, + mp_obj_t bus, uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, + uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte); + +bool displayio_display_core_show(displayio_display_core_t* self, displayio_group_t* root_group); + +uint16_t displayio_display_core_get_width(displayio_display_core_t* self); +uint16_t displayio_display_core_get_height(displayio_display_core_t* self); + +bool displayio_display_core_bus_free(displayio_display_core_t *self); +bool displayio_display_core_begin_transaction(displayio_display_core_t* self); +void displayio_display_core_end_transaction(displayio_display_core_t* self); + +void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area); + +void release_display_core(displayio_display_core_t* self); + +void displayio_display_core_start_refresh(displayio_display_core_t* self); +void displayio_display_core_finish_refresh(displayio_display_core_t* self); + +void displayio_display_core_collect_ptrs(displayio_display_core_t* self); + +bool displayio_display_core_fill_area(displayio_display_core_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer); + +bool displayio_display_core_clip_area(displayio_display_core_t *self, const displayio_area_t* area, displayio_area_t* clipped); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_CORE_H From 24b30965c41ae32b82c56b166f3287cf2c14f419 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 20 Aug 2019 21:35:42 -0700 Subject: [PATCH 06/18] Refresh ePaper displays once code.py is done running --- main.c | 8 ++++++++ shared-bindings/displayio/__init__.c | 2 +- shared-module/displayio/EPaperDisplay.c | 27 +++++++++++++++++++++++++ shared-module/displayio/EPaperDisplay.h | 1 + shared-module/displayio/__init__.c | 24 ++++++++++++---------- shared-module/displayio/display_core.c | 3 ++- 6 files changed, 52 insertions(+), 13 deletions(-) diff --git a/main.c b/main.c index 6ab50fc3c..076674c44 100755 --- a/main.c +++ b/main.c @@ -253,6 +253,7 @@ bool run_code_py(safe_mode_t safe_mode) { } bool serial_connected_before_animation = false; + bool refreshed_epaper_display = false; rgb_status_animation_t animation; prep_rgb_status_animation(&result, found_main, safe_mode, &animation); while (true) { @@ -290,6 +291,13 @@ bool run_code_py(safe_mode_t safe_mode) { } serial_connected_before_animation = serial_connected(); + // Refresh the ePaper display if we have one. That way it'll show an error message. + #if CIRCUITPY_DISPLAYIO + if (!refreshed_epaper_display) { + refreshed_epaper_display = maybe_refresh_epaperdisplay(); + } + #endif + tick_rgb_status_animation(&animation); } } diff --git a/shared-bindings/displayio/__init__.c b/shared-bindings/displayio/__init__.c index 8c5d1f228..f78325593 100644 --- a/shared-bindings/displayio/__init__.c +++ b/shared-bindings/displayio/__init__.c @@ -77,7 +77,7 @@ //| //| Releases any actively used displays so their busses and pins can be used again. This will also //| release the builtin display on boards that have one. You will need to reinitialize it yourself -//| afterwards. +//| afterwards. This may take seconds to complete if an active EPaperDisplay is refreshing. //| //| Use this once in your code.py if you initialize a display. Place it right before the //| initialization so the display is active as long as possible. diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 6ff060a6a..7e65502d4 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -170,6 +170,9 @@ void displayio_epaperdisplay_start_refresh(displayio_epaperdisplay_obj_t* self) } uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self) { + if (self->core.last_refresh == 0) { + return 0; + } // Refresh at seconds per frame rate. uint32_t elapsed_time = ticks_ms - self->core.last_refresh; if (elapsed_time > self->milliseconds_per_frame) { @@ -343,6 +346,13 @@ void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self) { } void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { + if (self->refreshing) { + wait_for_busy(self); + self->refreshing = false; + // Run stop sequence but don't wait for busy because busy is set when sleeping. + send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); + } + release_display_core(&self->core); if (self->busy.base.type == &digitalio_digitalinout_type) { common_hal_digitalio_digitalinout_deinit(&self->busy); @@ -352,3 +362,20 @@ void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t* self) { displayio_display_core_collect_ptrs(&self->core); } + +bool maybe_refresh_epaperdisplay(void) { + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + if (displays[i].epaper_display.base.type != &displayio_epaperdisplay_type || + displays[i].epaper_display.core.current_group != &circuitpython_splash) { + // Skip regular displays and those not showing the splash. + continue; + } + displayio_epaperdisplay_obj_t* display = &displays[i].epaper_display; + if (common_hal_displayio_epaperdisplay_get_time_to_refresh(display) != 0) { + return false; + } + return common_hal_displayio_epaperdisplay_refresh(display); + } + // Return true if no ePaper displays are available to pretend it was updated. + return true; +} diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index 88b5ebfaf..2be2add4b 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -60,6 +60,7 @@ typedef struct { void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self); void release_epaperdisplay(displayio_epaperdisplay_obj_t* self); +bool maybe_refresh_epaperdisplay(void); void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t* self); diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 0a3b1fd10..a41884c78 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -54,6 +54,19 @@ void displayio_background(void) { } void common_hal_displayio_release_displays(void) { + // Release displays before busses so that they can send any final commands to turn the display + // off properly. + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + mp_const_obj_t display_type = displays[i].display.base.type; + if (display_type == NULL || display_type == &mp_type_NoneType) { + continue; + } else if (display_type == &displayio_display_type) { + release_display(&displays[i].display); + } else if (display_type == &displayio_epaperdisplay_type) { + release_epaperdisplay(&displays[i].epaper_display); + } + displays[i].display.base.type = &mp_type_NoneType; + } for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { mp_const_obj_t bus_type = displays[i].fourwire_bus.base.type; if (bus_type == NULL || bus_type == &mp_type_NoneType) { @@ -67,17 +80,6 @@ void common_hal_displayio_release_displays(void) { } displays[i].fourwire_bus.base.type = &mp_type_NoneType; } - for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - mp_const_obj_t display_type = displays[i].display.base.type; - if (display_type == NULL || display_type == &mp_type_NoneType) { - continue; - } else if (display_type == &displayio_display_type) { - release_display(&displays[i].display); - } else if (display_type == &displayio_epaperdisplay_type) { - release_epaperdisplay(&displays[i].epaper_display); - } - displays[i].display.base.type = &mp_type_NoneType; - } supervisor_stop_terminal(); } diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index f8a8d8fea..24d8ab51f 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -52,6 +52,7 @@ void displayio_display_core_construct(displayio_display_core_t* self, self->current_group = NULL; self->colstart = colstart; self->rowstart = rowstart; + self->last_refresh = 0; if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { self->bus_reset = common_hal_displayio_parallelbus_reset; @@ -140,7 +141,7 @@ bool displayio_display_core_show(displayio_display_core_t* self, displayio_group if (!circuitpython_splash.in_group) { root_group = &circuitpython_splash; } else if (self->current_group == &circuitpython_splash) { - return false; + return true; } } if (root_group == self->current_group) { From 3a98de12368a63de1538f61da7690e9fa230b540 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 21 Aug 2019 11:49:49 -0700 Subject: [PATCH 07/18] Add reset() to display busses to detect whether it works --- .../boards/itsybitsy_m0_express/mpconfigboard.mk | 3 +++ .../common-hal/displayio/ParallelBus.c | 7 ++++++- shared-bindings/displayio/FourWire.c | 16 ++++++++++++++++ shared-bindings/displayio/FourWire.h | 2 +- shared-bindings/displayio/I2CDisplay.c | 16 ++++++++++++++++ shared-bindings/displayio/I2CDisplay.h | 2 +- shared-bindings/displayio/ParallelBus.c | 16 ++++++++++++++++ shared-bindings/displayio/ParallelBus.h | 2 +- shared-module/displayio/FourWire.c | 8 +++++++- shared-module/displayio/I2CDisplay.c | 10 +++++++--- shared-module/displayio/display_core.h | 2 +- 11 files changed, 75 insertions(+), 9 deletions(-) diff --git a/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk index fd66f425d..410a0e087 100644 --- a/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk @@ -12,6 +12,9 @@ EXTERNAL_FLASH_DEVICE_COUNT = 2 EXTERNAL_FLASH_DEVICES = "W25Q16FW, GD25Q16C" LONGINT_IMPL = MPZ +CIRCUITPY_I2CSLAVE = 0 +CIRCUITPY_RTC = 0 + CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 diff --git a/ports/atmel-samd/common-hal/displayio/ParallelBus.c b/ports/atmel-samd/common-hal/displayio/ParallelBus.c index a43d20511..e2ce9952b 100644 --- a/ports/atmel-samd/common-hal/displayio/ParallelBus.c +++ b/ports/atmel-samd/common-hal/displayio/ParallelBus.c @@ -79,6 +79,7 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel self->write_group = &PORT->Group[write->number / 32]; self->write_mask = 1 << (write->number % 32); + self->reset.base.type = &mp_type_NoneType; if (reset != NULL) { self->reset.base.type = &digitalio_digitalinout_type; common_hal_digitalio_digitalinout_construct(&self->reset, reset); @@ -108,12 +109,16 @@ void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self) reset_pin_number(self->reset.pin->number); } -void common_hal_displayio_parallelbus_reset(mp_obj_t obj) { +bool common_hal_displayio_parallelbus_reset(mp_obj_t obj) { displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); + if (self->reset.base.type == &mp_type_NoneType) { + return false; + } common_hal_digitalio_digitalinout_set_value(&self->reset, false); common_hal_mcu_delay_us(4); common_hal_digitalio_digitalinout_set_value(&self->reset, true); + return true; } bool common_hal_displayio_parallelbus_bus_free(mp_obj_t obj) { diff --git a/shared-bindings/displayio/FourWire.c b/shared-bindings/displayio/FourWire.c index efd553e2e..c69623344 100644 --- a/shared-bindings/displayio/FourWire.c +++ b/shared-bindings/displayio/FourWire.c @@ -103,6 +103,21 @@ STATIC mp_obj_t displayio_fourwire_make_new(const mp_obj_type_t *type, size_t n_ return self; } +//| .. method:: reset() +//| +//| Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin +//| is available. +//| +STATIC mp_obj_t displayio_fourwire_obj_reset(mp_obj_t self_in) { + displayio_fourwire_obj_t *self = self_in; + + if (!common_hal_displayio_fourwire_reset(self)) { + mp_raise_RuntimeError(translate("no reset pin available")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_fourwire_reset_obj, displayio_fourwire_obj_reset); + //| .. method:: send(command, data, *, toggle_every_byte=False) //| //| Sends the given command value followed by the full set of data. Display state, such as @@ -140,6 +155,7 @@ STATIC mp_obj_t displayio_fourwire_obj_send(size_t n_args, const mp_obj_t *pos_a MP_DEFINE_CONST_FUN_OBJ_KW(displayio_fourwire_send_obj, 3, displayio_fourwire_obj_send); STATIC const mp_rom_map_elem_t displayio_fourwire_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&displayio_fourwire_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_fourwire_send_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_fourwire_locals_dict, displayio_fourwire_locals_dict_table); diff --git a/shared-bindings/displayio/FourWire.h b/shared-bindings/displayio/FourWire.h index ee69a63ac..9c71d63cc 100644 --- a/shared-bindings/displayio/FourWire.h +++ b/shared-bindings/displayio/FourWire.h @@ -40,7 +40,7 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self, void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self); -void common_hal_displayio_fourwire_reset(mp_obj_t self); +bool common_hal_displayio_fourwire_reset(mp_obj_t self); bool common_hal_displayio_fourwire_bus_free(mp_obj_t self); bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c index 4428e8dbb..4de5e83ef 100644 --- a/shared-bindings/displayio/I2CDisplay.c +++ b/shared-bindings/displayio/I2CDisplay.c @@ -95,6 +95,21 @@ STATIC mp_obj_t displayio_i2cdisplay_make_new(const mp_obj_type_t *type, size_t return self; } +//| .. method:: reset() +//| +//| Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin +//| is available. +//| +STATIC mp_obj_t displayio_i2cdisplay_obj_reset(mp_obj_t self_in) { + displayio_i2cdisplay_obj_t *self = self_in; + + if (!common_hal_displayio_i2cdisplay_reset(self)) { + mp_raise_RuntimeError(translate("no reset pin available")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_i2cdisplay_reset_obj, displayio_i2cdisplay_obj_reset); + //| .. method:: send(command, data) //| //| Sends the given command value followed by the full set of data. Display state, such as @@ -124,6 +139,7 @@ STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_ob MP_DEFINE_CONST_FUN_OBJ_3(displayio_i2cdisplay_send_obj, displayio_i2cdisplay_obj_send); STATIC const mp_rom_map_elem_t displayio_i2cdisplay_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&displayio_i2cdisplay_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_i2cdisplay_send_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_i2cdisplay_locals_dict, displayio_i2cdisplay_locals_dict_table); diff --git a/shared-bindings/displayio/I2CDisplay.h b/shared-bindings/displayio/I2CDisplay.h index 6a75fc488..683cff383 100644 --- a/shared-bindings/displayio/I2CDisplay.h +++ b/shared-bindings/displayio/I2CDisplay.h @@ -37,7 +37,7 @@ void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self, void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self); -void common_hal_displayio_i2cdisplay_reset(mp_obj_t self); +bool common_hal_displayio_i2cdisplay_reset(mp_obj_t self); bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t self); bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/ParallelBus.c b/shared-bindings/displayio/ParallelBus.c index e260f9b7e..a08c37679 100644 --- a/shared-bindings/displayio/ParallelBus.c +++ b/shared-bindings/displayio/ParallelBus.c @@ -106,6 +106,21 @@ STATIC mp_obj_t displayio_parallelbus_make_new(const mp_obj_type_t *type, size_t return self; } +//| .. method:: reset() +//| +//| Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin +//| is available. +//| +STATIC mp_obj_t displayio_parallelbus_obj_reset(mp_obj_t self_in) { + displayio_parallelbus_obj_t *self = self_in; + + if (!common_hal_displayio_parallelbus_reset(self)) { + mp_raise_RuntimeError(translate("no reset pin available")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_parallelbus_reset_obj, displayio_parallelbus_obj_reset); + //| .. method:: send(command, data) //| //| Sends the given command value followed by the full set of data. Display state, such as @@ -133,6 +148,7 @@ STATIC mp_obj_t displayio_parallelbus_obj_send(mp_obj_t self, mp_obj_t command_o MP_DEFINE_CONST_FUN_OBJ_3(displayio_parallelbus_send_obj, displayio_parallelbus_obj_send); STATIC const mp_rom_map_elem_t displayio_parallelbus_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&displayio_parallelbus_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_parallelbus_send_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_parallelbus_locals_dict, displayio_parallelbus_locals_dict_table); diff --git a/shared-bindings/displayio/ParallelBus.h b/shared-bindings/displayio/ParallelBus.h index b8da91041..a0f967332 100644 --- a/shared-bindings/displayio/ParallelBus.h +++ b/shared-bindings/displayio/ParallelBus.h @@ -40,7 +40,7 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self); -void common_hal_displayio_parallelbus_reset(mp_obj_t self); +bool common_hal_displayio_parallelbus_reset(mp_obj_t self); bool common_hal_displayio_parallelbus_bus_free(mp_obj_t self); bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t self); diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c index 64ad80665..7294e9772 100644 --- a/shared-module/displayio/FourWire.c +++ b/shared-module/displayio/FourWire.c @@ -55,7 +55,9 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self, 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); + self->reset.base.type = &mp_type_NoneType; if (reset != NULL) { + self->reset.base.type = &digitalio_digitalinout_type; common_hal_digitalio_digitalinout_construct(&self->reset, reset); common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); never_reset_pin_number(reset->number); @@ -76,12 +78,16 @@ void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self) { reset_pin_number(self->reset.pin->number); } -void common_hal_displayio_fourwire_reset(mp_obj_t obj) { +bool common_hal_displayio_fourwire_reset(mp_obj_t obj) { displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); + if (self->reset.base.type == &mp_type_NoneType) { + return false; + } common_hal_digitalio_digitalinout_set_value(&self->reset, false); common_hal_time_delay_ms(1); common_hal_digitalio_digitalinout_set_value(&self->reset, true); common_hal_time_delay_ms(1); + return true; } bool common_hal_displayio_fourwire_bus_free(mp_obj_t obj) { diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c index 23ebc0889..95830ba0e 100644 --- a/shared-module/displayio/I2CDisplay.c +++ b/shared-module/displayio/I2CDisplay.c @@ -55,7 +55,9 @@ void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self, self->address = device_address; + self->reset.base.type = &mp_type_NoneType; if (reset != NULL) { + self->reset.base.type = &digitalio_digitalinout_type; common_hal_digitalio_digitalinout_construct(&self->reset, reset); common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); never_reset_pin_number(reset->number); @@ -71,16 +73,18 @@ void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self) { reset_pin_number(self->reset.pin->number); } - -void common_hal_displayio_i2cdisplay_reset(mp_obj_t obj) { +bool common_hal_displayio_i2cdisplay_reset(mp_obj_t obj) { displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); + if (self->reset.base.type == &mp_type_NoneType) { + return false; + } common_hal_digitalio_digitalinout_set_value(&self->reset, false); common_hal_mcu_delay_us(1); common_hal_digitalio_digitalinout_set_value(&self->reset, true); + return true; } - bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t obj) { displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); if (!common_hal_busio_i2c_try_lock(self->bus)) { diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index c837ce913..b1a412883 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -33,7 +33,7 @@ #define NO_COMMAND 0x100 -typedef void (*display_bus_bus_reset)(mp_obj_t bus); +typedef bool (*display_bus_bus_reset)(mp_obj_t bus); typedef bool (*display_bus_bus_free)(mp_obj_t bus); typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); From f2a1972ba8a3eeeed33f9ac693ef4176c883aec4 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 21 Aug 2019 13:15:35 -0700 Subject: [PATCH 08/18] Add refresh_time to use if busy_pin is not given --- shared-bindings/displayio/EPaperDisplay.c | 11 +++++++---- shared-bindings/displayio/EPaperDisplay.h | 2 +- shared-module/displayio/EPaperDisplay.c | 14 +++++++++++--- shared-module/displayio/EPaperDisplay.h | 1 + 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index 8f3c16efd..dd773e410 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -51,7 +51,7 @@ //| Most people should not use this class directly. Use a specific display driver instead that will //| contain the startup and shutdown sequences at minimum. //| -//| .. class:: EPaperDisplay(display_bus, start_sequence, stop_sequence, *, width, height, ram_width, ram_height, colstart=0, rowstart=0, rotation=0, set_column_window_command=None, set_row_window_command=None, single_byte_bounds=False, write_black_ram_command, black_bits_inverted=False, write_color_ram_command=None, color_bits_inverted=False, highlight_color=0x000000, refresh_display_command, busy_pin=None, busy_state=True, seconds_per_frame=180, always_toggle_chip_select=False) +//| .. class:: EPaperDisplay(display_bus, start_sequence, stop_sequence, *, width, height, ram_width, ram_height, colstart=0, rowstart=0, rotation=0, set_column_window_command=None, set_row_window_command=None, single_byte_bounds=False, write_black_ram_command, black_bits_inverted=False, write_color_ram_command=None, color_bits_inverted=False, highlight_color=0x000000, refresh_display_command, refresh_time=40, busy_pin=None, busy_state=True, seconds_per_frame=180, always_toggle_chip_select=False) //| //| Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| @@ -83,13 +83,14 @@ //| :param bool color_bits_inverted: True if 0 bits are used to show the color. Otherwise, 1 means to show color. //| :param int highlight_color: RGB888 of source color to highlight with third ePaper color. //| :param int refresh_display_command: Command used to start a display refresh +//| :param float refresh_time: Time it takes to refresh the display before the stop_sequence should be sent. Ignored when busy_pin is provided. //| :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 int seconds_per_frame: Minimum number of seconds between screen refreshes +//| :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 //| 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_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 }; 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 }, @@ -111,6 +112,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size { MP_QSTR_color_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_highlight_color, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x000000} }, { MP_QSTR_refresh_display_command, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_refresh_time, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(40)} }, { MP_QSTR_busy_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, { 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)} }, @@ -152,6 +154,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size mp_raise_RuntimeError(translate("Too many displays")); } + mp_float_t refresh_time = mp_obj_get_float(args[ARG_refresh_time].u_obj); mp_float_t seconds_per_frame = mp_obj_get_float(args[ARG_seconds_per_frame].u_obj); mp_int_t write_color_ram_command = NO_COMMAND; @@ -168,7 +171,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size 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, + 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 ); diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index 2a3cb921f..786fc3628 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -43,7 +43,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, 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, + 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); bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self); diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 7e65502d4..bf0e6676f 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -48,7 +48,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* int16_t colstart, int16_t rowstart, uint16_t rotation, 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, + 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) { if (highlight_color != 0x000000) { self->core.colorspace.tricolor = true; @@ -67,6 +67,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->write_color_ram_command = write_color_ram_command; self->color_bits_inverted = color_bits_inverted; self->refresh_display_command = refresh_display_command; + self->refresh_time = refresh_time * 1000; self->busy_state = busy_state; self->refreshing = false; self->milliseconds_per_frame = seconds_per_frame * 1000; @@ -336,8 +337,15 @@ bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* s } void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self) { - if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) { - if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) { + if (self->refreshing) { + bool refresh_done = false; + if (self->busy.base.type == &digitalio_digitalinout_type) { + bool busy = common_hal_digitalio_digitalinout_get_value(&self->busy); + refresh_done = busy != self->busy_state; + } else { + refresh_done = ticks_ms - self->core.last_refresh > self->refresh_time; + } + if (refresh_done) { self->refreshing = false; // Run stop sequence but don't wait for busy because busy is set when sleeping. send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index 2be2add4b..a5d4ec93f 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -43,6 +43,7 @@ typedef struct { uint32_t start_sequence_len; uint8_t* stop_sequence; uint32_t stop_sequence_len; + uint16_t refresh_time; uint16_t set_column_window_command; uint16_t set_row_window_command; uint16_t set_current_column_command; From f8e4ccac45fff441da135a55fb794c340939a403 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 21 Aug 2019 13:18:43 -0700 Subject: [PATCH 09/18] Fix builds without displayio --- main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.c b/main.c index 076674c44..6b56f5ff6 100755 --- a/main.c +++ b/main.c @@ -253,7 +253,9 @@ bool run_code_py(safe_mode_t safe_mode) { } bool serial_connected_before_animation = false; + #if CIRCUITPY_DISPLAYIO bool refreshed_epaper_display = false; + #endif rgb_status_animation_t animation; prep_rgb_status_animation(&result, found_main, safe_mode, &animation); while (true) { From 2497cbe186359feac880cc127298a5945ed95456 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 21 Aug 2019 14:14:47 -0700 Subject: [PATCH 10/18] Fix nrf builds --- ports/nrf/common-hal/displayio/ParallelBus.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ports/nrf/common-hal/displayio/ParallelBus.c b/ports/nrf/common-hal/displayio/ParallelBus.c index efb8c15b9..a8c2b9f73 100644 --- a/ports/nrf/common-hal/displayio/ParallelBus.c +++ b/ports/nrf/common-hal/displayio/ParallelBus.c @@ -90,6 +90,7 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel } self->write_mask = 1 << (write->number % num_pins_in_write_port); + self->reset.base.type = &mp_type_NoneType; if (reset != NULL) { self->reset.base.type = &digitalio_digitalinout_type; common_hal_digitalio_digitalinout_construct(&self->reset, reset); @@ -119,12 +120,16 @@ void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self) reset_pin_number(self->reset.pin->number); } -void common_hal_displayio_parallelbus_reset(mp_obj_t obj) { +bool common_hal_displayio_parallelbus_reset(mp_obj_t obj) { displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); + if (self->reset.base.type == &mp_type_NoneType) { + return false; + } common_hal_digitalio_digitalinout_set_value(&self->reset, false); common_hal_mcu_delay_us(4); common_hal_digitalio_digitalinout_set_value(&self->reset, true); + return true; } bool common_hal_displayio_parallelbus_bus_free(mp_obj_t obj) { From 9993a999065d81282df67bacceda4056a404f05f Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 21 Aug 2019 23:41:28 -0700 Subject: [PATCH 11/18] Add initial Monster M4SK build --- .travis.yml | 2 +- ports/atmel-samd/boards/monster_m4sk/board.c | 100 ++++++++++++++++++ .../boards/monster_m4sk/mpconfigboard.h | 31 ++++++ .../boards/monster_m4sk/mpconfigboard.mk | 18 ++++ ports/atmel-samd/boards/monster_m4sk/pins.c | 48 +++++++++ py/circuitpy_mpconfig.h | 4 + supervisor/shared/filesystem.c | 2 +- 7 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 ports/atmel-samd/boards/monster_m4sk/board.c create mode 100644 ports/atmel-samd/boards/monster_m4sk/mpconfigboard.h create mode 100644 ports/atmel-samd/boards/monster_m4sk/mpconfigboard.mk create mode 100644 ports/atmel-samd/boards/monster_m4sk/pins.c diff --git a/.travis.yml b/.travis.yml index 9a058aa64..d084a3042 100755 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ env: - TRAVIS_BOARDS="itsybitsy_m0_express metro_m0_express pirkey_m0 pyruler trinket_m0 trinket_m0_haxpress arduino_mkr1300 arduino_mkrzero arduino_zero bast_pro_mini_m0 catwan_usbstick datum_distance datum_imu datum_weather" TRAVIS_SDK=arm - TRAVIS_BOARDS="escornabot_makech meowmeow pewpew10 robohatmm1_m0 snekboard sparkfun_lumidrive sparkfun_redboard_turbo sparkfun_samd21_dev sparkfun_samd21_mini uchip ugame10" TRAVIS_SDK=arm # Adafruit SAMD51 (M4) + Other SAMD51 - - TRAVIS_BOARDS="feather_m4_express grandcentral_m4_express itsybitsy_m4_express metro_m4_airlift_lite metro_m4_express pybadge pybadge_airlift pygamer pygamer_advance" TRAVIS_SDK=arm + - TRAVIS_BOARDS="feather_m4_express grandcentral_m4_express itsybitsy_m4_express metro_m4_airlift_lite metro_m4_express pybadge pybadge_airlift pygamer pygamer_advance monster_m4sk" TRAVIS_SDK=arm - TRAVIS_BOARDS="pyportal pyportal_titano trellis_m4_express capablerobot_usbhub cp32-m4 datalore_ip_m4 datum_light kicksat-sprite mini_sam_m4 robohatmm1_m4 sam32" TRAVIS_SDK=arm diff --git a/ports/atmel-samd/boards/monster_m4sk/board.c b/ports/atmel-samd/boards/monster_m4sk/board.c new file mode 100644 index 000000000..2377f4a9d --- /dev/null +++ b/ports/atmel-samd/boards/monster_m4sk/board.c @@ -0,0 +1,100 @@ +/* + * 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. + */ + +#include "boards/board.h" +#include "mpconfigboard.h" +#include "hal/include/hal_gpio.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/displayio/FourWire.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "tick.h" + +displayio_fourwire_obj_t board_display_obj; + +#define DELAY 0x80 + +uint8_t display_init_sequence[] = { + 0x01, 0 | DELAY, 150, // SWRESET + 0x11, 0 | DELAY, 255, // SLPOUT + 0x36, 1, 0x00, // _MADCTL bottom to top refresh in vsync aligned order. + 0x3a, 1, 0x55, // COLMOD - 16bit color + 0x38, 0, // Idle mode off + 0x21, 0, // _INVON + 0x13, 0, // _NORON + 0x29, 0 | DELAY, 255 // _DISPON +}; + +void board_init(void) { + busio_spi_obj_t* spi = &displays[0].fourwire_bus.inline_bus; + common_hal_busio_spi_construct(spi, &pin_PA13, &pin_PA12, NULL); + common_hal_busio_spi_never_reset(spi); + + displayio_fourwire_obj_t* bus = &displays[0].fourwire_bus; + bus->base.type = &displayio_fourwire_type; + common_hal_displayio_fourwire_construct(bus, + spi, + &pin_PA07, // TFT_DC Command or data + &pin_PA06, // TFT_CS Chip select + &pin_PA04, // TFT_RST Reset + 60000000); + + displayio_display_obj_t* display = &displays[0].display; + display->base.type = &displayio_display_type; + common_hal_displayio_display_construct(display, + bus, + 240, // Width (after rotation) + 240, // Height (after rotation) + 0, // column start + 0, // row start + 180, // rotation + 16, // Color depth + false, // Grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + MIPI_COMMAND_SET_COLUMN_ADDRESS, // Set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command + MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command + 0x37, // set vertical scroll command + display_init_sequence, + sizeof(display_init_sequence), + &pin_PA23, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness (ignored) + true, // auto_brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} diff --git a/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.h b/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.h new file mode 100644 index 000000000..484f3d7b2 --- /dev/null +++ b/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.h @@ -0,0 +1,31 @@ +#define MICROPY_HW_BOARD_NAME "Adafruit Monster M4SK" +#define MICROPY_HW_MCU_NAME "samd51j19" + +#define CIRCUITPY_MCU_FAMILY samd51 + +#define MICROPY_HW_LED_STATUS (&pin_PA27) + +// These are pins not to reset. +// QSPI Data pins +#define MICROPY_PORT_A (PORT_PA08 | PORT_PA09 | PORT_PA10 | PORT_PA11) +// DotStar pins, QSPI CS, and QSPI SCK +#define MICROPY_PORT_B (PORT_PB10 | PORT_PB11) +#define MICROPY_PORT_C (0) +#define MICROPY_PORT_D (0) + +#define AUTORESET_DELAY_MS 500 + +// If you change this, then make sure to update the linker scripts as well to +// make sure you don't overwrite code +#define CIRCUITPY_INTERNAL_NVM_SIZE 8192 + +#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE) + +#define DEFAULT_I2C_BUS_SCL (&pin_PA01) +#define DEFAULT_I2C_BUS_SDA (&pin_PA00) + +// USB is always used internally so skip the pin objects for it. +#define IGNORE_PIN_PA24 1 +#define IGNORE_PIN_PA25 1 + +#define CIRCUITPY_FS_NAME "MONSTERM4SK" diff --git a/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.mk b/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.mk new file mode 100644 index 000000000..534b7468f --- /dev/null +++ b/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.mk @@ -0,0 +1,18 @@ +LD_FILE = boards/samd51x19-bootloader-external-flash.ld +USB_VID = 0x239A +USB_PID = 0x8048 +USB_PRODUCT = "Monster M4SK" +USB_MANUFACTURER = "Adafruit Industries LLC" + +CHIP_VARIANT = SAMD51J19A +CHIP_FAMILY = samd51 + +QSPI_FLASH_FILESYSTEM = 1 +EXTERNAL_FLASH_DEVICE_COUNT = 1 +EXTERNAL_FLASH_DEVICES = GD25Q64C +LONGINT_IMPL = MPZ + +CIRCUITPY_AUDIOIO = 1 +CIRCUITPY_DISPLAYIO = 1 +# No touch on SAMD51 yet +CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/monster_m4sk/pins.c b/ports/atmel-samd/boards/monster_m4sk/pins.c new file mode 100644 index 000000000..11f9a063f --- /dev/null +++ b/ports/atmel-samd/boards/monster_m4sk/pins.c @@ -0,0 +1,48 @@ +#include "shared-bindings/board/__init__.h" + +#include "boards/board.h" +#include "shared-module/displayio/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_PA02) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_HEADPHONE_LEFT), MP_ROM_PTR(&pin_PA02) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_HEADPHONE_RIGHT), MP_ROM_PTR(&pin_PA05) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PA05) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PB03) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_NOSE), MP_ROM_PTR(&pin_PB03) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PB02) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA27) }, + + // I2C + { MP_OBJ_NEW_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA00) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA01) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_ACCELEROMETER_INTERRUPT), MP_ROM_PTR(&pin_PA22) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_SPEAKER_ENABLE), MP_ROM_PTR(&pin_PA14) }, + + { MP_ROM_QSTR(MP_QSTR_MICROPHONE_CLOCK), MP_ROM_PTR(&pin_PA16) }, + { MP_ROM_QSTR(MP_QSTR_MICROPHONE_DATA), MP_ROM_PTR(&pin_PA17) }, + + // Right TFT control pins + { MP_OBJ_NEW_QSTR(MP_QSTR_RIGHT_TFT_LITE), MP_ROM_PTR(&pin_PA23) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_RIGHT_TFT_MOSI), MP_ROM_PTR(&pin_PA12) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_RIGHT_TFT_SCK), MP_ROM_PTR(&pin_PA13) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_RIGHT_TFT_RST), MP_ROM_PTR(&pin_PA04) }, + { MP_ROM_QSTR(MP_QSTR_RIGHT_TFT_CS), MP_ROM_PTR(&pin_PA06) }, + { MP_ROM_QSTR(MP_QSTR_RIGHT_TFT_DC), MP_ROM_PTR(&pin_PA07) }, + + // Left TFT control pins. Some pins are attached through the SeeSaw chip. + { MP_OBJ_NEW_QSTR(MP_QSTR_LEFT_TFT_MOSI), MP_ROM_PTR(&pin_PB02) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LEFT_TFT_SCK), MP_ROM_PTR(&pin_PB03) }, + { MP_ROM_QSTR(MP_QSTR_LEFT_TFT_CS), MP_ROM_PTR(&pin_PB23) }, + { MP_ROM_QSTR(MP_QSTR_LEFT_TFT_DC), MP_ROM_PTR(&pin_PB22) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}, + { MP_ROM_QSTR(MP_QSTR_RIGHT_DISPLAY), MP_ROM_PTR(&displays[0].display)} +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index c2e2e2d02..923c02b9e 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -657,4 +657,8 @@ void run_background_tasks(void); #define CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS 1000 #define CIRCUITPY_BOOT_OUTPUT_FILE "/boot_out.txt" +#ifndef CIRCUITPY_FS_NAME +#define CIRCUITPY_FS_NAME "CIRCUITPY" +#endif + #endif // __INCLUDED_MPCONFIG_CIRCUITPY_H diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c index c50d7f4ee..36b30f462 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -91,7 +91,7 @@ void filesystem_init(bool create_allowed, bool force_create) { } // set label - f_setlabel(&vfs_fat->fatfs, "CIRCUITPY"); + f_setlabel(&vfs_fat->fatfs, CIRCUITPY_FS_NAME); // inhibit file indexing on MacOS f_mkdir(&vfs_fat->fatfs, "/.fseventsd"); From 8d836fa248d10b8943945423a069a3fba387f8a2 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 22 Aug 2019 00:33:27 -0700 Subject: [PATCH 12/18] Regular display fixes including refresh tweaks --- shared-module/displayio/Display.c | 25 ++++++++++++++++++------- shared-module/displayio/Display.h | 2 ++ shared-module/displayio/EPaperDisplay.c | 8 +++++--- shared-module/displayio/TileGrid.c | 2 +- shared-module/displayio/TileGrid.h | 2 +- shared-module/displayio/__init__.c | 4 +--- shared-module/displayio/display_core.c | 11 +++++++---- 7 files changed, 35 insertions(+), 19 deletions(-) diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 86800328f..109b91507 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -64,21 +64,23 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->write_ram_command = write_ram_command; self->brightness_command = brightness_command; self->auto_brightness = auto_brightness; + self->auto_refresh = auto_refresh; + self->first_manual_refresh = !auto_refresh; self->data_as_commands = data_as_commands; self->native_frames_per_second = native_frames_per_second; self->native_frame_time = 1000 / native_frames_per_second; uint32_t i = 0; - while (!displayio_display_core_begin_transaction(&self->core)) { - RUN_BACKGROUND_TASKS; - } while (i < init_sequence_len) { uint8_t *cmd = init_sequence + i; uint8_t data_size = *(cmd + 1); bool delay = (data_size & DELAY) != 0; data_size &= ~DELAY; uint8_t *data = cmd + 2; + while (!displayio_display_core_begin_transaction(&self->core)) { + RUN_BACKGROUND_TASKS; + } if (self->data_as_commands) { uint8_t full_command[data_size + 1]; full_command[0] = cmd[0]; @@ -88,6 +90,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->core.send(self->core.bus, true, true, cmd, 1); self->core.send(self->core.bus, false, false, data, data_size); } + self->core.end_transaction(self->core.bus); uint16_t delay_length_ms = 10; if (delay) { data_size++; @@ -99,7 +102,6 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, common_hal_time_delay_ms(delay_length_ms); i += 2 + data_size; } - self->core.end_transaction(self->core.bus); supervisor_start_terminal(width, height); @@ -192,9 +194,10 @@ STATIC const displayio_area_t* _get_refresh_areas(displayio_display_obj_t *self) if (self->core.full_refresh) { self->core.area.next = NULL; return &self->core.area; - } else { + } else if (self->core.current_group != NULL) { return displayio_group_get_refresh_areas(self->core.current_group, NULL); } + return NULL; } STATIC void _send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length) { @@ -242,7 +245,7 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* // Allocated and shared as a uint32_t array so the compiler knows the // alignment everywhere. uint32_t buffer[buffer_size]; - volatile uint32_t mask_length = (pixels_per_buffer / 32) + 1; + uint32_t mask_length = (pixels_per_buffer / 32) + 1; uint32_t mask[mask_length]; uint16_t remaining_rows = displayio_area_height(&clipped); @@ -311,7 +314,7 @@ uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self } void common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_frame_time, uint32_t maximum_frame_time) { - if (!self->auto_refresh) { + if (!self->auto_refresh && !self->first_manual_refresh) { uint64_t current_time = ticks_ms; uint32_t current_frame_time = current_time - self->core.last_refresh; // Test to see if the real frame time is below our minimum. @@ -332,6 +335,7 @@ void common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_ #endif } } + self->first_manual_refresh = false; _refresh_display(self); } @@ -341,6 +345,7 @@ bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t* self, bool auto_refresh) { + self->first_manual_refresh = !auto_refresh; self->auto_refresh = auto_refresh; } @@ -376,6 +381,12 @@ void release_display(displayio_display_obj_t* self) { } } +void reset_display(displayio_display_obj_t* self) { + self->auto_refresh = true; + self->auto_brightness = true; + common_hal_displayio_display_show(self, NULL); +} + void displayio_display_collect_ptrs(displayio_display_obj_t* self) { displayio_display_core_collect_ptrs(&self->core); } diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index cff566a61..bf2889c6d 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -51,6 +51,7 @@ typedef struct { uint8_t set_row_command; uint8_t write_ram_command; bool auto_refresh; + bool first_manual_refresh; bool data_as_commands; bool auto_brightness; bool updating_backlight; @@ -58,6 +59,7 @@ typedef struct { void displayio_display_background(displayio_display_obj_t* self); void release_display(displayio_display_obj_t* self); +void reset_display(displayio_display_obj_t* self); void displayio_display_collect_ptrs(displayio_display_obj_t* self); diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index bf0e6676f..48143f14f 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -102,10 +102,12 @@ bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self } const displayio_area_t* displayio_epaperdisplay_get_refresh_areas(displayio_epaperdisplay_obj_t *self) { - const displayio_area_t* first_area; if (self->core.full_refresh) { - first_area = &self->core.area; - } else { + self->core.area.next = NULL; + return &self->core.area; + } + const displayio_area_t* first_area = NULL; + if (self->core.current_group != NULL) { first_area = displayio_group_get_refresh_areas(self->core.current_group, NULL); } if (first_area != NULL && self->set_row_window_command == NO_COMMAND) { diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index 6553cf901..f34d2fc52 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -207,7 +207,7 @@ uint8_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint1 void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint8_t tile_index) { if (tile_index >= self->tiles_in_bitmap) { - mp_raise_ValueError(translate("Tile value out of bounds")); + mp_raise_ValueError(translate("Tile index out of bounds")); } uint8_t* tiles = self->tiles; if (self->inline_tiles) { diff --git a/shared-module/displayio/TileGrid.h b/shared-module/displayio/TileGrid.h index 222aaed19..0a414b062 100644 --- a/shared-module/displayio/TileGrid.h +++ b/shared-module/displayio/TileGrid.h @@ -43,7 +43,7 @@ typedef struct { uint16_t pixel_width; uint16_t pixel_height; uint16_t bitmap_width_in_tiles;; - uint8_t tiles_in_bitmap; + uint16_t tiles_in_bitmap; uint16_t width_in_tiles; uint16_t height_in_tiles; uint16_t tile_width; diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index a41884c78..af22cb0df 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -143,9 +143,7 @@ void reset_displays(void) { // Reset the displayed group. Only the first will get the terminal but // that's ok. if (displays[i].display.base.type == &displayio_display_type) { - displayio_display_obj_t* display = &displays[i].display; - display->auto_brightness = true; - common_hal_displayio_display_show(display, NULL); + reset_display(&displays[i].display); } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { displayio_epaperdisplay_obj_t* display = &displays[i].epaper_display; common_hal_displayio_epaperdisplay_show(display, NULL); diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 24d8ab51f..88878866a 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -82,8 +82,8 @@ void displayio_display_core_construct(displayio_display_core_t* self, self->width = width; self->height = height; - self->ram_width = width; - self->ram_height = height; + self->ram_width = ram_width; + self->ram_height = ram_height; rotation = rotation % 360; self->transform.x = 0; self->transform.y = 0; @@ -206,7 +206,7 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[0] = column_command; uint8_t data_length = 1; if (!data_as_commands) { - self->send(self->bus, true, true, data, 1); + self->send(self->bus, true, false, data, 1); data_length = 0; } if (self->ram_width < 0x100) { @@ -227,11 +227,14 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, self->send(self->bus, false, always_toggle_chip_select, data, data_length / 2); } + displayio_display_core_end_transaction(self); + displayio_display_core_begin_transaction(self); + // Set row. data[0] = row_command; data_length = 1; if (!data_as_commands) { - self->send(self->bus, true, true, data, 1); + self->send(self->bus, true, false, data, 1); data_length = 0; } if (self->ram_height < 0x100) { From d2d27a01b9671c74ae34b5fcc7146e29a4ac59f0 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 22 Aug 2019 12:59:17 -0700 Subject: [PATCH 13/18] Update translations --- locale/ID.po | 28 ++++++++++++++++++++++------ locale/circuitpython.pot | 28 ++++++++++++++++++++++------ locale/de_DE.po | 28 ++++++++++++++++++++++------ locale/en_US.po | 28 ++++++++++++++++++++++------ locale/en_x_pirate.po | 28 ++++++++++++++++++++++------ locale/es.po | 37 +++++++++++++++++++++++++++++-------- locale/fil.po | 28 ++++++++++++++++++++++------ locale/fr.po | 36 +++++++++++++++++++++++++++++------- locale/it_IT.po | 28 ++++++++++++++++++++++------ locale/pl.po | 35 ++++++++++++++++++++++++++++------- locale/pt_BR.po | 28 ++++++++++++++++++++++------ locale/zh_Latn_pinyin.po | 35 ++++++++++++++++++++++++++++------- 12 files changed, 290 insertions(+), 77 deletions(-) diff --git a/locale/ID.po b/locale/ID.po index 61991e611..95b1c26dc 100644 --- a/locale/ID.po +++ b/locale/ID.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-08-22 15:20-0400\n" +"POT-Creation-Date: 2019-08-22 14:29-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -301,6 +301,10 @@ msgstr "" "Auto-reload aktif. Silahkan simpan data-data (files) melalui USB untuk " "menjalankannya atau masuk ke REPL untukmenonaktifkan.\n" +#: shared-module/displayio/Display.c +msgid "Below minimum frame rate" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must share a clock unit" msgstr "Bit clock dan word harus memiliki kesamaan pada clock unit" @@ -533,6 +537,7 @@ msgid "Display must have a 16 bit colorspace." msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Display rotation must be in 90 degree increments" msgstr "" @@ -749,6 +754,7 @@ msgid "Function requires lock" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Group already used" msgstr "" @@ -1026,8 +1032,8 @@ msgstr "" #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" -"Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp " -"given" +"Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: " +"%d bpp given" msgstr "" #: shared-bindings/_pixelbuf/PixelBuf.c @@ -1104,6 +1110,10 @@ msgstr "sistem file (filesystem) bersifat Read-only" msgid "Read-only object" msgstr "sistem file (filesystem) bersifat Read-only" +#: shared-bindings/displayio/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "Right channel unsupported" msgstr "Channel Kanan tidak didukung" @@ -1218,11 +1228,11 @@ msgstr "" msgid "Tile height must exactly divide bitmap height" msgstr "" -#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c msgid "Tile index out of bounds" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c msgid "Tile value out of bounds" msgstr "" @@ -1244,6 +1254,7 @@ msgid "Too many display busses" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Too many displays" msgstr "" @@ -1315,7 +1326,7 @@ msgstr "" msgid "Unsupported baudrate" msgstr "Baudrate tidak didukung" -#: shared-module/displayio/Display.c +#: shared-module/displayio/display_core.c #, fuzzy msgid "Unsupported display bus type" msgstr "Baudrate tidak didukung" @@ -2198,6 +2209,11 @@ msgstr "tidak ada ikatan/bind pada temuan nonlocal" msgid "no module named '%q'" msgstr "tidak ada modul yang bernama '%q'" +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c +#: shared-bindings/displayio/ParallelBus.c +msgid "no reset pin available" +msgstr "" + #: py/runtime.c shared-bindings/_pixelbuf/__init__.c msgid "no such attribute" msgstr "" diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 50de690fe..d478baef4 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: 2019-08-22 15:20-0400\n" +"POT-Creation-Date: 2019-08-22 14:29-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -297,6 +297,10 @@ msgid "" "disable.\n" msgstr "" +#: shared-module/displayio/Display.c +msgid "Below minimum frame rate" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must share a clock unit" msgstr "" @@ -522,6 +526,7 @@ msgid "Display must have a 16 bit colorspace." msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Display rotation must be in 90 degree increments" msgstr "" @@ -734,6 +739,7 @@ msgid "Function requires lock" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Group already used" msgstr "" @@ -1010,8 +1016,8 @@ msgstr "" #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" -"Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp " -"given" +"Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: " +"%d bpp given" msgstr "" #: shared-bindings/_pixelbuf/PixelBuf.c @@ -1085,6 +1091,10 @@ msgstr "" msgid "Read-only object" msgstr "" +#: shared-bindings/displayio/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "Right channel unsupported" msgstr "" @@ -1195,11 +1205,11 @@ msgstr "" msgid "Tile height must exactly divide bitmap height" msgstr "" -#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c msgid "Tile index out of bounds" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c msgid "Tile value out of bounds" msgstr "" @@ -1221,6 +1231,7 @@ msgid "Too many display busses" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Too many displays" msgstr "" @@ -1292,7 +1303,7 @@ msgstr "" msgid "Unsupported baudrate" msgstr "" -#: shared-module/displayio/Display.c +#: shared-module/displayio/display_core.c msgid "Unsupported display bus type" msgstr "" @@ -2163,6 +2174,11 @@ msgstr "" msgid "no module named '%q'" msgstr "" +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c +#: shared-bindings/displayio/ParallelBus.c +msgid "no reset pin available" +msgstr "" + #: py/runtime.c shared-bindings/_pixelbuf/__init__.c msgid "no such attribute" msgstr "" diff --git a/locale/de_DE.po b/locale/de_DE.po index c74e5b1ff..e39d157f4 100644 --- a/locale/de_DE.po +++ b/locale/de_DE.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-08-22 15:20-0400\n" +"POT-Creation-Date: 2019-08-22 14:29-0700\n" "PO-Revision-Date: 2018-07-27 11:55-0700\n" "Last-Translator: Pascal Deneaux\n" "Language-Team: Sebastian Plamauer, Pascal Deneaux\n" @@ -301,6 +301,10 @@ msgstr "" "Automatisches Neuladen ist aktiv. Speichere Dateien über USB um sie " "auszuführen oder verbinde dich mit der REPL zum Deaktivieren.\n" +#: shared-module/displayio/Display.c +msgid "Below minimum frame rate" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must share a clock unit" msgstr "Bit clock und word select müssen eine clock unit teilen" @@ -526,6 +530,7 @@ msgid "Display must have a 16 bit colorspace." msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Display rotation must be in 90 degree increments" msgstr "Die Rotation der Anzeige muss in 90-Grad-Schritten erfolgen" @@ -738,6 +743,7 @@ msgid "Function requires lock" msgstr "Die Funktion erwartet, dass der 'lock'-Befehl zuvor ausgeführt wurde" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Group already used" msgstr "" @@ -1025,8 +1031,8 @@ msgstr "" #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" -"Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp " -"given" +"Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: " +"%d bpp given" msgstr "" #: shared-bindings/_pixelbuf/PixelBuf.c @@ -1102,6 +1108,10 @@ msgstr "Schreibgeschützte Dateisystem" msgid "Read-only object" msgstr "Schreibgeschützte Objekt" +#: shared-bindings/displayio/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "Right channel unsupported" msgstr "Rechter Kanal wird nicht unterstützt" @@ -1224,11 +1234,11 @@ msgstr "" msgid "Tile height must exactly divide bitmap height" msgstr "" -#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c msgid "Tile index out of bounds" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c msgid "Tile value out of bounds" msgstr "" @@ -1250,6 +1260,7 @@ msgid "Too many display busses" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Too many displays" msgstr "Zu viele displays" @@ -1323,7 +1334,7 @@ msgstr "" msgid "Unsupported baudrate" msgstr "Baudrate wird nicht unterstützt" -#: shared-module/displayio/Display.c +#: shared-module/displayio/display_core.c msgid "Unsupported display bus type" msgstr "Nicht unterstützter display bus type" @@ -2210,6 +2221,11 @@ msgstr "" msgid "no module named '%q'" msgstr "Kein Modul mit dem Namen '%q'" +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c +#: shared-bindings/displayio/ParallelBus.c +msgid "no reset pin available" +msgstr "" + #: py/runtime.c shared-bindings/_pixelbuf/__init__.c msgid "no such attribute" msgstr "" diff --git a/locale/en_US.po b/locale/en_US.po index ff4643875..186ac9a4f 100644 --- a/locale/en_US.po +++ b/locale/en_US.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-08-22 15:20-0400\n" +"POT-Creation-Date: 2019-08-22 14:29-0700\n" "PO-Revision-Date: 2018-07-27 11:55-0700\n" "Last-Translator: \n" "Language-Team: \n" @@ -297,6 +297,10 @@ msgid "" "disable.\n" msgstr "" +#: shared-module/displayio/Display.c +msgid "Below minimum frame rate" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must share a clock unit" msgstr "" @@ -522,6 +526,7 @@ msgid "Display must have a 16 bit colorspace." msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Display rotation must be in 90 degree increments" msgstr "" @@ -734,6 +739,7 @@ msgid "Function requires lock" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Group already used" msgstr "" @@ -1010,8 +1016,8 @@ msgstr "" #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" -"Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp " -"given" +"Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: " +"%d bpp given" msgstr "" #: shared-bindings/_pixelbuf/PixelBuf.c @@ -1085,6 +1091,10 @@ msgstr "" msgid "Read-only object" msgstr "" +#: shared-bindings/displayio/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "Right channel unsupported" msgstr "" @@ -1195,11 +1205,11 @@ msgstr "" msgid "Tile height must exactly divide bitmap height" msgstr "" -#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c msgid "Tile index out of bounds" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c msgid "Tile value out of bounds" msgstr "" @@ -1221,6 +1231,7 @@ msgid "Too many display busses" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Too many displays" msgstr "" @@ -1292,7 +1303,7 @@ msgstr "" msgid "Unsupported baudrate" msgstr "" -#: shared-module/displayio/Display.c +#: shared-module/displayio/display_core.c msgid "Unsupported display bus type" msgstr "" @@ -2163,6 +2174,11 @@ msgstr "" msgid "no module named '%q'" msgstr "" +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c +#: shared-bindings/displayio/ParallelBus.c +msgid "no reset pin available" +msgstr "" + #: py/runtime.c shared-bindings/_pixelbuf/__init__.c msgid "no such attribute" msgstr "" diff --git a/locale/en_x_pirate.po b/locale/en_x_pirate.po index 08b3db299..21c49745c 100644 --- a/locale/en_x_pirate.po +++ b/locale/en_x_pirate.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-08-22 15:20-0400\n" +"POT-Creation-Date: 2019-08-22 14:29-0700\n" "PO-Revision-Date: 2018-07-27 11:55-0700\n" "Last-Translator: \n" "Language-Team: @sommersoft, @MrCertainly\n" @@ -301,6 +301,10 @@ msgstr "" "Auto-reload be on. Put yer files on USB to weigh anchor, er' bring'er about " "t' the REPL t' scuttle.\n" +#: shared-module/displayio/Display.c +msgid "Below minimum frame rate" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must share a clock unit" msgstr "" @@ -526,6 +530,7 @@ msgid "Display must have a 16 bit colorspace." msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Display rotation must be in 90 degree increments" msgstr "" @@ -738,6 +743,7 @@ msgid "Function requires lock" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Group already used" msgstr "" @@ -1014,8 +1020,8 @@ msgstr "" #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" -"Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp " -"given" +"Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: " +"%d bpp given" msgstr "" #: shared-bindings/_pixelbuf/PixelBuf.c @@ -1089,6 +1095,10 @@ msgstr "" msgid "Read-only object" msgstr "" +#: shared-bindings/displayio/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "Right channel unsupported" msgstr "" @@ -1199,11 +1209,11 @@ msgstr "" msgid "Tile height must exactly divide bitmap height" msgstr "" -#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c msgid "Tile index out of bounds" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c msgid "Tile value out of bounds" msgstr "" @@ -1225,6 +1235,7 @@ msgid "Too many display busses" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Too many displays" msgstr "" @@ -1296,7 +1307,7 @@ msgstr "" msgid "Unsupported baudrate" msgstr "" -#: shared-module/displayio/Display.c +#: shared-module/displayio/display_core.c msgid "Unsupported display bus type" msgstr "" @@ -2167,6 +2178,11 @@ msgstr "" msgid "no module named '%q'" msgstr "" +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c +#: shared-bindings/displayio/ParallelBus.c +msgid "no reset pin available" +msgstr "" + #: py/runtime.c shared-bindings/_pixelbuf/__init__.c msgid "no such attribute" msgstr "" diff --git a/locale/es.po b/locale/es.po index 3b1b8ece5..89052a6ba 100644 --- a/locale/es.po +++ b/locale/es.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-08-22 15:20-0400\n" +"POT-Creation-Date: 2019-08-22 14:29-0700\n" "PO-Revision-Date: 2018-08-24 22:56-0500\n" "Last-Translator: \n" "Language-Team: \n" @@ -305,6 +305,10 @@ msgstr "" "Auto-reload habilitado. Simplemente guarda los archivos via USB para " "ejecutarlos o entra al REPL para desabilitarlos.\n" +#: shared-module/displayio/Display.c +msgid "Below minimum frame rate" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must share a clock unit" msgstr "Bit clock y word select deben compartir una unidad de reloj" @@ -530,6 +534,7 @@ msgid "Display must have a 16 bit colorspace." msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Display rotation must be in 90 degree increments" msgstr "Rotación de display debe ser en incrementos de 90 grados" @@ -743,6 +748,7 @@ msgid "Function requires lock" msgstr "La función requiere lock" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Group already used" msgstr "" @@ -1029,11 +1035,9 @@ msgstr "" #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" -"Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp " -"given" +"Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: " +"%d bpp given" msgstr "" -"Solo se admiten BMP monocromos, indexados de 8bpp y 16bpp o superiores:% d " -"bppdado" #: shared-bindings/_pixelbuf/PixelBuf.c #, fuzzy @@ -1113,6 +1117,10 @@ msgstr "Sistema de archivos de solo-Lectura" msgid "Read-only object" msgstr "Solo-lectura" +#: shared-bindings/displayio/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "Right channel unsupported" msgstr "Canal derecho no soportado" @@ -1235,11 +1243,11 @@ msgstr "El signo del sample no iguala al del mixer" msgid "Tile height must exactly divide bitmap height" msgstr "La altura del Tile debe dividir exacto la altura del bitmap" -#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c msgid "Tile index out of bounds" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c msgid "Tile value out of bounds" msgstr "" @@ -1261,6 +1269,7 @@ msgid "Too many display busses" msgstr "Demasiados buses de pantalla" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Too many displays" msgstr "Muchos displays" @@ -1332,7 +1341,7 @@ msgstr "Número incomparable de elementos en RHS (%d esperado,%d obtenido)" msgid "Unsupported baudrate" msgstr "Baudrate no soportado" -#: shared-module/displayio/Display.c +#: shared-module/displayio/display_core.c #, fuzzy msgid "Unsupported display bus type" msgstr "tipo de bitmap no soportado" @@ -2222,6 +2231,11 @@ msgstr "no se ha encontrado ningún enlace para nonlocal" msgid "no module named '%q'" msgstr "ningún módulo se llama '%q'" +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c +#: shared-bindings/displayio/ParallelBus.c +msgid "no reset pin available" +msgstr "" + #: py/runtime.c shared-bindings/_pixelbuf/__init__.c msgid "no such attribute" msgstr "no hay tal atributo" @@ -2887,6 +2901,13 @@ msgstr "paso cero" #~ msgid "Only bit maps of 8 bit color or less are supported" #~ msgstr "Solo se admiten bit maps de color de 8 bits o menos" +#~ msgid "" +#~ "Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d " +#~ "bpp given" +#~ msgstr "" +#~ "Solo se admiten BMP monocromos, indexados de 8bpp y 16bpp o superiores:" +#~ "% d bppdado" + #~ msgid "Only true color (24 bpp or higher) BMP supported %x" #~ msgstr "Solo color verdadero (24 bpp o superior) BMP admitido %x" diff --git a/locale/fil.po b/locale/fil.po index 3abdd882f..b034afba0 100644 --- a/locale/fil.po +++ b/locale/fil.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-08-22 15:20-0400\n" +"POT-Creation-Date: 2019-08-22 14:29-0700\n" "PO-Revision-Date: 2018-12-20 22:15-0800\n" "Last-Translator: Timothy \n" "Language-Team: fil\n" @@ -303,6 +303,10 @@ msgstr "" "Ang awtomatikong pag re-reload ay ON. i-save lamang ang mga files sa USB " "para patakbuhin sila o pasukin ang REPL para i-disable ito.\n" +#: shared-module/displayio/Display.c +msgid "Below minimum frame rate" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must share a clock unit" msgstr "Ang bit clock at word select dapat makibahagi sa isang clock unit" @@ -534,6 +538,7 @@ msgid "Display must have a 16 bit colorspace." msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Display rotation must be in 90 degree increments" msgstr "" @@ -752,6 +757,7 @@ msgid "Function requires lock" msgstr "Function nangangailangan ng lock" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Group already used" msgstr "" @@ -1037,8 +1043,8 @@ msgstr "" #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" -"Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp " -"given" +"Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: " +"%d bpp given" msgstr "" #: shared-bindings/_pixelbuf/PixelBuf.c @@ -1118,6 +1124,10 @@ msgstr "Basahin-lamang mode" msgid "Read-only object" msgstr "Basahin-lamang" +#: shared-bindings/displayio/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "Right channel unsupported" msgstr "Hindi supportado ang kanang channel" @@ -1238,11 +1248,11 @@ msgstr "Ang signedness ng sample hindi tugma sa mixer" msgid "Tile height must exactly divide bitmap height" msgstr "" -#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c msgid "Tile index out of bounds" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c msgid "Tile value out of bounds" msgstr "" @@ -1264,6 +1274,7 @@ msgid "Too many display busses" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Too many displays" msgstr "" @@ -1336,7 +1347,7 @@ msgstr "" msgid "Unsupported baudrate" msgstr "Hindi supportadong baudrate" -#: shared-module/displayio/Display.c +#: shared-module/displayio/display_core.c #, fuzzy msgid "Unsupported display bus type" msgstr "Hindi supportadong tipo ng bitmap" @@ -2234,6 +2245,11 @@ msgstr "no binding para sa nonlocal, nahanap" msgid "no module named '%q'" msgstr "walang module na '%q'" +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c +#: shared-bindings/displayio/ParallelBus.c +msgid "no reset pin available" +msgstr "" + #: py/runtime.c shared-bindings/_pixelbuf/__init__.c msgid "no such attribute" msgstr "walang ganoon na attribute" diff --git a/locale/fr.po b/locale/fr.po index c9c81da61..d386723eb 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-08-22 15:20-0400\n" +"POT-Creation-Date: 2019-08-22 14:29-0700\n" "PO-Revision-Date: 2019-04-14 20:05+0100\n" "Last-Translator: Pierrick Couturier \n" "Language-Team: fr\n" @@ -308,6 +308,10 @@ msgstr "" "Auto-chargement activé. Copiez simplement les fichiers en USB pour les " "lancer ou entrez sur REPL pour le désactiver.\n" +#: shared-module/displayio/Display.c +msgid "Below minimum frame rate" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must share a clock unit" msgstr "'bit clock' et 'word select' doivent partager une horloge" @@ -538,6 +542,7 @@ msgid "Display must have a 16 bit colorspace." msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Display rotation must be in 90 degree increments" msgstr "La rotation d'affichage doit se faire par incréments de 90 degrés" @@ -757,6 +762,7 @@ msgid "Function requires lock" msgstr "La fonction nécessite un verrou" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Group already used" msgstr "" @@ -1049,10 +1055,9 @@ msgstr "" #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" -"Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp " -"given" +"Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: " +"%d bpp given" msgstr "" -"Seul les BMP monochromes, 8bit indexé et 16bit sont supportés: %d bpp fourni" #: shared-bindings/_pixelbuf/PixelBuf.c #, fuzzy @@ -1134,6 +1139,10 @@ msgstr "Système de fichier en lecture seule" msgid "Read-only object" msgstr "Objet en lecture seule" +#: shared-bindings/displayio/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "Right channel unsupported" msgstr "Canal droit non supporté" @@ -1259,11 +1268,11 @@ msgstr "Le signe de l'échantillon ne correspond pas à celui du mixer" msgid "Tile height must exactly divide bitmap height" msgstr "La hauteur de la tuile doit diviser exactement la hauteur de l'image" -#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c msgid "Tile index out of bounds" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c msgid "Tile value out of bounds" msgstr "" @@ -1285,6 +1294,7 @@ msgid "Too many display busses" msgstr "Trop de bus d'affichage" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Too many displays" msgstr "Trop d'affichages" @@ -1361,7 +1371,7 @@ msgstr "" msgid "Unsupported baudrate" msgstr "Débit non supporté" -#: shared-module/displayio/Display.c +#: shared-module/displayio/display_core.c #, fuzzy msgid "Unsupported display bus type" msgstr "Type de bus d'affichage non supporté" @@ -2268,6 +2278,11 @@ msgstr "pas de lien trouvé pour nonlocal" msgid "no module named '%q'" msgstr "pas de module '%q'" +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c +#: shared-bindings/displayio/ParallelBus.c +msgid "no reset pin available" +msgstr "" + #: py/runtime.c shared-bindings/_pixelbuf/__init__.c msgid "no such attribute" msgstr "pas de tel attribut" @@ -2938,6 +2953,13 @@ msgstr "'step' nul" #~ msgid "Only bit maps of 8 bit color or less are supported" #~ msgstr "Seules les bitmaps de 8bits par couleur ou moins sont supportées" +#~ msgid "" +#~ "Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d " +#~ "bpp given" +#~ msgstr "" +#~ "Seul les BMP monochromes, 8bit indexé et 16bit sont supportés: %d bpp " +#~ "fourni" + #~ msgid "Only true color (24 bpp or higher) BMP supported %x" #~ msgstr "Seul les BMP 24bits ou plus sont supportés %x" diff --git a/locale/it_IT.po b/locale/it_IT.po index 4fb0b502f..293ae97a0 100644 --- a/locale/it_IT.po +++ b/locale/it_IT.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-08-22 15:20-0400\n" +"POT-Creation-Date: 2019-08-22 14:29-0700\n" "PO-Revision-Date: 2018-10-02 16:27+0200\n" "Last-Translator: Enrico Paganin \n" "Language-Team: \n" @@ -302,6 +302,10 @@ msgstr "" "L'auto-reload è attivo. Salva i file su USB per eseguirli o entra nel REPL " "per disabilitarlo.\n" +#: shared-module/displayio/Display.c +msgid "Below minimum frame rate" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must share a clock unit" msgstr "" @@ -534,6 +538,7 @@ msgid "Display must have a 16 bit colorspace." msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Display rotation must be in 90 degree increments" msgstr "" @@ -751,6 +756,7 @@ msgid "Function requires lock" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Group already used" msgstr "" @@ -1037,8 +1043,8 @@ msgstr "" #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" -"Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp " -"given" +"Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: " +"%d bpp given" msgstr "" #: shared-bindings/_pixelbuf/PixelBuf.c @@ -1122,6 +1128,10 @@ msgstr "Filesystem in sola lettura" msgid "Read-only object" msgstr "Sola lettura" +#: shared-bindings/displayio/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "Right channel unsupported" msgstr "Canale destro non supportato" @@ -1237,11 +1247,11 @@ msgstr "" msgid "Tile height must exactly divide bitmap height" msgstr "" -#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c msgid "Tile index out of bounds" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c msgid "Tile value out of bounds" msgstr "" @@ -1263,6 +1273,7 @@ msgid "Too many display busses" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Too many displays" msgstr "Troppi schermi" @@ -1335,7 +1346,7 @@ msgstr "" msgid "Unsupported baudrate" msgstr "baudrate non supportato" -#: shared-module/displayio/Display.c +#: shared-module/displayio/display_core.c #, fuzzy msgid "Unsupported display bus type" msgstr "tipo di bitmap non supportato" @@ -2228,6 +2239,11 @@ msgstr "nessun binding per nonlocal trovato" msgid "no module named '%q'" msgstr "nessun modulo chiamato '%q'" +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c +#: shared-bindings/displayio/ParallelBus.c +msgid "no reset pin available" +msgstr "" + #: py/runtime.c shared-bindings/_pixelbuf/__init__.c msgid "no such attribute" msgstr "attributo inesistente" diff --git a/locale/pl.po b/locale/pl.po index 8d995d93a..c275bd4d0 100644 --- a/locale/pl.po +++ b/locale/pl.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-08-22 15:20-0400\n" +"POT-Creation-Date: 2019-08-22 14:29-0700\n" "PO-Revision-Date: 2019-03-19 18:37-0700\n" "Last-Translator: Radomir Dopieralski \n" "Language-Team: pl\n" @@ -300,6 +300,10 @@ msgstr "" "Samo-przeładowywanie włączone. Po prostu zapisz pliki przez USB aby je " "uruchomić, albo wejdź w konsolę aby wyłączyć.\n" +#: shared-module/displayio/Display.c +msgid "Below minimum frame rate" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must share a clock unit" msgstr "Zegar bitowy i wybór słowa muszą współdzielić jednostkę zegara" @@ -525,6 +529,7 @@ msgid "Display must have a 16 bit colorspace." msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Display rotation must be in 90 degree increments" msgstr "Wyświetlacz można obracać co 90 stopni" @@ -737,6 +742,7 @@ msgid "Function requires lock" msgstr "Funkcja wymaga blokady" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Group already used" msgstr "" @@ -1020,9 +1026,9 @@ msgstr "Wspierane są tylko nieskompresowane pliki BMP: wielkość nagłówka %d #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" -"Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp " -"given" -msgstr "Wspierane są tylko pliki BMP czarno-białe, 8bpp i 16bpp: %d bpp " +"Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: " +"%d bpp given" +msgstr "" #: shared-bindings/_pixelbuf/PixelBuf.c msgid "Only slices with step=1 (aka None) are supported" @@ -1095,6 +1101,10 @@ msgstr "System plików tylko do odczytu" msgid "Read-only object" msgstr "Obiekt tylko do odczytu" +#: shared-bindings/displayio/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "Right channel unsupported" msgstr "Prawy kanał jest niewspierany" @@ -1215,11 +1225,11 @@ msgstr "Znak nie pasuje do miksera" msgid "Tile height must exactly divide bitmap height" msgstr "Wysokość bitmapy musi być wielokrotnością wysokości kafelka" -#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c msgid "Tile index out of bounds" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c msgid "Tile value out of bounds" msgstr "" @@ -1241,6 +1251,7 @@ msgid "Too many display busses" msgstr "Zbyt wiele magistrali" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Too many displays" msgstr "Zbyt wiele wyświetlaczy" @@ -1312,7 +1323,7 @@ msgstr "Zła liczba obiektów po prawej stronie (oczekiwano %d, jest %d)." msgid "Unsupported baudrate" msgstr "Zła szybkość transmisji" -#: shared-module/displayio/Display.c +#: shared-module/displayio/display_core.c msgid "Unsupported display bus type" msgstr "Zły typ magistrali wyświetlaczy" @@ -2188,6 +2199,11 @@ msgstr "brak wiązania dla zmiennej nielokalnej" msgid "no module named '%q'" msgstr "brak modułu o nazwie '%q'" +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c +#: shared-bindings/displayio/ParallelBus.c +msgid "no reset pin available" +msgstr "" + #: py/runtime.c shared-bindings/_pixelbuf/__init__.c msgid "no such attribute" msgstr "nie ma takiego atrybutu" @@ -2769,6 +2785,11 @@ msgstr "zerowy krok" #~ msgid "Must be a Group subclass." #~ msgstr "Musi dziedziczyć z Group." +#~ msgid "" +#~ "Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d " +#~ "bpp given" +#~ msgstr "Wspierane są tylko pliki BMP czarno-białe, 8bpp i 16bpp: %d bpp " + #~ msgid "Tile indices must be 0 - 255" #~ msgstr "Indeks kafelka musi być pomiędzy 0 a 255 włącznie" diff --git a/locale/pt_BR.po b/locale/pt_BR.po index 6e7edbc2f..2ae16f992 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-08-22 15:20-0400\n" +"POT-Creation-Date: 2019-08-22 14:29-0700\n" "PO-Revision-Date: 2018-10-02 21:14-0000\n" "Last-Translator: \n" "Language-Team: \n" @@ -300,6 +300,10 @@ msgid "" "disable.\n" msgstr "" +#: shared-module/displayio/Display.c +msgid "Below minimum frame rate" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must share a clock unit" msgstr "" @@ -529,6 +533,7 @@ msgid "Display must have a 16 bit colorspace." msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Display rotation must be in 90 degree increments" msgstr "" @@ -746,6 +751,7 @@ msgid "Function requires lock" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Group already used" msgstr "" @@ -1028,8 +1034,8 @@ msgstr "" #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" -"Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp " -"given" +"Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: " +"%d bpp given" msgstr "" #: shared-bindings/_pixelbuf/PixelBuf.c @@ -1105,6 +1111,10 @@ msgstr "Sistema de arquivos somente leitura" msgid "Read-only object" msgstr "Somente leitura" +#: shared-bindings/displayio/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "Right channel unsupported" msgstr "Canal direito não suportado" @@ -1215,11 +1225,11 @@ msgstr "" msgid "Tile height must exactly divide bitmap height" msgstr "" -#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c msgid "Tile index out of bounds" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c msgid "Tile value out of bounds" msgstr "" @@ -1241,6 +1251,7 @@ msgid "Too many display busses" msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Too many displays" msgstr "" @@ -1312,7 +1323,7 @@ msgstr "" msgid "Unsupported baudrate" msgstr "Taxa de transmissão não suportada" -#: shared-module/displayio/Display.c +#: shared-module/displayio/display_core.c #, fuzzy msgid "Unsupported display bus type" msgstr "Taxa de transmissão não suportada" @@ -2189,6 +2200,11 @@ msgstr "" msgid "no module named '%q'" msgstr "" +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c +#: shared-bindings/displayio/ParallelBus.c +msgid "no reset pin available" +msgstr "" + #: py/runtime.c shared-bindings/_pixelbuf/__init__.c msgid "no such attribute" msgstr "" diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po index 9a380fefc..886bba62a 100644 --- a/locale/zh_Latn_pinyin.po +++ b/locale/zh_Latn_pinyin.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: circuitpython-cn\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-08-22 15:20-0400\n" +"POT-Creation-Date: 2019-08-22 14:29-0700\n" "PO-Revision-Date: 2019-04-13 10:10-0700\n" "Last-Translator: hexthat\n" "Language-Team: Chinese Hanyu Pinyin\n" @@ -301,6 +301,10 @@ msgstr "" "Zìdòng chóngxīn jiāzài. Zhǐ xū tōngguò USB bǎocún wénjiàn lái yùnxíng tāmen " "huò shūrù REPL jìnyòng.\n" +#: shared-module/displayio/Display.c +msgid "Below minimum frame rate" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must share a clock unit" msgstr "Bǐtè shízhōng hé dānzì xuǎnzé bìxū gòngxiǎng shízhōng dānwèi" @@ -526,6 +530,7 @@ msgid "Display must have a 16 bit colorspace." msgstr "" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Display rotation must be in 90 degree increments" msgstr "Xiǎnshì xuánzhuǎn bìxū 90 dù jiā xīn" @@ -738,6 +743,7 @@ msgid "Function requires lock" msgstr "Hánshù xūyào suǒdìng" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Group already used" msgstr "" @@ -1023,10 +1029,9 @@ msgstr "" #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" -"Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp " -"given" +"Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: " +"%d bpp given" msgstr "" -"Jǐn zhīchí dān sè, suǒyǐn 8bpp hé 16bpp huò gèng dà de BMP: %d bpp tígōng" #: shared-bindings/_pixelbuf/PixelBuf.c msgid "Only slices with step=1 (aka None) are supported" @@ -1100,6 +1105,10 @@ msgstr "Zhǐ dú wénjiàn xìtǒng" msgid "Read-only object" msgstr "Zhǐ dú duìxiàng" +#: shared-bindings/displayio/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "Right channel unsupported" msgstr "Bù zhīchí yòu tōngdào" @@ -1222,11 +1231,11 @@ msgstr "Yàngběn de qiānmíng yǔ hǔn yīn qì de qiānmíng bù pǐpèi" msgid "Tile height must exactly divide bitmap height" msgstr "Píng pū gāodù bìxū huàfēn wèi tú gāodù" -#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c msgid "Tile index out of bounds" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +#: shared-bindings/displayio/TileGrid.c msgid "Tile value out of bounds" msgstr "" @@ -1248,6 +1257,7 @@ msgid "Too many display busses" msgstr "Xiǎnshì zǒngxiàn tài duōle" #: shared-bindings/displayio/Display.c +#: shared-bindings/displayio/EPaperDisplay.c msgid "Too many displays" msgstr "Xiǎnshì tài duō" @@ -1319,7 +1329,7 @@ msgstr "RHS (yùqí %d, huòdé %d) shàng wèi pǐpèi de xiàngmù." msgid "Unsupported baudrate" msgstr "Bù zhīchí de baudrate" -#: shared-module/displayio/Display.c +#: shared-module/displayio/display_core.c msgid "Unsupported display bus type" msgstr "Bù zhīchí de gōnggòng qìchē lèixíng" @@ -2202,6 +2212,11 @@ msgstr "zhǎo bù dào fēi běndì de bǎng dìng" msgid "no module named '%q'" msgstr "méiyǒu mókuài '%q'" +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c +#: shared-bindings/displayio/ParallelBus.c +msgid "no reset pin available" +msgstr "" + #: py/runtime.c shared-bindings/_pixelbuf/__init__.c msgid "no such attribute" msgstr "méiyǒu cǐ shǔxìng" @@ -2798,6 +2813,12 @@ msgstr "líng bù" #~ msgid "Only bit maps of 8 bit color or less are supported" #~ msgstr "Jǐn zhīchí 8 wèi yánsè huò xiǎoyú" +#~ msgid "" +#~ "Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d " +#~ "bpp given" +#~ msgstr "" +#~ "Jǐn zhīchí dān sè, suǒyǐn 8bpp hé 16bpp huò gèng dà de BMP: %d bpp tígōng" + #~ msgid "Tile indices must be 0 - 255" #~ msgstr "Píng pū zhǐshù bìxū wèi 0 - 255" From fd8050b36956718acfc740132aa27498c24d846b Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 22 Aug 2019 15:19:45 -0700 Subject: [PATCH 14/18] Turn off features to make room for ePaper --- .../boards/feather_m0_express/mpconfigboard.mk | 4 ++++ .../boards/feather_m0_supersized/mpconfigboard.mk | 4 ++++ .../boards/hallowing_m0_express/mpconfigboard.h | 4 ++++ .../boards/hallowing_m0_express/mpconfigboard.mk | 9 +++++++-- .../atmel-samd/boards/metro_m0_express/mpconfigboard.mk | 3 +++ .../boards/sparkfun_redboard_turbo/mpconfigboard.mk | 3 +++ .../boards/trinket_m0_haxpress/mpconfigboard.mk | 4 ++++ ports/atmel-samd/boards/ugame10/board.c | 4 +++- 8 files changed, 32 insertions(+), 3 deletions(-) diff --git a/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk index 756c293ad..5b89f1be4 100644 --- a/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk @@ -12,5 +12,9 @@ EXTERNAL_FLASH_DEVICE_COUNT = 2 EXTERNAL_FLASH_DEVICES = "S25FL216K, GD25Q16C" LONGINT_IMPL = MPZ +CIRCUITPY_BITBANGIO = 0 +CIRCUITPY_FREQUENCYIO = 0 +CIRCUITPY_I2CSLAVE = 0 + CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 diff --git a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk index e34d06962..c5fef4373 100644 --- a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk @@ -12,5 +12,9 @@ EXTERNAL_FLASH_DEVICE_COUNT = 1 EXTERNAL_FLASH_DEVICES = "S25FL064L" LONGINT_IMPL = MPZ +CIRCUITPY_BITBANGIO = 0 +CIRCUITPY_FREQUENCYIO = 0 +CIRCUITPY_I2CSLAVE = 0 + CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 diff --git a/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.h b/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.h index 4b5460706..d5c274500 100644 --- a/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.h +++ b/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.h @@ -35,3 +35,7 @@ // USB is always used internally so skip the pin objects for it. #define IGNORE_PIN_PA24 1 #define IGNORE_PIN_PA25 1 + +// SWD is only available on the test pads so skip the pin objects. +#define IGNORE_PIN_PA30 1 +#define IGNORE_PIN_PA31 1 diff --git a/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.mk index 92374721f..988d10d1c 100644 --- a/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.mk @@ -13,10 +13,15 @@ EXTERNAL_FLASH_DEVICES = "W25Q64JV_IQ, GD25Q64C" LONGINT_IMPL = MPZ # To keep the build small -CIRCUITPY_I2CSLAVE = 0 -CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_AUDIOBUSIO = 0 CIRCUITPY_BITBANGIO = 0 +CIRCUITPY_FREQUENCYIO = 0 +CIRCUITPY_GAMEPAD = 0 +CIRCUITPY_I2CSLAVE = 0 +CIRCUITPY_ROTARYIO = 0 +CIRCUITPY_RTC = 0 + +CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 # Include these Python libraries in firmware. diff --git a/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk index 93a8ffc11..d3f35ba8b 100644 --- a/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk @@ -12,5 +12,8 @@ EXTERNAL_FLASH_DEVICE_COUNT = 2 EXTERNAL_FLASH_DEVICES = "S25FL216K, GD25Q16C" LONGINT_IMPL = MPZ +CIRCUITPY_BITBANGIO = 0 +CIRCUITPY_I2CSLAVE = 0 + CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 diff --git a/ports/atmel-samd/boards/sparkfun_redboard_turbo/mpconfigboard.mk b/ports/atmel-samd/boards/sparkfun_redboard_turbo/mpconfigboard.mk index 3be1a17d3..e80ef6277 100755 --- a/ports/atmel-samd/boards/sparkfun_redboard_turbo/mpconfigboard.mk +++ b/ports/atmel-samd/boards/sparkfun_redboard_turbo/mpconfigboard.mk @@ -12,5 +12,8 @@ EXTERNAL_FLASH_DEVICE_COUNT = 1 EXTERNAL_FLASH_DEVICES = "W25Q32FV" LONGINT_IMPL = MPZ +CIRCUITPY_BITBANGIO = 0 +CIRCUITPY_I2CSLAVE = 0 + CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 diff --git a/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk b/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk index 76c33a333..c20358e19 100644 --- a/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk +++ b/ports/atmel-samd/boards/trinket_m0_haxpress/mpconfigboard.mk @@ -12,4 +12,8 @@ EXTERNAL_FLASH_DEVICE_COUNT = 1 EXTERNAL_FLASH_DEVICES = W25Q32BV LONGINT_IMPL = MPZ +CIRCUITPY_BITBANGIO = 0 +CIRCUITPY_FREQUENCYIO = 0 +CIRCUITPY_I2CSLAVE = 0 + SUPEROPT_GC = 0 diff --git a/ports/atmel-samd/boards/ugame10/board.c b/ports/atmel-samd/boards/ugame10/board.c index 72b0ed577..ce389a2b1 100644 --- a/ports/atmel-samd/boards/ugame10/board.c +++ b/ports/atmel-samd/boards/ugame10/board.c @@ -106,7 +106,9 @@ void board_init(void) { 1.0f, // brightness false, // auto_brightness false, // single_byte_bounds - false); // data as commands + false, // data as commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { From 72e7ffa324f8184cb2d9a5ca9fa620a2a5a56b69 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 22 Aug 2019 16:16:09 -0700 Subject: [PATCH 15/18] More cleanup --- ports/atmel-samd/boards/snekboard/mpconfigboard.mk | 3 +++ shared-bindings/displayio/EPaperDisplay.c | 2 +- shared-bindings/displayio/EPaperDisplay.h | 6 ------ shared-module/displayio/ColorConverter.c | 1 - shared-module/displayio/Group.c | 3 --- shared-module/displayio/OnDiskBitmap.c | 4 +--- 6 files changed, 5 insertions(+), 14 deletions(-) diff --git a/ports/atmel-samd/boards/snekboard/mpconfigboard.mk b/ports/atmel-samd/boards/snekboard/mpconfigboard.mk index 9892ade8f..6ad78b0da 100644 --- a/ports/atmel-samd/boards/snekboard/mpconfigboard.mk +++ b/ports/atmel-samd/boards/snekboard/mpconfigboard.mk @@ -12,5 +12,8 @@ EXTERNAL_FLASH_DEVICE_COUNT = 1 EXTERNAL_FLASH_DEVICES = "W25Q16JV_IQ" LONGINT_IMPL = MPZ +CIRCUITPY_GAMEPAD = 0 +CIRCUITPY_I2CSLAVE = 0 + CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index dd773e410..5d0d8ac94 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -42,7 +42,7 @@ //| .. currentmodule:: displayio //| //| :class:`EPaperDisplay` -- Manage updating an epaper display over a display bus -//| ========================================================================== +//| ============================================================================== //| //| This initializes an epaper display and connects it into CircuitPython. Unlike other //| objects in CircuitPython, EPaperDisplay objects live until `displayio.release_displays()` diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index 786fc3628..e4b81c883 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -53,15 +53,9 @@ bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self // Returns time in milliseconds. uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self); -bool common_hal_displayio_epaperdisplay_get_auto_brightness(displayio_epaperdisplay_obj_t* self); -void common_hal_displayio_epaperdisplay_set_auto_brightness(displayio_epaperdisplay_obj_t* self, bool auto_brightness); - uint16_t common_hal_displayio_epaperdisplay_get_width(displayio_epaperdisplay_obj_t* self); uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_obj_t* self); -mp_float_t common_hal_displayio_epaperdisplay_get_brightness(displayio_epaperdisplay_obj_t* self); -bool common_hal_displayio_epaperdisplay_set_brightness(displayio_epaperdisplay_obj_t* self, mp_float_t brightness); - mp_obj_t common_hal_displayio_epaperdisplay_get_bus(displayio_epaperdisplay_obj_t* self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 0277c79f0..e0c4ca286 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -142,7 +142,6 @@ bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d uint8_t luma = displayio_colorconverter_compute_luma(input_color); *output_color = luma >> (8 - colorspace->depth); return true; - } else if (!colorspace->grayscale && colorspace->depth == 1) { } return false; } diff --git a/shared-module/displayio/Group.c b/shared-module/displayio/Group.c index eb6e9a453..38418a029 100644 --- a/shared-module/displayio/Group.c +++ b/shared-module/displayio/Group.c @@ -304,9 +304,6 @@ void displayio_group_finish_refresh(displayio_group_t *self) { } displayio_area_t* displayio_group_get_refresh_areas(displayio_group_t *self, displayio_area_t* tail) { - if (self->base.type != &displayio_group_type) { - asm("bkpt"); - } if (self->item_removed) { self->dirty_area.next = tail; tail = &self->dirty_area; diff --git a/shared-module/displayio/OnDiskBitmap.c b/shared-module/displayio/OnDiskBitmap.c index 10fc0c4a2..993fc03de 100644 --- a/shared-module/displayio/OnDiskBitmap.c +++ b/shared-module/displayio/OnDiskBitmap.c @@ -149,10 +149,8 @@ uint32_t common_hal_displayio_ondiskbitmap_get_pixel(displayio_ondiskbitmap_t *s if (self->bits_per_pixel == 1) { if (index == 1) { return 0xFFFFFF; - } else if (index == 0) { - return 0x000000; } else { - asm("bkpt"); + return 0x000000; } } return self->palette_data[index]; From b992ca80e77ccd95397ed0f12063c30f6161e08f Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 22 Aug 2019 20:29:58 -0700 Subject: [PATCH 16/18] Rejigger builds to fit under 50 minute limit --- .travis.yml | 5 +++-- .../atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk | 3 +-- ports/atmel-samd/boards/snekboard/mpconfigboard.mk | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index d084a3042..47e7dea78 100755 --- a/.travis.yml +++ b/.travis.yml @@ -35,8 +35,9 @@ env: - TRAVIS_BOARDS="itsybitsy_m0_express metro_m0_express pirkey_m0 pyruler trinket_m0 trinket_m0_haxpress arduino_mkr1300 arduino_mkrzero arduino_zero bast_pro_mini_m0 catwan_usbstick datum_distance datum_imu datum_weather" TRAVIS_SDK=arm - TRAVIS_BOARDS="escornabot_makech meowmeow pewpew10 robohatmm1_m0 snekboard sparkfun_lumidrive sparkfun_redboard_turbo sparkfun_samd21_dev sparkfun_samd21_mini uchip ugame10" TRAVIS_SDK=arm # Adafruit SAMD51 (M4) + Other SAMD51 - - TRAVIS_BOARDS="feather_m4_express grandcentral_m4_express itsybitsy_m4_express metro_m4_airlift_lite metro_m4_express pybadge pybadge_airlift pygamer pygamer_advance monster_m4sk" TRAVIS_SDK=arm - - TRAVIS_BOARDS="pyportal pyportal_titano trellis_m4_express capablerobot_usbhub cp32-m4 datalore_ip_m4 datum_light kicksat-sprite mini_sam_m4 robohatmm1_m4 sam32" TRAVIS_SDK=arm + - TRAVIS_BOARDS="feather_m4_express grandcentral_m4_express itsybitsy_m4_express metro_m4_airlift_lite metro_m4_express pybadge pybadge_airlift" TRAVIS_SDK=arm + - TRAVIS_BOARDS="pyportal pyportal_titano trellis_m4_express capablerobot_usbhub cp32-m4 datalore_ip_m4 datum_light" TRAVIS_SDK=arm + - TRAVIS_BOARDS="pygamer pygamer_advance monster_m4sk kicksat-sprite mini_sam_m4 robohatmm1_m4 sam32" TRAVIS_SDK=arm addons: diff --git a/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk index 410a0e087..10975931f 100644 --- a/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk @@ -12,11 +12,10 @@ EXTERNAL_FLASH_DEVICE_COUNT = 2 EXTERNAL_FLASH_DEVICES = "W25Q16FW, GD25Q16C" LONGINT_IMPL = MPZ +CIRCUITPY_GAMEPAD = 0 CIRCUITPY_I2CSLAVE = 0 CIRCUITPY_RTC = 0 CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 -CIRCUITPY_I2CSLAVE = 0 -CIRCUITPY_RTC = 0 diff --git a/ports/atmel-samd/boards/snekboard/mpconfigboard.mk b/ports/atmel-samd/boards/snekboard/mpconfigboard.mk index 6ad78b0da..db2e511ab 100644 --- a/ports/atmel-samd/boards/snekboard/mpconfigboard.mk +++ b/ports/atmel-samd/boards/snekboard/mpconfigboard.mk @@ -12,6 +12,7 @@ EXTERNAL_FLASH_DEVICE_COUNT = 1 EXTERNAL_FLASH_DEVICES = "W25Q16JV_IQ" LONGINT_IMPL = MPZ +CIRCUITPY_BITBANGIO = 0 CIRCUITPY_GAMEPAD = 0 CIRCUITPY_I2CSLAVE = 0 From 7324b70a7c231a20be971ed81050c8359b87aaab Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 23 Aug 2019 15:27:21 -0700 Subject: [PATCH 17/18] Rework based on Dan's review --- .../boards/monster_m4sk/mpconfigboard.h | 2 - .../common-hal/displayio/ParallelBus.c | 4 +- ports/nrf/common-hal/displayio/ParallelBus.c | 5 +- py/circuitpy_mpconfig.h | 4 -- shared-bindings/_stage/__init__.c | 2 +- shared-bindings/displayio/Display.c | 24 +++++++--- shared-bindings/displayio/Display.h | 2 +- shared-bindings/displayio/EPaperDisplay.c | 2 +- shared-bindings/displayio/FourWire.c | 8 +++- shared-bindings/displayio/FourWire.h | 4 +- shared-bindings/displayio/I2CDisplay.c | 2 +- shared-bindings/displayio/I2CDisplay.h | 4 +- shared-bindings/displayio/ParallelBus.c | 4 +- shared-bindings/displayio/ParallelBus.h | 5 +- shared-bindings/displayio/__init__.h | 19 ++++++++ shared-module/_stage/__init__.c | 4 +- shared-module/displayio/ColorConverter.c | 38 +++------------ shared-module/displayio/Display.c | 47 +++++++++---------- shared-module/displayio/Display.h | 2 +- shared-module/displayio/EPaperDisplay.c | 24 ++++------ shared-module/displayio/EPaperDisplay.h | 2 +- shared-module/displayio/FourWire.c | 7 +-- shared-module/displayio/I2CDisplay.c | 7 +-- shared-module/displayio/display_core.c | 38 ++++++++++----- shared-module/displayio/display_core.h | 7 +-- supervisor/shared/filesystem.c | 2 +- 26 files changed, 137 insertions(+), 132 deletions(-) diff --git a/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.h b/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.h index 484f3d7b2..fc77520f5 100644 --- a/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.h +++ b/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.h @@ -27,5 +27,3 @@ // USB is always used internally so skip the pin objects for it. #define IGNORE_PIN_PA24 1 #define IGNORE_PIN_PA25 1 - -#define CIRCUITPY_FS_NAME "MONSTERM4SK" diff --git a/ports/atmel-samd/common-hal/displayio/ParallelBus.c b/ports/atmel-samd/common-hal/displayio/ParallelBus.c index e2ce9952b..2479e3b40 100644 --- a/ports/atmel-samd/common-hal/displayio/ParallelBus.c +++ b/ports/atmel-samd/common-hal/displayio/ParallelBus.c @@ -131,9 +131,9 @@ bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t obj) { return true; } -void common_hal_displayio_parallelbus_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_parallelbus_send(mp_obj_t obj, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length) { displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); - common_hal_digitalio_digitalinout_set_value(&self->command, !command); + common_hal_digitalio_digitalinout_set_value(&self->command, byte_type == DISPLAY_DATA); uint32_t* clear_write = (uint32_t*) &self->write_group->OUTCLR.reg; uint32_t* set_write = (uint32_t*) &self->write_group->OUTSET.reg; uint32_t mask = self->write_mask; diff --git a/ports/nrf/common-hal/displayio/ParallelBus.c b/ports/nrf/common-hal/displayio/ParallelBus.c index a8c2b9f73..be4b28a6e 100644 --- a/ports/nrf/common-hal/displayio/ParallelBus.c +++ b/ports/nrf/common-hal/displayio/ParallelBus.c @@ -142,9 +142,10 @@ bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t obj) { return true; } -void common_hal_displayio_parallelbus_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { +// This ignores chip_select behaviour because data is clocked in by the write line toggling. +void common_hal_displayio_parallelbus_send(mp_obj_t obj, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length) { displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); - common_hal_digitalio_digitalinout_set_value(&self->command, !command); + common_hal_digitalio_digitalinout_set_value(&self->command, byte_type == DISPLAY_DATA); uint32_t* clear_write = (uint32_t*) &self->write_group->OUTCLR; uint32_t* set_write = (uint32_t*) &self->write_group->OUTSET; uint32_t mask = self->write_mask; diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 923c02b9e..c2e2e2d02 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -657,8 +657,4 @@ void run_background_tasks(void); #define CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS 1000 #define CIRCUITPY_BOOT_OUTPUT_FILE "/boot_out.txt" -#ifndef CIRCUITPY_FS_NAME -#define CIRCUITPY_FS_NAME "CIRCUITPY" -#endif - #endif // __INCLUDED_MPCONFIG_CIRCUITPY_H diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c index 1d970cce4..d18d306f4 100644 --- a/shared-bindings/_stage/__init__.c +++ b/shared-bindings/_stage/__init__.c @@ -107,7 +107,7 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { area.y2 = y1; displayio_display_core_set_region_to_update(&display->core, display->set_column_command, display->set_row_command, NO_COMMAND, NO_COMMAND, display->data_as_commands, false, &area); - display->core.send(display->core.bus, true, true, &display->write_ram_command, 1); + display->core.send(display->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, &display->write_ram_command, 1); render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size, display, scale); displayio_display_core_end_transaction(&display->core); diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index ded4119ca..1eb1943b8 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -218,16 +218,22 @@ STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) } MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show); -//| .. method:: refresh(*, target_frames_per_second=None, minimum_frames_per_second=1) +//| .. method:: refresh(*, target_frames_per_second=60, minimum_frames_per_second=1) //| -//| When auto refresh is off, waits for the target frame rate and then refreshes the display. If -//| the call is too late for the given target frame rate, then the refresh returns immediately -//| without updating the screen to hopefully help getting caught up. If the current frame rate -//| is below the minimum frame rate, then an exception will be raised. +//| When auto refresh is off, waits for the target frame rate and then refreshes the display, +//| returning True. If the call has taken too long since the last refresh call for the given +//| target frame rate, then the refresh returns False immediately without updating the screen to +//| hopefully help getting caught up. +//| +//| If the time since the last successful refresh is below the minimum frame rate, then an +//| exception will be raised. Set minimum_frames_per_second to 0 to disable. //| //| When auto refresh is on, updates the display immediately. (The display will also update //| without calls to this.) //| +//| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. +//| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second. +//| STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_target_frames_per_second, ARG_minimum_frames_per_second }; static const mp_arg_t allowed_args[] = { @@ -238,8 +244,12 @@ STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); displayio_display_obj_t *self = native_display(pos_args[0]); - common_hal_displayio_display_refresh(self, 1000 / args[ARG_target_frames_per_second].u_int, 1000 / args[ARG_minimum_frames_per_second].u_int); - return mp_const_none; + uint32_t maximum_ms_per_real_frame = 0xffffffff; + mp_int_t minimum_frames_per_second = args[ARG_minimum_frames_per_second].u_int; + if (minimum_frames_per_second > 0) { + maximum_ms_per_real_frame = 1000 / minimum_frames_per_second; + } + return mp_obj_new_bool(common_hal_displayio_display_refresh(self, 1000 / args[ARG_target_frames_per_second].u_int, maximum_ms_per_real_frame)); } MP_DEFINE_CONST_FUN_OBJ_KW(displayio_display_refresh_obj, 1, displayio_display_obj_refresh); diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index 06c848d0d..2d7b68c4e 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -51,7 +51,7 @@ bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); // Times in ms. -void common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_frame_time, uint32_t maximum_frame_time); +bool common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame); bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self); void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t* self, bool auto_refresh); diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index 5d0d8ac94..81e06f82f 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -55,7 +55,7 @@ //| //| Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| -//| The ``start_sequence`` and ``stop_sequence`` bitpacked to minimize the ram impact. Every +//| The ``start_sequence`` and ``stop_sequence`` are bitpacked to minimize the ram impact. Every //| command begins with a command byte followed by a byte to determine the parameter count and if //| a delay is need after. When the top bit of the second byte is 1, the next byte will be the //| delay time in milliseconds. The remaining 7 bits are the parameter count excluding any delay diff --git a/shared-bindings/displayio/FourWire.c b/shared-bindings/displayio/FourWire.c index c69623344..51203d460 100644 --- a/shared-bindings/displayio/FourWire.c +++ b/shared-bindings/displayio/FourWire.c @@ -146,8 +146,12 @@ STATIC mp_obj_t displayio_fourwire_obj_send(size_t n_args, const mp_obj_t *pos_a while (!common_hal_displayio_fourwire_begin_transaction(self)) { RUN_BACKGROUND_TASKS; } - common_hal_displayio_fourwire_send(self, true, args[ARG_toggle_every_byte].u_bool, &command, 1); - common_hal_displayio_fourwire_send(self, false, args[ARG_toggle_every_byte].u_bool, ((uint8_t*) bufinfo.buf), bufinfo.len); + display_chip_select_behavior_t chip_select = CHIP_SELECT_UNTOUCHED; + if (args[ARG_toggle_every_byte].u_bool) { + chip_select = CHIP_SELECT_TOGGLE_EVERY_BYTE; + } + common_hal_displayio_fourwire_send(self, DISPLAY_COMMAND, chip_select, &command, 1); + common_hal_displayio_fourwire_send(self, DISPLAY_DATA, chip_select, ((uint8_t*) bufinfo.buf), bufinfo.len); common_hal_displayio_fourwire_end_transaction(self); return mp_const_none; diff --git a/shared-bindings/displayio/FourWire.h b/shared-bindings/displayio/FourWire.h index 9c71d63cc..d0935f063 100644 --- a/shared-bindings/displayio/FourWire.h +++ b/shared-bindings/displayio/FourWire.h @@ -28,6 +28,8 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_FOURWIRE_H #include "shared-module/displayio/FourWire.h" + +#include "shared-bindings/displayio/__init__.h" #include "common-hal/microcontroller/Pin.h" #include "shared-module/displayio/Group.h" @@ -45,7 +47,7 @@ bool common_hal_displayio_fourwire_bus_free(mp_obj_t self); bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t self); -void common_hal_displayio_fourwire_send(mp_obj_t self, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); +void common_hal_displayio_fourwire_send(mp_obj_t self, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length); void common_hal_displayio_fourwire_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c index 4de5e83ef..4339d182f 100644 --- a/shared-bindings/displayio/I2CDisplay.c +++ b/shared-bindings/displayio/I2CDisplay.c @@ -131,7 +131,7 @@ STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_ob uint8_t full_command[bufinfo.len + 1]; full_command[0] = command; memcpy(full_command + 1, ((uint8_t*) bufinfo.buf), bufinfo.len); - common_hal_displayio_i2cdisplay_send(self, true, false, full_command, bufinfo.len + 1); + common_hal_displayio_i2cdisplay_send(self, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, full_command, bufinfo.len + 1); common_hal_displayio_i2cdisplay_end_transaction(self); return mp_const_none; diff --git a/shared-bindings/displayio/I2CDisplay.h b/shared-bindings/displayio/I2CDisplay.h index 683cff383..bae53c491 100644 --- a/shared-bindings/displayio/I2CDisplay.h +++ b/shared-bindings/displayio/I2CDisplay.h @@ -28,6 +28,8 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H #include "shared-module/displayio/I2CDisplay.h" + +#include "shared-bindings/displayio/__init__.h" #include "common-hal/microcontroller/Pin.h" extern const mp_obj_type_t displayio_i2cdisplay_type; @@ -42,7 +44,7 @@ bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t self); bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t self); -void common_hal_displayio_i2cdisplay_send(mp_obj_t self, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); +void common_hal_displayio_i2cdisplay_send(mp_obj_t self, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length); void common_hal_displayio_i2cdisplay_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/ParallelBus.c b/shared-bindings/displayio/ParallelBus.c index a08c37679..f7195b9cc 100644 --- a/shared-bindings/displayio/ParallelBus.c +++ b/shared-bindings/displayio/ParallelBus.c @@ -139,8 +139,8 @@ STATIC mp_obj_t displayio_parallelbus_obj_send(mp_obj_t self, mp_obj_t command_o while (!common_hal_displayio_parallelbus_begin_transaction(self)) { RUN_BACKGROUND_TASKS; } - common_hal_displayio_parallelbus_send(self, true, false, &command, 1); - common_hal_displayio_parallelbus_send(self, false, false, ((uint8_t*) bufinfo.buf), bufinfo.len); + common_hal_displayio_parallelbus_send(self, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, &command, 1); + common_hal_displayio_parallelbus_send(self, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ((uint8_t*) bufinfo.buf), bufinfo.len); common_hal_displayio_parallelbus_end_transaction(self); return mp_const_none; diff --git a/shared-bindings/displayio/ParallelBus.h b/shared-bindings/displayio/ParallelBus.h index a0f967332..be2aef7d4 100644 --- a/shared-bindings/displayio/ParallelBus.h +++ b/shared-bindings/displayio/ParallelBus.h @@ -28,8 +28,9 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_PARALLELBUS_H #include "common-hal/displayio/ParallelBus.h" -#include "common-hal/microcontroller/Pin.h" +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/displayio/__init__.h" #include "shared-module/displayio/Group.h" extern const mp_obj_type_t displayio_parallelbus_type; @@ -45,7 +46,7 @@ bool common_hal_displayio_parallelbus_bus_free(mp_obj_t self); bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t self); -void common_hal_displayio_parallelbus_send(mp_obj_t self, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); +void common_hal_displayio_parallelbus_send(mp_obj_t self, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length); void common_hal_displayio_parallelbus_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/__init__.h b/shared-bindings/displayio/__init__.h index 427ddb47d..122b1fbcb 100644 --- a/shared-bindings/displayio/__init__.h +++ b/shared-bindings/displayio/__init__.h @@ -27,6 +27,25 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H #define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H +#include "py/obj.h" + +typedef enum { + DISPLAY_COMMAND, + DISPLAY_DATA +} display_byte_type_t; + + +typedef enum { + CHIP_SELECT_UNTOUCHED, + CHIP_SELECT_TOGGLE_EVERY_BYTE +} display_chip_select_behavior_t; + +typedef bool (*display_bus_bus_reset)(mp_obj_t bus); +typedef bool (*display_bus_bus_free)(mp_obj_t bus); +typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); +typedef void (*display_bus_send)(mp_obj_t bus, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length); +typedef void (*display_bus_end_transaction)(mp_obj_t bus); + void common_hal_displayio_release_displays(void); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H diff --git a/shared-module/_stage/__init__.c b/shared-module/_stage/__init__.c index bfef165e7..2c525be87 100644 --- a/shared-module/_stage/__init__.c +++ b/shared-module/_stage/__init__.c @@ -57,7 +57,7 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, index += 1; // The buffer is full, send it. if (index >= buffer_size) { - display->core.send(display->core.bus, false, false, ((uint8_t*)buffer), + display->core.send(display->core.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ((uint8_t*)buffer), buffer_size * 2); index = 0; } @@ -67,6 +67,6 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, } // Send the remaining data. if (index) { - display->core.send(display->core.bus, false, false, ((uint8_t*)buffer), index * 2); + display->core.send(display->core.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ((uint8_t*)buffer), index * 2); } } diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index e0c4ca286..940aaa1c6 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -26,6 +26,8 @@ #include "shared-bindings/displayio/ColorConverter.h" +#include "py/misc.h" + void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self) { } @@ -45,39 +47,12 @@ uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888) { return (r8 * 19) / 255 + (g8 * 182) / 255 + (b8 + 54) / 255; } -void compute_bounds(uint8_t r8, uint8_t g8, uint8_t b8, uint8_t* min, uint8_t* max) { - if (r8 > g8) { - if (b8 > r8) { - *max = b8; - } else { - *max = r8; - } - if (b8 < g8) { - *min = b8; - } else { - *min = g8; - } - } else { - if (b8 > g8) { - *max = b8; - } else { - *max = g8; - } - if (b8 < r8) { - *min = b8; - } else { - *min = r8; - } - } -} - uint8_t displayio_colorconverter_compute_chroma(uint32_t color_rgb888) { uint32_t r8 = (color_rgb888 >> 16); uint32_t g8 = (color_rgb888 >> 8) & 0xff; uint32_t b8 = color_rgb888 & 0xff; - uint8_t max; - uint8_t min; - compute_bounds(r8, g8, b8, &min, &max); + uint8_t max = MAX(r8, MAX(g8, b8)); + uint8_t min = MIN(r8, MIN(g8, b8)); return max - min; } @@ -85,9 +60,8 @@ uint8_t displayio_colorconverter_compute_hue(uint32_t color_rgb888) { uint32_t r8 = (color_rgb888 >> 16); uint32_t g8 = (color_rgb888 >> 8) & 0xff; uint32_t b8 = color_rgb888 & 0xff; - uint8_t max; - uint8_t min; - compute_bounds(r8, g8, b8, &min, &max); + uint8_t max = MAX(r8, MAX(g8, b8)); + uint8_t min = MIN(r8, MIN(g8, b8)); uint8_t c = max - min; if (c == 0) { return 0; diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 109b91507..cb5051bb7 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -69,7 +69,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->data_as_commands = data_as_commands; self->native_frames_per_second = native_frames_per_second; - self->native_frame_time = 1000 / native_frames_per_second; + self->native_ms_per_frame = 1000 / native_frames_per_second; uint32_t i = 0; while (i < init_sequence_len) { @@ -85,10 +85,10 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t full_command[data_size + 1]; full_command[0] = cmd[0]; memcpy(full_command + 1, data, data_size); - self->core.send(self->core.bus, true, true, full_command, data_size + 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, full_command, data_size + 1); } else { - self->core.send(self->core.bus, true, true, cmd, 1); - self->core.send(self->core.bus, false, false, data, data_size); + self->core.send(self->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, cmd, 1); + self->core.send(self->core.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, data, data_size); } self->core.end_transaction(self->core.bus); uint16_t delay_length_ms = 10; @@ -168,12 +168,12 @@ bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, if (ok) { if (self->data_as_commands) { uint8_t set_brightness[2] = {self->brightness_command, (uint8_t) (0xff * brightness)}; - self->core.send(self->core.bus, true, true, set_brightness, 2); + self->core.send(self->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, set_brightness, 2); } else { uint8_t command = self->brightness_command; uint8_t hex_brightness = 0xff * brightness; - self->core.send(self->core.bus, true, true, &command, 1); - self->core.send(self->core.bus, false, false, &hex_brightness, 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, &command, 1); + self->core.send(self->core.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, &hex_brightness, 1); } displayio_display_core_end_transaction(&self->core); } @@ -202,9 +202,9 @@ STATIC const displayio_area_t* _get_refresh_areas(displayio_display_obj_t *self) STATIC void _send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length) { if (!self->data_as_commands) { - self->core.send(self->core.bus, true, true, &self->write_ram_command, 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, &self->write_ram_command, 1); } - self->core.send(self->core.bus, false, false, pixels, length); + self->core.send(self->core.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, pixels, length); } STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* area) { @@ -270,12 +270,8 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); } - for (uint16_t k = 0; k < mask_length; k++) { - mask[k] = 0x00000000; - } - for (uint16_t k = 0; k < buffer_size; k++) { - buffer[k] = 0x00000000; - } + memset(mask, 0, mask_length * sizeof(uint32_t)); + memset(buffer, 0, buffer_size * sizeof(uint32_t)); displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); @@ -313,30 +309,29 @@ uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self return self->core.rotation; } -void common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_frame_time, uint32_t maximum_frame_time) { +bool common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame) { if (!self->auto_refresh && !self->first_manual_refresh) { uint64_t current_time = ticks_ms; - uint32_t current_frame_time = current_time - self->core.last_refresh; + uint32_t current_ms_since_real_refresh = current_time - self->core.last_refresh; // Test to see if the real frame time is below our minimum. - if (current_frame_time > maximum_frame_time) { + if (current_ms_since_real_refresh > maximum_ms_per_real_frame) { mp_raise_RuntimeError(translate("Below minimum frame rate")); } - uint32_t current_call_time = current_time - self->last_refresh_call; + uint32_t current_ms_since_last_call = current_time - self->last_refresh_call; self->last_refresh_call = current_time; // Skip the actual refresh to help catch up. - if (current_call_time > target_frame_time) { - return; + if (current_ms_since_last_call > target_ms_per_frame) { + return false; } - uint32_t remaining_time = target_frame_time - (current_frame_time % target_frame_time); + uint32_t remaining_time = target_ms_per_frame - (current_ms_since_real_refresh % target_ms_per_frame); // We're ahead of the game so wait until we align with the frame rate. while (ticks_ms - self->last_refresh_call < remaining_time) { - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP ; - #endif + RUN_BACKGROUND_TASKS; } } self->first_manual_refresh = false; _refresh_display(self); + return true; } bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self) { @@ -366,7 +361,7 @@ STATIC void _update_backlight(displayio_display_obj_t* self) { void displayio_display_background(displayio_display_obj_t* self) { _update_backlight(self); - if (self->auto_refresh && (ticks_ms - self->core.last_refresh) > self->native_frame_time) { + if (self->auto_refresh && (ticks_ms - self->core.last_refresh) > self->native_ms_per_frame) { _refresh_display(self); } } diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index bf2889c6d..e5fe0a708 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -46,7 +46,7 @@ typedef struct { mp_float_t current_brightness; uint16_t brightness_command; uint16_t native_frames_per_second; - uint16_t native_frame_time; + uint16_t native_ms_per_frame; uint8_t set_column_command; uint8_t set_row_command; uint8_t write_ram_command; diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 48143f14f..38b63df0f 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -71,7 +71,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->busy_state = busy_state; self->refreshing = false; self->milliseconds_per_frame = seconds_per_frame * 1000; - self->always_toggle_chip_select = always_toggle_chip_select; + self->always_toggle_chip_select = always_toggle_chip_select ? CHIP_SELECT_TOGGLE_EVERY_BYTE : CHIP_SELECT_UNTOUCHED; self->start_sequence = start_sequence; self->start_sequence_len = start_sequence_len; @@ -130,9 +130,7 @@ STATIC void wait_for_busy(displayio_epaperdisplay_obj_t* self) { return; } while (common_hal_digitalio_digitalinout_get_value(&self->busy) == self->busy_state) { - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP - #endif + RUN_BACKGROUND_TASKS; } } @@ -145,8 +143,8 @@ STATIC void send_command_sequence(displayio_epaperdisplay_obj_t* self, bool shou data_size &= ~DELAY; uint8_t *data = cmd + 2; displayio_display_core_begin_transaction(&self->core); - self->core.send(self->core.bus, true, self->always_toggle_chip_select, cmd, 1); - self->core.send(self->core.bus, false, self->always_toggle_chip_select, data, data_size); + self->core.send(self->core.bus, DISPLAY_COMMAND, self->always_toggle_chip_select, cmd, 1); + self->core.send(self->core.bus, DISPLAY_DATA, self->always_toggle_chip_select, data, data_size); displayio_display_core_end_transaction(&self->core); uint16_t delay_length_ms = 0; if (delay) { @@ -187,7 +185,7 @@ uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaper void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self) { // Actually refresh the display now that all pixel RAM has been updated. displayio_display_core_begin_transaction(&self->core); - self->core.send(self->core.bus, true, self->always_toggle_chip_select, &self->refresh_display_command, 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, self->always_toggle_chip_select, &self->refresh_display_command, 1); displayio_display_core_end_transaction(&self->core); self->refreshing = true; @@ -248,7 +246,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c write_command = self->write_color_ram_command; } displayio_display_core_begin_transaction(&self->core); - self->core.send(self->core.bus, true, self->always_toggle_chip_select, &write_command, 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, self->always_toggle_chip_select, &write_command, 1); displayio_display_core_end_transaction(&self->core); for (uint16_t j = 0; j < subrectangles; j++) { @@ -266,12 +264,8 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c uint16_t subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); - for (uint16_t k = 0; k < mask_length; k++) { - mask[k] = 0x00000000; - } - for (uint16_t k = 0; k < buffer_size; k++) { - buffer[k] = 0x00000000; - } + memset(mask, 0, mask_length * sizeof(uint32_t)); + memset(buffer, 0, buffer_size * sizeof(uint32_t)); self->core.colorspace.grayscale = true; if (pass == 1) { @@ -291,7 +285,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c // Can't acquire display bus; skip the rest of the data. Try next display. return false; } - self->core.send(self->core.bus, false, self->always_toggle_chip_select, (uint8_t*) buffer, subrectangle_size_bytes); + self->core.send(self->core.bus, DISPLAY_DATA, self->always_toggle_chip_select, (uint8_t*) buffer, subrectangle_size_bytes); displayio_display_core_end_transaction(&self->core); // TODO(tannewt): Make refresh displays faster so we don't starve other diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index a5d4ec93f..580171a5f 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -56,7 +56,7 @@ typedef struct { bool black_bits_inverted; bool color_bits_inverted; bool refreshing; - bool always_toggle_chip_select; + display_chip_select_behavior_t always_toggle_chip_select; } displayio_epaperdisplay_obj_t; void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self); diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c index 7294e9772..fcc4c1a20 100644 --- a/shared-module/displayio/FourWire.c +++ b/shared-module/displayio/FourWire.c @@ -33,6 +33,7 @@ #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/time/__init__.h" +#include "shared-module/displayio/display_core.h" #include "tick.h" @@ -110,10 +111,10 @@ bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t obj) { return true; } -void common_hal_displayio_fourwire_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_fourwire_send(mp_obj_t obj, display_byte_type_t data_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length) { displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); - common_hal_digitalio_digitalinout_set_value(&self->command, !command); - if (toggle_every_byte) { + common_hal_digitalio_digitalinout_set_value(&self->command, data_type == DISPLAY_DATA); + if (chip_select == CHIP_SELECT_TOGGLE_EVERY_BYTE) { // Toggle chip select after each command byte in case the display driver // IC latches commands based on it. for (size_t i = 0; i < data_length; i++) { diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c index 95830ba0e..87261dca0 100644 --- a/shared-module/displayio/I2CDisplay.c +++ b/shared-module/displayio/I2CDisplay.c @@ -35,6 +35,7 @@ #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/time/__init__.h" +#include "shared-module/displayio/display_core.h" #include "tick.h" @@ -80,7 +81,7 @@ bool common_hal_displayio_i2cdisplay_reset(mp_obj_t obj) { } common_hal_digitalio_digitalinout_set_value(&self->reset, false); - common_hal_mcu_delay_us(1); + common_hal_mcu_delay_us(4); common_hal_digitalio_digitalinout_set_value(&self->reset, true); return true; } @@ -97,9 +98,9 @@ bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t obj) { return common_hal_displayio_i2cdisplay_bus_free(obj); } -void common_hal_displayio_i2cdisplay_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_i2cdisplay_send(mp_obj_t obj, display_byte_type_t data_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length) { displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); - if (command) { + if (data_type == DISPLAY_COMMAND) { uint8_t command_bytes[2 * data_length]; for (uint32_t i = 0; i < data_length; i++) { command_bytes[2 * i] = 0x80; diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 88878866a..0f449ea34 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -184,7 +184,6 @@ void displayio_display_core_end_transaction(displayio_display_core_t* self) { } void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area) { - displayio_display_core_begin_transaction(self); uint16_t x1 = area->x1; uint16_t x2 = area->x2; uint16_t y1 = area->y1; @@ -201,13 +200,22 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, } } + display_chip_select_behavior_t chip_select = CHIP_SELECT_UNTOUCHED; + if (always_toggle_chip_select || data_as_commands) { + chip_select = CHIP_SELECT_TOGGLE_EVERY_BYTE; + } + // Set column. + displayio_display_core_begin_transaction(self); uint8_t data[5]; data[0] = column_command; uint8_t data_length = 1; + display_byte_type_t data_type = DISPLAY_DATA; if (!data_as_commands) { - self->send(self->bus, true, false, data, 1); + self->send(self->bus, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, data, 1); data_length = 0; + } else { + data_type = DISPLAY_COMMAND; } if (self->ram_width < 0x100) { data[data_length++] = x1 + self->colstart; @@ -220,21 +228,23 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[data_length++] = x2 >> 8; data[data_length++] = x2 & 0xff; } - self->send(self->bus, data_as_commands, data_as_commands, data, data_length); + self->send(self->bus, data_type, chip_select, data, data_length); + displayio_display_core_end_transaction(self); if (set_current_column_command != NO_COMMAND) { uint8_t command = set_current_column_command; - self->send(self->bus, true, always_toggle_chip_select, &command, 1); - self->send(self->bus, false, always_toggle_chip_select, data, data_length / 2); + displayio_display_core_begin_transaction(self); + self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1); + self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2); + displayio_display_core_end_transaction(self); } - displayio_display_core_end_transaction(self); - displayio_display_core_begin_transaction(self); // Set row. + displayio_display_core_begin_transaction(self); data[0] = row_command; data_length = 1; if (!data_as_commands) { - self->send(self->bus, true, false, data, 1); + self->send(self->bus, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, data, 1); data_length = 0; } if (self->ram_height < 0x100) { @@ -248,14 +258,16 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[data_length++] = y2 >> 8; data[data_length++] = y2 & 0xff; } - self->send(self->bus, data_as_commands, data_as_commands, data, data_length); + self->send(self->bus, data_type, chip_select, data, data_length); + displayio_display_core_end_transaction(self); + if (set_current_row_command != NO_COMMAND) { uint8_t command = set_current_row_command; - self->send(self->bus, true, always_toggle_chip_select, &command, 1); - self->send(self->bus, false, always_toggle_chip_select, data, data_length / 2); + displayio_display_core_begin_transaction(self); + self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1); + self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2); + displayio_display_core_end_transaction(self); } - - displayio_display_core_end_transaction(self); } void displayio_display_core_start_refresh(displayio_display_core_t* self) { diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index b1a412883..e92fdbc9f 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -27,18 +27,13 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_CORE_H #define MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_CORE_H +#include "shared-bindings/displayio/__init__.h" #include "shared-bindings/displayio/Group.h" #include "shared-module/displayio/area.h" #define NO_COMMAND 0x100 -typedef bool (*display_bus_bus_reset)(mp_obj_t bus); -typedef bool (*display_bus_bus_free)(mp_obj_t bus); -typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); -typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); -typedef void (*display_bus_end_transaction)(mp_obj_t bus); - typedef struct { mp_obj_t bus; displayio_group_t *current_group; diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c index 36b30f462..c50d7f4ee 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -91,7 +91,7 @@ void filesystem_init(bool create_allowed, bool force_create) { } // set label - f_setlabel(&vfs_fat->fatfs, CIRCUITPY_FS_NAME); + f_setlabel(&vfs_fat->fatfs, "CIRCUITPY"); // inhibit file indexing on MacOS f_mkdir(&vfs_fat->fatfs, "/.fseventsd"); From bea77c651afd919e6cb87927341714adbddb939c Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 26 Aug 2019 16:37:59 -0700 Subject: [PATCH 18/18] Minor renames --- shared-bindings/displayio/Display.h | 1 - shared-module/displayio/Display.c | 4 ++-- shared-module/displayio/EPaperDisplay.c | 20 ++++++++++---------- shared-module/displayio/EPaperDisplay.h | 2 +- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index 2d7b68c4e..a3c77e4e8 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -50,7 +50,6 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); -// Times in ms. bool common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame); bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index cb5051bb7..f210a80c3 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -270,8 +270,8 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); } - memset(mask, 0, mask_length * sizeof(uint32_t)); - memset(buffer, 0, buffer_size * sizeof(uint32_t)); + memset(mask, 0, mask_length * sizeof(mask[0])); + memset(buffer, 0, buffer_size * sizeof(buffer[0])); displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 38b63df0f..efbd9f3dd 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 always_toggle_chip_select) { + const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool chip_select) { if (highlight_color != 0x000000) { self->core.colorspace.tricolor = true; self->core.colorspace.tricolor_hue = displayio_colorconverter_compute_hue(highlight_color); @@ -71,7 +71,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->busy_state = busy_state; self->refreshing = false; self->milliseconds_per_frame = seconds_per_frame * 1000; - self->always_toggle_chip_select = always_toggle_chip_select ? CHIP_SELECT_TOGGLE_EVERY_BYTE : CHIP_SELECT_UNTOUCHED; + self->chip_select = chip_select ? CHIP_SELECT_TOGGLE_EVERY_BYTE : CHIP_SELECT_UNTOUCHED; self->start_sequence = start_sequence; self->start_sequence_len = start_sequence_len; @@ -143,8 +143,8 @@ STATIC void send_command_sequence(displayio_epaperdisplay_obj_t* self, bool shou data_size &= ~DELAY; uint8_t *data = cmd + 2; displayio_display_core_begin_transaction(&self->core); - self->core.send(self->core.bus, DISPLAY_COMMAND, self->always_toggle_chip_select, cmd, 1); - self->core.send(self->core.bus, DISPLAY_DATA, self->always_toggle_chip_select, data, data_size); + self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, cmd, 1); + self->core.send(self->core.bus, DISPLAY_DATA, self->chip_select, data, data_size); displayio_display_core_end_transaction(&self->core); uint16_t delay_length_ms = 0; if (delay) { @@ -185,7 +185,7 @@ uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaper void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self) { // Actually refresh the display now that all pixel RAM has been updated. displayio_display_core_begin_transaction(&self->core); - self->core.send(self->core.bus, DISPLAY_COMMAND, self->always_toggle_chip_select, &self->refresh_display_command, 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, &self->refresh_display_command, 1); displayio_display_core_end_transaction(&self->core); self->refreshing = true; @@ -238,7 +238,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c uint16_t remaining_rows = displayio_area_height(&clipped); 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->always_toggle_chip_select, &clipped); + 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); } uint8_t write_command = self->write_black_ram_command; @@ -246,7 +246,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c write_command = self->write_color_ram_command; } displayio_display_core_begin_transaction(&self->core); - self->core.send(self->core.bus, DISPLAY_COMMAND, self->always_toggle_chip_select, &write_command, 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, &write_command, 1); displayio_display_core_end_transaction(&self->core); for (uint16_t j = 0; j < subrectangles; j++) { @@ -264,8 +264,8 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c uint16_t subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); - memset(mask, 0, mask_length * sizeof(uint32_t)); - memset(buffer, 0, buffer_size * sizeof(uint32_t)); + memset(mask, 0, mask_length * sizeof(mask[0])); + memset(buffer, 0, buffer_size * sizeof(buffer[0])); self->core.colorspace.grayscale = true; if (pass == 1) { @@ -285,7 +285,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c // Can't acquire display bus; skip the rest of the data. Try next display. return false; } - self->core.send(self->core.bus, DISPLAY_DATA, self->always_toggle_chip_select, (uint8_t*) buffer, subrectangle_size_bytes); + self->core.send(self->core.bus, DISPLAY_DATA, self->chip_select, (uint8_t*) buffer, subrectangle_size_bytes); displayio_display_core_end_transaction(&self->core); // TODO(tannewt): Make refresh displays faster so we don't starve other diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index 580171a5f..d08bed546 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -56,7 +56,7 @@ typedef struct { bool black_bits_inverted; bool color_bits_inverted; bool refreshing; - display_chip_select_behavior_t always_toggle_chip_select; + display_chip_select_behavior_t chip_select; } displayio_epaperdisplay_obj_t; void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self);