1. 程式人生 > >【linux】驅動-1-環境準備

【linux】驅動-1-環境準備

[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) *