From 7d1f378a0867550969226a689a9e86b1e443eb3d Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Thu, 15 Feb 2024 13:43:03 -0800 Subject: [PATCH 1/2] modules: Change dsi read/write to generic bus read/write. --- scripts/libraries/st7701.py | 72 ++++++++++++------------ src/omv/modules/py_display.c | 36 ++++++------ src/omv/modules/py_display.h | 7 +-- src/omv/ports/stm32/modules/py_display.c | 4 +- 4 files changed, 56 insertions(+), 63 deletions(-) diff --git a/scripts/libraries/st7701.py b/scripts/libraries/st7701.py index ee3033a1d..833704aec 100644 --- a/scripts/libraries/st7701.py +++ b/scripts/libraries/st7701.py @@ -51,76 +51,76 @@ class ST7701: self.dc = dc # Soft-reset - dc.dsi_write(DCS_SOFT_RESET) + dc.bus_write(DCS_SOFT_RESET) time.sleep_ms(200) # Exit sleep mode - dc.dsi_write(DCS_EXIT_SLEEP_MODE) + dc.bus_write(DCS_EXIT_SLEEP_MODE) time.sleep_ms(800) # Select bank 0 - dc.dsi_write(DSI_CMD2_BKX_SEL, b"\x77\x01\x00\x00\x10") + dc.bus_write(DSI_CMD2_BKX_SEL, b"\x77\x01\x00\x00\x10") # Display Control setting - dc.dsi_write(DSI_CMD2_BK0_LNESET, b"\x63\x00") - dc.dsi_write(DSI_CMD2_BK0_PORCTRL, b"\x11\x02") - dc.dsi_write(DSI_CMD2_BK0_INVSEL, b"\x01\x08") - # dc.dsi_write(0xCC, b"\x18") + dc.bus_write(DSI_CMD2_BK0_LNESET, b"\x63\x00") + dc.bus_write(DSI_CMD2_BK0_PORCTRL, b"\x11\x02") + dc.bus_write(DSI_CMD2_BK0_INVSEL, b"\x01\x08") + # dc.bus_write(0xCC, b"\x18") # Gamma cluster settings - dc.dsi_write( + dc.bus_write( 0xB0, b"\x40\xc9\x91\x0d\x12\x07\x02\x09\x09\x1f\x04\x50\x0f\xe4\x29\xdf" ) - dc.dsi_write( + dc.bus_write( 0xB1, b"\x40\xcb\xd0\x11\x92\x07\x00\x08\x07\x1c\x06\x53\x12\x63\xeb\xdf" ) # Select bank 1 - dc.dsi_write(DSI_CMD2_BKX_SEL, b"\x77\x01\x00\x00\x11") + dc.bus_write(DSI_CMD2_BKX_SEL, b"\x77\x01\x00\x00\x11") # Power control settings - dc.dsi_write(DSI_CMD2_BK1_VRHS, 0x65) - dc.dsi_write(DSI_CMD2_BK1_VCOM, 0x34) - dc.dsi_write(DSI_CMD2_BK1_VGHSS, 0x87) - dc.dsi_write(DSI_CMD2_BK1_TESTCMD, 0x80) - dc.dsi_write(DSI_CMD2_BK1_VGLS, 0x49) - dc.dsi_write(DSI_CMD2_BK1_PWCTLR1, 0x85) - dc.dsi_write(DSI_CMD2_BK1_PWCTLR2, 0x20) - dc.dsi_write(DSI_CMD2_BK1_DGMLUTR, 0x10) - dc.dsi_write(DSI_CMD2_BK1_SPD1, 0x78) - dc.dsi_write(DSI_CMD2_BK1_SPD2, 0x78) - dc.dsi_write(DSI_CMD2_BK1_MIPISET1, 0x88) + dc.bus_write(DSI_CMD2_BK1_VRHS, 0x65) + dc.bus_write(DSI_CMD2_BK1_VCOM, 0x34) + dc.bus_write(DSI_CMD2_BK1_VGHSS, 0x87) + dc.bus_write(DSI_CMD2_BK1_TESTCMD, 0x80) + dc.bus_write(DSI_CMD2_BK1_VGLS, 0x49) + dc.bus_write(DSI_CMD2_BK1_PWCTLR1, 0x85) + dc.bus_write(DSI_CMD2_BK1_PWCTLR2, 0x20) + dc.bus_write(DSI_CMD2_BK1_DGMLUTR, 0x10) + dc.bus_write(DSI_CMD2_BK1_SPD1, 0x78) + dc.bus_write(DSI_CMD2_BK1_SPD2, 0x78) + dc.bus_write(DSI_CMD2_BK1_MIPISET1, 0x88) time.sleep_ms(100) # GIP settings - dc.dsi_write(DSI_CMD2_BK1_SECTRL, b"\x00\x00\x02") - dc.dsi_write( + dc.bus_write(DSI_CMD2_BK1_SECTRL, b"\x00\x00\x02") + dc.bus_write( DSI_CMD2_BK1_NRCTRL, b"\x08\x00\x0A\x00\x07\x00\x09\x00\x00\x33\x33" ) - dc.dsi_write( + dc.bus_write( DSI_CMD2_BK1_SRPCTRL, b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", ) - dc.dsi_write(DSI_CMD2_BK1_CCCTRL, b"\x00\x00\x33\x33") - dc.dsi_write(DSI_CMD2_BK1_SKCTRL, b"\x44\x44") - dc.dsi_write( + dc.bus_write(DSI_CMD2_BK1_CCCTRL, b"\x00\x00\x33\x33") + dc.bus_write(DSI_CMD2_BK1_SKCTRL, b"\x44\x44") + dc.bus_write( 0xE5, b"\x0E\x60\xA0\xa0\x10\x60\xA0\xA0\x0A\x60\xA0\xA0\x0C\x60\xA0\xA0" ) - dc.dsi_write(0xE6, b"\x00\x00\x33\x33") - dc.dsi_write(0xE7, b"\x44\x44") - dc.dsi_write( + dc.bus_write(0xE6, b"\x00\x00\x33\x33") + dc.bus_write(0xE7, b"\x44\x44") + dc.bus_write( 0xE8, b"\x0D\x60\xA0\xA0\x0F\x60\xA0\xA0\x09\x60\xA0\xA0\x0B\x60\xA0\xA0" ) - dc.dsi_write(0xEB, b"\x02\x01\xE4\xE4\x44\x00\x40") - dc.dsi_write(0xEC, b"\x02\x01") - dc.dsi_write( + dc.bus_write(0xEB, b"\x02\x01\xE4\xE4\x44\x00\x40") + dc.bus_write(0xEC, b"\x02\x01") + dc.bus_write( 0xED, b"\xAB\x89\x76\x54\x01\xFF\xFF\xFF\xFF\xFF\xFF\x10\x45\x67\x98\xBA" ) - dc.dsi_write(DSI_CMD2_BKX_SEL, b"\x77\x01\x00\x00\x00") + dc.bus_write(DSI_CMD2_BKX_SEL, b"\x77\x01\x00\x00\x00") time.sleep_ms(10) - dc.dsi_write(DCS_SET_DISPLAY_ON, dcs=True) + dc.bus_write(DCS_SET_DISPLAY_ON, dcs=True) time.sleep_ms(200) def read_id(self): - return self.dc.dsi_read(0x04, 3) + return self.dc.bus_read(0x04, 3) diff --git a/src/omv/modules/py_display.c b/src/omv/modules/py_display.c index 332c79708..a3564a3fe 100644 --- a/src/omv/modules/py_display.c +++ b/src/omv/modules/py_display.c @@ -177,8 +177,7 @@ STATIC mp_obj_t py_display_write(uint n_args, const mp_obj_t *pos_args, mp_map_t } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_display_write_obj, 2, py_display_write); -#ifdef OMV_DSI_DISPLAY_CONTROLLER -STATIC mp_obj_t py_display_dsi_write(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +STATIC mp_obj_t py_display_bus_write(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_cmd, ARG_args, ARG_dcs }; static const mp_arg_t allowed_args[] = { { MP_QSTR_cmd, MP_ARG_INT | MP_ARG_REQUIRED }, @@ -192,23 +191,23 @@ STATIC mp_obj_t py_display_dsi_write(uint n_args, const mp_obj_t *pos_args, mp_m mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); py_display_p_t *display_p = (py_display_p_t *) MP_OBJ_TYPE_GET_SLOT(self->base.type, protocol); - if (display_p->dsi_write == NULL) { - mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Expected a DSI display controller")); + if (display_p->bus_write == NULL) { + mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Expected a display controller")); } else if (args[ARG_args].u_obj == mp_const_none) { - display_p->dsi_write(self, args[ARG_cmd].u_int, NULL, 0, args[ARG_dcs].u_bool); + display_p->bus_write(self, args[ARG_cmd].u_int, NULL, 0, args[ARG_dcs].u_bool); } else if (mp_obj_is_int(args[ARG_args].u_obj)) { uint8_t arg = mp_obj_get_int(args[ARG_args].u_obj); - display_p->dsi_write(self, args[ARG_cmd].u_int, &arg, 1, args[ARG_dcs].u_bool); + display_p->bus_write(self, args[ARG_cmd].u_int, &arg, 1, args[ARG_dcs].u_bool); } else { mp_buffer_info_t rbuf; mp_get_buffer_raise(args[ARG_args].u_obj, &rbuf, MP_BUFFER_READ); - display_p->dsi_write(self, args[ARG_cmd].u_int, rbuf.buf, rbuf.len, args[ARG_dcs].u_bool); + display_p->bus_write(self, args[ARG_cmd].u_int, rbuf.buf, rbuf.len, args[ARG_dcs].u_bool); } return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_display_dsi_write_obj, 1, py_display_dsi_write); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_display_bus_write_obj, 1, py_display_bus_write); -STATIC mp_obj_t py_display_dsi_read(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +STATIC mp_obj_t py_display_bus_read(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_cmd, ARG_len, ARG_args, ARG_dcs }; static const mp_arg_t allowed_args[] = { { MP_QSTR_cmd, MP_ARG_INT | MP_ARG_REQUIRED }, @@ -225,23 +224,22 @@ STATIC mp_obj_t py_display_dsi_read(uint n_args, const mp_obj_t *pos_args, mp_ma py_display_p_t *display_p = (py_display_p_t *) MP_OBJ_TYPE_GET_SLOT(self->base.type, protocol); mp_obj_array_t *wbuf = MP_OBJ_TO_PTR(mp_obj_new_bytearray_by_ref(args[ARG_len].u_int, m_new(byte, args[ARG_len].u_int))); - if (display_p->dsi_read == NULL) { - mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Expected a DSI display controller")); + if (display_p->bus_read == NULL) { + mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Expected a display controller")); } else if (args[ARG_args].u_obj == mp_const_none) { - display_p->dsi_read(self, args[ARG_cmd].u_int, NULL, 0, wbuf->items, wbuf->len, args[ARG_dcs].u_bool); + display_p->bus_read(self, args[ARG_cmd].u_int, NULL, 0, wbuf->items, wbuf->len, args[ARG_dcs].u_bool); } else if (mp_obj_is_int(args[ARG_args].u_obj)) { uint8_t arg = mp_obj_get_int(args[ARG_args].u_obj); - display_p->dsi_read(self, args[ARG_cmd].u_int, &arg, 1, wbuf->items, wbuf->len, args[ARG_dcs].u_bool); + display_p->bus_read(self, args[ARG_cmd].u_int, &arg, 1, wbuf->items, wbuf->len, args[ARG_dcs].u_bool); } else { mp_buffer_info_t rbuf; mp_get_buffer_raise(args[ARG_args].u_obj, &rbuf, MP_BUFFER_READ); - display_p->dsi_read(self, args[ARG_cmd].u_int, rbuf.buf, rbuf.len, + display_p->bus_read(self, args[ARG_cmd].u_int, rbuf.buf, rbuf.len, wbuf->items, wbuf->len, args[ARG_dcs].u_bool); } return MP_OBJ_FROM_PTR(wbuf); } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_display_dsi_read_obj, 1, py_display_dsi_read); -#endif +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_display_bus_read_obj, 1, py_display_bus_read); STATIC const mp_rom_map_elem_t py_display_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_display) }, @@ -256,10 +254,8 @@ STATIC const mp_rom_map_elem_t py_display_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&py_display_clear_obj) }, { MP_ROM_QSTR(MP_QSTR_backlight), MP_ROM_PTR(&py_display_backlight_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&py_display_write_obj) }, - #ifdef OMV_DSI_DISPLAY_CONTROLLER - { MP_ROM_QSTR(MP_QSTR_dsi_write), MP_ROM_PTR(&py_display_dsi_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_dsi_read), MP_ROM_PTR(&py_display_dsi_read_obj) }, - #endif + { MP_ROM_QSTR(MP_QSTR_bus_write), MP_ROM_PTR(&py_display_bus_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_bus_read), MP_ROM_PTR(&py_display_bus_read_obj) }, }; MP_DEFINE_CONST_DICT(py_display_locals_dict, py_display_locals_dict_table); diff --git a/src/omv/modules/py_display.h b/src/omv/modules/py_display.h index 3375a69ad..93322fc2d 100644 --- a/src/omv/modules/py_display.h +++ b/src/omv/modules/py_display.h @@ -72,11 +72,8 @@ typedef struct _py_display_p_t { float x_scale, float y_scale, rectangle_t *roi, int rgb_channel, int alpha, const uint16_t *color_palette, const uint8_t *alpha_palette, image_hint_t hint); void (*set_backlight) (py_display_obj_t *self, uint32_t intensity); - #ifdef OMV_DSI_DISPLAY_CONTROLLER - // To be implemented by MIPI DSI controllers. - int (*dsi_write) (py_display_obj_t *self, uint8_t cmd, uint8_t *args, size_t n_args, bool dcs); - int (*dsi_read) (py_display_obj_t *self, uint8_t cmd, uint8_t *args, size_t n_args, uint8_t *buf, size_t len, bool dcs); - #endif + int (*bus_write) (py_display_obj_t *self, uint8_t cmd, uint8_t *args, size_t n_args, bool dcs); + int (*bus_read) (py_display_obj_t *self, uint8_t cmd, uint8_t *args, size_t n_args, uint8_t *buf, size_t len, bool dcs); } py_display_p_t; extern const mp_obj_type_t py_spi_display_type; diff --git a/src/omv/ports/stm32/modules/py_display.c b/src/omv/ports/stm32/modules/py_display.c index 5896fe090..5f3e8b363 100644 --- a/src/omv/ports/stm32/modules/py_display.c +++ b/src/omv/ports/stm32/modules/py_display.c @@ -637,8 +637,8 @@ STATIC const py_display_p_t py_display_p = { .set_backlight = display_set_backlight, #endif #ifdef OMV_DSI_DISPLAY_CONTROLLER - .dsi_write = display_dsi_write, - .dsi_read = display_dsi_read, + .bus_write = display_dsi_write, + .bus_read = display_dsi_read, #endif }; From 179888f2336a14a2cf3b9c584dcfb26ad4ff7723 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Thu, 15 Feb 2024 13:43:46 -0800 Subject: [PATCH 2/2] modules: Add controller and bus write support to spi display. --- src/omv/modules/py_spi_display.c | 43 ++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/omv/modules/py_spi_display.c b/src/omv/modules/py_spi_display.c index 3d5804f0f..6d45319cf 100644 --- a/src/omv/modules/py_spi_display.c +++ b/src/omv/modules/py_spi_display.c @@ -73,13 +73,18 @@ static void spi_switch_mode(py_display_obj_t *self, int bits, bool dma) { omv_spi_init(&self->spi_bus, &spi_config); } -static void spi_display_command(py_display_obj_t *self, uint8_t cmd, uint8_t arg) { +static int spi_write(py_display_obj_t *self, uint8_t cmd, uint8_t *args, size_t n_args, bool dcs) { omv_gpio_write(OMV_SPI_DISPLAY_RS_PIN, 0); spi_transmit(self, (uint8_t []) { cmd }, 1); omv_gpio_write(OMV_SPI_DISPLAY_RS_PIN, 1); - if (arg) { - spi_transmit(self, (uint8_t []) { arg }, 1); + if (n_args) { + spi_transmit(self, args, n_args); } + return 0; +} + +static void spi_display_command(py_display_obj_t *self, uint8_t cmd, uint8_t arg) { + spi_write(self, cmd, &arg, (arg > 0) ? 1 : 0, false); } static void spi_display_callback(omv_spi_t *spi, void *userdata, void *buf) { @@ -308,7 +313,10 @@ static void spi_display_deinit(py_display_obj_t *self) { } mp_obj_t spi_display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_width, ARG_height, ARG_refresh, ARG_bgr, ARG_byte_swap, ARG_triple_buffer, ARG_backlight }; + enum { + ARG_width, ARG_height, ARG_refresh, ARG_bgr, ARG_byte_swap, ARG_triple_buffer, + ARG_controller, ARG_backlight + }; static const mp_arg_t allowed_args[] = { { MP_QSTR_width, MP_ARG_INT, {.u_int = 128 } }, { MP_QSTR_height, MP_ARG_INT, {.u_int = 160 } }, @@ -316,6 +324,7 @@ mp_obj_t spi_display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n { MP_QSTR_bgr, MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_byte_swap, MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_triple_buffer, MP_ARG_BOOL, {.u_bool = LCD_TRIPLE_BUFFER_DEFAULT} }, + { MP_QSTR_controller, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_backlight, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} }, }; @@ -343,6 +352,7 @@ mp_obj_t spi_display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n self->triple_buffer = args[ARG_triple_buffer].u_bool; self->bgr = args[ARG_bgr].u_bool; self->byte_swap = args[ARG_byte_swap].u_bool; + self->controller = args[ARG_controller].u_obj; self->bl_controller = args[ARG_backlight].u_obj; omv_spi_config_t spi_config; @@ -367,13 +377,23 @@ mp_obj_t spi_display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n omv_gpio_write(OMV_SPI_DISPLAY_RST_PIN, 1); mp_hal_delay_ms(100); - // Sleep out - spi_display_command(self, LCD_COMMAND_SLPOUT, 0); - mp_hal_delay_ms(120); - // Memory data access control - spi_display_command(self, LCD_COMMAND_MADCTL, self->bgr ? 0xC8 : 0xC0); - // Interface pixel format - spi_display_command(self, LCD_COMMAND_COLMOD, 0x05); + // Init the display controller. + if (self->controller != mp_const_none) { + mp_obj_t dest[3]; + mp_load_method_maybe(self->controller, MP_QSTR_init, dest); + if (dest[0] != MP_OBJ_NULL) { + dest[2] = MP_OBJ_FROM_PTR(self); + mp_call_method_n_kw(1, 0, dest); + } + } else { + // Sleep out + spi_display_command(self, LCD_COMMAND_SLPOUT, 0); + mp_hal_delay_ms(120); + // Memory data access control + spi_display_command(self, LCD_COMMAND_MADCTL, self->bgr ? 0xC8 : 0xC0); + // Interface pixel format + spi_display_command(self, LCD_COMMAND_COLMOD, 0x05); + } if (self->triple_buffer) { fb_alloc_mark(); @@ -394,6 +414,7 @@ STATIC const py_display_p_t py_display_p = { #ifdef OMV_SPI_DISPLAY_BL_PIN .set_backlight = spi_display_set_backlight, #endif + .bus_write = spi_write, }; MP_DEFINE_CONST_OBJ_TYPE(