Rework refresh API and factor common display stuff out

NOT TESTED! Just compiles

Fixes #1691
crypto-aes
Scott Shawcroft 3 years ago
parent c247e7df9c
commit 36a23e0fe3
No known key found for this signature in database
GPG Key ID: 9349BC7E64B1921E
  1. 3
      ports/atmel-samd/Makefile
  2. 4
      ports/atmel-samd/boards/hallowing_m0_express/board.c
  3. 4
      ports/atmel-samd/boards/pybadge/board.c
  4. 4
      ports/atmel-samd/boards/pybadge_airlift/board.c
  5. 4
      ports/atmel-samd/boards/pygamer/board.c
  6. 4
      ports/atmel-samd/boards/pygamer_advance/board.c
  7. 4
      ports/atmel-samd/boards/pyportal/board.c
  8. 4
      ports/atmel-samd/boards/pyportal_titano/board.c
  9. 3
      ports/nrf/Makefile
  10. 3
      ports/stm32f4/Makefile
  11. 6
      py/circuitpy_defns.mk
  12. 10
      shared-bindings/_stage/__init__.c
  13. 54
      shared-bindings/displayio/Display.c
  14. 23
      shared-bindings/displayio/Display.h
  15. 10
      shared-bindings/displayio/EPaperDisplay.c
  16. 19
      shared-bindings/displayio/EPaperDisplay.h
  17. 4
      shared-module/_stage/__init__.c
  18. 479
      shared-module/displayio/Display.c
  19. 27
      shared-module/displayio/Display.h
  20. 350
      shared-module/displayio/EPaperDisplay.c
  21. 28
      shared-module/displayio/EPaperDisplay.h
  22. 10
      shared-module/displayio/__init__.c
  23. 309
      shared-module/displayio/display_core.c
  24. 90
      shared-module/displayio/display_core.h

@ -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

@ -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) {

@ -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) {

@ -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) {

@ -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) {

@ -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) {

@ -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) {

@ -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) {

@ -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

@ -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))

@ -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/,\

@ -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;
}

@ -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) },

@ -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

@ -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) },

@ -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

@ -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);
}
}

@ -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 <stdint.h>
#include <string.h>
@ -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);
}

@ -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

@ -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"));