你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

如何在STM32H743驱动RGB屏幕并移植LVGL v8.0

[复制链接]
STMCU小助手 发布时间:2022-8-27 19:22
硬件准备
正点原子H743开发板+7寸 RGB LCD显示屏 + SDRAM (注意RGB屏幕必须外扩显存)

2_6~]MI0{20`2K_8JHQ(%ZO.png

软件准备
        STM32cubeMX 6.1.2 + Keil 5

创建cubeMX工程
首先打开STM32cubeMX软件,选择 ACCESS TO MCU SELECTOR

]RRNN9AM[I812VFAR9O3I1D.png

进入MCU 选择界面选中 STM32H743 然后开始项目

N)(D9K$Z0~BK9_{WE(DIV3E.png

进入STM32cubeMX工程配置界面

5`CISFKIJX}CS45FU9$@%7Q.png

首先切换选项卡到 Project Manager,我们注意到软件标题栏有个 Untitled * ,带星号表示当前进行过的操作未保存,按下ctrl + s 可以保存。我们每次操作完都尽量按下保存,防止cubeMX卡死导致没保存工程。

首先填写项目名称,已经项目保存路径,工具链IDE 我们选择为 MDK-ARM (keil 5)。修改堆区和栈区空间大小为0x2000。因为后面要移植lvgl,默认的堆区大小是不够的,栈区我们也放大一点。

_I6ZNV[V45K]J$GS%%(@WVJ.png

然后给我圈起来的地方打个√,这样配置的外设都会单独生成c和h文件,不会都挤在main.c里面。

6KC$($XCZIBLHFTDV1QS45U.png

然后我们切换到引脚配置界面,按下ctrl+S保存项目,这样标题栏的星号就消失了。



配置SDRAM
     一般的MCU接口屏,比如SPI屏,8080接口屏,IIC接口屏是可以不需要外置显存的。这些屏幕可以通过发送命令当方式告诉屏幕坐标,然后再发送对应的像素值。但是RGB接口屏没命令可以发,一般是告诉LTDC一个内存地址,由LTDC控制器去内存拿像素值不断去扫描刷新屏幕的。所以要用到SDRAM或者SRAM。我们这里用到的是 W9825G6KH 这颗SDRAM,容量32MByte。我们的屏幕是1024 * 600的,颜色格式RGB 565 ,所以需要 1024*600*2 = 1,228,800 字节 = 1200 K字节 内存作为 屏幕显存。

SDRAM原理图

[4278HA73UWE]$(KTEB6U~A.png

首先在最左侧栏目选中FMC,然后选择SDRAM1,配置如下。如果你用的不是上面的原理图,则需要根据具体硬件连接配置。

%PCLG]0J%HQS4[(0C@H$$(3.png

然后是下面部分时序的配置,这个是在 W9825G6KH 数据手册里的。

STF%C}R4V)UI]$RHP{)BJ00.png

GPIO settings 不用管,如果你用的是正点原子H743核心板。直接点右上角生成工程,然后打开就可以了。

TH8RXV}ZELDMGNESZR3AAZK.png

这里我们打开 fmc.c 文件,然后将SDRAM的初始化代码加入到 我圈到的位置。SDRAM芯片内部是有寄存器的,我们要通过fmc接口去发送命令配置这些寄存器然后才可以使用。

E$QG4MSN]~X5_2A)J`6F9YG.png

需要插入在/* USER CODE BEGIN 0 */注释行和 /* USER CODE END 0 */ 之间的代码如下

  1. extern SDRAM_HandleTypeDef hsdram1;

  2. #define SDRAM_MODEREG_BURST_LENGTH_1             ((uint16_t)0x0000)
  3. #define SDRAM_MODEREG_BURST_LENGTH_2             ((uint16_t)0x0001)
  4. #define SDRAM_MODEREG_BURST_LENGTH_4             ((uint16_t)0x0002)
  5. #define SDRAM_MODEREG_BURST_LENGTH_8             ((uint16_t)0x0004)
  6. #define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL      ((uint16_t)0x0000)
  7. #define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED     ((uint16_t)0x0008)
  8. #define SDRAM_MODEREG_CAS_LATENCY_2              ((uint16_t)0x0020)
  9. #define SDRAM_MODEREG_CAS_LATENCY_3              ((uint16_t)0x0030)
  10. #define SDRAM_MODEREG_OPERATING_MODE_STANDARD    ((uint16_t)0x0000)
  11. #define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
  12. #define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE     ((uint16_t)0x0200)

  13. uint8_t SDRAM_Send_Cmd(uint8_t bankx,uint8_t cmd,uint8_t refresh,uint16_t regval)
  14. {
  15.     uint32_t target_bank=0;
  16.     FMC_SDRAM_CommandTypeDef Command;

  17.     if(bankx==0) target_bank=FMC_SDRAM_CMD_TARGET_BANK1;
  18.     else if(bankx==1) target_bank=FMC_SDRAM_CMD_TARGET_BANK2;
  19.     Command.CommandMode=cmd;
  20.     Command.CommandTarget=target_bank;
  21.     Command.AutoRefreshNumber=refresh;
  22.     Command.ModeRegisterDefinition=regval;
  23.     if(HAL_SDRAM_SendCommand(&hsdram1,&Command,0XFFFF)==HAL_OK)
  24.     {
  25.         return 0;
  26.     }
  27.     else return 1;
  28. }

  29. void SDRAM_Initialization_Sequence(void)
  30. {
  31.         uint32_t temp=0;


  32.   SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_CLK_ENABLE,1,0);
  33.   HAL_Delay(1);
  34.         SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_PALL,1,0);
  35.   SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_AUTOREFRESH_MODE,8,0);
  36.         temp=(uint32_t)SDRAM_MODEREG_BURST_LENGTH_1       | \
  37.               SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |        \
  38.               SDRAM_MODEREG_CAS_LATENCY_2           |        \
  39.               SDRAM_MODEREG_OPERATING_MODE_STANDARD |  \
  40.               SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
  41.   SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_LOAD_MODE,1,temp);
  42.         HAL_SDRAM_ProgramRefreshRate(&hsdram1,677);
  43. }
复制代码

并在 MX_FMC_Init 中调用该初始化函数

2GHJ3Q)MY`V@BID@H}5V]FT.png

编译并进入调试模式,我们在 main 中的while(1) 前面加个断点,运行到这里。然后在memory中访问 0XC0000000 地址,如果能看到一堆  FF ,就说明SDRAM 已经初始化成功了。如果是问号? 则说明初始化有问题,这样你就需要重新检查一下了。

66CJ2L%VK(S80G1PR(DBJYH.png

然后我们提升下主频,这样就能更快的访问SDRAM了。只需要更改 1. 处的时钟到480Mhz 然后回车,然后其它三处红圈的频率会自动更改。由于我们配置了 SDRAM的频率是 HCLK /2 ,所以此时SDRAM的运行频率是 120Mhz。W9825G6KH -6 这款芯片最快是到166Mhz,懒得配置了。

0X82X))`12_M)}%LTH[`8`3.png

重新点击右上方生成代码,如果我们没有关闭 MDK工程的话点击 Close就可以了。

QV$~FYYF~WJH81$$W6R26[0.png

切换会Keil 会提示 文件被外部修改,需要重新载入。我们全选 YES就可以了

2XCLE_@C7]]QWJ2PB{DT35K.png

重新下载程序,,然后进入仿真检查,SDRAM是否可以正确访问。此时SDRAM就算配置完毕。

RGB-LTDC配置

D~PT1DX2G$G2X66Z}JKUUGC.png

接下来进入屏幕的配置。打开LTDC 然后选择RGB565模式,下面的配置如下

)N7W(0J$~}YOWWK$@7LR$`G.png

还需要配置层,一般我们用一层就可以了。层的帧缓存起始地址就是我们的SDRAM访问起始地址0XC0000000

@[LPE]]_B0{G16B0$U71SXP.png


接下来要配置GPIO, 这里需要改的引脚比较多。我们按照 LTDC_B  LTDC_G LTDC_R的顺序修改。如果按照RGB的顺序修改你会发现有些引脚原本就被LTDC_B占了,如果你直接改cubeMX的 LTDC会自动关闭,再次打开你之前进行的操作就没了。(很坑)

需要改动的引脚如下

  1. LTDC_B3  --> PG11
  2. LTDC_B4  --> PI4
  3. LTDC_B5  --> PI5
  4. LTDC_B6  --> PI6
  5. LTDC_B7  --> PI7
  6. LTDC_G2  --> PH13
  7. LTDC_G3  --> PH14
  8. LTDC_G4  --> PH15
  9. LTDC_G5  --> PI0
  10. LTDC_G6  --> PI1
  11. LTDC_R3  --> PH9
  12. LTDC_R4  --> PH10
  13. LTDC_R5  --> PH11
  14. LTDC_R6  --> PH12
复制代码

直接搜索引脚,然后选中对应功能就算完事了。

然后把所有引脚的输出速度调到Hign,默认是 Low和very LOW。如果你用的默认引脚配置,那么你的屏幕速度只能到30Mhz,而且还闪烁。这款屏幕是可以到51.2Mhz的。

%H16]_$P`6EJO1[7O14KD}W.png

根据原理图,还有个屏幕背光引脚 PB5,我们设置为推挽输出,默认是高电平就可以了。

PD_Y)VA`_PSW4[~3NZ`07{A.png

再调整下LTDC主频,到51.2Mhz。设置PLL3锁相环的DIVR3 除频器到 /5就可以了。

83`UNG3N9XDL93N9US[B0WV.png

重新生成代码,然后打开KEIL5,编写屏幕测试代码

}$N})DKXYHNS~K4R0Y5CEQ4.png

测试代码

  1. #include <string.h>
  2. static uint16_t LCD_BUFFER[600][1024] __attribute__((at(0XC0000000)));
  3. while(1){
  4.         memset(LCD_BUFFER,0xFF,sizeof(LCD_BUFFER));
  5.         HAL_Delay(1000);
  6.         memset(LCD_BUFFER,0xAA,sizeof(LCD_BUFFER));
  7.         HAL_Delay(1000);
  8.         memset(LCD_BUFFER,0xD0,sizeof(LCD_BUFFER));
  9.         HAL_Delay(1000);
  10.         memset(LCD_BUFFER,0x00,sizeof(LCD_BUFFER));
  11.         HAL_Delay(1000);
  12. }
复制代码

声明一个 静态数组,并且固定到 0XC0000000 地址(SDRAM)。

下载代码并复位开发板应该可以看到屏幕在 白 --> 红 -->紫 -->黑 四种颜色进行切换。

至此屏幕的配置就算完成

LVGL 移植

下载lvgl源码,解压放到我们的项目文件夹中

TFWG{`36E[YDP41~Q45D$(6.png

进入lvgl-master文件夹,删除多余没用的文件,只剩下这些

]6TO45$G0~M_H7$`E(9J)VN.png

修改lv_conf_template.h名称为 lv_conf.h

WUJZIF)[]7QMU6@D`PJM(EL.png

将examples文件夹内的porting文件夹复制到lvgl_cong.h 同级目录



进入porting文件夹修改lv_port_disp_template.h 和对应的c 文件名称

8VM4PORP@0P)H%M@%FQDAOM.png

打开KEIL5 修改添加几个目录 LV_CORE  LV_PORT LV_DEMO,分别存放lvgl源代码,lvgl移植文件,lvgl 演示程序

~XJR2}4@E}LMU)WRWTBHM~M.png

将src 路径下所有c文件添加到LVGL_CORE ,注意是 递归添加(大概几百个文件。。。)

KYXAB~7R]D9ZZMT_IJ)1W.png

port里只添加 disp 的和 lv_conf.h 。这里我只演示移植显示,不移植触控

[Q22I6SP3]KK)2S3905Z5.png

demo我们添加 demo/benchmark 下的文件,如果你想试试其它demo也可以都添加了

`SQX8C25E(I2A3]5]{C@Z1R.png

添加 lv-master 包含目录



在Define里添加个全局宏  LV_CONF_INCLUDE_SIMPLE  前面要有个英文逗号

R1(CL{O%8I~FC5NZ3`2PVZ0.png

打开lv_conf.h lv_port_disp.c  lv_port_disp.h三个文件,开头有个if 0 ,把0 改成1,我画圈的地方要注意。还有lv_port_disp.h 在lv_port_disp.c中的名称

]5PZ}}$K`C]GH4HR}F2JR]S.png

然后编译一遍会有1个错误和五百多个警告。警告不用管,我们解决下这个错误。

就是找不到包含的文件,改成我圈起来的。被注释掉的包含是之前的。

~9~CSD6%7}2$K4%4(ELMGQF.png

还有lv_port_disp.h中的包含也要改

D1N5}JHWF{2Q{B4E1MLE@SS.png

再次编译还有3错误

N0GXFK0NVVKNJPFC96LX]N7.png

打开lv_port_disp.c 注意两个画圈的地方。

]H{S]8W)VH3}1Y_%A`[Z[K6.png

修改这三个画圈的地方

0T~N1`5NM50[EY)J`0PN0BJ.png

找到这个函数,添加这行代码。

L7YD%~TEQK7)`(~LO(%}Y51.png

回到main.c 添加两个头文件的包含

NM`3_X]}1LBO_V_VU`3JZZ1.png

找到滴答定时器的中断入口,添加这两行代码。

@PX1E4)0$]6JV{YY`5WRTWD.png

打开lvgl_conf.h  LV_USE_DEMO_BENCHMARK 设置为1 ,才能用这个demo

UDSC[Z9RA3A~A]OKDF1UQTC.png

再次回到 main 修改如下。其中第一个圈和第二个圈是固定的,以后就不要动了。中间的圈是启动演示程序,该程序会进行一个图形跑分测试。

`06(N`$FYQDN35H$I54J9TF.png

编译然后下载程序,不出意外,会进行一个跑分程序

Z322L~X98PDIVK%YZ2(23DM.png

至此,所有移植就算完毕!!!

当然还可以通过 DMA2D 帮我们搬运像素。这样屏幕刷新会更快。
作者:捉住一只皮皮虾


({X6WU8CN)0M4JG}R]]2LJ5.png
收藏 1 评论0 发布时间:2022-8-27 19:22

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版