当前位置:首页 > 公众号精选 > 裸机思维
[导读]在前面的文章《【例说Arm-2D界面设计】“手撸GUI”的利器——场景播放器》中,我们详细介绍了智能设备时代一种“基于面板(Panel)的嵌入式界面设计范式”,并以Arm-2D的场景播放器(Scene Player)为例,介绍了小资源环境下具体“手搓GUI”的方式。

【说在前面的话】


在前面的文章《【例说Arm-2D界面设计】“手撸GUI”的利器——场景播放器》中,我们详细介绍了智能设备时代一种“基于面板(Panel)的嵌入式界面设计范式”,并以Arm-2D的场景播放器(Scene Player)为例,介绍了小资源环境下具体“手搓GUI”的方式。
很多小伙伴看了以后大为震撼,并纷纷发出了叩问灵魂的拷问:

我芯片内部Flash已经很紧张了,随便一个背景图你让我存哪里?


这是个好问题。一般来说,我们所说的小资源环境是指:内部FLASH空间小于64K,当然也包括那些虽然芯片Flash较大(比如有128K)但原本的应用代码已经非常庞大——“留给GUI的空间已经不多”的情况。总之,留给Arm-2D的代码空间已经捉襟见肘,图片资源又该保存到哪里呢?

一般来说,很多芯片会提供一个叫做 XIP 的外设(也许你的芯片中对应的外设并不叫这个名字,但你可以根据下面的功能描述来对号入座),以便:
  • 通过QSPI接口连接外部的SPI Flash芯片;
  • 将外部Flash芯片中的内容映射到4G地址空间中

换句话说,我们可以像访问内部Flash那样使用芯片外部的SPI Flash,这其中不仅包括存储数据(比如图片),甚至还可以执行代码。


如果你芯片拥有XIP,那么你的芯片已经不属于我们所讨论的“资源受限”的环境了——因为大容量的片外Flash不仅长见而且廉价。相信很多人对此都非常熟悉,我就不再赘述了。


如果你的芯片没有XIP,而你也只能通过外设 SPI 和自己编写的驱动来访问外部 Flash,此时,我们如何使用 Arm-2D 来简化“手搓GUI” 的开发过程呢?不要急,本文就将为你揭晓谜底。


【什么是虚拟资源(Virtual Resource)】


Arm-2D几乎所有API的基本操作单位都是“贴图(Tile)”,它的数据结构定义如下:
/*! * \brief a type for tile *  */typedef struct arm_2d_tile_t arm_2d_tile_t;struct arm_2d_tile_t { implement_ex(struct { uint8_t bIsRoot              : 1; //!< is this tile a root tile uint8_t bHasEnforcedColour   : 1; //!< does this tile contains enforced colour info uint8_t bDerivedResource     : 1; //!< indicate whether this is a derived resources (when bIsRoot == 0) uint8_t bVirtualResource     : 1; //!< indicate whether the resource should be loaded on-demand uint8_t : 4; uint8_t : 8; uint8_t : 8; arm_2d_color_info_t tColourInfo; //!< enforced colour }, tInfo);  implement_ex(arm_2d_region_t, tRegion); //!< the region of the tile  union { /* when bIsRoot is true, phwBuffer is available, * otherwise ptParent is available */ arm_2d_tile_t *ptParent; //!< a pointer points to the parent tile uint8_t *pchBuffer; //!< a pointer points to a buffer in a 8bit colour type uint16_t *phwBuffer; //!< a pointer points to a buffer in a 16bit colour type uint32_t *pwBuffer; //!< a pointer points to a buffer in a 32bit colour type  intptr_t nAddress; //!< a pointer in integer };};
如果看着比较晕,不要紧,其实它就只有三大部分而已:
  • 贴图的各类属性描述信息:tInfo

  • 贴图的尺寸和位置信息: tRegion

  • 贴图的指针或引用


贴图从种类上来说分类两种:根贴图(Root Tile)子贴图(Child Tile)。其中,根贴图是指那些直接“拥有”具体图片资源(或者是显示缓冲区)的贴图(Tile),这表现在:
  • 根贴图的属性 tInfo.bIsRoot 一定为 true
  • 根贴图的指针直接指向具体的资源数组或者现实缓冲区

从前面的数据结构中,我们可以看到union中有很多指针,比如 pchBuffer、phwBuffer和pwBuffer。由于他们都是共用体,因此这些指针保存的地址值都是相同的,而具体使用哪个类型的指针则取决于目标资源的颜色格式,这一信息可以是省略的,但一般通过 img2c.py 脚本转换出来的tile都会在tInfo.tColourInfo中包含具体的颜色信息。

值得强调的是 ptParent 仅在子贴图中有意义,用于指向自己的父贴图(Parent Tile),而 nAddress 仅仅是方便对地址值进行四则运算的一个整形变量(uintptr_t)。


推论1:我们所有的图片资源都是用根贴图来描述的。
也许你已经从根贴图的指针看出了端倪:普通的根贴图要求其指向的图片资源必须存在于4G地址空间中——换句话说就是普通指针可以访问的地方——保存在外部Flash中的图片资源(在未经XIP帮助的情况下)则无法满足上述要求,因此无法直接用 arm_2d_tile_t 进行描述

为了解决这一问题,arm-2d 在基类 arm_2d_tile_t 的基础上派生出了一个新的类:虚拟资源(Virtual Resource),arm_2d_vres_t——专门用于描述这类无法直接访问的图片资源。其数据结构如下:

/*! * \brief a type for virtual resource * * \note the flag tTile.tInfo.bVirtualResource must be true (1) */typedef struct arm_2d_vres_t arm_2d_vres_t;struct arm_2d_vres_t {  /*! base class: tTile */ implement_ex( arm_2d_tile_t, tTile);  /*!  a reference of an user object  */ uintptr_t pTarget;  /*! *  \brief a method to load a specific part of an image *  \param[in] pTarget a reference of an user object  *  \param[in] ptVRES a reference of this virtual resource *  \param[in] ptRegion the target region of the image *  \return intptr_t the address of a resource buffer which holds the content */ intptr_t (*Load)   ( uintptr_t pTarget,  arm_2d_vres_t *ptVRES,  arm_2d_region_t *ptRegion);  /*! *  \brief a method to despose the buffer *  \param[in] pTarget a reference of an user object  *  \param[in] ptVRES a reference of this virtual resource *  \param[in] pBuffer the target buffer */ void (*Depose) ( uintptr_t pTarget,  arm_2d_vres_t *ptVRES,  intptr_t pBuffer );};



对上述结构提描述感到一头雾水的小伙伴不要慌张——实际使用中,我们并不需要与 arm_2d_vres_t 的内部结构打交道——arm-2d为我们提供了傻瓜式的封装服务,使用起来依然非常简单


【如何使用虚拟资源?】


这里,我们假设你已经按照文章《【喂到嘴边了的模块】准备徒手撸GUI?用Arm-2D三分钟就够了》的步骤完成了Arm-2D的部署。
准备阶段:
在工程管理器中展开 Acceleration,并找到你的LCD驱动模板 arm_2d_disp_adapter_0.h(这里假设你只有一个屏幕):


通过Configuraion Wizard打开图形配置界面:


假设你已经配置好了其它部分,勾选这里的“Enable the virtual resoure helper service” 选项后保存——至此,我们就为 Display Adapter 0 开启了其专属的虚拟资源辅助服务(Helper Service)。需要强调的是,每个Display Adapter 都有自己独立的虚拟资源辅助服务,需要独立的打开


此时,如果直接编译,会看到如下的错误:
Error: L6218E: Undefined symbol __disp_adapter0_vres_get_asset_address (referred from arm_2d_disp_adapter_0.o).Error: L6218E: Undefined symbol __disp_adapter0_vres_read_memory (referred from arm_2d_disp_adapter_0.o).

不要慌,这是我们有意为之——它提醒我们作为用户需要提供(实现)两个最基本额接口函数:

  • __disp_adapter0_vres_read_memory()

一个专门用于从外部存储器的指定地址读取指定长度字节的函数,其原型如下:
void __disp_adapter0_vres_read_memory( intptr_t pObj,  void *pBuffer, uintptr_t pAddress, size_t nSizeInByte);

这里:

    • pObj 我们可以暂时忽略

    • pBuffer 指向一块缓冲区,用于保存我们从外部存储器中读取到的内容;

    • pAddress 保存的是目标内容在外部存储器中的地址;

    • nSizeInByte 保存的是要读取的字节数


一般来说,如果我们已经事先调试好了一个SPI Flash读取函数,就可以轻松的实现这一函数,比如:

extern void spi_flash_read(void *pBuffer,  uint32_t nAddressInFlash, size_t nSize); void __disp_adapter0_vres_read_memory(intptr_t pObj,  void *pBuffer, uintptr_t pAddress, size_t nSizeInByte){ ARM_2D_UNUSED(pObj); /* it is just a demo, in real application, you can place a function to  * read SPI Flash  */ spi_flash_read(pBuffer, (void * const)pAddress, nSizeInByte);}



  • __disp_adapter0_vres_get_asset_address()

一个专门用于返回当前虚拟资源起始地址的函数。需要注意的是,它的返回类型是 uintptr_t,在Cortex-M环境下是一个32位的无符号整形(uint32_t),我们用它来返回目标图片在SPI Flash中的起始地址绰绰有余。其函数原型是:
uintptr_t __disp_adapter0_vres_get_asset_address( uintptr_t pObj, arm_2d_vres_t *ptVRES);

这里:

    • pObj 我们可以暂时忽略

    • ptVRES 指向的是我们的目标虚拟资源


在最简单的情况下,假设你的系统只有一背景图保存在外部SPI Flash中,且地址为 0x00000000,那么这个函数就极其简单了:

uintptr_t __disp_adapter0_vres_get_asset_address(uintptr_t pObj, arm_2d_vres_t *ptVRES){ ARM_2D_UNUSED(ptVRES); ARM_2D_UNUSED(pObj);  return 0x00000000;}

也许你要问,如果我要处理多个图片该怎么办呢?别着急,后面会有专门的章节详细介绍。现阶段我们先专注于完成一个最简单的例子。


完成了上述准备工作,再次编译就应该毫无问题了。




创建自己的虚拟资源:


在要创建虚拟资源的源代码中加入对 Display Adapter 0 的头文件引用:

#include "arm_2d_disp_adapter_0.h"


定义一个 arm_2d_vres_t 类型的静态变量(或者全局变量),并使用专门的宏 disp_adapter0_impl_vres 来描述资源的颜色和尺寸信息,比如:

static arm_2d_vres_t s_tMyVirtualRes =  disp_adapter0_impl_vres(  ARM_2D_COLOUR_RGB565, // 图片的颜色格式 320, // 图片的宽度 256, // 图片的高度 );

其中,宏disp_adapter0_impl_vres() Display Adapter 0 专用的,以此类推,如果你的虚拟资源要在 Display Adapter 1上使用,则对应的描述宏为 disp_adapter1_impl_vres()。不管如何,它们的原型是一样的:

disp_adapter0_impl_vres(__COLOUR_FORMAT, __WIDTH, __HEIGHT,...)

这里:

    • __COLOUR_FORMAT 是目标素材的颜色格式,具体可用的颜色在 arm_2d_type.h 中定义,都以 ARM_2D_COLOUR_ 作为前缀。

    • __WIDTH 是目标素材的像素宽度

    • __HEIGHT是目标素材的像素高度

    • ... 是一系列可选的参数,主要用于初始化 arm_2d_vres_t 中的一些特殊成员(比如 pTarget),这个在随后的章节中会用到。


在上述例子中,我们创建了一个虚拟资源 s_tMyVirtualRes,由于它是 arm_2d_tile_t 的派生类,因此可以像普通的贴图那样在arm-2d的API中作为素材(source tile)蒙版(mask)来直接使用,比如:

/* 把 虚拟素材 显示在屏幕上 */arm_2d_tile_copy(   &s_tMyVirtualRes.tTile, /* 素材 */ ptTile, /* 目标缓冲区 */ NULL,  ARM_2D_CP_MODE_COPY); 


效果如下:




正如我们前面说过的,虚拟素材(virtual resource)也是贴图(Tile)的一种,因此,也可以在它的基础上创建子贴图(Child Tile),比如:

staticconst arm_2d_tile_t c_tChildImage = { .tRegion = { .tLocation = { .iX = 160, .iY = 128, }, .tSize = { .iWidth = 160, .iHeight = 128, }, }, .tInfo = { .bIsRoot = false, .bDerivedResource = true, }, .ptParent = (arm_2d_tile_t *)&s_tMyVirtualRes.tTile,};

这里:

  • bIsRootfalse,清晰的标明了 c_tChildImage 的子贴图身份;

  • 创建子贴图作为素材时,bDerivedResource一定要设置为 true切记切记!

  • 这个例子中,观察 tLocationtSize容易发现:我们实际上是取了原图右下角的1/4作为新的素材


修改代码,将新的素材也拷贝到屏幕上:

/* 把 虚拟素材 显示在屏幕上 */arm_2d_tile_copy(   &s_tMyVirtualRes.tTile, /* 素材 */ ptTile, /* 目标缓冲区 */ NULL,  ARM_2D_CP_MODE_COPY);/* 把 子贴图 显示在屏幕上 */arm_2d_tile_copy(   &c_tChildImage, /* 素材 */ ptTile, /* 目标缓冲区 */ NULL,  ARM_2D_CP_MODE_COPY);

由于我们在拷贝子贴图时没有指定要复制的位置(给了NULL),因此被默认放置到了屏幕的左上角,形成了如下的效果:





【我们有多个图片该怎么办?】


前面的例子中,为了让小伙伴们快速的体验虚拟资源的爽快,因此我们对内容作了简化——只演示了一个图片的情况——实际应用中,显然这是无法满足要求的。

聪明的小伙伴也许已经注意到了,当存在多个图片资源的时候,决定我们实际读取那一张图片的关键就是函数 __disp_adapter0_vres_get_asset_address() 的返回值——它返回谁的地址,读取的就是谁的图片。
观察它的函数原型,容易发现两个形参都很有潜质。
uintptr_t __disp_adapter0_vres_get_asset_address( uintptr_t pObj, arm_2d_vres_t *ptVRES)

换句话说,支持多图片的关键就在于如何使用传递进来的参数返回对应图片在外部存储器中的地址


进一步观察 arm_2d_vres_t 的结构,我们可以注意到一个有趣的成员 pTarget
 typedef struct arm_2d_vres_t arm_2d_vres_t;struct arm_2d_vres_t { ... /*!  a reference of an user object  */ uintptr_t pTarget; ...};


无论我们给它赋任何内容,它的值都会作为第一个实参传递给接口函数

__disp_adapter0_vres_read_memory(intptr_t pObj, …… )

__disp_adapter0_vres_get_asset_address(uintptr_t pObj, ……)

也就是这里的 pObj。


至此,对多图片的支持实际上就形成了两种方式:

  • 面向对象的方式(OOPC)

  • 所见即所得的方式


对于熟悉使用C语言进行面向对象开发(OOPC)的小伙伴来说,恐怕看了上面的描述就已经心领神会了吧。这里就不再赘述。


剩下的篇幅,我们将着重介绍“所见即所得”的方法:


步骤一:在建立(描述)虚拟资源时,将目标图片在外部存储器中的地址直接赋值给 pTarget。比如:
static arm_2d_vres_t s_tVRes0 =  disp_adapter0_impl_vres(  ARM_2D_COLOUR_RGB565, 32, 32, .pTarget = <这个资源在外部存储器中的地址> ); static arm_2d_vres_t s_tVRes1 =  disp_adapter0_impl_vres(  ARM_2D_COLOUR_RGB565, 32, 32, .pTarget = <这个资源在外部存储器中的地址> );...


步骤二:在函数 __disp_adapter0_vres_get_asset_address 直接将 pObj 的值(也就是 ptVRES->pTarget)的值返回:

uintptr_t __disp_adapter0_vres_get_asset_address(uintptr_t pObj, arm_2d_vres_t *ptVRES){ ARM_2D_UNUSED(ptVRES); return pObj;}


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭