1. LiteOS裸機驅動移植系列
俗話說的好,光說不練假把式,上一個系列 LiteOS內核實戰教程 中講述了內核中任務如何管理、如何使用信號量同步多個任務的運行,如何用互斥鎖保護共享資源,如何申請分配動態內存空間,但是在嵌入式系統中,如果不能將內核有效的應用在實際場景中控制外圍設備,那么一切都是紙上談兵。在這個系列中,本教程將會帶領大家,手把手添加一些常用的外設驅動到LiteOS系統中,掌握外設驅動的移植方法。
2. 何為裸機驅動
驅動層代碼,簡單通俗的來說就是向上給用戶提供一層可以控制設備的API,向下負責和設備打交道,直接操作硬件。
比如LED的驅動代碼可以給用戶提供一個初始化的 API 和打開/關閉的 API ,按鍵的驅動代碼可以提供初始化的 API 和讀取按鍵狀態的 API,LCD的驅動代碼可以提供初始化的 API 和屏幕上顯示相關內容的API,傳感器的驅動代碼可以提供傳感器初始化的API 和讀取數據的 API,等等。
這里以使用 STM32CuebMX 生成的 LED 閃爍的裸機工程為例,其中 Src 目錄下的gpio.c文件就相當於 LED 的驅動層文件,其中提供了 LED 的初始化代碼:

有了該文件,也就是驅動層代碼,我們可以直接調用MX_GPIO_Init來初始化LED。
那么,驅動層代碼從哪里來呢?
如果是比較簡單的外設,比如LED,按鍵這種,只使用了GPIO,可以直接使用STM32CubeMX生成的gpio.c文件和gpio.h文件;
3. 如何移植驅動到LiteOS
復制裸機驅動文件
LiteOS 工程 target 目錄結構如下:

其中和設備驅動相關的有三個文件夾:
- Inc:對應STM32CubeMX生成裸機工程中的Inc
- Src: 對應STM32CubeMX生成裸機工程中的Src
- Hardware:存放自己編寫的設備驅動代碼
復制文件的時候按照情況復制到對應的文件夾即可。
這里LED相關的代碼文件只有gpio.h和gpio.c,所以復制gpio.h到 Inc 文件夾,復制gpio.c到 Src 文件夾。
使用IoT-Studio創建的HelloWorld工程中已經提供好了這兩個文件,了解這個操作即可,不用再次復制。
添加裸機驅動文件路徑
因為 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下(工程中默認已添加,無需重復添加):

LED驅動的gpio.h文件添加到USER_INC下(工程中默認已添加,無需重復添加):

至此,復制文件到LiteOS工程中,並將新復制的文件路徑添加到makefile中,加入工程編譯,就完成了驅動的移植。
4. 外設驅動文件的使用
初始化外設
在使用外設之前,首先需要初始化外設,在LiteOS中,初始化設備有兩種方式:
- 在系統啟動調度之前初始化:設備在系統中隨時可被任意任務使用
- 在任務中初始化:設備一般只在該任務中被使用
舉個例子:
像LED這種的驅動,一般都是任意的任務需要點亮或者關閉LED,沒有專門的LED點亮任務或者關閉任務,在系統啟動調度之前初始化比較好;
像光照強度傳感器這種驅動,一般都是有專門的數據采集任務,專門去讀取傳感器數據,不需要別的線程去調用驅動讀取數據,所以放在該數據采集任務中初始化就可以。
在任務中調用初始化API比較簡單,那么,如何在系統啟動之前調用初始化API呢?
其實,答案就在 Src 文件夾下的main.c中,main函數如下:

可以看到,系統上電后首先調用 HardWare_Init 函數初始化硬件設備,然后初始化內核,初始化shell,最后啟動LOS內核。
同樣在main.c中存放着HardWare_Init函數的實現,來一探究竟:

怎么樣?有沒有驚喜?是不是和裸機工程的main函數開始部分一模一樣?
我們可以將初始化函數盡情的扔到這個函數里,比如LED的初始化函數MX_GPIO_Init(),在系統上電的時候自動將LED初始化,是不是很爽。
修復gpio.c文件中的小bug
在IoT Studio默認提供的gpio.c文件的MX函數中,沒有對 LED 的引腳 PC13 進行初始化,手動添加如下的初始化代碼:

操作外設
接下來首先創建一個文件夾,用於存放本系列教程實驗的代碼:


在該文件夾中創建一個文件:

編寫代碼:
#include <osal.h>
#include <gpio.h>
static int led_blink_entry()
{
while (1)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
osal_task_sleep(1*1000);
}
}
int standard_app_demo_main()
{
osal_task_create("led_blink",led_blink_entry,NULL,0x400,NULL,2);
return 0;
}
然后按照之前的方法,在 user_demo.mk 中將led_driver_demo.c文件添加到makefile中,加入編譯:

最后在.sdkconfig中配置開啟宏定義:

編譯,燒錄,即可看到LED開始閃爍:

