Add address_little_endian for displayio

Add address_little_endian for epaper displays with little endian
(low byte first) addresses.

Also clears allocated display and display bus memory so it has a
known state. The acep member wasn't always set so it varied
accidentally.

Fixes #7560. May fix #7778. Fixes #5119.
This commit is contained in:
Scott Shawcroft 2023-04-20 16:15:06 -07:00
parent d078bc3ae1
commit 7089ea4d65
No known key found for this signature in database
GPG Key ID: 0DFD512649C052DA
14 changed files with 181 additions and 129 deletions

View File

@ -80,7 +80,8 @@
//| grayscale: bool = False,
//| advanced_color_epaper: bool = False,
//| two_byte_sequence_length: bool = False,
//| start_up_time: float = 0
//| start_up_time: float = 0,
//| address_little_endian: bool = False
//| ) -> None:
//| """Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `paralleldisplay.ParallelBus`).
//|
@ -122,6 +123,7 @@
//| :param bool advanced_color_epaper: When true, the display is a 7-color advanced color epaper (ACeP)
//| :param bool two_byte_sequence_length: When true, use two bytes to define sequence length
//| :param float start_up_time: Time to wait after reset before sending commands
//| :param bool address_little_endian: Send the least significant byte (not bit) of multi-byte addresses first. Ignored when ram is addressed with one byte
//| """
//| ...
STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
@ -132,7 +134,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size
ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color,
ARG_refresh_display_command, ARG_refresh_time, ARG_busy_pin, ARG_busy_state,
ARG_seconds_per_frame, ARG_always_toggle_chip_select, ARG_grayscale, ARG_advanced_color_epaper,
ARG_two_byte_sequence_length, ARG_start_up_time };
ARG_two_byte_sequence_length, ARG_start_up_time, ARG_address_little_endian };
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 },
@ -163,6 +165,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size
{ MP_QSTR_advanced_color_epaper, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
{ MP_QSTR_two_byte_sequence_length, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
{ MP_QSTR_start_up_time, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(0)} },
{ MP_QSTR_address_little_endian, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@ -228,7 +231,8 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size
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, refresh_buf, refresh_buf_len, refresh_time,
busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame,
args[ARG_always_toggle_chip_select].u_bool, args[ARG_grayscale].u_bool, args[ARG_advanced_color_epaper].u_bool, two_byte_sequence_length
args[ARG_always_toggle_chip_select].u_bool, args[ARG_grayscale].u_bool, args[ARG_advanced_color_epaper].u_bool,
two_byte_sequence_length, args[ARG_address_little_endian].u_bool
);
return self;

View File

@ -37,12 +37,18 @@ extern const mp_obj_type_t displayio_epaperdisplay_type;
#define NO_COMMAND 0x100
void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t *self,
mp_obj_t bus, const uint8_t *start_sequence, uint16_t start_sequence_len, mp_float_t start_up_time, const 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,
mp_obj_t bus, const uint8_t *start_sequence, uint16_t start_sequence_len, mp_float_t start_up_time,
const 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 highlight_color, const uint8_t *refresh_sequence, uint16_t refresh_sequence_len, 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 grayscale, bool acep, bool two_byte_sequence_length);
uint16_t write_black_ram_command, bool black_bits_inverted,
uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color,
const uint8_t *refresh_sequence, uint16_t refresh_sequence_len, 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 grayscale, bool acep, bool two_byte_sequence_length,
bool address_little_endian);
bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t *self);

View File

@ -46,10 +46,7 @@ void render_stage(
area.y1 = y0 * scale;
area.x2 = x1 * scale;
area.y2 = y1 * scale;
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->SH1107_addressing);
displayio_display_core_set_region_to_update(&display->core, &area);
while (!displayio_display_core_begin_transaction(&display->core)) {
RUN_BACKGROUND_TASKS;

View File

@ -190,7 +190,7 @@ void reset_board_buses(void) {
bool display_using_i2c = false;
#if CIRCUITPY_DISPLAYIO
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
if (displays[i].bus_base.type == &displayio_i2cdisplay_type && displays[i].i2cdisplay_bus.bus == &i2c_obj[instance]) {
if (display_buses[i].bus_base.type == &displayio_i2cdisplay_type && display_buses[i].i2cdisplay_bus.bus == &i2c_obj[instance]) {
display_using_i2c = true;
break;
}
@ -211,13 +211,13 @@ void reset_board_buses(void) {
bool display_using_spi = false;
#if CIRCUITPY_DISPLAYIO
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
mp_const_obj_t bus_type = displays[i].bus_base.type;
if (bus_type == &displayio_fourwire_type && displays[i].fourwire_bus.bus == &spi_obj[instance]) {
mp_const_obj_t bus_type = display_buses[i].bus_base.type;
if (bus_type == &displayio_fourwire_type && display_buses[i].fourwire_bus.bus == &spi_obj[instance]) {
display_using_spi = true;
break;
}
#if CIRCUITPY_SHARPDISPLAY
if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type && displays[i].sharpdisplay.bus == &spi_obj[instance]) {
if (bus_type == &sharpdisplay_framebuffer_type && display_buses[i].sharpdisplay.bus == &spi_obj[instance]) {
display_using_spi = true;
break;
}

View File

@ -64,16 +64,14 @@ void common_hal_displayio_display_construct(displayio_display_obj_t *self,
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, reverse_bytes_in_word);
color_depth, grayscale, pixels_in_byte_share_row, bytes_per_cell, reverse_pixels_in_byte, reverse_bytes_in_word,
set_column_command, set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false /* always_toggle_chip_select */,
SH1107_addressing && color_depth == 1, false /*address_little_endian */);
self->set_column_command = set_column_command;
self->set_row_command = set_row_command;
self->write_ram_command = write_ram_command;
self->brightness_command = brightness_command;
self->first_manual_refresh = !auto_refresh;
self->data_as_commands = data_as_commands;
self->backlight_on_high = backlight_on_high;
self->SH1107_addressing = SH1107_addressing && color_depth == 1;
self->native_frames_per_second = native_frames_per_second;
self->native_ms_per_frame = 1000 / native_frames_per_second;
@ -294,9 +292,7 @@ STATIC bool _refresh_area(displayio_display_obj_t *self, const displayio_area_t
}
remaining_rows -= rows_per_buffer;
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, self->SH1107_addressing);
displayio_display_core_set_region_to_update(&self->core, &subrectangle);
uint16_t subrectangle_size_bytes;
if (self->core.colorspace.depth >= 8) {

View File

@ -58,28 +58,30 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t
uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color,
const uint8_t *refresh_sequence, uint16_t refresh_sequence_len, mp_float_t refresh_time,
const mcu_pin_obj_t *busy_pin, bool busy_state, mp_float_t seconds_per_frame,
bool chip_select, bool grayscale, bool acep, bool two_byte_sequence_length) {
bool chip_select, bool grayscale, bool acep, bool two_byte_sequence_length, bool address_little_endian) {
uint16_t color_depth = 1;
bool core_grayscale = true;
if (highlight_color != 0x000000) {
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);
} else {
self->core.colorspace.tricolor = false;
}
self->acep = acep;
self->core.colorspace.sevencolor = acep;
if (acep) {
self->core.colorspace.sevencolor = true;
color_depth = 4; // bits. 7 colors + clean
self->acep = acep;
grayscale = false;
core_grayscale = false;
}
displayio_display_core_construct(&self->core, bus, width, height, ram_width, ram_height, colstart, rowstart, rotation, color_depth, core_grayscale, true, 1, true, true);
displayio_display_core_construct(&self->core, bus, width, height, ram_width, ram_height,
colstart, rowstart, rotation, color_depth, core_grayscale, true, 1, true, true,
set_column_window_command, set_row_window_command, set_current_column_command, set_current_row_command,
false /* data_as_commands */, chip_select,
false /* SH1107_addressing */, address_little_endian);
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;
@ -137,7 +139,7 @@ STATIC const displayio_area_t *displayio_epaperdisplay_get_refresh_areas(display
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) {
if (first_area != NULL) {
self->core.area.next = NULL;
return &self->core.area;
}
@ -310,10 +312,8 @@ STATIC bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t *
for (uint8_t pass = 0; pass < passes; pass++) {
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->chip_select, &clipped, false /* SH1107_addressing */);
if (self->core.row_command != NO_COMMAND) {
displayio_display_core_set_region_to_update(&self->core, &clipped);
}
uint8_t write_command = self->write_black_ram_command;

View File

@ -46,10 +46,6 @@ typedef struct {
uint16_t refresh_sequence_len;
uint16_t start_up_time_ms;
uint16_t refresh_time;
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 hue;

View File

@ -543,7 +543,6 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self,
((uint8_t *)buffer)[offset / pixels_per_byte] |= output_pixel.pixel << shift;
}
}
(void)input_pixel;
}
}
return full_coverage;

View File

@ -48,6 +48,7 @@
#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
#endif
primary_display_bus_t display_buses[CIRCUITPY_DISPLAY_LIMIT];
primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT];
displayio_buffer_transform_t null_transform = {
@ -87,19 +88,19 @@ void displayio_background(void) {
return;
}
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) {
mp_const_obj_t display_type = displays[i].display.base.type;
if (display_type == NULL || display_type == &mp_type_NoneType) {
// Skip null display.
continue;
}
if (displays[i].display.base.type == &displayio_display_type) {
if (display_type == &displayio_display_type) {
displayio_display_background(&displays[i].display);
#if CIRCUITPY_FRAMEBUFFERIO
} else if (displays[i].framebuffer_display.base.type == &framebufferio_framebufferdisplay_type) {
} else if (display_type == &framebufferio_framebufferdisplay_type) {
framebufferio_framebufferdisplay_background(&displays[i].framebuffer_display);
#endif
} else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) {
} else if (display_type == &displayio_epaperdisplay_type) {
displayio_epaperdisplay_background(&displays[i].epaper_display);
}
}
@ -110,7 +111,7 @@ 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;
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) {
@ -125,39 +126,39 @@ void common_hal_displayio_release_displays(void) {
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;
mp_const_obj_t bus_type = display_buses[i].bus_base.type;
if (bus_type == NULL || bus_type == &mp_type_NoneType) {
continue;
} else if (bus_type == &displayio_fourwire_type) {
common_hal_displayio_fourwire_deinit(&displays[i].fourwire_bus);
common_hal_displayio_fourwire_deinit(&display_buses[i].fourwire_bus);
} else if (bus_type == &displayio_i2cdisplay_type) {
common_hal_displayio_i2cdisplay_deinit(&displays[i].i2cdisplay_bus);
common_hal_displayio_i2cdisplay_deinit(&display_buses[i].i2cdisplay_bus);
#if CIRCUITPY_PARALLELDISPLAY
} else if (bus_type == &paralleldisplay_parallelbus_type) {
common_hal_paralleldisplay_parallelbus_deinit(&displays[i].parallel_bus);
common_hal_paralleldisplay_parallelbus_deinit(&display_buses[i].parallel_bus);
#endif
#if CIRCUITPY_RGBMATRIX
} else if (bus_type == &rgbmatrix_RGBMatrix_type) {
common_hal_rgbmatrix_rgbmatrix_deinit(&displays[i].rgbmatrix);
common_hal_rgbmatrix_rgbmatrix_deinit(&display_buses[i].rgbmatrix);
#endif
#if CIRCUITPY_IS31FL3741
} else if (bus_type == &is31fl3741_FrameBuffer_type) {
common_hal_is31fl3741_FrameBuffer_deinit(&displays[i].is31fl3741);
common_hal_is31fl3741_FrameBuffer_deinit(&display_buses[i].is31fl3741);
#endif
#if CIRCUITPY_SHARPDISPLAY
} else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) {
common_hal_sharpdisplay_framebuffer_deinit(&displays[i].sharpdisplay);
} else if (bus_type == &sharpdisplay_framebuffer_type) {
common_hal_sharpdisplay_framebuffer_deinit(&display_buses[i].sharpdisplay);
#endif
#if CIRCUITPY_VIDEOCORE
} else if (displays[i].bus_base.type == &videocore_framebuffer_type) {
common_hal_videocore_framebuffer_deinit(&displays[i].videocore);
} else if (bus_type == &videocore_framebuffer_type) {
common_hal_videocore_framebuffer_deinit(&display_buses[i].videocore);
#endif
#if CIRCUITPY_PICODVI
} else if (displays[i].bus_base.type == &picodvi_framebuffer_type) {
common_hal_picodvi_framebuffer_deinit(&displays[i].picodvi);
#endif
}
displays[i].fourwire_bus.base.type = &mp_type_NoneType;
display_buses[i].bus_base.type = &mp_type_NoneType;
}
supervisor_stop_terminal();
@ -166,10 +167,11 @@ void common_hal_displayio_release_displays(void) {
void reset_displays(void) {
// The SPI buses used by FourWires may be allocated on the heap so we need to move them inline.
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
if (displays[i].fourwire_bus.base.type == &displayio_fourwire_type) {
displayio_fourwire_obj_t *fourwire = &displays[i].fourwire_bus;
if (((size_t)fourwire->bus) < ((size_t)&displays) ||
((size_t)fourwire->bus) > ((size_t)&displays + CIRCUITPY_DISPLAY_LIMIT)) {
mp_const_obj_t display_bus_type = display_buses[i].bus_base.type;
if (display_bus_type == &displayio_fourwire_type) {
displayio_fourwire_obj_t *fourwire = &display_buses[i].fourwire_bus;
if (((size_t)fourwire->bus) < ((size_t)&display_buses) ||
((size_t)fourwire->bus) > ((size_t)&display_buses + CIRCUITPY_DISPLAY_LIMIT * sizeof(primary_display_bus_t))) {
busio_spi_obj_t *original_spi = fourwire->bus;
#if CIRCUITPY_BOARD_SPI
// We don't need to move original_spi if it is a board.SPI object because it is
@ -186,18 +188,19 @@ void reset_displays(void) {
#endif
memcpy(&fourwire->inline_bus, original_spi, sizeof(busio_spi_obj_t));
fourwire->bus = &fourwire->inline_bus;
// Check for other displays that use the same spi bus and swap them too.
// Check for other display buses that use the same spi bus and swap them too.
for (uint8_t j = i + 1; j < CIRCUITPY_DISPLAY_LIMIT; j++) {
if (displays[i].fourwire_bus.base.type == &displayio_fourwire_type &&
displays[i].fourwire_bus.bus == original_spi) {
displays[i].fourwire_bus.bus = &fourwire->inline_bus;
if (display_buses[j].fourwire_bus.base.type == &displayio_fourwire_type &&
display_buses[j].fourwire_bus.bus == original_spi) {
display_buses[j].fourwire_bus.bus = &fourwire->inline_bus;
}
}
}
} else if (displays[i].i2cdisplay_bus.base.type == &displayio_i2cdisplay_type) {
displayio_i2cdisplay_obj_t *i2c = &displays[i].i2cdisplay_bus;
if (((size_t)i2c->bus) < ((size_t)&displays) ||
((size_t)i2c->bus) > ((size_t)&displays + CIRCUITPY_DISPLAY_LIMIT)) {
} else if (display_bus_type == &displayio_i2cdisplay_type) {
displayio_i2cdisplay_obj_t *i2c = &display_buses[i].i2cdisplay_bus;
// Check to see if we need to inline the I2C bus.
if (((size_t)i2c->bus) < ((size_t)&display_buses) ||
((size_t)i2c->bus) > ((size_t)&display_buses + CIRCUITPY_DISPLAY_LIMIT * sizeof(primary_display_bus_t))) {
busio_i2c_obj_t *original_i2c = i2c->bus;
#if CIRCUITPY_BOARD_I2C
// We don't need to move original_i2c if it is a board.I2C object because it is
@ -211,15 +214,15 @@ void reset_displays(void) {
i2c->bus = &i2c->inline_bus;
// Check for other displays that use the same i2c bus and swap them too.
for (uint8_t j = i + 1; j < CIRCUITPY_DISPLAY_LIMIT; j++) {
if (displays[i].i2cdisplay_bus.base.type == &displayio_i2cdisplay_type &&
displays[i].i2cdisplay_bus.bus == original_i2c) {
displays[i].i2cdisplay_bus.bus = &i2c->inline_bus;
if (display_buses[j].i2cdisplay_bus.base.type == &displayio_i2cdisplay_type &&
display_buses[j].i2cdisplay_bus.bus == original_i2c) {
display_buses[j].i2cdisplay_bus.bus = &i2c->inline_bus;
}
}
}
#if CIRCUITPY_RGBMATRIX
} else if (displays[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) {
rgbmatrix_rgbmatrix_obj_t *pm = &displays[i].rgbmatrix;
} else if (display_bus_type == &rgbmatrix_RGBMatrix_type) {
rgbmatrix_rgbmatrix_obj_t *pm = &display_buses[i].rgbmatrix;
if (!any_display_uses_this_framebuffer(&pm->base)) {
common_hal_rgbmatrix_rgbmatrix_deinit(pm);
} else {
@ -227,11 +230,11 @@ void reset_displays(void) {
}
#endif
#if CIRCUITPY_IS31FL3741
} else if (displays[i].is31fl3741.base.type == &is31fl3741_FrameBuffer_type) {
is31fl3741_FrameBuffer_obj_t *is31fb = &displays[i].is31fl3741;
} else if (display_bus_type == &is31fl3741_FrameBuffer_type) {
is31fl3741_FrameBuffer_obj_t *is31fb = &display_buses[i].is31fl3741;
if (((uint32_t)is31fb->is31fl3741->i2c) < ((uint32_t)&displays) ||
((uint32_t)is31fb->is31fl3741->i2c) > ((uint32_t)&displays + CIRCUITPY_DISPLAY_LIMIT)) {
if (((uint32_t)is31fb->is31fl3741->i2c) < ((uint32_t)&display_buses) ||
((uint32_t)is31fb->is31fl3741->i2c) > ((uint32_t)&display_buses + CIRCUITPY_DISPLAY_LIMIT)) {
#if CIRCUITPY_BOARD_I2C
// 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
@ -257,13 +260,13 @@ void reset_displays(void) {
}
#endif
#if CIRCUITPY_SHARPDISPLAY
} else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) {
sharpdisplay_framebuffer_obj_t *sharp = &displays[i].sharpdisplay;
} else if (display_bus_type == &sharpdisplay_framebuffer_type) {
sharpdisplay_framebuffer_obj_t *sharp = &display_buses[i].sharpdisplay;
common_hal_sharpdisplay_framebuffer_reset(sharp);
#endif
#if CIRCUITPY_VIDEOCORE
} else if (displays[i].bus_base.type == &videocore_framebuffer_type) {
videocore_framebuffer_obj_t *vc = &displays[i].videocore;
} else if (display_bus_type == &videocore_framebuffer_type) {
videocore_framebuffer_obj_t *vc = &display_buses[i].videocore;
if (!any_display_uses_this_framebuffer(&vc->base)) {
common_hal_videocore_framebuffer_deinit(vc);
}
@ -286,13 +289,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.
if (displays[i].display.base.type == &displayio_display_type) {
mp_const_obj_t display_type = displays[i].display_base.type;
if (display_type == &displayio_display_type) {
reset_display(&displays[i].display);
} else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) {
} else if (display_type == &displayio_epaperdisplay_type) {
displayio_epaperdisplay_obj_t *display = &displays[i].epaper_display;
common_hal_displayio_epaperdisplay_show(display, NULL);
#if CIRCUITPY_FRAMEBUFFERIO
} else if (displays[i].framebuffer_display.base.type == &framebufferio_framebufferdisplay_type) {
} else if (display_type == &framebufferio_framebufferdisplay_type) {
framebufferio_framebufferdisplay_reset(&displays[i].framebuffer_display);
#endif
}
@ -301,35 +305,42 @@ void reset_displays(void) {
void displayio_gc_collect(void) {
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
mp_const_obj_t display_bus_type = display_buses[i].bus_base.type;
if (display_bus_type == NULL || display_bus_type == &mp_type_NoneType) {
continue;
}
#if CIRCUITPY_RGBMATRIX
if (displays[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) {
rgbmatrix_rgbmatrix_collect_ptrs(&displays[i].rgbmatrix);
if (display_bus_type == &rgbmatrix_RGBMatrix_type) {
rgbmatrix_rgbmatrix_collect_ptrs(&display_buses[i].rgbmatrix);
}
#endif
#if CIRCUITPY_IS31FL3741
if (displays[i].is31fl3741.base.type == &is31fl3741_FrameBuffer_type) {
is31fl3741_FrameBuffer_collect_ptrs(&displays[i].is31fl3741);
if (display_bus_type == &is31fl3741_FrameBuffer_type) {
is31fl3741_FrameBuffer_collect_ptrs(&display_buses[i].is31fl3741);
}
#endif
#if CIRCUITPY_SHARPDISPLAY
if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) {
common_hal_sharpdisplay_framebuffer_collect_ptrs(&displays[i].sharpdisplay);
if (display_bus_type == &sharpdisplay_framebuffer_type) {
common_hal_sharpdisplay_framebuffer_collect_ptrs(&display_buses[i].sharpdisplay);
}
#endif
}
if (displays[i].display.base.type == NULL) {
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;
}
// 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) {
if (display_type == &displayio_display_type) {
displayio_display_collect_ptrs(&displays[i].display);
#if CIRCUITPY_FRAMEBUFFERIO
} else if (displays[i].framebuffer_display.base.type == &framebufferio_framebufferdisplay_type) {
} else if (display_type == &framebufferio_framebufferdisplay_type) {
framebufferio_framebufferdisplay_collect_ptrs(&displays[i].framebuffer_display);
#endif
} else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) {
} else if (display_type == &displayio_epaperdisplay_type) {
displayio_epaperdisplay_collect_ptrs(&displays[i].epaper_display);
}
}
@ -339,6 +350,10 @@ primary_display_t *allocate_display(void) {
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) {
// Clear this memory so it is in a known state before init.
memset(&displays[i], 0, sizeof(displays[i]));
// Default to None so that it works as board.DISPLAY.
displays[i].display_base.type = &mp_type_NoneType;
return &displays[i];
}
}
@ -352,18 +367,22 @@ primary_display_t *allocate_display_or_raise(void) {
}
mp_raise_RuntimeError(translate("Too many displays"));
}
primary_display_t *allocate_display_bus(void) {
primary_display_bus_t *allocate_display_bus(void) {
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
mp_const_obj_t display_bus_type = displays[i].bus_base.type;
mp_const_obj_t display_bus_type = display_buses[i].bus_base.type;
if (display_bus_type == NULL || display_bus_type == &mp_type_NoneType) {
return &displays[i];
// Clear this memory so it is in a known state before init.
memset(&display_buses[i], 0, sizeof(display_buses[i]));
display_buses[i].bus_base.type = &mp_type_NoneType;
return &display_buses[i];
}
}
return NULL;
}
primary_display_t *allocate_display_bus_or_raise(void) {
primary_display_t *result = allocate_display_bus();
primary_display_bus_t *allocate_display_bus_or_raise(void) {
primary_display_bus_t *result = allocate_display_bus();
if (result) {
return result;
}

View File

@ -79,6 +79,9 @@ typedef struct {
picodvi_framebuffer_obj_t picodvi;
#endif
};
} primary_display_bus_t;
typedef struct {
union {
mp_obj_base_t display_base;
displayio_display_obj_t display;
@ -89,6 +92,7 @@ typedef struct {
};
} primary_display_t;
extern primary_display_bus_t display_buses[CIRCUITPY_DISPLAY_LIMIT];
extern primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT];
extern displayio_group_t circuitpython_splash;
@ -99,7 +103,7 @@ void displayio_gc_collect(void);
primary_display_t *allocate_display(void);
primary_display_t *allocate_display_or_raise(void);
primary_display_t *allocate_display_bus(void);
primary_display_t *allocate_display_bus_or_raise(void);
primary_display_bus_t *allocate_display_bus(void);
primary_display_bus_t *allocate_display_bus_or_raise(void);
#endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO___INIT___H

View File

@ -47,7 +47,9 @@
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 reverse_bytes_in_word) {
uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, bool reverse_bytes_in_word,
uint16_t column_command, uint16_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command,
bool data_as_commands, bool always_toggle_chip_select, bool SH1107_addressing, bool address_little_endian) {
self->colorspace.depth = color_depth;
self->colorspace.grayscale = grayscale;
self->colorspace.grayscale_bit = 8 - color_depth;
@ -61,6 +63,15 @@ void displayio_display_core_construct(displayio_display_core_t *self,
self->rowstart = rowstart;
self->last_refresh = 0;
self->column_command = column_command;
self->row_command = row_command;
self->set_current_column_command = set_current_column_command;
self->set_current_row_command = set_current_row_command;
self->data_as_commands = data_as_commands;
self->always_toggle_chip_select = always_toggle_chip_select;
self->SH1107_addressing = SH1107_addressing;
self->address_little_endian = address_little_endian;
// (framebufferdisplay already validated its 'bus' is a buffer-protocol object)
if (bus) {
#if CIRCUITPY_PARALLELDISPLAY
@ -214,10 +225,7 @@ 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, bool SH1107_addressing) {
void displayio_display_core_set_region_to_update(displayio_display_core_t *self, displayio_area_t *area) {
uint16_t x1 = area->x1 + self->colstart;
uint16_t x2 = area->x2 + self->colstart;
uint16_t y1 = area->y1 + self->rowstart;
@ -239,17 +247,17 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t *self,
y2 -= 1;
display_chip_select_behavior_t chip_select = CHIP_SELECT_UNTOUCHED;
if (always_toggle_chip_select || data_as_commands) {
if (self->always_toggle_chip_select || self->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;
data[0] = self->column_command;
uint8_t data_length = 1;
display_byte_type_t data_type = DISPLAY_DATA;
if (!data_as_commands) {
if (!self->data_as_commands) {
self->send(self->bus, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, data, 1);
data_length = 0;
} else {
@ -260,6 +268,10 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t *self,
data[data_length++] = x1;
data[data_length++] = x2;
} else {
if (self->address_little_endian) {
x1 = __builtin_bswap16(x1);
x2 = __builtin_bswap16(x2);
}
data[data_length++] = x1 >> 8;
data[data_length++] = x1 & 0xff;
data[data_length++] = x2 >> 8;
@ -268,7 +280,7 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t *self,
// Quirk for SH1107 "SH1107_addressing"
// Column lower command = 0x00, Column upper command = 0x10
if (SH1107_addressing) {
if (self->SH1107_addressing) {
data[0] = ((x1 >> 4) & 0x0F) | 0x10; // 0x10 to 0x17
data[1] = x1 & 0x0F; // 0x00 to 0x0F
data_length = 2;
@ -277,10 +289,11 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t *self,
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;
if (self->set_current_column_command != NO_COMMAND) {
uint8_t command = self->set_current_column_command;
displayio_display_core_begin_transaction(self);
self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1);
// Only send the first half of data because it is the first coordinate.
self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2);
displayio_display_core_end_transaction(self);
}
@ -288,9 +301,9 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t *self,
// Set row.
displayio_display_core_begin_transaction(self);
data[0] = row_command;
data[0] = self->row_command;
data_length = 1;
if (!data_as_commands) {
if (!self->data_as_commands) {
self->send(self->bus, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, data, 1);
data_length = 0;
}
@ -299,6 +312,10 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t *self,
data[data_length++] = y1;
data[data_length++] = y2;
} else {
if (self->address_little_endian) {
y1 = __builtin_bswap16(y1);
y2 = __builtin_bswap16(y2);
}
data[data_length++] = y1 >> 8;
data[data_length++] = y1 & 0xff;
data[data_length++] = y2 >> 8;
@ -307,7 +324,7 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t *self,
// Quirk for SH1107 "SH1107_addressing"
// Page address command = 0xB0
if (SH1107_addressing) {
if (self->SH1107_addressing) {
// set the page to our y value
data[0] = 0xB0 | y1;
data_length = 1;
@ -316,10 +333,11 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t *self,
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;
if (self->set_current_row_command != NO_COMMAND) {
uint8_t command = self->set_current_row_command;
displayio_display_core_begin_transaction(self);
self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1);
// Only send the first half of data because it is the first coordinate.
self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2);
displayio_display_core_end_transaction(self);
}

View File

@ -53,13 +53,26 @@ typedef struct {
_displayio_colorspace_t colorspace;
int16_t colstart;
int16_t rowstart;
// Refresh area related.
uint16_t column_command;
uint16_t row_command;
uint16_t set_current_column_command;
uint16_t set_current_row_command;
bool data_as_commands;
bool always_toggle_chip_select;
bool SH1107_addressing;
bool address_little_endian;
bool full_refresh; // New group means we need to refresh the whole display.
bool refresh_in_progress;
} 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 reverse_bytes_in_word);
uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, bool reverse_bytes_in_word,
uint16_t column_command, uint16_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command,
bool data_as_commands, bool always_toggle_chip_select, bool SH1107_addressing, bool address_little_endian);
bool displayio_display_core_set_root_group(displayio_display_core_t *self, displayio_group_t *root_group);
@ -75,10 +88,7 @@ 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, bool SH1107_addressing);
void displayio_display_core_set_region_to_update(displayio_display_core_t *self, displayio_area_t *area);
void release_display_core(displayio_display_core_t *self);

View File

@ -72,7 +72,10 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu
fb_getter_default(get_pixels_in_byte_share_row, false),
fb_getter_default(get_bytes_per_cell, 2),
fb_getter_default(get_reverse_pixels_in_byte, false),
fb_getter_default(get_reverse_pixels_in_word, false)
fb_getter_default(get_reverse_pixels_in_word, false),
// Region update related settings that aren't used by framebuffer display.
NO_COMMAND, NO_COMMAND, NO_COMMAND, NO_COMMAND,
false, false, false, false
);
self->first_pixel_offset = fb_getter_default(get_first_pixel_offset, 0);

View File

@ -189,14 +189,14 @@ void supervisor_display_move_memory(void) {
#if CIRCUITPY_DISPLAYIO
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
#if CIRCUITPY_RGBMATRIX
if (displays[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) {
rgbmatrix_rgbmatrix_obj_t *pm = &displays[i].rgbmatrix;
if (display_buses[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) {
rgbmatrix_rgbmatrix_obj_t *pm = &display_buses[i].rgbmatrix;
common_hal_rgbmatrix_rgbmatrix_reconstruct(pm, NULL);
}
#endif
#if CIRCUITPY_SHARPDISPLAY
if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) {
sharpdisplay_framebuffer_obj_t *sharp = &displays[i].sharpdisplay;
if (display_buses[i].bus_base.type == &sharpdisplay_framebuffer_type) {
sharpdisplay_framebuffer_obj_t *sharp = &display_buses[i].sharpdisplay;
common_hal_sharpdisplay_framebuffer_reconstruct(sharp);
}
#endif