专栏首页裸机思维为什么说Arm-2D是小资源单片机的GUI人权卡!

为什么说Arm-2D是小资源单片机的GUI人权卡!

【Arm-2D究竟算什么?屁股决定脑袋】


自从Arm低调发布Arm-2D以来,小范围内引起了一些讨论,诸如:

"Arm-2D是要抢GUI的饭碗么?"

“Arm-2D为什么带了一些GUI的功能?”

“Arm-2D也是for循环里套像素处理,也没什么黑科技啊!”

“Arm-2D究竟是什么?有没有搞头”

……

之类直指要害的质疑涌现出来。其实,这里的核心问题可以被拆解为如下的逻辑:

  • Arm-2D要服务的目标客户是谁?
  • 这个目标客户的痛点是什么?
  • Arm-2D为目标痛点究竟有没有提供切实的帮助?

实际上,不光很多明眼人看得出来,Arm-2D自己也在仓库的README里写的明明白白:

"Arm-2D focuses on accelerating the low-level 2D image processing... will not compete with the GUI service providers in the Arm ecosystem. In fact, because Arm has proposed a unified set of low-level acceleration APIs, a full ecological level of cooperation can be quickly established between chip manufacturers that provide hardware accelerators and software providers that provide GUI services. Everyone can concentrate on their own works: For example, chip manufacturers can ensure that they receive a wide range of software support by adding drivers for their dedicated 2D accelerators following the Arm-2D standard, and GUI providers only need to build their GUI stack upon Arm-2D APIs; hence a wide range of device support is ensured."

翻译过来:

"Arm-2D致力于在底层加速2D图像处理...不会与Arm生态系统中的GUI服务提供商竞争。实际上,由于Arm提出了一套统一的底层加速API,因此可以在“提供硬件加速器的芯片制造商”与“提供GUI服务的软件提供商”之间快速建立完整的生态级合作——每个人都可以专注于自己的工作:例如,芯片制造商可以通过提供遵循Arm-2D标准的专用2D加速器驱动程序来确保获得广泛的GUI软件支持;而GUI提供商仅需要在 Arm-2D API基础上构建GUI就可以确保获得广泛的芯片支持。"

根据前面的拆解,显然Arm-2D要服务的目标客户包含了半导体厂商和GUI的软件服务提供商,而痛点可以简单的表述为:

  • 芯片厂商和GUI服务提供商很多;
  • 它们彼此都想获得对方的支持;
  • 这是一个多对多的合作问题;
  • 如何将原本点对点的合作方式变成点对面的合作方式,或者说有没有什么一劳永逸的方法,一下节省所有人的时间——就是Arm-2D所要解决的问题。

作为应对,Arm提供的方案就是一个“公共”的API集合——如果大家都按照这一集合来开发就自然而然地实现了一个全生态级别的合作。常言道:“如人饮水冷暖自知”——Arm-2D的想法虽然好,但实际市场接受度如何,还要看这些“受益者”自己怎么觉得了

那么,作为“吃瓜群众的我们”是不是可以进一步理解为:Arm-2D服务的是芯片厂商和GUI服务提供商,而且Arm-2D提供的便利对普通的GUI用户来说是不可见的。

既然如此:Arm-2D“关我屁事”?散了散了。

然而,事实并非如此。

【普通开发者也是目标客户】


如果草率的判断 Arm-2D 只是嵌入式版本的 Direct2D,而与普通开发者无关那就大错特错了。由于嵌入式系统不同于类似PC机这样的通用计算机系统——需要在满足应用需求的情况下尽可能地进行裁剪(不了解这一逻辑的小伙伴可以阅读文章《什么是嵌入式系统(上)—— “为用而专”》),因此长期存在一批需要在“蚊子腿上刮肉”、“螺蛳壳里做道场”的贫下中农——这些开发者受到成本的压迫,不的不在资源极端受限的环境下进行开发:

一块32~64K Flash4~32K SRAMCortex-M0/M3/M4单片机就是面朝黄土背朝天的码农们每天996所要耕耘的土地。

另一方面,由于习惯了智能手机所建立的“事实上的图形交互标准”,很多嵌入式产品也试图模仿这样一套图形交互机制来凸显自身的“智能”“高端”——毕竟“看起来”、“用起来”都像手机一样,就显得“高端大气上档次”了嘛。

通过观察市场,容易注意到这样的事实:一方面,一个带彩色大屏的咖啡机肯定不会比按钮式的咖啡机做出来的咖啡更好喝(都是胶囊,好意思么?),但另一方面,在消费者心中“看起来高端”的咖啡机,做出来的咖啡似乎真的似乎更好喝了呢。(是添加了智商税的“咸味”么?)

这里可能会有小伙伴吐槽:傻孩子,你不要凡尔赛了,奶茶我都快喝不起了,你跟我说什么咖啡机?

当然,我只是举个例子,我家里也没有咖啡机(我喝白开水),但这里的消费“升级”现象是真实的——一方面厂家尝试在竞争中引入更多“智能交互”的“噱头”(哪怕只是彩屏触摸按个按钮),另一方面,理性的用户也希望能更多“白嫖”这样的功能提升。这里的博弈逻辑就是:

  • 消费者知道加个触摸屏其实没啥卵用,服务本质没变
  • 消费者也知道,加个屏幕看起来更高大上,脸上有面子
  • 所以消费者希望,厂家最好白送这个面子工程——也就是白嫖
  • 厂家很清楚面子工程有用(增加竞争力),但消费者愿意多付出的成本有限(毕竟没有实质性改善服务);
  • 最终厂家愿意投入在产品上的成本并不会增加多少——具体表现为,简单的给电路板加个廉价的彩色LCD,芯片都不会换的

老板动动嘴……工程师跑断腿

以下是嵌入式小剧场:


小王:老板,这 320 * 240 RGB16 的屏幕光缓冲就要 150KB,咱们芯片的RAM总共才32K,不够用啊

老板:不是有那什么LVGL么?支持部分缓冲技术(Partial Framebuffer,PFB),不需要完整缓冲,你看这效果多好?

(图片来源于LVGL: https://lvgl.io/)

小王:老板,人家最小配置要 64K Flash,8K RAM,我们应用原本就塞得差不多了,哪有这个富裕啊?就算有空间,你不还寻思着要做功能升级么?

老板既然人家能用PFB做到,说明小资源环境是绝对能够做到的。那么,你就可以考虑参考LVGL的原理,自己写一套?

小王:(心里想,你给我多少钱工资啊,PFB是那么容易能做到的么?裸机实现成熟GUI的效果?你咋不上天呢?)……

老板:我也不是要为难你,你看,我们的确不需要多复杂的界面,可能就是几个按钮,几个进度条不得了了。不是有那句话么?8帧不卡,9帧流畅,10帧电竞……实际上我们也不需要动画或者高帧率啊。用户按下按钮,2秒内有响应他们就很开心了

小王:就是说我要自己绘制界面咯?

老板:可以贴图啊!事先存好几个图片放在外部FLASH里,用的时候直接刷到LCD里不就行了?我也不是抠门,给你再加个外部FLASH吧,你看咱们屏幕就那么点大,8M空间的还要啥界面绘制?

小王:那我就全贴图咯?

老板也不能全贴图啊!什么半透明啊,光标动画啊,按钮突出啊,基本的智能手机里有的效果还是要有的啊。否则我加这个屏幕做啥呢?

小王:我……我研究下……

老板:年轻人,努努力,我知道有难度,别人做不出来,你做出来了,多有成就啊?明天给我个方案,争取下周出样机。

当晚,灯火阑珊处,又多了一个在各大论坛和技术群里苦苦追寻答案的苦命人:

“跪求大佬如何在裸机下编写图形菜单?”

“跪求如何把参数设置与菜单框架联系在一起”

“跪求如何用状态机实现图形界面”

……

“跪求”……


这样的故事虽然是我杜撰的,但他真真切切的就发生在很多人的身边……

然而,曙光初现了:

Arm-2D 把我们这样的苦命人也作为服务对象:

  • 裸机或者RTOS
  • 小资源
  • 贴图为主
  • 低帧率
  • 有一定特效要求

Arm-2D体会到了这里的痛点:

  • 要支持PFB(部分缓冲技术)来节省RAM资源;
  • 使用PFB来实现图形界面时:理论上能做到的不代表人人都能做到;老鸟能做到不代表能很容易的就可以做到;
  • 开发一定要简单、傻瓜化;
  • 开发一定要简单、傻瓜化;
  • 开发一定要简单、傻瓜化;

Arm-2D提供的解决方案是:

  • 为 PFB 提供了专用 Helper 服务,而用户仅需提供最小的信息:
    • 屏幕的大小
    • PFB的大小
    • 一个向LCD传送像素的函数;
    • 一个图形界面的绘制函数;
  • 用户在绘制图形界面的时候,可以假装使用了完整的 Framebuffer。或者换句话说,PFB对界面的绘制来说是完全透明的;
  • 用户可以自由的配置PFB的大小来平衡帧率和资源的使用,简单理解就是可以在“RAM消耗”和“帧率”之间进行“无级变速”
  • 用户无需担心窗体切割的问题,Arm-2D所有的API都自动处理“贴图、目标缓存和窗体之间尺寸不一致问题”;
  • 提供对脏矩阵列表的支持——随心所欲的指定只刷新屏幕的哪“几个”区域
  • 而在上述特性的基础上,你可以:
    • 进行多个透明图层的合成(Alpha-blending)
    • 在指定的区域里像贴瓷砖那样进行贴图填充(Texture Paving)
    • 文字显示(bit Pattern)
    • 以抠图的方式显示光标(Colour-Masking)
    • 拷贝图片,或者只拷贝图片的一部分(2D-Copy)
    • 画点(有了画点,基本上就啥都成为可能了)
    • 画横线或者竖线
    • 用指定颜色填充指定区域(甚至还可以指定透明度)

简单来说:对普通单片机开发者来说,Arm-2D就是一张GUI的人权卡——通过它,你可以在小资源环境中快速且简单的实现自己所需的简单界面,并且自动获得PFB的支持

从结论上说:

Arm-2D 真的也认真的服务于我们普通人!

Arm-2D真的跟我们普通开发有关!

Arm-2D不一定提供最优的效率(如果你用的是Cortex-M55,它是目前你能获得的最优方案),但它真的节省我们大量的开发时间!

【人权卡的部署也很简单】


Arm-2D的基本设计理念是“傻瓜化”,它表现在部署上就是:

  • 支持“无脑”添加所有 C 源文件
  • 默认情况下无需复杂配置
  • 使用前,调用 arm_2d_init() 即可
  • 本身占用RAM极小;
  • 支持最高优化等级(-O3,-Os,-Oz,-Ofast,-Omax,-Omin)

废话少说,下面我们就来实际动手进行Arm-2D的部署吧。

准备阶段:


1、准备一个已有的工程,确保该工程已经能够实现基础的LCD初始化,并能提供一个向LCD指定区域传送位图的函数,其原型如下:

/**
  \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)

这里,5个参数之间的关系如下图所示:

简单来说,这个函数就是把 bitmap 指针所指向的“连续存储区域” 中保存的像素信息拷贝到LCD的一个指定矩形区域内,这一矩形区域由位置信息(x,y)和体积信息(widthheight)共同确定。

很多LCD都支持一个叫做“操作窗口”的概念,这里的窗口其实就是上图中的矩形区域——一旦你通过指令设置好了窗口,随后连续写入的像素就会被依次自动填充到指定的矩形区域内(而无需用户去考虑何时进行折行的问题)。

此外,如果你有幸使用带LCD控制器的芯片——LCD的显示缓冲区被直接映射到Cortex-M芯片的4GB地址空间中,则我们可以使用简单的存储器读写操作来实现上述函数,以STM32F746G-Discovery开发板为例:

//! STM32F746G-Discovery
#define GLCD_WIDTH     480
#define GLCD_HEIGHT    272

#define LCD_DB_ADDR   0xC0000000
#define LCD_DB_PTR    ((volatile uint16_t *)LCD_DB_ADDR)

int32_t GLCD_DrawBitmap (uint32_t x, 
                         uint32_t y, 
                         uint32_t width, 
                         uint32_t height, 
                         const uint8_t *bitmap) 
{
    volatile uint16_t *phwDes = LCD_DB_PTR + y * GLCD_WIDTH + x;
    const uint16_t *phwSrc = (const uint16_t *)bitmap;
    for (int_fast16_t i = 0; i < height; i++) {
        memcpy ((uint16_t *)phwDes, phwSrc, width * 2);
        phwSrc += width;
        phwDes += GLCD_WIDTH;
    }

    return 0;
}

2、获取Arm-2D库:

访问网址:

https://github.com/ARM-software/EndpointAI

或者在【裸机思维】公众号中发送关键字“arm-2d”获取对应压缩包。

需要说明的是,Arm-2D是Arm仓库EndpointAI的一部分。目前与Arm-2D相关的分支有4个:

  • master——主分支,包含了最简的arm-2d库
  • main-arm-2d-developing——主分支对应的开发分支
  • main-arm-2d-more-examples——包含了与主分支一样的内容,并提供了额外的例子(推荐尝鲜的小伙伴使用)
  • main-arm-2d-more-example-developing——上述分支的开发分支

后续内容,我们将假设下载的是main-arm-2d-more-examples分支中的内容。

部署阶段:


1、提取Arm-2D

解压缩压缩包,然后顺着以下路径找到Arm-2D目录:

"\Kernels\Research\"

将Arm-2D目录整体拷贝出来,放置到你的目标工程目录下,比如:

2、将Arm-2D添加到MDK工程中

在工程管理器中新建一个名为“Arm-2D”的分组,并将文件夹“Arm-2D/Library”下“Include”和“Source”中所有内容都添加到分组中:

为了获取PFB支持,我们还需要再添加对应的Helper服务到工程中来。同样新建一个分组,名为“Arm-2D-Helper”,并将“Arm-2D/Helper”目录下“Include”和“Source”中的所有内容都添加到分组中:

3、配置编译环境

将“Arm-2D/Library/Include”和“Arm-2D/Helper/Include”添加到Include搜索路径列表里:

如果你使用Arm Compiler 6(armclang),则需要打开对C11GNU扩展的支持,即直接在"Language C"中选择“gnu11”:

如果你使用的是Arm Compiler 5(armcc),则需要打开对C99GNU扩展的支持,如下图所示:

此外,由于现阶段Arm-2D还没有正式完成对armcc的warning清理工作,因此,你会看到海量的warning。在官方正式完成对armcc支持之前,推荐直接手工屏蔽它们,或者干脆关闭所有warning。具体方法为:在工程管理器中,右键键单击Arm-2D,选择“Option for Group”、“C/C++”;在“Misc Controls”文本框中添加如下内容:

--diag_suppress=513,144,174,2803,64,68,188,177

对待"Arm-2D-Helper"如法炮制,这里就不再赘述。

至此,我们就应该能够成功的完成编译了。

仔细想想,部署Arm-2D我们其实也没做啥特别的事情,是不是特别简单?

使用准备阶段:


1、包含头文件

在要使用Arm-2D的地方直接包含“arm_2d.h”,比如:

#include "arm_2d.h"

2、初始化Arm-2D

在使用任何Arm-2D服务之前,需要对库进行初始化,比如:

void main(void)
{
    ...
    arm_2d_init();
    ...
    while(1) {
        ...
    }
}

如果你的芯片SRAM财大气粗——不需要使用PFB,则至此我们已经完成了Arm-2D的全部部署工作。你可以着手第一个“Hello Arm-2D”啦。

PFB Helper 服务的部署:


1、包含头文件

在要使用PFB Helper服务的地方直接包含“arm_2d_helper.h”,比如:

#include "arm_2d_helper.h"

2、建立对象

理论上,我们可以建立多个PFB Helper对象——依据应用实际情况而定。这里,我们可以直接使用类型 arm_2d_helper_pfb_t 来建立一个静态实例:

static arm_2d_helper_pfb_t s_tPFBHelper;

3、初始化PFB服务:

在使用 PFB Helper之前,我们需要对其进行必要的初始化。Arm-2D提供了一个宏模板,可以帮我们简化必要的步骤:

    //! initialise FPB helper
    if (ARM_2D_HELPER_PFB_INIT( 
            <PFB Helper对象的地址>,          //!< FPB Helper object
            <LCD的像素宽度>,                 //!< screen width
            <LCD的像素高度>,                 //!< screen height
            <像素的数据类型,比如uint16_t>,   //!< colour date type
            <PFB的像素宽度>,                 //!< PFB block width
            <PBF的像素高度>,                 //!< PFB block height
            <PFB池中PFB的数量,一般写1>,      //!< number of PFB in the PFB pool
            {
                .evtOnLowLevelRendering = {
                    //! callback for low level rendering 
                    .fnHandler = &<底层绘图函数>,                         
                },
                .evtOnDrawing = {
                    //! callback for drawing GUI 
                    .fnHandler = &<图形面绘制函数>, 
                },
            }
        ) < 0) {
        //! error detected
        assert(false);
    }

比如,一个典型的例子是:

    //! initialise FPB helper
    if (ARM_2D_HELPER_PFB_INIT( 
            &s_tPFBHelper,     //!< FPB Helper object
            320,               //!< screen width
            240,               //!< screen height
            uint16_t,          //!< colour date type
            16,                //!< PFB block width
            16,                //!< PFB block height
            1,                 //!< number of PFB in the PFB pool
            {
                .evtOnLowLevelRendering = {
                    //! callback for low level rendering 
                    .fnHandler = &__pfb_render_handler,                         
                },
                .evtOnDrawing = {
                    //! callback for drawing GUI 
                    .fnHandler = &__pfb_draw_handler_t, 
                },
            }
        ) < 0) {
        //! error detected
        assert(false);
    }

其中,底层LCD像素绘制函数__pfb_render_handler()负责将PFB中的像素发送给LCD:

static void __pfb_render_handler( void *pTarget, const arm_2d_pfb_t *ptPFB)
{
    const arm_2d_tile_t *ptTile = &(ptPFB->tTile);

    ARM_2D_UNUSED(pTarget);

    GLCD_DrawBitmap(ptTile->tRegion.tLocation.iX,
                    ptTile->tRegion.tLocation.iY,
                    ptTile->tRegion.tSize.iWidth,
                    ptTile->tRegion.tSize.iHeight,
                    ptTile->pchBuffer);

    arm_2d_helper_report_rendering_complete(&s_tPFBHelper, 
                                            (arm_2d_pfb_t *)ptPFB);
}

这里的arm_2d_helper_report_rendering_complete() 负责释放从PFB池中分配到的 arm_2d_pfb_t 对象——这点非常关键。


对于使用DMA来异步刷新LCD的系统来说,用户就需要对上述过程做一个修改:

  1. __pfb_render_handler() 中向DMA发送刷新请求;
  2. 当DMA完成刷新后,在对应的完成中断处理程序中调用用 arm_2d_helper_report_rendering_complete() 来释放 PFB对象;

这里的 __pfb_draw_handler_t() 就是我们绘制图形界面的函数:

static arm_fsm_rt_t __pfb_draw_handler_t( void *pTarget,
                                          const arm_2d_tile_t *ptTile)
{
    ARM_2D_UNUSED(pTarget);
    
    arm_2d_region_t tBox = {
        .tLocation = {50,50},
        .tSize = {200, 100},
    };
    //! 背景填充白色
    arm_2d_rgb16_fill_colour(ptTile, NULL, GLCD_COLOR_WHITE);
    //! 在box指定的区域绘制黑色影子
    arm_2d_rgb16_fill_colour(ptTile, &tBox, GLCD_COLOR_BLACK);
    //! 适当向左上角移动box
    tBox.tLocation.iX -= 10;
    tBox.tLocation.iY -= 10;
    //! 在box指定的区域填充蓝色,并且使用 50%(128/255)的透明效果
    arm_2d_rgb565_fill_colour_with_alpha(   
        ptTile, 
        &tBox, 
        (arm_2d_color_rgb565_t){GLCD_COLOR_BLUE}, 
        128);      //!< 透明度
   
    return arm_fsm_rt_cpl;
}

在这个例子中,我们简单的实现了一个半透明浮动窗口的效果,(这篇文章实在太长了,就简单做个例子凑个数吧):

4、调用 PFB Helper服务任务:

要想使用PFB,还需要在超级循环或者某个RTOS任务里调用PFB的服务函数 arm_2d_helper_pfb_task(),由于它是非阻塞的、返回值为状态机的状态 arm_fsm_rt_t,因此使用方法非常灵活,例如:

int main (void) 
{
    lcd_init();
    arm_2d_init();
    
    //! initialise FPB helper
    if (ARM_2D_HELPER_PFB_INIT( 
            &s_tPFBHelper,     //!< FPB Helper object
            320,               //!< screen width
            240,               //!< screen height
            uint16_t,          //!< colour date type
            320,               //!< PFB block width
            1,                 //!< PFB block height
            1,                 //!< number of PFB in the PFB pool
            {
                .evtOnLowLevelRendering = {
                    //! callback for low level rendering 
                    .fnHandler = &__pfb_render_handler,                         
                },
                .evtOnDrawing = {
                    //! callback for drawing GUI 
                    .fnHandler = &__pfb_draw_handler_t, 
                },
            }
        ) < 0) {
        //! error detected
        assert(false);
    }

    while(1) {
        //! call partial framebuffer helper service
        while(arm_fsm_rt_cpl != arm_2d_helper_pfb_task(&s_tPFBHelper, NULL));
    }

}

值得特别说明的是,函数arm_2d_helper_pfb_task() 的第二个参数是脏矩阵列表(的地址),简单说就是一个由用户指定的刷新区域列表——你让PFB只刷哪些区域,它就只刷哪些区域。为了方便用户,Arm-2D还专门提供了一套宏模板来简化用户的脏矩阵列表定义工作,例如:

    /*! define dirty regions */
    IMPL_ARM_2D_REGION_LIST(s_tDirtyRegions, static const)
        
        /* a region for the busy wheel */
        ADD_REGION_TO_LIST(s_tDirtyRegions,
            .tLocation = {(APP_SCREEN_WIDTH - 80) / 2,
                          (APP_SCREEN_HEIGHT - 80) / 2},
            .tSize = {
                .iWidth = 80,
                .iHeight = 80,  
            },
        ),
        
        /* a region for the status bar on the bottom of the screen */
        ADD_LAST_REGION_TO_LIST(s_tDirtyRegions,
            .tLocation = {0,APP_SCREEN_HEIGHT - 8},
            .tSize = {
                .iWidth = APP_SCREEN_WIDTH,
                .iHeight = 8,  
            },
        ),

    END_IMPL_ARM_2D_REGION_LIST()

    //! call partial framebuffer helper service
    while(arm_fsm_rt_cpl != arm_2d_helper_pfb_task( 
             &s_tExamplePFB, 
             (arm_2d_region_list_item_t *)s_tDirtyRegions));

在这个例子中,代码定义了两个区域:一个是屏幕正中央一块 80*80 的区域,以及屏幕底部一个高度为8像素的条状区域(可以用于状态信息的显示)——最终的效果是,每次使用PFB进行刷新,这两个区域以外的部分都会被跳过(保持不变),从而节省了大量的处理时间,客观上提高了用户实际可见的帧率(Arm-2D中对于这种情况使用 Update per second而不是Frame per second 进行描述)。

借助这一范例很容易发现:通过宏 ADD_REGION_TO_LIST()我们可以几乎毫无限制的向列表中添加任意数量的区域,其语法为:

ADD_REGION_TO_LIST(<列表名称>,
    .tLocation = {<坐标信息>},
    .tSize = {<尺寸信息>}
),

需要注意的是,列表的最后一个元素一定要用 ADD_LAST_REGION_TO_LIST()来添加,否则代码一定会出现内存溢出的惨状。

整个列表的语法为:

/*! define dirty regions */
IMPL_ARM_2D_REGION_LIST(列表名称, <列表变量的修饰>)
    ...
END_IMPL_ARM_2D_REGION_LIST()

这里,“列表名称”实际上就是列表的变量名,而“列表变量的修饰” 则是大家熟悉的类型修饰符,比如 staticconst 一类——正确使用修饰符既可以节省RAM消耗,也可以在需要的情况下建立允许动态修改内容的列表。

【说在后面的话】


至此,我们完成了Arm-2D在工程中的部署,赋予了那些资源极端受限的单片机以“低帧率换低资源消耗”的方式 实现较为华丽图形界面的“人权”。

其实,不光是小资源系统可以使用PFB来解决“从无到有”的问题资源较为宽裕的芯片也可以使用1/2 甚至是1/4的PFB来换取更多的 SRAM 用于改善或者拓展其它应用性能,比如,改善音频处理类应用的缓冲效果等等。

另一方面,如果将PFB大小设置为完整的屏幕尺寸,实际上就可以将PFB Helper服务当做一个帧缓冲池来使用;此外,倘若上层的GUI软件能向PFB Helper传递脏矩阵列表,就能在刷新帧率上获得极大的优化空间。

作为本系列的第二篇,我们介绍了Arm-2D对普通单片机的意义,并提供了一个手把手的部署教程。后续内容,我们将在PFB平台的基础上以一个个具体的控件特效为例,详细为您介绍Arm-2D API的使用和技巧——什么进度条啊,滑动列表啊,菜单啊,统统都会安排上。如果你想一起追剧,就赶快搭建好测试平台吧。


本文分享自微信公众号 - 裸机思维(bare-metal),作者:GorgonMeducer 傻孩子

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-04-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 活久见!Arm居然为Cortex-M发布了专属显卡驱动

    (2D图形处理的技术其实早在红白机时代就成熟了,6502能做到的事情,Cortex-M自然也不在话下)

    GorgonMeducer 傻孩子
  • 懒人玩Arm-2D究竟有几种姿势

    如果你是第一次接触Arm-2D,可以单击这篇文章《为什么说Arm-2D是小资源单片机的GUI人权卡!》来了解大概、或是观看公开课(https://aijishu...

    GorgonMeducer 傻孩子
  • 【教程更新】一网打尽Arm-2D的资料和傻瓜部署教程

    随着时间的推移,从4月份更新第一个版本以来,Arm-2D也逐渐走入成熟期,截止到我编写这篇文稿的时间,其版本已经来到了0.9.8,而Github开发分支上的版本...

    GorgonMeducer 傻孩子
  • 【教程更新】Arm-2D的公开课你错过了么?

    最近受到极客社区的邀请,我有幸为大家献上了一期名为“Arm-2D初探——填补空白还是屋上架屋”的公开课。原本计划是1个小时,无奈说的太嗨了,一不小心就讲了3个小...

    GorgonMeducer 傻孩子
  • 【Arm-2D】不整活儿玩啥GUI?

    之前,我们说过Arm-2D虽然本意是在底层默默的为各类商用和开源GUI软件协议栈提供加速服务,但考虑到在资源受限的深度嵌入式系统环境下,仍然有一大批贫下中农不辞...

    GorgonMeducer 傻孩子
  • 【例说Arm-2D界面设计】从不规则图标的显示说起

    Arm-2D是Arm公司为Cortex-M处理器平台量身打造的一款2D图形处理方案。针对已有的经典Cortex-M内核,诸如Cortex-M0/M0+/M3/M...

    GorgonMeducer 傻孩子
  • 【例说Arm-2D界面设计】任意尺寸的圆角矩形(上)

    在上篇文章《【例说Arm-2D界面设计】做剪影风也太简单了8!》中我们介绍了使用透明蒙版的方法来实现“性冷淡风”图标显示的方法。其中,我们提到了使用透明蒙版的三...

    GorgonMeducer 傻孩子
  • 【例说Arm-2D界面设计】做剪影风也太简单了8!

    在上一篇文章《【例说Arm-2D界面设计】从不规则图标的显示说起》的最后,我们展示了如何使用Arm-2D在RGB565环境下显示带有Alpha通道的图片的(比如...

    GorgonMeducer 傻孩子
  • 第001课 不要再用老方法学习单片机和ARM

    我们的第一期是教大家如何将ARM开发板当作单片机来用,但在这期视频的第一节,我告诉你们,学习单片机是没有前途的。

    韦东山
  • 慌不择路?ARM建网站专撕RISC-V,连自家员工都看不下去了

    量子位
  • 一个程序员应该怎样学会编写带GUI的程序?

    图形用户界面,英文为Graphical User Interface,简写为GUI。

    程序员LIYI
  • OS开发爱好者福利来了:树莓派上编译C语言,顺便掌握一波硬件知识

    近日,有人在 GitHub 上开源了一个关于树莓派的教程。不同于以往的树莓派开发,这篇教程的核心内容是讨论如何在树莓派上进行裸机编程。

    机器之心
  • 嵌入式相关开源项目、库、资料大全

    学习初期最难找的就是找学习资料了,本贴精心汇总了一些嵌入式相关资源,包括但不限于编程语言、单片机、开源项目、物联网、操作系统、Linux等资源,并且在不断地更新...

    单片机点灯小能手
  • 嵌入式开发概述

    嵌入式系统在术语上被定义为:以应用为中心、以计算机技术为基础、软件硬件可裁剪、适用于应用系统,对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。它的特点...

    韦东山
  • Arm 传奇

    1964 年夏天,一位奥地利富商对他的儿子说:“我知道你长大后想成为物理学家,但是现在英语很重要,所以你这个暑假要去海峡对面的英国学习英语”

    FPGA开源工作室
  • 嵌入式软件工程师笔试面试指南-ARM体系与架构

    注意:nandflash和norflash的0地址是不冲突的,norflash占用BANK地址,而nandflash不占用BANK地址,它的0地址是内部的。

    嵌入式与Linux那些事
  • 四面受敌!ARM暂停与华为合作,芯片备胎计划还能执行么?

    继谷歌限制华为的安卓服务后,当地时间5月22日,BBC报道英国芯片设计商ARM刚刚宣布暂停与华为合作!

    大数据文摘
  • Godot3游戏引擎入门之零零:简单的想法

    2018-08-15 by Liuqingwen | Tags: Godot | Hits

    IT自学不成才
  • 如何“优雅”的测量系统性能

    在之前的文章《【嵌入式秘术】相约榨干SysTick的每一滴汁水》里,我们介绍了一个以“寄居”形式(也就是在不影响用户已有SysTick应用的情况下)测量CPU性...

    GorgonMeducer 傻孩子

扫码关注云+社区

领取腾讯云代金券