1总架构
1.1总架构框图
1.2抽象层说明
操作系统抽象层
整洁的嵌入式架构会引入操作系统抽象层(OSAL),将软件与操作系统分隔开。 在某些情况下,实现这个抽象层就像给函数改个名字那么简单。另一些情况下,则需要将几个函数封装在一起。OSAL还可以帮助高价值的应用程序实现在目标平台、目标操作系统之外进行测试。
模块抽象层
嵌入式架构会在驱动模块以上,进行功能的整合,实现具体的外设模块。外设模块存在多种型号,实现方式会有所区别。模块抽象层隐藏具体的模块实现,对上提供统一的功能服务。
硬件抽象层
软件与固件之间的边界被称为硬件抽象层(HAL),不要向上层的用户暴露硬件细节,软件与固件之间的分割线往往没有代码与硬件之间的分割线那么清晰 ,为了给他上层的软件提供服务,以便隐藏具体的实现细节 。
HAL层是按照应用程序的需要来提供服务的。在硬件层里包括处理器的实现。在整洁的嵌入式架构中,我们会将这些用于设备访问的寄存 器访问集中在一起,并将其限制在固件层中。如果我们需要使用微处理器,固件就必须将这类底层函数隔离成处理器抽象层。使用PAL的固件代码就可以在目标平台之外被测试了。
2分层说明
2.1FlowControl
任务文件夹
以任务来划分文件,以通信处理为例。从buff取出数据,解析及调用相应处理函数在InstrExpTask。
2.2FuntionApp
App基于module层接口,对单片机控制板级多个外设资源组件进行功能流程包装。并为任务流程提供调用接口。
以应用划分文件。具体以通信处理为例。升级指令的处理函数在UpdateApp。
流程和功能都在App层。
在任务和功能,不要直接使用硬件挂钩的名称,避免app和硬件绑定。例如控制各种亮灯方式的App,不要直接写为LedApp,可考虑LightAlarmApp,以后移植功能时如果另一个板子不使用led提示,使用数码管提示也能兼容。
2.3Rtos
操作系统文件夹
封装操作系统虚拟层
2.4Module
单元(模块)文件夹。基于driver层包装的接口,进行板级外设配置。以单元功能划分函数。
例如步进电机为一个模块,而控制电机的I2c接口则在driver
封装模块虚拟层。
struct cola_device_ops
{
int (*init) (cola_device_t *dev);
int (*open) (cola_device_t *dev, int oflag);
int (*close) (cola_device_t *dev);
int (*read) (cola_device_t *dev, int pos, void *buffer, int size);
int (*write) (cola_device_t *dev, int pos, const void *buffer, int size);
int (*peek) (cola_device_t *dev, int pos, void *buffer, int size);
int (*control)(cola_device_t *dev, int cmd, void *args);
int (*config) (cola_device_t *dev, void *args, void *var);
};
虚拟层以下对接具体实现函数。
2.5Driver
驱动层主要为单片机外设接口包装,此部分在厂家提供的驱动开发包基础上进行开发,后续代码调用基于该包装接口。
Spi,can,sdio,io等管脚相关的驱动。
封装驱动虚拟层。
2.6Bsp
板级支持包
STM32H7xx_HAL_Driver,CORE等官方提供的板级支持包里的内容
2.7Lib和公共模块
应用到开源的Lib和已有的公共模块不需要划分单独的层,根据功能放到对应层里。
例如使用到开源的加密算法,属于Module层。
2.8分层注意事项
App和Module的划分思路:app会涉及到流程,多模块的组合处理。如果是在任务里的简单模块调用,可以直接调用module层的接口函数。例如收到读eeprom配置信息的命令(InstrExe任务),可调用module的EepromModule。
Module,Driver,Bsp层之间,最终要禁止隔层调用函数。该要求当前可适当放松,但写代码时尽量避免隔层调用函数。