diff --git a/Drivers/ili9341-module/source/ili9341.cpp b/Drivers/ili9341-module/source/ili9341.cpp index 5f47dc426..c9ef6d983 100644 --- a/Drivers/ili9341-module/source/ili9341.cpp +++ b/Drivers/ili9341-module/source/ili9341.cpp @@ -324,6 +324,21 @@ static error_t ili9341_set_gap(Device* device, int32_t x_gap, int32_t y_gap) { return esp_lcd_panel_set_gap(internal->panel_handle, x_gap, y_gap) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; } +// Reads the devicetree-configured baseline, not live hardware state - see DisplayApi::get_gap_x(). +// Must match what start() actually programmed into the panel (physical CASET/RASET-space, swapped +// when swap_xy is set) - lvgl_display.c treats this as the LV_DISPLAY_ROTATION_0 baseline and +// re-applies it verbatim, so returning the raw unswapped config here would silently clobber +// start()'s gap back to the wrong axes as soon as a display is bound. +static int32_t ili9341_get_gap_x(Device* device) { + const auto* config = GET_CONFIG(device); + return config->swap_xy ? config->gap_y : config->gap_x; +} + +static int32_t ili9341_get_gap_y(Device* device) { + const auto* config = GET_CONFIG(device); + return config->swap_xy ? config->gap_x : config->gap_y; +} + static error_t ili9341_invert_color(Device* device, bool invert_color_data) { auto* internal = static_cast(device_get_driver_data(device)); return esp_lcd_panel_invert_color(internal->panel_handle, invert_color_data) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; @@ -392,6 +407,8 @@ static const DisplayApi ili9341_display_api = { .get_mirror_x = ili9341_get_mirror_x, .get_mirror_y = ili9341_get_mirror_y, .set_gap = ili9341_set_gap, + .get_gap_x = ili9341_get_gap_x, + .get_gap_y = ili9341_get_gap_y, .invert_color = ili9341_invert_color, .disp_on_off = ili9341_disp_on_off, .disp_sleep = ili9341_disp_sleep, diff --git a/Drivers/ili9488-module/source/ili9488.cpp b/Drivers/ili9488-module/source/ili9488.cpp index 0a4ba4bea..7af093784 100644 --- a/Drivers/ili9488-module/source/ili9488.cpp +++ b/Drivers/ili9488-module/source/ili9488.cpp @@ -246,6 +246,21 @@ static error_t ili9488_set_gap(Device* device, int32_t x_gap, int32_t y_gap) { return esp_lcd_panel_set_gap(internal->panel_handle, x_gap, y_gap) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; } +// Reads the devicetree-configured baseline, not live hardware state - see DisplayApi::get_gap_x(). +// Must match what start() actually programmed into the panel (physical CASET/RASET-space, swapped +// when swap_xy is set) - lvgl_display.c treats this as the LV_DISPLAY_ROTATION_0 baseline and +// re-applies it verbatim, so returning the raw unswapped config here would silently clobber +// start()'s gap back to the wrong axes as soon as a display is bound. +static int32_t ili9488_get_gap_x(Device* device) { + const auto* config = GET_CONFIG(device); + return config->swap_xy ? config->gap_y : config->gap_x; +} + +static int32_t ili9488_get_gap_y(Device* device) { + const auto* config = GET_CONFIG(device); + return config->swap_xy ? config->gap_x : config->gap_y; +} + static error_t ili9488_invert_color(Device* device, bool invert_color_data) { auto* internal = static_cast(device_get_driver_data(device)); return esp_lcd_panel_invert_color(internal->panel_handle, invert_color_data) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; @@ -311,6 +326,8 @@ static const DisplayApi ili9488_display_api = { .get_mirror_x = ili9488_get_mirror_x, .get_mirror_y = ili9488_get_mirror_y, .set_gap = ili9488_set_gap, + .get_gap_x = ili9488_get_gap_x, + .get_gap_y = ili9488_get_gap_y, .invert_color = ili9488_invert_color, .disp_on_off = ili9488_disp_on_off, .disp_sleep = ili9488_disp_sleep, diff --git a/Drivers/st7735-module/source/st7735.cpp b/Drivers/st7735-module/source/st7735.cpp index 840e02689..66c2a0b22 100644 --- a/Drivers/st7735-module/source/st7735.cpp +++ b/Drivers/st7735-module/source/st7735.cpp @@ -138,11 +138,13 @@ static error_t start(Device* device) { esp_lcd_panel_init(internal->panel_handle) == ESP_OK && (!config->invert_color || esp_lcd_panel_invert_color(internal->panel_handle, true) == ESP_OK); - // set_gap() just stores x_gap/y_gap and adds them as raw offsets wherever draw_bitmap()'s - // (already logical, post-swap) x/y land - independent of swap_xy/mirror state (confirmed via - // ESP-IDF's esp_lcd_panel_st7789.c, same pattern), so gap_x/gap_y are passed through unswapped. + // set_gap()'s x/y map straight to the physical CASET/RASET column/row registers, not to + // draw_bitmap()'s logical (post-swap) x/y - swap_xy transposes which physical axis those + // registers address, so the configured gaps must swap with it too + int32_t gap_x = config->swap_xy ? config->gap_y : config->gap_x; + int32_t gap_y = config->swap_xy ? config->gap_x : config->gap_y; if (ok) { - ok = (config->gap_x == 0 && config->gap_y == 0) || esp_lcd_panel_set_gap(internal->panel_handle, config->gap_x, config->gap_y) == ESP_OK; + ok = (gap_x == 0 && gap_y == 0) || esp_lcd_panel_set_gap(internal->panel_handle, gap_x, gap_y) == ESP_OK; } ok = ok && (!config->swap_xy || esp_lcd_panel_swap_xy(internal->panel_handle, true) == ESP_OK); ok = ok && ((!config->mirror_x && !config->mirror_y) || esp_lcd_panel_mirror(internal->panel_handle, config->mirror_x, config->mirror_y) == ESP_OK); @@ -252,12 +254,18 @@ static error_t st7735_set_gap(Device* device, int32_t x_gap, int32_t y_gap) { } // Reads the devicetree-configured baseline, not live hardware state - see DisplayApi::get_gap_x(). +// Must match what start() actually programmed into the panel (physical CASET/RASET-space, swapped +// when swap_xy is set) - lvgl_display.c treats this as the LV_DISPLAY_ROTATION_0 baseline and +// re-applies it verbatim, so returning the raw unswapped config here would silently clobber +// start()'s gap back to the wrong axes as soon as a display is bound. static int32_t st7735_get_gap_x(Device* device) { - return GET_CONFIG(device)->gap_x; + const auto* config = GET_CONFIG(device); + return config->swap_xy ? config->gap_y : config->gap_x; } static int32_t st7735_get_gap_y(Device* device) { - return GET_CONFIG(device)->gap_y; + const auto* config = GET_CONFIG(device); + return config->swap_xy ? config->gap_x : config->gap_y; } static error_t st7735_invert_color(Device* device, bool invert_color_data) { diff --git a/Drivers/st7789-i8080-module/source/st7789_i8080.cpp b/Drivers/st7789-i8080-module/source/st7789_i8080.cpp index a405cbd27..d897c6f34 100644 --- a/Drivers/st7789-i8080-module/source/st7789_i8080.cpp +++ b/Drivers/st7789-i8080-module/source/st7789_i8080.cpp @@ -275,6 +275,21 @@ static bool st7789_i8080_get_mirror_y(Device* device) { return GET_CONFIG(device)->mirror_y; } +// Reads the devicetree-configured baseline, not live hardware state - see DisplayApi::get_gap_x(). +// Must match what start() actually programmed into the panel (physical CASET/RASET-space, swapped +// when swap_xy is set) - lvgl_display.c treats this as the LV_DISPLAY_ROTATION_0 baseline and +// re-applies it verbatim, so returning the raw unswapped config here would silently clobber +// start()'s gap back to the wrong axes as soon as a display is bound. +static int32_t st7789_i8080_get_gap_x(Device* device) { + const auto* config = GET_CONFIG(device); + return config->swap_xy ? config->gap_y : config->gap_x; +} + +static int32_t st7789_i8080_get_gap_y(Device* device) { + const auto* config = GET_CONFIG(device); + return config->swap_xy ? config->gap_x : config->gap_y; +} + static error_t st7789_i8080_set_gap(Device* device, int32_t x_gap, int32_t y_gap) { auto* internal = static_cast(device_get_driver_data(device)); return esp_lcd_panel_set_gap(internal->panel_handle, x_gap, y_gap) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE; @@ -342,6 +357,8 @@ static const DisplayApi st7789_i8080_display_api = { .get_mirror_x = st7789_i8080_get_mirror_x, .get_mirror_y = st7789_i8080_get_mirror_y, .set_gap = st7789_i8080_set_gap, + .get_gap_x = st7789_i8080_get_gap_x, + .get_gap_y = st7789_i8080_get_gap_y, .invert_color = st7789_i8080_invert_color, .disp_on_off = st7789_i8080_disp_on_off, .disp_sleep = st7789_i8080_disp_sleep, diff --git a/Drivers/st7789-module/source/st7789.cpp b/Drivers/st7789-module/source/st7789.cpp index 06b704f4c..071a88d5d 100644 --- a/Drivers/st7789-module/source/st7789.cpp +++ b/Drivers/st7789-module/source/st7789.cpp @@ -138,11 +138,13 @@ static error_t start(Device* device) { esp_lcd_panel_init(internal->panel_handle) == ESP_OK && (!config->invert_color || esp_lcd_panel_invert_color(internal->panel_handle, true) == ESP_OK); - // set_gap() just stores x_gap/y_gap and adds them as raw offsets wherever draw_bitmap()'s - // (already logical, post-swap) x/y land - independent of swap_xy/mirror state (confirmed via - // ESP-IDF's esp_lcd_panel_st7789.c), so gap_x/gap_y are passed through unswapped. + // set_gap()'s x/y map straight to the physical CASET/RASET column/row registers, not to + // draw_bitmap()'s logical (post-swap) x/y - swap_xy transposes which physical axis those + // registers address, so the configured gaps must swap with it too. + int32_t gap_x = config->swap_xy ? config->gap_y : config->gap_x; + int32_t gap_y = config->swap_xy ? config->gap_x : config->gap_y; if (ok) { - ok = (config->gap_x == 0 && config->gap_y == 0) || esp_lcd_panel_set_gap(internal->panel_handle, config->gap_x, config->gap_y) == ESP_OK; + ok = (gap_x == 0 && gap_y == 0) || esp_lcd_panel_set_gap(internal->panel_handle, gap_x, gap_y) == ESP_OK; } ok = ok && (!config->swap_xy || esp_lcd_panel_swap_xy(internal->panel_handle, true) == ESP_OK); ok = ok && ((!config->mirror_x && !config->mirror_y) || esp_lcd_panel_mirror(internal->panel_handle, config->mirror_x, config->mirror_y) == ESP_OK); @@ -252,12 +254,18 @@ static error_t st7789_set_gap(Device* device, int32_t x_gap, int32_t y_gap) { } // Reads the devicetree-configured baseline, not live hardware state - see DisplayApi::get_gap_x(). +// Must match what start() actually programmed into the panel (physical CASET/RASET-space, swapped +// when swap_xy is set) - lvgl_display.c treats this as the LV_DISPLAY_ROTATION_0 baseline and +// re-applies it verbatim, so returning the raw unswapped config here would silently clobber +// start()'s gap back to the wrong axes as soon as a display is bound. static int32_t st7789_get_gap_x(Device* device) { - return GET_CONFIG(device)->gap_x; + const auto* config = GET_CONFIG(device); + return config->swap_xy ? config->gap_y : config->gap_x; } static int32_t st7789_get_gap_y(Device* device) { - return GET_CONFIG(device)->gap_y; + const auto* config = GET_CONFIG(device); + return config->swap_xy ? config->gap_x : config->gap_y; } static error_t st7789_invert_color(Device* device, bool invert_color_data) {