【linux】驅動-1-環境準備
阿新 • • 發佈:2021-03-17
[toc]
---
## 前言
* 以野火i.M 6U為例
## 1. 開發環境搭建
**驅動執行條件**:
* 裝置驅動是具有獨立功能的程式,它可以被單獨編譯,但不能獨立執行, 在執行時它被連結到核心作為核心的一部分在核心空間執行。
* **因此想要我們寫的核心模組在某個版本的核心上執行, 那麼就必須在該核心版本上編譯它,如果我們編譯的核心與我們執行的核心具備不相同的特性,裝置驅動則可能無法執行。**
**驅動簡要編譯步驟**:
* 首先我們需要知道核心版本,並準備好該版本的核心原始碼,使用交叉編譯工具編譯核心原始碼。
* 其次,依賴編譯的核心原始碼編譯我們的驅動模組以及裝置樹檔案。
* 最終將驅動模組和裝置樹拷貝到開發板上執行。
### 1.1 環境準備
#### 1.1.1 安裝工具
在編譯原始碼前需要準備好交叉編譯環境,安裝必要的依賴和工具,如:
* **gcc-arm-linux-gnueabihf** 交叉編譯器
* **bison** 語法分析器
* **flex** 詞法分析器
* **libssl-dev OpenSSL** 通用庫
* **lzop LZO**壓縮庫的壓縮軟體
參考命令:
* **`sudo apt install make gcc-arm-linux-gnueabihf gcc bison flex libssl-dev dpkg-dev lzop`**
#### 1.1.2 編譯核心
編譯好核心,有以下兩個用途:
* 製作系統映象,燒錄至開發板
* 保留一份在開發環境的系統中,用於輔助驅動開發
##### 1.1.2.1 獲取核心原始碼
若核心已經燒寫至開發板上,則可以通過命令 **`uname -a`** 檢視核心版本。
*
知道核心版本後可在其官網上下載其核心原始碼,如並章節以版本為 **Linux npi 4.1.9.71-imx-r1** 為例,可在gitee或github上下載(*野火官方提供*)
* 命令:**`git clone https://gitee.com/Embedfire/ebf-buster-linux.git`**
##### 1.1.2.2 編譯核心
編譯核心的步驟過程根據不同官方提供的腳步和Makefile不一樣而不同。以下為野火的i.M 6U編譯linux核心例程。
單獨新建一個工作目錄,將其核心原始碼放在該目錄下,切換到核心原始碼目錄,找到 **make_deb.sh** 指令碼,修改裡面的配置引數,如核心編譯位置等等。修改好配置引數後,只需要執行指令碼即可編譯核心。(***其它核心可以參考該指令碼,也可以自己手寫一個編譯指令碼***)
```sh
deb_distro=bionic
DISTRO=stable
build_opts="-j 6"
build_opts="${build_opts} O=build_image/build"
build_opts="${build_opts} ARCH=arm"
build_opts="${build_opts} KBUILD_DEBARCH=${DEBARCH}"
build_opts="${build_opts} LOCALVERSION=-imx-r1"
build_opts="${build_opts} KDEB_CHANGELOG_DIST=${deb_distro}"
build_opts="${build_opts} KDEB_PKGVERSION=1${DISTRO}"
build_opts="${build_opts} CROSS_COMPILE=arm-linux-gnueabihf-"
build_opts="${build_opts} KDEB_SOURCENAME=linux-upstream"
make ${build_opts} npi_v7_defconfig
make ${build_opts}
make ${build_opts} bindeb-pkg
```
* **`O=build_image/build`**:指定編譯好的核心放置的位置。
* **`ARCH=arm`**:目標是 ARM 體系結構核心。
* **`KBUILD_DEBARCH=${DEBARCH}`**:對於deb-pkg目標,允許覆蓋deb-pkg部署的常規啟發式。
* **`LOCALVERSION=-imx-r1`**:使用核心配置選項 "LOCALVERSION" 為常規核心版本附加一個唯一的字尾。
* **`KDEB_CHANGELOG_DIST=${deb_distro}`**:
* **`KDEB_PKGVERSION=1${DISTRO}`**:版本資訊。
* **`CROSS_COMPILE=arm-linux-gnueabihf-`**:指定交叉編譯器。
* **`KDEB_SOURCENAME=linux-upstream`**:KDEB_SOURCENAME make變數僅控制已打包的源tarball的名稱,並不影響bind -pkg和deb-pkg輸出的.deb包名稱。
* **`make ${build_opts} npi_v7_defconfig`**:生成配置檔案。
* **`make ${build_opts} bindeb-pkg`**:編譯檔案進行打包。
### 1.2 核心驅動模組編譯和載入
**hello** 例程可以去 [李柱明的gitee clone: demo_code_for_mystudy/linux/driverTest/helloModule](https://gitee.com/lidreaming/demo_code_for_mystudy.git)
#### 1.2.1 hello 例程分析
**這只是一個模組例程,不含驅動部分**
必須內容可分為以下幾點:
* 入口函式
* 出口函式
* 協議
hello_module.c
```c
/** @file hello_module.c
* @brief 簡要說明
* @details 詳細說明
* @author lzm
* @date 2021-02-21 18:08:07
* @version v1.0
* @copyright Copyright By lizhuming, All Rights Reserved
*
**********************************************************
* @LOG 修改日誌:
**********************************************************
*/
#include
#include
#include
// 入口函式:安裝驅動時呼叫的函式
static int __init hello_init(void)
{
printk(KERN_EMERG "[ KERN_EMERG ] Hello Module Init\n");
printk( "[ default ] Hello Module Init\n");
return 0;
}
// 出口函式:解除安裝驅動時呼叫的函式
static void __exit hello_exit(void)
{
printk("[ default ] Hello Module Exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
//MODULE_LICENSE("GPL2");
MODULE_AUTHOR("embedfire ");
MODULE_DESCRIPTION("hello world module");
MODULE_ALIAS("test_module");
```
#### 1.2.2 和核心原始碼一起編譯
#### 1.2.3 載入核心驅動模組
編譯好得到的核心驅動模組 xx.ko 可以通過多種方式拷貝到 ARM 板上,如NFS網路檔案系統、SCP命令得到。
掛載方法可以參考[李柱明部落格園NFS篇章](https://www.cnblogs.com/lizhuming/p/13946107.html)。
### 1.3 裝置樹編譯和載入
裝置樹是在 Linux3.x 才引入的,用於描述一個硬體平臺的板級細節。
*本系列筆記的驅動例程如無特殊說明,都是依賴於裝置樹的*。
下面簡略演示裝置樹的編譯和載入,具體原理由具體篇章說明。
#### 1.3.1 裝置樹編譯
##### 1.3.1.1 使用核心中的dtc根據編譯
編譯後的核心會自動生成 **dtc** 工具。其路徑是:**核心/scripts/dtc/dtc**。
編譯命令:**`核心構建目錄/scripts/dtc/dtc -I dts -O dtb -o xxx.dtbo xxx.dts`**
* 意為編譯 dts 為 dtb
##### 1.3.1.2 在核心原始碼中編譯(推薦)
編譯核心時都會自動編譯裝置樹,此時,只需要把裝置樹原始檔放到規定位置即可,裝置樹原始檔、編譯生成的裝置樹檔案及我們所用到的裝置樹檔案都會存放在 **核心原始碼/arch/arm/boot/dts** 裡面。但是,編譯核心耗時長,所以,推薦只編譯裝置樹,方法如下:
* 兩條命令都在核心原始碼頂層路徑下執行(*其實就是利用頂層Makefile*):
* 如果在核心原始碼中執行了 **make distclean** ,則必須執行第一條命令來生成預設的配置檔案。
```sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- npi_v7_defconfig
make ARCH=arm -j4 CROSS_COMPILE=arm-linux-gnueabihf- dtbs
```
##### 1.3.1.3 載入裝置樹
替換裝置樹的方法:
* 第一種:裝置樹是編譯到核心中的,所以,重新編譯核心,重新制作映象即可。(麻煩,不推薦)
* 第二種:將編譯好的**裝置樹或裝置樹外掛**替換到開發板裡面的。(推薦)
* 第三種:將編譯好的裝置樹放到開發板中,**/boot/dtbs/xxx/,修改boot啟動引數。(推薦)
檢視是否載入成功:
* 進入 **/proc/device-tree** 目錄下檢視已載入的裝置節點,看看有沒有改動。
### 1.4 裝置樹外掛的編譯和載入
Linux4.4 以後引入了動態裝置樹,裝置樹外掛被動態的載入到系統中,供核心識別。
裝置樹外掛一般用於只修改新增部分硬體資訊。如只新增 RGB 燈的硬體資訊,就只需要編譯 RGB 燈的 **.dts** 檔案為 **.dtbo** 即可。
編譯裝置樹外掛的時候,無需重新編譯整個裝置樹外掛,只需要編譯修改的部分即可。
#### 1.4.1 單獨使用dtc工具編譯
裝置樹和裝置樹外掛都是使用 DTC 編譯工具編譯。
裝置樹編譯後得到的是 **.dtb** 檔案;
而裝置樹外掛編譯後得到的是 **.dtbo** 檔案。
使用野火提供的一鍵式編譯工具:
* 地址:[git clone https://gitee.com/Embedfire/ebf-linux-dtoverlays.git](https://gitee.com/Embedfire/ebf-linux-dtoverlays.git)
* 要編譯的裝置樹外掛原始檔放在 **ebf-linux-dtoverlays/overlays/ebf** 目錄下, 然後回到編譯工具的根目錄 **ebf-linux-dtoverlays/** 執行“make”即可。
* 生成的.dtbo位於 **~/ebf-linux-dtoverlays/output** 目錄下。
* 需要注意的是,如果你在執行“make”後出現報錯,可以嘗試先解除安裝device-tree-compiler(解除安裝命令為:“sudo apt-get autoremove device-tree-compiler”), 重新安裝,然後在“ebf-linux-dtoverlays/basic/fixdep檔案的許可權, 修改許可權命令為:“chmod 777 scripts/basic/fixdep”。
#### 1.4.2 核心dtc工具編譯裝置樹外掛
編譯裝置樹外掛和編譯裝置樹類似,這裡使用核心中的dtc工具編譯編譯裝置樹外掛。
編譯命令:**`核心構建目錄/scripts/dtc/dtc -I dts -O dtb -o xxx.dtbo xxx.dts`**
* 意為編譯 dts 為 dtbo
#### 1.4.3 載入裝置樹外掛
先拷貝裝置樹外掛檔案到開發板上。
##### 1.4.3.1 使用 echo 命令載入
先在 **/sys/kernel/config/device-tree/overlays/下建立一個新目錄**,名字自定義。
然後將 **dtbo** 韌體 **echo** 到 **path** 屬性檔案中或將 **dtbo** 的內容 **cat** 到 **dtbo** 屬性檔案中。
```sh
echo xxx.dtbo > /sys/kernel/config/device-tree/overlays/xxx/path
# 或
cat xxx.dtbo >/sys/kernel/config/device-tree/overlays/xxx/dtbo
```
刪除裝置外掛:**`rmdir /sys/kernel/config/device-tree/overlays/xxx`**。
##### 1.4.3.2 uboot 載入
不同的板子可能不支援。
修改環境變數檔案即可,進入/boot目錄下 修改 **vim uEnv.txt**
## 參考:
* [李柱明部落格園](https://www.cnblogs.com/lizhuming/p/14545835.html)
*