记录学习STM32H743在CubeIDE下运行LVGL过程中遇到的各种坑

本文作者分享了在STM32H743上使用正点原子阿波罗H743开发板移植LVGL8.4过程中遇到的挑战,如MPU设置、SDRAM配置、CubeIDE与Keil的区别、DMA2D时钟问题以及头文件路径问题等,并提供了相应的解决方案。
摘要由CSDN通过智能技术生成

本人手中的是正点原子阿波罗H743+4.3寸RGB屏,最近开始学习点亮屏幕并尝试移植LVGL8.4。学习过程中遇到了好多坑,而且基本很难搜到对应的解答,好在碰巧解决了几个问题,记录一下备忘,也希望对其他新手有帮助。

1.本人直接是从CubeIDE开始学起没有用Keil,刚开始新建项目时会弹出一个窗口,建议开启MPU。我也不懂是啥意思,就选同意了,这个无意中的选择让我后面花了大量的时间去排错。

因为点亮屏幕最重要的一步是设置SDRAM,就是因为MPU这个默认的“ALL ACCESS NOT PERMITTED” 选项,导致我无论如何无法访问到SDRAM,同时屏幕一直花屏。而恰好点亮屏幕需要设置包括FMC、LTDC在内的很多参数,我也吃不准问题出在哪里,于是我对着正点原子的代码以及上网搜了好多帖子,各种调整参数,弄了好几天还是无法运行。几乎就要放弃的时候瞎点进了MPU,试着关掉了MPU Region,结果代码正常运行了。。。

另外,CubeIDE和Keil不同,无法通过at指定图像缓存地址,需要用到section关键字。这个问题也花了一些时间,不过还是搜到了解决方法。下面的参数设置对于H743来说是能正常运行的,记录一下。

  hsdram1.Instance = FMC_SDRAM_DEVICE;
  /* hsdram1.Init */
  hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
  hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
  hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
  hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
  hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
  hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
  hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
  hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
  hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
  hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
  /* SdramTiming */
  SdramTiming.LoadToActiveDelay = 2;
  SdramTiming.ExitSelfRefreshDelay = 9;
  SdramTiming.SelfRefreshTime = 6;
  SdramTiming.RowCycleDelay = 8;
  SdramTiming.WriteRecoveryTime = 4;
  SdramTiming.RPDelay = 2;
  SdramTiming.RCDDelay = 2;
//发送SDRAM初始化序列
void SDRAM_Init(void){
	uint32_t temp=0;
    //SDRAM控制器初始化完成以后还需要按照如下顺序初始化SDRAM
    SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_CLK_ENABLE,1,0); //时钟配置使能
    HAL_Delay(1);                                  //至少延时200us
    SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_PALL,1,0);       //对所有存储区预充电
    SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_AUTOREFRESH_MODE,8,0);//设置自刷新次数
    //配置模式寄存器,SDRAM的bit0~bit2为指定突发访问的长度,
	//bit3为指定突发访问的类型,bit4~bit6为CAS值,bit7和bit8为运行模式
	//bit9为指定的写突发模式,bit10和bit11位保留位
	temp=(uint32_t)SDRAM_MODEREG_BURST_LENGTH_1     |	//设置突发长度:1(可以是1/2/4/8)
              SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |	//设置突发类型:连续(可以是连续/交错)
              SDRAM_MODEREG_CAS_LATENCY_2           |	//设置CAS值:3(可以是2/3)
              SDRAM_MODEREG_OPERATING_MODE_STANDARD |   //设置操作模式:0,标准模式
              SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;     //设置突发写模式:1,单点访问
    SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_LOAD_MODE,1,temp);   //设置SDRAM的模式寄存器

    //刷新频率计数器(以SDCLK频率计数),计算方法:
	//COUNT=SDRAM刷新周期/行数-20=SDRAM刷新周期(us)*SDCLK频率(Mhz)/行数
    //我们使用的SDRAM刷新周期为64ms,SDCLK=240/2=120Mhz,行数为8192(2^13).
	//所以,COUNT=64*1000*120/8192-20=918
	HAL_SDRAM_ProgramRefreshRate(&hsdram1,918);

}
/* 这个不行*/
//u16 ltdc_lcd_framebuf[1280][800] __attribute__((at(LCD_FRAME_BUF_ADDR)));

uint16_t framebuf[1280][800] __attribute__((section (".sdram_data")));

/* STM32H743IITX_FLASH.ld 文件添加代码*/

MEMORY
{
  FLASH (rx)     : ORIGIN = 0x08000000, LENGTH = 2048K
  DTCMRAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 128K
  RAM_D1 (xrw)   : ORIGIN = 0x24000000, LENGTH = 512K
  RAM_D2 (xrw)   : ORIGIN = 0x30000000, LENGTH = 288K
  RAM_D3 (xrw)   : ORIGIN = 0x38000000, LENGTH = 64K
  ITCMRAM (xrw)  : ORIGIN = 0x00000000, LENGTH = 64K
  
  SDRAM (xrw)    : ORIGIN = 0xc0000000, LENGTH = 4M //添加此行
}

/* 末尾添加该代码 */
  .sdram_data (NOLOAD) :
  {
    . = ALIGN(4);
    _sdram_data_begin = .;
    *(.sdram_data)
    *(.sdram_data*)
    
    . = ALIGN(4);
    _sdram_data_end = .;
  } >SDRAM 

2. 跟着正点原子视频一步步移植LVGL,最开始是要建立目录,我照猫画虎在CubeIDE工程根目录下新建了Middlewares/LVGL/GUI/lvgl,然后放入LVGL相关文件并开始改代码,做到最后要添加定时器了,跑到ioc文件设置好并点击更新代码后,整个Middlewares目录及之下的文件居然全部删除了,之前算是白忙活了。。。后来查帖子才知道Middlewares应该是CubeIDE在添加好Freertos这样的中间件后会自动生成的目录,如果是自己新建的同名目录,在刷新代码后CubeIDE因为会发现其中没有中间件而自动删除。

3. 在全部移植好后,运行demo发现一直花屏。又是各种查帖子各种尝试调整(期间以为是LVGL8.4这个版本有问题,其实不是),发现在打点这一步如果不用正点原子代码中的LCD_Color_Fill函数,而是直接用lvgl模板中的for循环打点方法是没问题的。而LCD_Color_Fill最主要是用了DMA2D。于是一行一行地研究这个函数,最后发现了一个坑,代码中使能DMA2D时钟的是:RCC->AHB1ENR|=1<<23;

虽然这是正点原子H743教程的代码,但其实这句并不适用H743,看了STM32官方手册发现其实应该是:RCC->AHB3ENR|=1<<4;才对

DMA2D时钟没有正常开启当然会花屏。。。

不过即使调好了,发现还是会小花(如下图)。然后又是各种查原因,怎么也查不到。最后又瞎点到了MPU这个菜单,试着关掉了自己之前手欠开启的CPU I-Cache和D-Cache之后总算正常了。后来专门仔细看了正点原子关于MPU的讲解:

在使能 D Cache 之后, SRAM 里面的数据有可能会被缓存在 Cache 里面,此时如果有 DMA 之类的外设访问这个 SRAM 里面的数据,就有可能和 Cache 里面数据不同步, 导致数据出错,为了防止这种问题,保证数据的一致性,我们设置了 D Cache 的强制透写功能 (Write Through),这样 CPU 每次操作 Cache 里面的数据,同时也会更新到 SRAM 里面,保证D Cache 和 SRAM 里面数据一致。

我在添加了D-Cache强制透写语句SCB->CACR |= 1<<2;后发现仍然会有少量花屏现象,所以干脆直接关掉,然后就正常了。

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
     if(disp_flush_enabled) {
         /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
/*虽然官方注释是most simple but also the slowest,但确实好用*/
         int32_t x;
         int32_t y;
         for(y = area->y1; y <= area->y2; y++) {
             for(x = area->x1; x <= area->x2; x++) {
                 /*Put a pixel to the display. For example:*/
                 /*put_px(x, y, *color_p)*/
            	 LCD_DrawPoint(x, y, color_p->full);
                 color_p++;
             }
         }
     }

    //LCD_Color_Fill(area->x1,area->y1,area->x2,area->y2,(uint16_t *)color_p);

    /*IMPORTANT!!!
     *Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}

4. 除了以上问题,还有比较头疼的是头文件路径问题。我的工程目录结构如下,在项目头文件属性里设置好了各个文件夹的路径。最后在main文件里引用头文件的时候其他目录下的头文件都能直接引用,唯独TOUCH目录下的文件死活引用不了,必须设置绝对路径才行。到现在还没有找到原因,还请大神们指教(另外不知道TOUCH文件夹上的这个小扳手是啥意思)。

跟着正点原子的视频学习STM32有一阵子了,虽然其间碰到了各种莫名其妙抓狂的问题,但是也有不少收获。学习总归是伴随着痛苦的,尤其是编程,怪不得说程序猿头发少。幸好自己只是业余爱好,不靠这个吃饭,但也希望能继续坚持下去吧~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值