LiteOS学习笔记-2外设驱动移植方法
此文参考华为云官方社区多篇文章,如有侵权,请联系删除。
一、裸机驱动是什么?
驱动层代码,简单通俗的来说就是向上给用户提供一层可以控制设备的API,向下负责和设备打交道,直接操作硬件。
比如LED的驱动代码可以给用户提供一个初始化的 API 和打开/关闭的 API ,按键的驱动代码可以提供初始化的 API 和读取按键状态的 API,LCD的驱动代码可以提供初始化的 API 和屏幕上显示相关内容的API,传感器的驱动代码可以提供传感器初始化的API 和读取数据的 API,等等。
这里以使用 STM32CuebMX 生成的 LED 闪烁的裸机工程为例,其中 Src
目录下的gpio.c
文件就相当于 LED 的驱动层文件,其中提供了 LED 的初始化代码:
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = LED_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);
}
如果是比较简单的外设,比如LED,按键这种,只使用了GPIO,可以直接使用STM32CubeMX生成的gpio.c文件和gpio.h文件;
如果是比较复杂的外设,比如LCD的底层是使用SPI驱动的,那么除了 STM32CubeMX 生成的spi.h和spi.c文件,还需要自己在此基础上手写LCD屏幕的驱动文件。
二、移植步骤
1.复制裸机驱动文件
其中和设备驱动相关的有三个文件夹:
- Inc:对应STM32CubeMX生成裸机工程中的Inc
- Src: 对应STM32CubeMX生成裸机工程中的Src
- Hardware:存放自己编写的设备驱动代码
复制文件的时候按照情况复制到对应的文件夹即可。如LED相关的代码文件只有gpio.h和gpio.c,所以复制gpio.h到 Inc 文件夹,复制gpio.c到 Src 文件夹。
2.添加裸机驱动文件路径
因为 LiteOS 的整个项目工程使用 make 构建,所以复制驱动文件之后,需要添加驱动文件的路径到 makefile 中,加入编译。
project.mk文件指明了工程中所有文件的路径。
在该文件中:
C文件路径
- HARDWARE_SRC:对应Hardware文件夹下的Src文件夹
- USER_SRC:对应Src文件夹
头文件路径 - HARDWARE_INC:对应Hardware文件夹下的Inc文件夹
- USER_INC:对应Inc文件夹
如LED驱动的gpio.c文件默认已添加到USER_SRC下,gpio.h文件添加到USER_INC下。
至此,复制文件到LiteOS工程中,并将新复制的文件路径添加到makefile中,加入工程编译,就完成了驱动的移植。
三、使用驱动
1. 初始化外设
在使用外设之前,首先需要初始化外设,在LiteOS中,初始化设备有两种方式:
- 在系统启动调度之前初始化:设备在系统中随时可被任意任务使用。如LED可能在任意任务中调用以打开关闭LED。
在任务中初始化:设备一般只在该任务中被使用。如像光照强度传感器这种驱动,一般都是有专门的数据采集任务,专门去读取传感器数据,不需要别的线程去调用驱动读取数据,所以放在该数据采集任务中初始化就可以。
在系统启动之前调用初始化API
在 Src 文件夹下的main.c中,main函数如下:
int main(void)
{
UINT32 uwRet = LOS_OK;
HardWare_Init();
uwRet = LOS_KernelInit();
if (uwRet != LOS_OK)
{
return LOS_NOK;
}
extern void shell_uart_init(int baud);
shell_uart_init(115200);
if(!link_test())
{
LCD_ShowString(30, 170, 240, 16, 16, "Connect NET OK");
}
(void)LOS_Start();
return 0;
}
可以看到,系统上电后首先调用 HardWare_Init 函数初始化硬件设备,然后初始化内核,初始化shell,初始化网络连接,最后启动LOS内核。
HardWare_Init函数的实现
VOID HardWare_Init(VOID)
{
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_SPI2_Init();
dwt_delay_init(SystemCoreClock);
LCD_Init();
LCD_Clear(BLACK);
POINT_COLOR = GREEN;
LCD_ShowString(30, 170, 240, 16, 16, "Connecting NET......");
}
2. 调用外设
创建文件夹,在文件夹下创建源文件用以编写相关代码。
将源文件添加到makefile中
修改config文件添加对应宏
四、小熊派E53扩展板
E53接口
E53接口标准的E取自扩展(Expansion)的英文首字母,板子的尺寸为5×3cm,故采用E53作为前缀来命名尺寸为 5cm*3cm 类型的案例扩展板,任何一款满足标准设计的开发板均可直接适配E53扩展板。
E53扩展板是根据不同的应用场景来设计的,以最大的程度在扩展板上还原真实应用场景,不同案例的扩展板根据不同的应用场景来命名后缀。例如:E53_SC1,SC是智慧城市(Smart City)的缩写,SC1表示的是智慧城市中的智慧路灯,再比如SC2则表示的是智慧城市中的智慧井盖。
E53扩展接口在电气特性上,包含了常用的物联网感知层传感器通信接口,比如5V、3.3V、GND、SPI、UART、IIC、ADC、DAC等等,可以适配各种传感器,还留有4个普通GPIO,如图:
移植使用
参照上述步骤即可完成扩展板移植,然而除了操作project.mk
外,可在userdemo.mk
中动态添加。直接在user_demo.mk
中配置,只有当开启了该demo后,才会添加这些驱动文件路径,不会造成冲突。
#example for oc_agriculture_template
ifeq ($(CONFIG_USER_DEMO), "oc_agriculture_template")
user_demo_src = ${wildcard $(TARGET_DIR)/Demos/oc_agriculture_template/*.c}
user_demo_inc = -I $(TARGET_DIR)/Demos/oc_agriculture_template
user_hardware_src = ${wildcard $(TARGET_DIR)/Hardware/E53_IA1/*.c}
user_hardware_inc = -I ${wildcard $(TARGET_DIR)/Hardware/E53_IA1}
user_demo_defs = -D CONFIG_OC_ARRICULTURE_DEMO_ENABLE=1
endif