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


前言

  • 以野火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 //gitee.com/Embedfire/ebf-buster-linux.git
1.1.2.2 編譯內核

編譯內核的步驟過程根據不同官方提供的腳步和Makefile不一樣而不同。以下為野火的i.M 6U編譯linux內核例程。
單獨新建一個工作目錄,將其內核源碼放在該目錄下,切換到內核源碼目錄,找到 make_deb.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

1.2.1 hello 例程分析

這只是一個模塊例程,不含驅動部分
必須內容可分為以下幾點:

  • 入口函數
  • 出口函數
  • 協議

hello_module.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 <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
// 入口函數:安裝驅動時調用的函數
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篇章

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 ,則必須執行第一條命令來生成默認的配置文件。
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 //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 固件 echopath 屬性文件中或將 dtbo 的內容 catdtbo 屬性文件中。

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

參考: