随着越来越多用户选择i.MX RT系列芯片制作产品,产品的需求以及芯片的用法也越来越多。本文将介绍在i.MX RT平台中,如何创建LVGL项目并将其运行在内部SRAM而非SDRAM上。本文档包含4个部分:通过GUI Guider生成LVGL工程;LVGL工程的FlexRAM内存配置;修改工程配置使得程序运行;使用局部缓冲区节省SRAM空间。本文档以IAR项目为例。
用GUI Guider生成VGL工程
GUI Guider是恩智浦推出的一款图形用户界面开发工具,在往期的加油站文章中,也有关于它的介绍,在此就不多做描述。读者可以参考相关的文档资料进行了解学习。GUI GUIDER
1.创建LVGL工程
打开GUI Guider v1.9.1 GA,创建两个GUI Guider项目:一个LVGL v9项目,使用基于MIMXRT1170-EVKB和Rasberry Pi LCD显示屏的数字仪表盘模板。一个LVGL v8项目,使用基于MIMXRT1050-EVKB和RK043FN66HS LCD显示屏的数字仪表盘模板。以下是LVGL版本选择的屏幕截图。

2.根据你的设备修改工程配置
对于第一个RT1170-EVKB项目,无需修改GUI Guider中的配置。对于RT1050-EVKB项目,需要使用片内SRAM来保存帧缓冲区。在GUI Guider工具中,点击菜单上的“Project”按钮打开设置页面。窗口中可以看到一些项目设置。将“Frame Buffer Location”修改为SRAM,即可将缓冲区保存到内部RAM中。

FlexRAM配置
FlexRAM是一种高度可配置且灵活的RAM存储器阵列。该存储器阵列包含多个存储器组,每个存储器组可独立配置,以便由不同类型的接口访问,例如I-TCM(指令紧密耦合存储器)、D-TCM(数据紧密耦合存储器)或AX(系统)。存储器组可以用作ITCM、DTCM或OCRAM存储器。本文档将简要介绍RT1170和RT10XX系列的FlexRAM静态配置以及运行时配置。更改IOMUX_GPR_GPR17(在RT1170上,也包括IOMUX_GPR_GPR18)寄存器中定义的FLEXRAM_BANK_CFG字段的值。在设置IOMUX_GPR_GPR17/18的值之前,需要将IOMUXC_GPR_GPR16寄存器的FLEXRAM_BANK_CFG_SEL值设置为1,以启用FlexRAM配置。设置FLEXRAM_BANK_CFG值来配置RAM类型:
•00:RAM组n未使用
•01:RAM组n为OCRAM
•10:RAM组n为DTCM
•11:RAM组n为ITCM
1.i.MX RT芯片FlexRAM配置
不同的i.MX RT芯片具有不同的内存容量,因此每个芯片可配置的FlexRAM大小也不同。下表列出了不同i.MX RT芯片的FlexRAM信息。

对于i.MX RT1170,系统内存映射如下所示。i.MX RT1170 SRAM的默认配置如下表所示:

| ITCM | DTCM | OCRAM |
| 256KB | 256KB | 1.5MB |
2.FlexRAM静态配置
芯片通过POR上电后,i.MX RT会从eFuse中检查FlexRAM组的值,以确定FlexRAM的分配。
OCRAM的最小配置为64KB。这是因为ROM代码的执行至少需要64 KB的RAM。OCRAM的最小配置要求可能因设备而异。
本文档不使用静态配置方法,因此这里不再详细介绍静态配置。
3.FlexRAM动态配置
FlexRAM也可以通过在运行时更改IOMUXC_GPR寄存器的值来配置。首先,将IOMUXC_GPR_GPR16寄存器中定义的FLEXRAM_BANK_CFG_SEL位置1。然后,可以通过IOMUXC_GPR_GPR17(在RT1170上,还有IOMUXC_GPR_GPR18)寄存器中FLEXRAM_BANK_CFG的值来配置FlexRAM的大小。运行时配置比静态配置有两个优势:在静态配置中,eFUse只能烧写一次,而FlexRAM配置无法多次调整;eFuse中只有4/6位配置位,不会穷尽所有FlexRAM Bank组合。
3.1确定FlexRAM的分配
首先,通过IOMUXC_GPR17(以及RT1170中的IOMUXC_GPR18)寄存器的FLEXRAM_BANK_CFG位,可以自由指定每个Bank的最终形态(ITCM/DTCM/OCRAM)。以下是FLEXRAM_BANK_CFG(i.MX RT1170芯片)的说明。
FlexRAM bank configuration GPR17 of RT1170

FlexRAM bank configuration GPR18 of RT1170

3.2使能动态配置
分配好FlexRAM Bank后,将IOMUXC_GPR16寄存器中的FLEXRAM_BANK_CFG_SET设置为1,FLEXRAM_BANK_CFG指定的配置就会立即生效。
FlexRAM bank configuration GPR16 of RT1170

在片内RAM中运行LVGL工程
现在基于MIMXRT1170-EVKB创建了LVGL工程(2个全尺寸帧缓冲区),并介绍了配置FlexRAM的方法,下面是使项目在内部RAM而非外部SDRAM上运行的步骤。
1.在startup文件中配置FlexRAM
本工程中,所有内部RAM均配置为OCRAM,D-TCM和 I-TCM的大小均设置为0。此存储设置仅用于演示如何将所有程序都放入内部RAM,速度可能并非最快。打开“startup_MIMXRT1176_cm7.s”,并在“SystemInit”之前添加配置代码。参见以下代码:
Reset_Handler CPSID I ;Maskinterrupts LDR R0, =0xE000ED08 LDR R1, =__vector_table STR R1, [R0] LDR R2, [R1] MSR MSP,R2 /*FlexRam Configuration*///OCRAM = 512KB, DTCM = 0KB ,ITCM = 0KB, ldr R0,=0x400E4040//gpr16 Enable FLEXRAM_BANK_CFG ldr R1,=0x0000AA07 str R1,[R0] ldr R0,=0x400E4044//gpr17 0:15 ldr R1,=0x00005555 str R1,[R0] ldr R0,=0x400E4048//gpr18 0:15 ldr R1,=0x00005555 str R1,[R0] LDR R0, =SystemInit BLX R0 CPSIE I ;Unmaskinterrupts LDR R0, =__iar_program_start BX R0
现在OCRAM大小设置为2MB。保存更改,FlexRAM配置将在项目运行时生效。
2.修改链接文件
GUI Guider生成的基于i.MX RT芯片的LVGL工程默认存储在Nor Flash和SDRAM中。在工程选项中打开Linker File,删除其他data region,只保留1个data region。将整个OCRAM设置为data region。只保留data region配置,删除其他配置。参见以下代码:
/* define symbol m_interrupts_ram_start = 0x20200000; define symbol m_interrupts_ram_end = 0x20200000 + __ram_vector_table_offset__; define symbol m_data_start = m_interrupts_ram_start + __ram_vector_table_size__; define symbol m_data_end = 0x203FFFFF; */ definesymbolm_data_start =0x20240000; definesymbolm_data_end =0x203EFFFF; definesymbolm_ncache_start =0x203F0000; definesymbolm_ncache_end =0x203FFFFF; … define exportedsymbol__VECTOR_TABLE = m_interrupts_start; //define exported symbol __VECTOR_RAM = isdefinedsymbol(__ram_vector_table__) ? m_interrupts_ram_start : m_interrupts_start; define exportedsymbol__VECTOR_RAM = m_interrupts_start; define exportedsymbol__RAM_VECTOR_TABLE_SIZE =0x0; define memory memwithsize = 4G; define region TEXT_region =mem:[fromm_interrupts_start to m_interrupts_end] |mem:[fromm_text_start to m_text_end]; define region DATA_region =mem:[fromm_data_start to m_data_end-__size_cstack__]; define region CSTACK_region =mem:[fromm_data_end-__size_cstack__+1to m_data_end]; define region NCACHE_region =mem:[fromm_ncache_start to m_ncache_end]; …3. 减小代码尺寸
在GUI Guider生成的项目中,LVGL内存大小默认设置为2MB。通常项目不需要这么大的内存。因此,此处将LV_MEM_SIZE改为80kB,以节省SRAM。
/*Size of the memory available for `lv_malloc()` in bytes (>= 2kB)*/
#defineLV_MEM_SIZE (80U * 1024U)
4.编译运行工程
保存更改并构建项目,查看“lvgl_guider_cm7.map”文件。内存占用大小显示在底部。
203'063 bytes of readonlycode memory
7'351'345 bytes of readonlydata memory
1'753'889 bytes of readwrite data memory
将其下载到开发板,工程将成功运行。
局部缓冲区刷新
另一个基于MIMXRT1050-EVKB的LVGL v8项目使用局部缓冲区刷新来节省SRAM空间。将缓冲区位置配置到SRAM中,生成的项目将在内部SRAM而非外部SDRAM上运行。
在“lvgl_support.c”文件中,如果启用宏“FB_USE_SRAM”,则会创建两个不同大小的帧缓冲区:一个全尺寸缓冲区和一个部分尺寸缓冲区。
#ifFB_USE_SRAM
#defineDRAW_BUF_HEIGHT (LCD_HEIGHT / 5)
#defineDEMO_DB_SIZE LCD_WIDTH * DRAW_BUF_HEIGHT * LCD_FB_BYTE_PER_PIXEL
SDK_ALIGN(__attribute__((section("FrameBuffer")))staticuint8_ts_frameBuffer[1][DEMO_FB_SIZE], DEMO_FB_ALIGN);
SDK_ALIGN(__attribute__((section("DrawBuffer")))staticuint8_ts_lvglBuffer[DEMO_DB_SIZE], DEMO_FB_ALIGN);
#else
SDK_ALIGN(staticuint8_ts_frameBuffer[2][DEMO_FB_SIZE], DEMO_FB_ALIGN);
#endif
缓冲区初始化也不一样。
#ifFB_USE_SRAM lv_disp_draw_buf_init(&disp_buf, s_lvglBuffer,NULL, LCD_WIDTH * DRAW_BUF_HEIGHT); #else lv_disp_draw_buf_init(&disp_buf, s_frameBuffer[0], s_frameBuffer[1], LCD_WIDTH * LCD_HEIGHT); #endif … /* Partial refresh */ #ifFB_USE_SRAM disp_drv.full_refresh =0; #else disp_drv.full_refresh =1; #endif
Flush方式是更新改变的区域。
#ifFB_USE_SRAM staticvoidDEMO_WaitVsync(lv_disp_drv_t*disp_drv) { s_framePending =true; #ifdefined(SDK_OS_FREE_RTOS) if(xSemaphoreTake(s_frameSema, portMAX_DELAY) != pdTRUE) { PRINTF("Display flush failed "); assert(0); } #else while(s_framePending) { } #endif } staticvoidcopy_area(constlv_area_t*area,lv_color_t*color_p,uint8_t*fb,uint32_tfbStrideBytes) { uint32_ty; uint32_tareaWidth =lv_area_get_width(area); fb += (area->y1 * fbStrideBytes + area->x1 *sizeof(lv_color_t)); for(y = area->y1; y <= area->y2; y++) { lv_memcpy(fb, color_p, areaWidth *sizeof(lv_color_t)); fb += fbStrideBytes; color_p += areaWidth; } } staticvoidDEMO_FlushDisplay(lv_disp_drv_t*disp_drv,constlv_area_t*area,lv_color_t*color_p) { /* Wait VSYNC for each small update. */ DEMO_WaitVsync(disp_drv); /* Copy data from draw buffer to frame buffer. */ copy_area(area, color_p, (uint8_t*) s_frameBuffer, LCD_WIDTH * LCD_FB_BYTE_PER_PIXEL); SCB_CleanInvalidateDCache(); lv_disp_flush_ready(disp_drv); } #else staticvoidDEMO_FlushDisplay(lv_disp_drv_t*disp_drv,constlv_area_t*area,lv_color_t*color_p) { DCACHE_CleanInvalidateByRange((uint32_t)color_p, DEMO_FB_SIZE); ELCDIF_SetNextBufferAddr(LCDIF, (uint32_t)color_p); s_framePending =true; #ifdefined(SDK_OS_FREE_RTOS) if(xSemaphoreTake(s_frameSema, portMAX_DELAY) == pdTRUE) { /* IMPORTANT!!! * Inform the graphics library that you are ready with the flushing*/ lv_disp_flush_ready(disp_drv); } else { PRINTF("Display flush failed "); assert(0); } #else while(s_framePending) { } /* IMPORTANT!!! * Inform the graphics library that you are ready with the flushing*/ lv_disp_flush_ready(disp_drv); #endif } #endif
通过修改链接器文件,我们可以将“DrawBuffer”和“FrameBuffer”放入SRAM中,这些缓冲区的大小将远小于两个全尺寸缓冲区。因此,LVGL项目可以在内部RAM上运行。
小结
本文介绍了如何使基于i.MX RT芯片的LVGL工程在内部RAM上运行而不是外部SDRAM。一种方法是使用FlexRAM扩展OCRAM的大小,以便获得连续的RAM来存储缓冲区。另一种方法是使用部分缓冲区而不是全尺寸缓冲区,这样可以节省SRAM。
-
芯片
+关注
关注
462文章
53559浏览量
459315 -
SDRAM
+关注
关注
7文章
449浏览量
57293 -
恩智浦
+关注
关注
14文章
6052浏览量
135028 -
sram
+关注
关注
6文章
809浏览量
117229 -
LVGL
+关注
关注
2文章
116浏览量
4282
原文标题:在i.MX RT片内RAM中运行LVGL工程
文章出处:【微信号:NXP_SMART_HARDWARE,微信公众号:恩智浦MCU加油站】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
恩智浦i.MX RTxxx系列MCU的特性
i.MX RT1050平台的相关资料推荐
恩智浦最新的应用处理器 i.MX 95采用专有NPU IP进行片上AI加速
恩智浦i.MX RT1170开创GHz MCU时代
恩智浦i.MX RT1170在将该系列带上了更高的层面
恩智浦推出核跨界MCU的第二款产品i.MX RT1160
痞子衡嵌入式:恩智浦i.MX RTxxx系列MCU特性那些事(1)- 概览
i.MX RT开发笔记-08 | i.MX RT1062嵌套中断向量控制器NVIC(按键中断检测)

基于恩智浦i.MX RT芯片内部RAM运行LVGL工程
评论