当前位置:首页 > 显示光电 > 显示光电
[导读]“旋转显示”常被理解成把帧缓冲整帧重排一遍,其实90/180/270这种直角旋转,大多数情况不用动原始画面数据——只改“控制器怎么读显存”或“flush时往哪写”。驱动IC支持MADCTL就零拷贝,LTDC不支持就放flush里做块旋转。


“旋转显示”常被理解成把帧缓冲整帧重排一遍,其实90/180/270这种直角旋转,大多数情况不用动原始画面数据——只改“控制器怎么读显存”或“flush时往哪写”。驱动IC支持MADCTL就零拷贝,LTDC不支持就放flush里做块旋转。

一、旋转的两层做法

控制器侧(首选):带GRAM的屏驱(ST7789/ILI9341/RM67162)改MADCTL,行列扫描方向变了,主控仍按逻辑坐标绘图,像素数据原样发。

主控侧软件旋转:LTDC/RGB屏没有硬件旋转,只能在GUI flush回调里把脏矩形转到物理帧缓冲对应位置。

选错路线要么白吃CPU,要么坐标全歪。

二、MADCTL:最干净的方案

MADCTL(0x36)三位决定方向:

MY(0x80):行方向翻转

MX(0x40):列方向翻转

MV(0x20):行列交换(90°关键)

ILI9341常见组合:

void lcd_set_rotation(int rot){

   uint8_t v;

   switch(rot){

       case 0:   v = 0x48; break;   // 竖屏

       case 90:  v = 0x28; break;   // 横屏 MV=1

       case 180: v = 0x88; break;

       case 270: v = 0xE8; break;

   }

   lcd_write_cmd(0x36);

   lcd_write_data(v);

}

设完之后:

逻辑分辨率宽高互换(90/270时)

绘图API坐标不变

显存里的RGB数据一个字节都不用重排

地址窗口照常用0x2A/0x2B,驱动IC自己映射

注意MADCTL还管RGB/BGR位,换方向时别把颜色序弄反。

三、LTDC/RGB屏:flush里转

STM32 LTDC按行扫帧缓冲,硬件不旋转。 LVGL里正确姿势:

lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_90);

flush回调里用LVGL自带旋转把渲染块搬进物理fb:

void disp_flush(lv_display_t*d, const lv_area_t*a, uint8_t*px){

   lv_color_format_t cf = lv_display_get_color_format(d);

   lv_area_t ra = *a;

   lv_display_rotate_area(d, &ra);          // 算物理目标区


   uint32_t src_stride = lv_draw_buf_width_to_stride(

       lv_area_get_width(a), cf);

   uint32_t fb_stride = lv_draw_buf_width_to_stride(PHYS_W, cf);

   uint8_t*fb = fb_base

       + ra.y1*fb_stride + ra.x1*lv_color_format_get_size(cf);


   lv_draw_sw_rotate(px, fb,

       lv_area_get_width(a), lv_area_get_height(a),

       src_stride, fb_stride,

       lv_display_get_rotation(d), cf);


   lv_display_flush_ready(d);

}

要点:

用PARTIAL渲染模式,别用DIRECT——DIRECT直接写进fb,后面转不动

旋转开起来DMA2D flush失效,CPU做块拷贝

只转脏矩形,不是整屏重排,开销可控

Cache在外部SDRAM时要Clean/Invalidate

四、裸机无GUI:改DrawPixel映射

没LVGL时别重排显存,改写像素地址:

// 90°: (x,y) -> (H-1-y, x)

#define PXOFF(x,y) ((W*(H-1-y) + x)*2)

void put_px(int x,int y,uint16_t c){

   *(uint16_t*)(FB + PXOFF(x,y)) = c;

}

所有上层画图函数调用put_px即可,业务层坐标仍是逻辑坐标。代价是每次写像素多一次运算,静态界面无所谓,动画密集场景还是走MADCTL或硬件叠加层。

五、触控坐标必须跟着转

最容易被忘:屏转了,触摸没转,点按钮全偏。

void touch_remap(int*rx,int*ry){

   int tx=*rx, ty=*ry;

   switch(cur_rot){

       case 90:  *rx = ty;          *ry = PHYS_W-1-tx; break;

       case 180: *rx = PHYS_W-1-tx; *ry = PHYS_H-1-ty; break;

       case 270: *rx = PHYS_H-1-ty; *ry = tx; break;

   }

}

规则跟MADCTL映射对称,校准时按当前方向标一次点就行。

六、落坑清单

LTDC屏硬等“硬件旋转”→没有,只能软件转

只改MADCTL不换逻辑宽高→GUI布局算错

DIRECT模式开旋转→块写进fb后再也转不了

触控坐标不映射→点击偏移

MADCTL把BGR位清了→颜色反

90°后地址窗口还按原W/H设→写串

整屏memcpy旋转→完全没必要,块旋转就行

SPI屏CS没拉住就改MADCTL→命令被当数据

七、选型结论

SPI TFT(ST7789/ILI9341):MADCTL优先,零拷贝零重排

RGB/LTDC屏:LVGL rotation + flush块旋转

纯裸机RGB:改DrawPixel地址映射或DMA步长

视频层旋转(DSS类):改ROW_INC/PIXEL_INC让DMA按列取数

直角旋转的本质不是“重画一帧”,是“换寻址”。原始画面数据保持不变,控制器或DMA按新方向读显存,CPU只付出一次寄存器配置或脏矩形块拷贝。真要任意角度才需要像素重采样,那是另一回事;90/180/270在工程里都不该动源帧缓冲。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭