嵌入式硬件抽象框架常常面临着这样的尴尬:封装层次较高的(arduino,mbed)不能充分暴露必要的API并面临着性能问题,封装层次较低的(HAL,LL)接口复杂且开发困难。近日发现的一个框架Chrome Embed Controller(下简称EC)较好地权衡了开发效率和运行效率,还具有其他的一些可贵的特性。先来看看EC的几个常用API:
//GPIO declaration //GPIO(name, pin, flag)
), GPIO_OUT_HIGH)//declare as output
), GPIO_INPUT) //declare as input
); //set GPIO output
int input = gpio_get_level(GPIO_PC6); //read GPIO input
//initialize an i2c port
), GPIO_ODR_HIGH) // I2C port 1 SCL
), GPIO_ODR_HIGH) // I2C port 1 SDA
ALTERNATE(PIN_MASK(B, 0x00C0), GPIO_ALT_F1, MODULE_I2C, GPIO_PULL_UP)
const struct i2c_port_t i2c_ports[] = {
{, GPIO_I2C2_SCL, GPIO_I2C2_SDA},
};
const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
//int i2c_write8(int port, int slave_addr, int offset, int data)
, 0x40, 0x2 + bank, 0x4C); //write u2c output
//int i2c_read8(int port, int slave_addr, int offset, int *data)
, 0x40, 0x6 + bank, & tmp); //read i2c input
怎么样,是不是比stdlib和HAL什么的简洁多了?作为一个为专门用途设计的框架,将EC用于通用开发的资料哪怕在国外也寥寥无几。本文首先是我自己探索EC过程中的笔记,更希望能让这样一个优秀且有巨大潜力的框架为嵌入式开发者所知、所用。
由于不同型号的chromebook使用不同种类的EC控制器,EC固件需要进行跨平台适配
EC巧妙设计的API允许用户只针对不同SoC做少量设定即可移植代码
这些设定以宏定义的形式暴露给用户,包括系统时钟,FLASH和RAM大小等
每个平台的设定被写入独立的config文件中
注意:本教程以STM32为平台
EC不基于任何现有框架,而是直接对寄存器操作进行了一定层次的封装。这使得它甚至可以运行在32MHz/16kb RAM的STM32L151上——除非自己造轮子,这可能是现在最轻量的多任务嵌入式框架了。
例如,要声明一个GPIO引脚,只需要写一行 GPIO(name, pin, flags) ,让GPIO_XXXX()、GPIO_Typedef啥的都见鬼去吧
正如前文所述,EC是一个跨平台框架,目前已涉及意法STM32、德仪TM4、新唐npcx、Microchip mec1322等产品线,覆盖ARM cortex-m, cortex-m0, nds32等架构。EC将各平台上不同的底层操作封装成统一、高级、简洁的API供用户调用,实现了跨平台、高性能的硬件抽象。
如果你正在寻找一个合适的方案来辅助高级SoC(比如AP)的启动和硬件管理,那EC无疑是你的极佳选择!EC集成了boot,电源管理,常见IO设备驱动等必要的功能,可以大大简化你的开发流程。又或者你想驱动一些只有在笔记本上应用较多的设备,这些库对于嵌入式MCU不太常见(e.g.触摸板,PD物理层,etc.),EC很可能包含了这些驱动。
EC由Google团队开发和维护。EC为千万台chromebook产品提供底层支持。EC有完善的单元和闭环测试程序。EC迄今已有5年的历史,其间很好地证明了它可以胜任传统BIOS的工作并且做得更好。这几点保证了EC的代码质量和健壮性——相比之下,把个人建立和维护的封装库用在某些场合就显得不那么令人放心了。另外,EC的维护和更新至今仍然非常活跃,并且团队对于合并修改的请求的响应非常积极。
EC的任务调度器的内存分配机制不允许使用动态内存。尽管如此,EC仍然提供了一个共享缓冲区(Shared Memory Buffer)——目前仅用于debug。实际上因为缺少MMU,降低的可靠性和高昂的开销,在嵌入式系统上使用动态内存一直不被建议。而禁用堆从根本上杜绝了内存泄漏,这在稳定性上带来的巨大提升使得副作用的一点点限制显得不值一提了。
用作EC的MCU大多较为低端,所以很多高端MCU才有的功能并没有被EC实现或高层封装(e.g.DAC,FSMC,Ethernet,etc.),一些显然对于chromebook没用的功能也同样没有(e.g. CAN)。你可能想自己实现一些外设封装库,但要注意不要与EC的内存管理和资源锁机制冲突。
如果你对嵌入式开发毫无兴趣而只想make things work,EC极可能不是你的最佳选择。EC不是被设计用于通用嵌入式开发的,没有arduino、mbed等流行平台那样完善的生态和丰富的资源——实际上有关于使用EC进行通用开发的资料少得可怜。这意味着你需要自己实现每个EC未封装的功能并有相当的解决问题的能力。
EC在宏的应用上简直称得上出(sang)神(xin)入(bing)化(kuang),例如GPIO的三种声明全都是宏函数你敢信?虽然知道在嵌入式系统上为了提升运行时效率这是常规操作,但读源码的时候我还是想【脏话】
虽然EC并没有mbed等平台那样的宏图壮志,但却有着不输任何框架的独创设计——"独创"在这里没有褒义。EC使用枚举来声明引脚和任务,使用数组来声明外设,与主流框架使用函数的声明风格相比显得特立独行。尤其是任务和引脚的声明都需要写在独立的文件里,应该是出于被多个文件依赖和增加可维护性的考虑。这样的设计似乎有点声明式的味道,可能有更好的性能,也可能是为了简化针对多任务的统一资源管理的妥协。但无疑的是,这种集中的静态的声明风格损失了灵活性,增加了代码移植和进一步封装的难度,并产生了额外的学习负担。
EC的封装为我们省去了大量繁琐的初始化和配置等操作,但恼人的底层特性仍有部分残余,比如基于位操作的配置和令人眼花缭乱的16进制常量。可以通过添加一些简单的宏摆脱这些麻烦,不知为什么已经大面积使用宏的EC没有这么做。更致命的是,这些大量的宏给进一步的高层封装带来了巨大的困难,实际上除非从底层重构,我想不出在接口中完全消除这些宏的办法。
强烈推荐的一篇了解EC开发历史和概念的材料。chromebook固件核心工程师倾情巨献,最重要的是足够沙雕(
着重介绍了如何将EC作为通用开发框架使用。对一些概念和API做了简单易懂的解释,但欠详细
这是Google官方介绍EC的presentation。对于框架构成,项目目录结构,所有的基础概念等等细节都有详细的解释
手机扫一扫
移动阅读更方便
你可能感兴趣的文章