How to rotate AMOLED display with SH8601 driver and FT3168 touch driver

What do you want to achieve?

Rotate from portrait to landscape orientation on a ESP32-S3-AMOLED-1.64 from Waveshare

What have you tried so far?

According to Waveshare’s supplied wiki page on the product, hardware rotation isn’t an option, software rotation is supplied in the LVGL example code they provide. However when used, the display acts up and shows a partially shifted image.

The display rotation does work correctly when altering flush_cb, but i am unable to make the touch driver work that way (whatever I try it doesn’t rotate properly, the 280x456px area becomes 280x280px after “rotating”). When using the “example” software rotation method, the touch screen is fine but the display it self is not ( as shown below).

(just a quick lvgl design with a slider to test the full touch area)

Any help/suggestions to get me along the way would be greatly appreciated.
Thank you.

Code to reproduce

disp_drv.sw_rotate = 1;
disp_drv.rotated = LV_DISP_ROT_270;

Screenshot and/or video

Environment

  • MCU/MPU/Board: ESP32-S3 with SH8601 & FT3168 in Arduino IDE
  • LVGL version: 8.3.11

can you provide your flush_cb implementation?

In all honesty, found this elsewhere suggested online and managed to get it “working” by changing the variable names to the ones in the Waveshare’s provided code.

So no clue really how well this function is constructed.

static void rotated_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map){

    esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data;
    const int width  = drv->hor_res;
    const int height = drv->ver_res;

    const int offset_x = 0x14;
    const int offset_y = 0;

    uint32_t area_w = lv_area_get_width(area);
    uint32_t area_h = lv_area_get_height(area);

    static lv_color_t *rot_buf = NULL;
    static size_t rot_buf_size = 0;
    size_t needed_pixels = area_w * area_h;

    if (rot_buf == NULL || rot_buf_size < needed_pixels) {
        if (rot_buf) heap_caps_free(rot_buf);
        rot_buf = heap_caps_malloc(needed_pixels * sizeof(lv_color_t), MALLOC_CAP_DMA);
        assert(rot_buf);
        rot_buf_size = needed_pixels;
    }

    for (uint32_t y = 0; y < area_h; y++) {
        for (uint32_t x = 0; x < area_w; x++) {
            rot_buf[x * area_h + (area_h - 1 - y)] = color_map[y * area_w + x];
        }
    }

    lv_area_t rot_area;
    rot_area.x1 = height - area->y2 - 1;
    rot_area.x2 = height - area->y1 - 1;
    rot_area.y1 = area->x1;
    rot_area.y2 = area->x2;

    esp_lcd_panel_draw_bitmap(
        panel_handle,
        rot_area.x1 + offset_x,
        rot_area.y1 + offset_y,
        rot_area.x2 + 1 + offset_x,
        rot_area.y2 + 1 + offset_y,
        rot_buf
    );

    lv_disp_flush_ready(drv);
  }