Rotation display

Description

What MCU/Processor/Board and compiler are you using?

MCU: ESP32-P4
Board: JC8012P4A1
LCD:JD9365
Framework: Arduino
Compiler: pioarduino
LVGL Version: LVGL v9.3

What do you want to achieve?

Rotate the screen 90 degrees. I tried everything, but before I changed the flush function, nothing worked at all; the screen was always vertical. Now the screen is upside down, but it still feels vertical.

What have you tried so far?

Tried the function:

lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_90);

I tried the function and swapping the width (LCD_H_RES) and height(LCD_V_RES) when creating the display:

disp_drv = lv_display_create(LCD_H_RES, LCD_V_RES);

In both cases, I get artifacts.
I also tried playing with MADCTL, MV simply mirrors the screen and nothing more.

Code to reproduce

main.cpp

#pragma GCC push_options
#pragma GCC optimize("O3")

#include <Arduino.h>
#include "lvgl.h"
#include "pins_config.h"
#include "lcd/jd9365_lcd.h"
#include "touch/gsl3680_touch.h"

jd9365_lcd lcd = jd9365_lcd(LCD_RST);
gsl3680_touch touch = gsl3680_touch(TP_I2C_SDA, TP_I2C_SCL, TP_RST, TP_INT);

lv_display_t *disp_drv;
static uint32_t *buf;
static uint32_t *buf1;

static lv_obj_t *label;

void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
{
    const int32_t DISP_W = LCD_H_RES;   // Ширина в 0°
    const int32_t DISP_H = LCD_V_RES;  // Высота в 0°
    const lv_color_format_t COLOR_FORMAT = LV_COLOR_FORMAT_RGB565;
    const uint32_t BYTES_PER_PIXEL = 2; // RGB565 = 2 байта на пиксель
    
    lv_display_rotation_t rotation = LV_DISPLAY_ROTATION_90;
    lv_area_t rotated_area;
    if (rotation != LV_DISPLAY_ROTATION_0) {
        
        rotated_area = *area;
        lv_display_rotate_area(disp, &rotated_area);
        uint32_t src_stride = lv_draw_buf_width_to_stride(lv_area_get_width(area), COLOR_FORMAT);   // Исходный буфер
        uint32_t dest_stride = lv_draw_buf_width_to_stride(lv_area_get_width(&rotated_area), COLOR_FORMAT);

        static uint8_t *rotated_buf = nullptr;
        static size_t rotated_buf_size = 0;

        size_t needed_size = lv_area_get_width(&rotated_area) * lv_area_get_height(&rotated_area) * BYTES_PER_PIXEL;
        if (rotated_buf == nullptr || rotated_buf_size < needed_size) {
            if (rotated_buf) free(rotated_buf);
            rotated_buf = (uint8_t *)heap_caps_malloc(needed_size, MALLOC_CAP_SPIRAM);
            rotated_buf_size = needed_size;
            assert(rotated_buf);
        }

        int32_t src_w = lv_area_get_width(area);
        int32_t src_h = lv_area_get_height(area);
        lv_draw_sw_rotate(px_map, rotated_buf, src_w, src_h, src_stride, dest_stride, rotation, COLOR_FORMAT);
        area = &rotated_area;
        px_map = rotated_buf;
    }
    
    lcd.lcd_draw_bitmap(area->x1, area->y1, area->x2 + 1, area->y2 + 1, px_map);
    lv_display_flush_ready(disp);
}

void my_touchpad_read(lv_indev_t *indev_driver, lv_indev_data_t *data)
{
    bool touched;
    uint16_t touchX, touchY;

    touched = touch.getTouch(&touchX, &touchY);

    if (!touched)
    {
        data->state = LV_INDEV_STATE_REL;
    }
    else
    {
        data->state = LV_INDEV_STATE_PR;

        data->point.x = touchX;
        data->point.y = touchY;
        Serial.printf("x=%d,y=%d \r\n", touchX, touchY);
    }
}

void setup()
{
    Serial.begin(115200);
    Serial.println("ESP32P4 MIPI DSI LVGL");
    lcd.begin();
    //lcd.rotate(1);
    touch.begin();

    lv_init();
    
    uint32_t buffer_size = LCD_H_RES * LCD_V_RES * 2;

    buf = (uint32_t *)heap_caps_malloc(buffer_size, MALLOC_CAP_SPIRAM);
    buf1 = (uint32_t *)heap_caps_malloc(buffer_size, MALLOC_CAP_SPIRAM);
    assert(buf);
    assert(buf1);

    disp_drv = lv_display_create(LCD_H_RES, LCD_V_RES);
    lv_display_set_flush_cb(disp_drv, flush_cb);
    lv_display_set_buffers(disp_drv, buf, buf1, buffer_size * sizeof(uint32_t), LV_DISPLAY_RENDER_MODE_FULL);

    
    lv_indev_t *indev = lv_indev_create();
    lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
    lv_indev_set_read_cb(indev, my_touchpad_read);

    constexpr int BIT_DEPTH = 14;
    constexpr int MAX_PWM_VAL = 1 << BIT_DEPTH;
    if (!ledcAttachChannel(LCD_LED, 1220, BIT_DEPTH, 0))
    {
        log_e("Error setting ledc pin %i. system halted", LCD_LED);
        while (1)
            delay(1000);
    }

    if (!ledcWrite(LCD_LED, MAX_PWM_VAL >> 0))
    {
        log_e("Error setting ledc value. system halted");
        while (1)
            delay(1000);
    }

    lv_obj_set_style_bg_color(lv_scr_act(), lv_palette_main(LV_PALETTE_AMBER), 0);

    // create a style
    static lv_style_t style_big;
    lv_style_init(&style_big);
    lv_style_set_text_font(&style_big, &lv_font_montserrat_48);

    // create label
    label = lv_label_create(lv_scr_act());
    // apply style to label
    lv_obj_add_style(label, &style_big, 0);
    lv_label_set_text(label, "Hello World!");
    lv_obj_center(label);
}

void loop()
{
    lv_timer_handler();

    lv_indev_t *indev = lv_indev_get_next(nullptr);
    if (indev && lv_indev_get_type(indev) == LV_INDEV_TYPE_POINTER)
    {
        lv_point_t point;
        lv_indev_get_point(indev, &point); // gets current or last point
        lv_indev_state_t state = lv_indev_get_state(indev);

        static lv_point_t last = {-1, -1};
        static bool last_pressed = false;

        if (state == LV_INDEV_STATE_PRESSED &&
            (point.x != last.x || point.y != last.y || !last_pressed))
        {
            last = point;
            last_pressed = true;

            char buf[64];
            snprintf(buf, sizeof(buf), "Touch: %d, %d", point.x, point.y);
            lv_label_set_text(label, buf);
            lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
            lv_obj_set_style_text_color(label, lv_palette_main(LV_PALETTE_BLUE), 0);
        }
        else if (state == LV_INDEV_STATE_RELEASED && last_pressed)
        {
            last_pressed = false;
            lv_label_set_text(label, "JC8012P4A1 ESP32-P4");
            lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
            lv_obj_set_style_text_color(label, lv_palette_main(LV_PALETTE_NONE), 0);
        }
    }

    delay(5);
    lv_tick_inc(5);
}

Screenshot and/or video