(2D图形处理的技术其实早在红白机时代就成熟了,6502能做到的事情,Cortex-M自然也不在话下)
【说在前面的话】
在往期的文章《什么是嵌入式系统(下)——沉淀模型》我们曾提到过:
现在的计算机技术差不多领先嵌入式技术大约20年,现在嵌入式系统无论在资源上、理论上还是方法论上,都与上世纪80年代的计算机前沿技术相当。 GorgonMeducer 傻孩子,公众号:裸机思维什么是嵌入式(下)—— “重力”和“沉淀”
这意味着,作为2021年的今天,本世纪初应用在个人电脑上的一些技术也可能会被逐步引入到深度嵌入式系统上(Deep Embedded System)——这类系统的典型也就是大家所熟知的单片机或者说Cortex-M处理器。
这不,刚到四月份Arm就悄悄的、以试探性的态度在Github上发布了一个专门针对“全体” Cortex-M处理器的2D图形加速库——Arm-2D(地址如下):
https://github.com/ARM-software/EndpointAI/tree/master/Kernels/Research/Arm-2D
根据Github仓库中README的描述,我们可以简单的把这个2D图形加速库理解为是一个专门针对Cortex-M处理器的“显卡驱动”标准。虽然这里的“显卡驱动”只是一个夸张的说法——似乎没有哪个Cortex-M处理器“配得上”所谓的显卡,但其实也并没有差多远——因为根据最新的趋势,随着单片机资源的逐步丰富(较高级的工艺节点正在逐步降价),处理器不仅跑得越来越快、存储器越来越大,而且大量的厂商已经或者正在考虑给Cortex-M处理器配备专属的2D图形加速引擎——在这一方面,ST和NXP走的最靠前——相信Chrome-Art(又叫DMA2D)大家早已耳熟能详。实际上,一些芯片公司正在考虑给下一代Cortex-M处理器配备真正的2D-GPU。在这一背景下,也许是为了避开“愚人节项目”的嫌疑,Arm-2D的上线有意避开了4月1号——这传达了一个来自行业的清晰信号:兄弟们,这不是演习,一个属于Cortex-M专2D图形加速的时代到来了。
【Cortex-M的显卡驱动意义何在?】
Arm是行业内 “老” 生态玩家了——几乎所有的行为都会从生态的角度加以考量——所以要想搞清楚为啥Arm在此时为“Cortex-M”定制显卡驱动,就必须要搞清楚整个深度嵌入式生态究竟发生了什么。要想做到这一点,不妨设想一下:
你是一个芯片公司的产品经理:
你是一个GUI软件提供商:
总结来说:
突然有一天,累的吭哧吭哧的两方突然觉得哪里不对劲,然后都默默的把头转向了Arm——这个生态系统中一直号称中立的第三方……
于是Arm在大家灼热的目光下弱弱的在Github上扔了一个叫Arm-2D的显卡驱动标准,提出了这样一个议案:
“要不……我提供一个API抽象层?”
“什么什么?” 裸机用户惊呼:“不是B2B之间的事情么?咋突然有我们的福利了?”
先卖个关子,文章后面再讲。
【面向深度嵌入式的2D处理跑分】
虽然并没建立第三方2D跑分的意愿,Arm-2D为了展示不同处理器(及不同硬件加速器)在典型GUI负载下的2D处理能力,本着“实在找不到只能硬着头皮自己上”的态度,提供了一个参考的2D性能跑分——官方的名称是:实现30FPS所需的最小处理器频率:Minimal Frequency Required for 30FPS(MHz)。
其实际原理是这样的:
值得说明的是:
如果你真的在意在某种LCD连接方式下系统的实际FPS是多少,只要额外测量“刷新显存”所消耗的时间(比如毫秒),然后追加到渲染一帧所需的毫秒数上即可。比如,在上面GIF所示的效果图中,LCD Latency(也就是“刷新显存”所需时间)为43ms,而平均渲染一帧所需的时间是 4ms(229FPS),综合下来实际一帧的所消耗的时间是 43+4 = 47ms(为了简单,直接按照50ms计算),此时,我们可以认为最终帧率大约为 20FPS(1/50ms)。
上面这张表格,列举了大家常用的几类Cortex-M处理器在纯粹依靠“处理其本身”而不借助“专门2D图形加速器”的情况下,以320*240(RGB565)分辨率为目标,达到30帧每秒刷新率所需的最小频率,比如:
拥有双核Cortex-M0+跑133MHz的树莓派Pico狂喜
更直观的,这里是官方提供的2D性能的倍率比较(以Cortex-M4的性能为基准)。Cortex-M55 Helium居然是Cortex-M4性能的近乎6倍、Cortex-M0的10倍!——如果说Arm-2D是显卡驱动的话,那么Cortex-M55 Helium就是一款自带“集成显卡”的Cortex-M处理器了。
最后,值得说明的是:Arm-2D在Git仓库中提供了这一跑分的MDK工程——位于“examples/alpha_blending” 路径下。如果你对手边硬件的2D处理性能非常好奇,则只需要提供以下接口,就可以试它一试:
https://github.com/ARM-software/EndpointAI/blob/master/Kernels/Research/Arm-2D/examples/alpha_blending/display_adapter/display_adapter.c
其函数原型为:
/**
\fn int32_t GLCD_DrawBitmap (uint32_t x, uint32_t y, uint32_t width, uint32_t height, const uint8_t *bitmap)
\brief Draw bitmap (bitmap from BMP file without header)
\param[in] x Start x position in pixels (0 = left corner)
\param[in] y Start y position in pixels (0 = upper corner)
\param[in] width Bitmap width in pixels
\param[in] height Bitmap height in pixels
\param[in] bitmap Bitmap data
\returns
- \b 0: function succeeded
- \b -1: function failed
*/
int32_t GLCD_DrawBitmap (uint32_t x, uint32_t y, uint32_t width, uint32_t height, const uint8_t *bitmap);
#define GLCD_WIDTH 320 /* Screen Width (in pixels) */
#define GLCD_HEIGHT 240 /* Screen Height (in pixels) */
最后,需要注意,你手边硬件的跑分结果不一定与官方数据相吻合,因为它们取决于对应平台RAM和Flash的速度、有没有cache之类等环境要素——官方给出的数据是在“SRAM单周期访问”、“程序在RAM中执行”这样较为理想的状况下获得的。
实际上,例子工程已经提供了对好几个硬件平台的支持,比如Arm官方的MPS2平台(https://developer.arm.com/tools-and-software/development-boards/fpga-prototyping-boards/mps2):
MPS3平台(https://developer.arm.com/tools-and-software/development-boards/fpga-prototyping-boards/mps3):
——当然这样的神仙板子一般“寻常百姓”家估计是不会有的。如果你是正版MDK,其实可以直接使用FastModel这样的模拟器来尝鲜(注意:模拟器的跑分是完全不可信的)。
再或者,如果你幸运的拥有官方工程中所支持的STM32F746G-Discovery开发板(搞GUI评估的,谁手里没有一块?)就可以直接编译和下载了。
【面向普通用户的福利是啥】
对使用RTOS和裸机的普通用户来说,可能你的硬件平台是如下的情况:
其实,这样的芯片资源太普遍了——随手拿个Cortex-M0/M3就差不多了。考虑到作为面子工程的LCD屏幕其实也并不太贵——如果能用彩屏实现类似智能手机界面(没有动画)来提升逼格,那产品的竞争力肯定是“岗岗”的。
问题来了,4K~32K SRAM的实在太小了,就算目标屏幕是常见的 320*240 (RGB565)SPI/8080 接口屏,那么一个完整的屏幕缓冲区也要消耗掉 320*240*sizeof(uint16_t)= 150KB 的RAM——完全开销不起。
一般来说,此时我们面前有两个选择:
什么?你的应用和FLASH开销不起LVGL或者TouchGFX这样的GUI协议栈?
什么?你买不到STM32芯片?
啥?你用的是国产Cortex-M处理器……
啥,你用的是裸机?而且觉得界面本来就很简单,不想用GUI……
嗯……好吧……
你用Arm-2D吧。因为,它为“无法使用正规GUI协议栈”的用户提供了傻瓜式的PFB支持,且具有以下特性:
比如,下面这个动态进度条效果,其实只刷新了改变的部分,从而在很低的LCD带宽下实现了很高的帧率(>30FPS):
参考信息:
上述效果的硬件环境:
Program Size: Code=117236 RO-data=2904 RW-data=108 ZI-data=2516
其中包含:
1KByte 栈,
512Byte 堆,
FPB (160*1*sizeof(uint16_t))=320Byte
工程整体消耗RAM:2624Byte
是不是惊呆了?
例子工程在 “main-arm-2d-more-example” 分支下的example目录中可以找到。
【Arm-2D库怎么用呢?】
Arm-2D库的使用不仅简单直接,官方在document目录下也提供了必要的文档,例如Introduction.md提供了技术综述,How_to_use_tile_operations.md 提供了基本API的详细使用说明,how_to_deploy_the_arm_2d_library.md提供了手把手的移植教程等等。虽然这些文档是英文写的,不过不要紧,因为:
我会在近期以周更的形式,具体一个案例一个案例的为您介绍这些API的使用——力求做到以极小的资源消耗在裸机下实现酷炫的界面效果。例如,下面这个动态进度条的效果,其代码算上类型定义也总共不超过100行。