How to rotate the display direction of the LVGL interface

Description

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

STM32F407VG + MDK5

What LVGL version are you using?

LVGL v7

What do you want to achieve?

Switch screen orientation at runtime

What have you tried so far?

The RM68140 monitor (480 * 320) I use cannot modify the scanning direction, and the configuration of MADCTR (36h) is invalid. Is there an API for LVGL to switch the display direction?

Code to reproduce

Add a code snippet which can run in the simulator. It should contain only the relevant code that compiles without errors when separated from your main code base.

The code block(s) should be formatted like:

/*You code here*/
## Screenshot and/or video
If possible, add screenshots and/or videos about the current state.

![QQ截图0001|690x431](upload://3LYm669wM7xV4oegYyLePXMPiTx.jpeg) ![QQ截图002|690x456](upload://uFroSm8EbS0wIC59A7SKy4gYw4V.jpeg)

LVGL does not rotate the output data itself; it only changes the logical screen dimensions. You will need to flip the pixels in the display driver.

@xbee You can use the search function at the top of this page (magnifier glass symbol) to do a search for rotating or rotation.

Hello, my monitor cannot change the scanning direction. Is there a way to select LVGL data?

非常感谢,我已经搜索过,但没有找到解决方法

I don’t quite understand the meaning of this code, I tried to modify it into the MCU code, but it seems not correct


void get_col(const lv_color_t * src, const lv_area_t * area, lv_coord_t y, lv_color_t * dest)
{
    lv_coord_t w = lv_area_get_width(area);
    lv_coord_t h = lv_area_get_height(area);

    lv_coord_t i;
    for(i = 0; i < h; i++) {
        dest[i].full = src[y].full;
        src += w ;
    }
}

/* Flush the content of the internal buffer the specific area on the display
 * You can use DMA or any hardware acceleration to do this operation in the background but
 * 'lv_disp_flush_ready()' has to be called when finished. */
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
		
	
	
	  lv_coord_t x2 = area->x2;
    if(x2 >= disp_drv->ver_res) x2 = LV_VER_RES_MAX - 1;

    lv_color_t * dest = (lv_color_t *)color_p;
    dest +=  LV_HOR_RES_MAX * (LV_VER_RES_MAX - 1);
    dest -= LV_HOR_RES_MAX * area->x1;

    lv_coord_t x;
    for(x = area->x1; x <= x2; x++) {
          get_col(color_p, area, (x - area->x1), dest + area->y1);
          dest -= LV_HOR_RES_MAX;
    }
		
		LCD_Color_Fill(area->x1,area->x2,area->y1,area->y2,(uint16_t *)color_p);
    /* IMPORTANT!!!
     * Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}

我不太了解此代码的含义,我尝试将其修改为MCU代码,但似乎不正确

void get_col(const lv_color_t * src, const lv_area_t * area, lv_coord_t y, lv_color_t * dest)
{
    lv_coord_t w = lv_area_get_width(area);
    lv_coord_t h = lv_area_get_height(area);

    lv_coord_t i;
    for(i = 0; i < h; i++) {
        dest[i].full = src[y].full;
        src += w ;
    }
}

/* Flush the content of the internal buffer the specific area on the display
 * You can use DMA or any hardware acceleration to do this operation in the background but
 * 'lv_disp_flush_ready()' has to be called when finished. */
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
		
	
	
	  lv_coord_t x2 = area->x2;
    if(x2 >= disp_drv->ver_res) x2 = LV_VER_RES_MAX - 1;

    lv_color_t * dest = (lv_color_t *)color_p;
    dest +=  LV_HOR_RES_MAX * (LV_VER_RES_MAX - 1);
    dest -= LV_HOR_RES_MAX * area->x1;

    lv_coord_t x;
    for(x = area->x1; x <= x2; x++) {
          get_col(color_p, area, (x - area->x1), dest + area->y1);
          dest -= LV_HOR_RES_MAX;
    }
		
		LCD_Color_Fill(area->x1,area->x2,area->y1,area->y2,(uint16_t *)color_p);
    /* IMPORTANT!!!
     * Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}

You are right, your code isn’t correct.

The original code:

    lv_color_t * dest = (lv_color_t *)monitor.tft_fb;

your code:

    lv_color_t * dest = (lv_color_t *)color_p;

The pointer dest have to point to the start of the real frame buffer of your LCD. For the original code it is monitor.tft_fb.
You set the pointer dest to color_p, but this is the source of the data which should be written into the real (destination) frame buffer.

You have to set dest to the right frame buffer base address.

And also, you have to remove the call of the LCD_Color_Fill, as the copying of the source pixels to the destination is already done within the function get_col.

It seems the author want to direct transform the framebuffer already wrote to the vertical one, which is impossible . Is there any method to directly write the framebuffer in vertical mode?

Current implementation of lvgl does not support any display rotation.
For lvgl you define a horizontal and a vertical resolution.
Let’s say, you want a screen in 480 x 800 (portrait mode) resolution.
But your display is physically layed out as 800 x 480 (landscape mode),
and doesn’t allow any rotation internally by LCD’s hardware driver,
you have to write all the data which is provided by lvgl (in portrait mode)
rotated to the LCD’s framebuffer (in landscape mode).

Building rotation into lvgl would be not so hard for simple drawing routines
(like drawing pixels, lines, rectangles and circles) but would be more expensive for
drawing the glyphs, as you have to rotate any single glyph data according the needed rotation
(90, 180, 270) before you print it into the frame buffer.

So, if you’re logical (lvgl) resolution (portrait or landscape) doesn’t match the phsysical display mode,
you are forced to rotate lvgl’s output within the flush function.

And, if you need rotation, don’t use double buffering. Just use a single buffer in the size of e.g. LV_HOR_RES_MAX * 40. (more or less)

Many Thanks!
The realtime rotation is really hard to implement in the given MCU platform. Strong suggest to support the build-in vertical selection of the framebuffer, as many TFT were vertical type.

Best Regards,

Don’t know what your current MCU platform is, and why rotation is hard to implement for that given platform.
As you say, many TFT were vertical/portrait type displays. Of course many (or much more?) TFTs are of horizontal/landscape type.
You can setup lvgl for portrait mode (e.g. 480 x 800), or you can setup lvgl for landscape mode (e.g. 800 x 480). You only need rotation if your display is in portrait mode but you want to show in landscape, or vice versa, or you need a rotation of 180 degrees. Also there should exists some displays where the display can be rotated by changing the configuration of the hardware driver.
Currently, if you need rotation, you do it at one place, the flush function. It’s a simple algorithm, but
of course it needs some time to do rotation.
Building rotation right into lvgl would have much more impact in changing code, as more places of code are affected. It may have lower impact on code execution time (except when using images).

Many Thanks!
I mean the MIPS cost in MCU as there often has limited bandwidth. Especially the rotation is base on mcu copy one by one ,not the DMA.
If build-in support the vertical/portrait type displays, how about just modify the hal lever function ,like the lv_color_fill(), or the gpu_fill_cb and gpu_blend_cb to support the vertical/portrait type? And replace the font and IMG with the vertical scaned format? But yes, it is too complex for end user to work on it.
You are right , the rotation in mem is the easiest.

Best Regards,