如何在资源有限的MCU上进行图形应用设计

控制/MCU

1883人已加入

描述

众所周知,一款优秀的产品,不仅要有很高的性能,很好的稳定性,而且还要具备对用户非常友好和极具吸引力的图形交互界面。

然而,运行一个非常酷炫且极具吸引力的图形用户界面,就要求有一个高主频,高性能,存储资源丰富的MCU作为支撑。 

恩智浦拥有众多高性能,低功耗,大容量存储资源的MCU/MPU, 在这样的MCU/MPU上,流畅地运行图形元素丰富,酷炫且富于吸引力的图形用户界面完全没有压力。

但是,在实际的客户支持过程中,我发现有一些客户基于成本的考虑,会选择主频相对低一些,存储资源相对少一些的MCU。与此同时,他们仍然希望给自己的产品赋予一个精美的图形界面。

真实案例——电动车屏幕

因此,本文通过一个运行在LPC55S06上的,基于GUI Guider和LVGL的图形界面设计项目——电动车(简称EBike)为例,说明如何在资源有限的MCU上进行图形应用设计。

图片与字体的存储

在设计中, 电动车的GUI使用了大小为1.18MB的26个图片和大小为35KB的2种字体,共计约为1.22MB。

但事实上,LPC55S06的片上Flash容量为256KB,其中12KB为系统保留,可以为用户使用的Flash容量只有244KB,不可能将全部图片和字体存放到片上Flash中。

因此,为了能够容纳这些图片和字体,可以考虑外扩Flash。同时,为了兼顾显示性能,可以考虑将图片存放到外部串行Flash中,而将字体存放到片上Flash中。

归纳一下,在资源有限的MCU上进行图形界面开发,首先需要考虑的因素就是如何存储图片和字体。为了提高显示性能,可以把图片和字体尽可能放到片上Flash中存储。但是,随着开发的推进,用户会不断添加非图形界面业务逻辑。这时,如果遇到片上Flash存储空间不够的情况,可以将原本存放到片上Flash中的图片和字体放到外部Flash中,从而节省片上Flash存储空间给非图形界面业务逻辑使用。

存储区域的划分与分配

那么,这里存在一个关键问题,如何为图片和字体分配存储空间呢,依据什么原则呢?换句话说,哪些图片和字体存放到外部Flash,哪些图片和字体存放到片上Flash。

第一点,就是确保片上Flash可以容纳全部用户应用逻辑。

第二点,在满足第一点的情况下,将需要频繁刷新的图片保存到片上Flash。例如,视频所示界面中仪表盘的表针扫过的区域使用的图片,随着表针的转动,这些图片会不断地从外部Flash进行读取并被显示在屏幕上。

常见优化手段

除了将消耗片上Flash资源的大户放到外部Flash上,为了进一步减少用户应用对存储资源的消耗,一些优化手段也是必要的。

常用的优化手段包括如下几点:

将经常需要调用的公共代码段封装成函数 

调整编译优化等级。使用不同的编译优化等级编译生成的可执行文件大小是不同的,如果所选的编译器具有优化代码大小的编译优化选项,则可以通过使用该编译优化选项压缩可执行文件的大小,从而减少对Flash和RAM存储资源的占用。不同IDE中优化代码大小的编译选项如下所示。

电动车

图1 MCUXpresso IDE中的代码大小编译优化选项

电动车

图2 Keil uVision IDE中的代码大小编译优化选项

电动车

图3 IAR Embedded Workbench IDE中的代码大小优化选项

通过LVGL的配置文件lv_conf.h跳过设计中没有使用的模块的编译。例如,在我们的设计中没有用到控件,如SWICH, TABLE, TABVIEW和TILEVIEW, 就可以将相应控件的开关宏定义为0,这样没有使用的控件对应的C文件就不会编译到最终的可执行文件中,从而减少代码的大小。

电动车

图4 裁剪LVGL功能

选择合理的屏幕加载策略

了解LVGL的小伙伴都清楚,GUI上的每一个图形元素,如按钮、图片、标签、表格等,都是作为一个对象存在的,都是需要消耗一定的RAM资源。

如果我们的GUI设计包含多个屏幕,每个屏幕都包含大量的图形元素,如果一次性的创建所有的图形元素,很可能有限的RAM资源不足以容纳这些图形元素。因此,合理的选择屏幕加载策略很有必要。

基于LVGL的GUI开发工具采用不同的屏幕加载策略。目前,屏幕加载策略有两种:

第一种是以LVGL官方推出的SquareLine Studio为代表的静态加载策略,即一次性地把所有屏幕上的图形元素全部创建。这可以从其生成的代码工程看到。

以SquareLine Studio的POS机界面示例为例,其UI初始化函数如下图所示。我们可以看到其5个屏幕一次性创建,那么就意味着这种静态屏幕加载策略消耗更多的RAM资源。

电动车

图5 SquareLine Studio的UI初始化

第二种是以NXP官方推出的GUI Guider为代表的动态加载策略,即只加载在系统启动后显示的屏幕,后面如果需要显示哪一个屏幕再动态加载。

下图所示是GUI Guider的官方示例ScreenTransition。这个示例总共有两个屏幕,即screen1与screen2。函数setup_ui是UI初始化函数。

可以看到,在UI初始化函数setup_ui中只是静态加载了屏幕screen1,没有加载screen2。只有当screen1的Next Screen按钮按下时,在事件回调函数screen_btn1_event_handler中才会调用setup_scr_screen2动态加载screen2。

电动车

图6 ScreenTransition示例的第一个屏幕

电动车

图7 ScreenTransition示例的第二个屏幕

电动车

图8 GUI Guider的UI初始化

电动车

图9 Next Screen按钮的事件回调函数

由此可见,NXP的GUI Guider的动态屏幕加载策略,充分考虑了在资源有限的微控制器上从事GUI开发时,遇到的存储资源利用效率问题。

当然,如果您所选择的MCU或者MPU的存储资源丰富,可以采用第一种策略,那样的话,可以能在一定程度上提高显示性能。

总结

本篇文章以一个GUI示例——电动车为例,重点关注如何在资源有限的微控制器上进行GUI开发,给出了图片和字体的存储策略,以及若干存储资源优化方法。

有关电动车的技术细节,可以参考AN13730: How to Develop LVGL GUI Demo on Memory-constrained MCU with GUI Guider.

编辑:黄飞

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分