【MCU】把"安卓HAL层思想"引到单片机软件开发中

1、聊一聊

    今天跟大家推荐一首bug菌常听的歌曲<Yellow>,歌曲的旋律一定是你熟悉的。歌名"Yellow"不要想Y了,Yellow表示颜色是黄色的意思,但也可表示胆怯、内敛,热情的。

     在之前的文章中bug菌有提到过stm32的HAL层,而该层与安卓的硬件抽象层却迥然不同,相对而言stm32的HAL层更像是每个外设的驱动程序,所以这里bug菌把安卓HAL层的思想引到MCU中来跟大家聊聊!

2、话题引出


咬金,你平时写单片机程序有考虑抽象出硬件抽象层吗?

硬件抽象层 ? 你是说像stm32的HAL库那样子吗?

。。。,不是啦,stm32的HAL库我感觉还只能算个驱动程序吧,真正的HAL层得要像安卓那样。

安卓? 有点高大上呀,不敢碰!

没你想得那么可怕,知识都是互通的呀,最近接触这些东西感觉收获颇丰。而且现在MCU越来越强大,需要学习更多的设计思路了。

你真是个狠人呀!那你学的HAL层的思想大致跟我讲讲呗,让我也学习一下。

行,那我就露两手给你瞧瞧~

1

什么是HAL层 ? 

1

Hal简介

    HAL层又叫硬件抽象层,英文全名为(Hardware Abstraction Layer),从名字上就觉得高大上,就像字面意思这个层面会把所有的硬件都进行抽象,它就像一款万能的遥控器,可以操作所有的旧彩电、冰箱、洗衣机、空调、热水器......(怎么感觉像收废品的)。

(上图安卓框架源于网络)

    上图是经典的安卓架构图,然而HAL层的提出最早并不是在Linux中出现,而是由Microsoft公司为确保WindowsNT的稳定性和兼容性而提出的,Microsoft发现直接操作硬件不仅会带来软件上的不兼容,而且对系统稳定性也是不利因素,所以就有了类似于虚拟机这样的HAL层。

2

win VS 安卓

    Windows下的HAL层是位于物理硬件设备之上的,也就是说该HAL层直接操作底层寄存器,从而形成一套统一的HAL层接口给上层操作系统使用的,那么所编写的硬件驱动都需要满足HAL层的规范才能够被使用。

    而对于安卓系统所实现的HAL却与win有所差异,大家可以看看前面安卓系统层次图,其HAL层位于操作系统内核和驱动程序之上,且位于用户空间。

    那么为什么会形成如此的差异呢?

  • 由于window不开源而Linux内核需要遵循的是GPL开源协议,说白了就是要开源代码,但是基于Linux开发的硬件驱动和应用程序不必遵循GPL许可。

  • 为了保障各个厂家的利益,所以就有了HAL层的诞生,当然HAL层虽然位于内核之上,不过其功能还是通过系统调用与底层打交道,所以也叫用户空间驱动程序。那么不想开源的厂家就可以把关键的处理逻辑放到HAL层并且加密处理以后发布,而不需要开放,而内核部分只需要基础的与底层交互的机制即可。

2

安卓HAL层实现思路

    这里不会详细的讲解每一步是如何实现的,仅仅把系统的结构理顺一下,并且把关键的调用关系理一理,让系统HAL层设计的思想为我们所用,所以这里我们只分析三层与C程序关联更多的部分,HAL层以上均认为是应用层,如下图所示 :

1

应用层-->HAL层

  • 我们都知道安卓上都是用java语言开发,而到了HAL以及底层都是用C或者C++,那么从上层服务层到HAL层就必须要有一套JAVA转C/C++的接口实现,比如JNI,只要遵循该规范 Java 代码就能够与其它编程语言互相操作,也允许 Java代码调用 C/C++或汇编语言编写的程序和库。

  • 那么HAL层就只需要为上层提供必须要的方法供其调用即可。

2

HAL层-->底层寄存器 

  • 这个层面应该是对抽象硬件非常值得参考的一部分,这里我们通过一些代码研究一下:

HAL层三大结构体 :

  • hw_module_t 

  • hw_module_methods_t 

  • hw_device_t

  • 从上面的三大结构体的结构体和包含关系我们大致可以了解到,HAL层的都是以硬件模块类module进行抽象的,每个module里面会有一个methods方法,而methods结构体中仅仅包含Open指针,通过向该Open中传入id即可获得一个device指针对象,同时每个device都会存储硬件设备的公共属性和操作方法,并指向相应的module类型。

  • 感觉有点抽象,其实都是固定的一些套路,我觉得来点个灯就会大彻大悟了!

  • 1、首先采用面向对象的思路分别继承两个重要的结构体,这样就可以通过父类common(也叫通用结构)在外部传递从而保持接口的统一,而内部通过强制类型转化为之类led_xxx_t来获得更多的操作接口丰富内部实现。

  • 2、这里的Open函数相当于一个提取器,把子类设备实例化dev以后通过父类device对象指针传递出去,从而给JNI层,这样JNI层就可以直接调用Set_LED方法了。

    

  • 3、HAL_MODULE_INFO_SYM是和上层应用约定的结构,Android 会根据这些元数据来找到并正确加载 HAL 模块。JNI层通过调用hw_get_module函数(该函数内部会通过id和load函数加载模块,即前面实现的那些内容),hw_get_module函数返回的数据类型为led_module_t型指针, 然后可以通过module->methods->open(module,LED_HARDWARE_MODULE_ID,(struct hw_device_t**)device);来调用hal层的open函数得到led硬件操作的led_control_device_t结构体实例,这样应用程序就可以通过该对象使用对应的接口了。

    然而,从上面看来HAL层仅仅只是对硬件进行了抽象,并且其操作的还是系统调用,然而要操作具体的寄存器还需要通过系统调用进入到Linux内核以Open/Write/Read/Ioctl等等接口来进行操作,这一块又是操作平时的cdev和file_Operation结构套路了。

    所以在HAL可以实现大部分的逻辑和命令处理,而对应的驱动程序相对比较单一,简单的配置和发送数据等即可,所以安卓的HAL层的最终目的中不仅仅满足了厂家驱动不想开源的想法,而且还达到了抽象底层硬件的目的。

3

HAL层在单片机上的应用

    虽然在单片机中没有所谓的用户态和内核态,大部分情况也不需要动态加载,但是相关的抽象思想是完全可以模仿的,比如用C实现面向对象的继承方式;把系统抽象为模块和设备,比如一类音频模块包括USB音频设备,蓝牙音频设备等等;平台相关驱动和逻辑分离等等。

    如上的module层可以认为是HAL层,我们可以在MCU中引入HAL的三大结构体,从而实现设备接口上的统一和抽象,当我们驱动层发生了变化,只需要重新编写出满足HAL层接口即可。

666,好像有点东西,我得再看一篇!

哈哈,慢慢啃吧!

3、结束语

    文本到这里就结束了,单片机仅仅只是一个工具,思维的高度才会能决定代码的质量!

    好了,这里是公众号:“最后一个bug”,一个为大家打造的技术知识提升基地,如果你喜欢交流可以添加下方bug菌微信,我拉你加入公众号技术交流群。

推荐好文  点击蓝色字体即可跳转

【开源】bug菌把"动态数字显示"开源了!

【MCU】可怕,别人把我MCU固件给反汇编了!(逆向)

☞ 【MCU】寄存器、标准库、HAL库、LL库,这么多库!你叫我怎么选?

☞ 【嵌入式C】你有想过"数组下标"为何从0开始吗?

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值