最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

基于imx8m plus開發(fā)板全體系開發(fā)教程4:Linux系統(tǒng)開發(fā)

2023-04-14 11:33 作者:華清遠(yuǎn)見研發(fā)中心  | 我要投稿

前言:

i.MX8M Plus 開發(fā)板是一款擁有 4 個(gè) Cortex-A53 核心,運(yùn)行頻率 1.8GHz;1 個(gè) Cortex-M7 核心,運(yùn)行頻率 800MHz;此外還集成了一個(gè) 2.3 TOPS 的 NPU,大大加速機(jī)器學(xué)習(xí)推理。

?

全文所使用的開發(fā)平臺(tái)均為與NXP官方合作的FS-IMX8MPCA開發(fā)板(華清遠(yuǎn)見imx8mp開發(fā)板),支持Weston、ubuntu20.04、Android11 等操作系統(tǒng);同時(shí)支持 Xenomai 硬實(shí)時(shí)內(nèi)核、EtherCAT 總線、TSN 時(shí)間敏感網(wǎng)絡(luò)、ROS1.0、ROS2.0 等工業(yè)與機(jī)器人領(lǐng)域應(yīng)用;可以用于工業(yè)互聯(lián)網(wǎng)、人工智能、邊緣計(jì)算、多屏異顯等應(yīng)用方向。華清遠(yuǎn)見研發(fā)中心編寫了大量開發(fā)教程并錄制了豐富視頻教學(xué)資源免費(fèi)提供給大家!

開發(fā)板更多資料可關(guān)注華清遠(yuǎn)見在線實(shí)驗(yàn)室(微信號(hào):hqyjlab)領(lǐng)取~~~

Linux 系統(tǒng)開發(fā)

TF-A 編譯

配置交叉編譯工具鏈

在進(jìn)行源碼編譯之前需要先導(dǎo)入交叉編譯工具鏈,之前章節(jié)已經(jīng)介紹過具體安裝過程,這里不再贅述,如果還沒有安裝可參考《交叉編譯工具鏈安裝》章節(jié)

linux@ubuntu:$ source /opt/fsl-imx-xwayland/5.4-zeus/environment-setup-aarch64-poky-lin

ux

linux@ubuntu:$ $CC --version

編譯 TF-A 編譯

將當(dāng)前工作目錄切換到 TF-A 源碼目錄下,這里為“~/workdir/imx8mp/imx-yocto-bsp/bsp

_source/imx-atf”

linux@ubuntu:$ cd ~/workdir/imx8mp/imx-yocto-bsp/bsp_source/imx-atf

編譯之前可以先清除之前的緩存

linux@ubuntu:$ make clean PLAT=imx8mp

編譯

linux@ubuntu:$ LDFLAGS="" make PLAT=imx8mp

編譯成功后在 build/imx8mp/release/目錄下生成相關(guān)鏡像

Bootloader 的編譯與運(yùn)行

配置交叉編譯工具鏈

在進(jìn)行源碼編譯之前需要先導(dǎo)入交叉編譯工具鏈,之前章節(jié)已經(jīng)介紹過具體安裝過程,

這里不再贅述,如果還沒有安裝可參考《交叉編譯工具鏈安裝》章節(jié)

linux@ubuntu:$ source /opt/fsl-imx-xwayland/5.4-zeus/environment-setup-aarch64-poky-lin

ux

linux@ubuntu:$ $CC --version

Bootloader編譯

將當(dāng)前工作目錄切換到 bootloader 源碼目錄下,這里為“~/workdir/imx8mp/bsp_source/u

boot-imx”

linux@ubuntu:$ cd ~/workdir/imx8mp/bsp_source/uboot-imx

? 配置

linux@ubuntu:$ make imx8mp_ai_robot_defconfig

? 編譯

linux@ubuntu:$ make

編譯成功后在 spl 目錄下生成 u-boot-spl.bin 相關(guān)鏡像,在根目錄下生成 u-boot.img 鏡像

制作 imx-boot

在我們前面編譯的標(biāo)準(zhǔn) u-boot 無法自動(dòng)啟動(dòng)設(shè)備,imx8mp 需要通過 imx-mkimage 構(gòu)建

imx-boot。

imx-boot 鏡像包括 U-boot、tf-a、uboot spl 和 ddr 固件。因此我們需要將前面編譯的 uboot-imx 鏡像和 imx-atf 以及 ddr 固件復(fù)制到 imx-boot/iMX8M 目錄下來制作 imx-boot 鏡像。

linux@ubuntu:$ cd ~/workdir/imx8mp/bsp_source/imx-boot

? 復(fù)制 u-boot 鏡像

linux@ubuntu:$ cp ../u-boot-imx/u-boot-nodtb.bin iMX8M/

linux@ubuntu:$ cp ../u-boot-imx/spl/u-boot-spl.bin iMX8M/

linux@ubuntu:$ cp ../u-boot-imx/tools/mkimage iMX8M/mkimage_uboot

linux@ubuntu:$ cp ../u-boot-imx/arch/arm/dts/imx8mp-ai-robot.dtb iMX8M/

? 復(fù)制 DDR 固件

linux@ubuntu:$ cp ../firmware-imx-8.10/firmware/ddr/synopsys/ddr4_*_202006* iMX8M/

? 復(fù)制 tf-a 鏡像

linux@ubuntu:$ cp ../imx-atf/build/imx8mp/release/bl31.bin iMX8M/

? 編譯生成 imx-boot

linux@ubuntu:$ make SOC=iMX8MP flash_ai_robot

編譯成功之后會(huì)在 iMX8M 目錄下生成 flash.bin 文件,使用此文件通過 uuu 工具燒錄到

開發(fā)板便可使用自己編譯的 u-boot 和 tf-a 鏡像啟動(dòng)開發(fā)板。

dos@windows:$ uuu -b emmc flash.bin

u-boot 常用命令介紹

linux 系統(tǒng)環(huán)境變量

linux 下的環(huán)境變量可以通過在 u-boot 階段進(jìn)行設(shè)置,在 u-boot 啟動(dòng)過程中倒計(jì)時(shí)結(jié)束之

前按任意鍵停在 u-boot 進(jìn)行環(huán)境變量設(shè)置。

如果要查看當(dāng)前環(huán)境變量可以使用“print”命令

如果想要恢復(fù)至出廠時(shí)的環(huán)境變量可以使用“env default -f -a”命令進(jìn)行重置

如果想要保存當(dāng)前的環(huán)境變量可以使用“saveenv”進(jìn)行保存。

a) 設(shè)置 linux 內(nèi)核加載地址

? linux 內(nèi)核加載地址

u-boot=> setenv loadaddr 0x80080000

? 設(shè)備樹加載地址

u-boot=> setenv fdtaddr 0x80f00000

? 設(shè)備樹文件名稱

u-boot=> setenv fdt_file imx8mp-evk.dtb

b) 顯示設(shè)置

? HDMI 顯示

u-boot=> setenv fdt_file imx8mp-ai-robot.dtb

? LVDS 和 HDMI 雙屏顯示

u-boot=> setenv fdt_file imx8mp-ai-robot-lvds070.dtb

? MIPI 和 HDMI 雙屏顯示

u-boot=> setenv fdt_file imx8mp-ai-robot-mipi070.dtb

? LVDS、MIPI 和 HDMI 三屏顯示

u-boot=> imx8mp-ai-robot-mipi-lvds-dual.dts

c) 設(shè)置跟文件系統(tǒng)位置

? 通過 NFS 掛載

u-boot=> setenv rootfsinfo 'root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp'

u-boot=> setenv rootfsinfo 'root=/dev/nfs ip=dhcp weim-nor nfsroot=${serverip}:${nfsroo

t},v3,tcp'

? 通過 eMMC 掛載

u-boot=> setenv rootfsinfo 'root=/dev/mmcblk0p2 rootwait rw' /* eMMC */

常用命令介紹

uboot 命令類似于 linux 行緩沖命令行,當(dāng)我們向終端命令行輸入命令的時(shí)候,這些命令沒有立即被系統(tǒng)識(shí)別,而是被緩沖到一個(gè)緩存區(qū)(也就是系統(tǒng)認(rèn)為我換沒有輸入完),當(dāng)我們按下回車鍵(換行)后,系統(tǒng)就認(rèn)為輸入完了,然后將緩沖區(qū)中所有剛才輸入的命令拿去處理。

? 第一個(gè)命令:printenv/print

printenv 命令不用帶參數(shù),作用是打印出系統(tǒng)中所有的環(huán)境變量。

printenv 環(huán)境變量名 查看指定的環(huán)境變量值。

? 常用環(huán)境變量

bootdelay uboot 啟動(dòng)后,倒計(jì)時(shí)多少秒后自動(dòng)執(zhí)行環(huán)境變量 bootcmd 的語句

bootcmd 倒計(jì)時(shí)到 0 后,自動(dòng)執(zhí)行里面的語句

bootargs 是用于提供給內(nèi)核的啟動(dòng)參數(shù)語句

ipaddr 當(dāng)前開發(fā)板的 IP 地址

? 設(shè)置添加/更改環(huán)境變量:setenv/set

用法:set name value

例如:set bootdelay 3

? 保存環(huán)境變量的更改:saveenv/save

saveenv/save 作用是將內(nèi)存中的環(huán)境變量的值同步保存到 flash 中環(huán)境變量的分區(qū)

? 網(wǎng)絡(luò)測試指令:ping

用法:ping IP 地址

此命令需要先設(shè)置好開發(fā)板的網(wǎng)絡(luò)環(huán)境,包括網(wǎng)關(guān),子網(wǎng)掩碼,本機(jī) IP 地址。之后才可以使用該命令。

? tftp 下載命令

用于通過 tftp 協(xié)議從 tftp 服務(wù)器上下載文件。

eg: tftp 0x40480000 Image 將 tftp 服務(wù)器上的 Image 文件下載到本地內(nèi)存的

0x40480000 地址處。

? 內(nèi)存操作指令:mw、md

md 內(nèi)存地址 用于查看內(nèi)存地址上的值

md.b 0x40008000 100 從內(nèi)存地址 0x40008000 開始,查看 0x100 個(gè)字節(jié)并輸出值

md.w 0x40008000 100 從內(nèi)存地址 0x40008000 開始,查看 0x100 個(gè) 16 位值并輸出值

md.l 0x40008000 100 從內(nèi)存地址 0x40008000 開始,查看 0x100 個(gè) 32 位值并輸出值

mw 用于修改內(nèi)存地址上的值

mw.b x40008000 0xab 100 從內(nèi)存地址 0x40008000 開始的 0x100 字節(jié)空間,設(shè)值為 0xab

mw.w 0x40008000 0xabcd 100 從內(nèi)存地址 0x40008000 開始的 0x200 字節(jié)空間,每 16 位值設(shè)為 0xabcd

mw.l 0x40008000 0xabcdef88 100 從內(nèi)存地址 0x40008000 開始的 0x400字節(jié)空間,每 32 位值設(shè)為 0xabcdef88

? 幫助指令

上面介紹的指令為 bootloader 中常用的一些指令介紹,如果需要使用其它指令,可以通

過 help 命令來查看具體描述及用法。

Linux 內(nèi)核源碼編譯

配置交叉編譯工具鏈

在進(jìn)行源碼編譯之前需要先導(dǎo)入交叉編譯工具鏈,之前章節(jié)已經(jīng)介紹過具體安裝過程,

這里不再贅述,如果還沒有安裝可參考《交叉編譯工具鏈安裝》章節(jié)

linux@ubuntu:$ source /opt/fsl-imx-xwayland/5.4-zeus/environment-setup-aarch64-poky-lin

ux

linux@ubuntu:$ $CC --version

linux 編譯

將當(dāng)前工作目錄切換到 linux 內(nèi)核源碼目錄下,這里為“~/workdir/imx8mp/imx-yocto-bsp

/bsp_source/ linux-imx”?

linux@ubuntu:$ cd ~/workdir/imx8mp/imx-yocto-bsp/bsp_source/linux-imx

添加 nxp 官方標(biāo)準(zhǔn) imx_v8 配置

linux@ubuntu:$ make imx_v8_defconfig

添加自定義配置

linux@ubuntu:$ ./scripts/kconfig/merge_config.sh -m .config arch/arm64/configs/aicar.config

添加完配置后我們可以通過 menuconfig 進(jìn)行內(nèi)核配置和裁剪

linux@ubuntu:$ make menuconfig

編譯內(nèi)核文件

linux@ubuntu:$ make

編譯成功后在 arch/arm64/boot/目錄下生成 Image 內(nèi)核鏡像,在arch/arm64/boot/dts/freescale/目錄下生成設(shè)備樹鏡像

單獨(dú)編譯設(shè)備樹文件

linux@ubuntu:$ make dtbs

編譯成功后在 arch/arm64/boot/dts/freescale/目錄下生成設(shè)備樹鏡像

通過 tftp 服務(wù)器更新內(nèi)核鏡像

上面章節(jié)已經(jīng)將 VMware 的橋接網(wǎng)絡(luò)配置好了,本小節(jié)將要通過 TFTP 服務(wù)器來下載內(nèi)核及設(shè)備樹,我們分為兩部分介紹,第一部分通過網(wǎng)線直連電腦的方式進(jìn)行驗(yàn)收,第二部分通過路由器連接開發(fā)板和電腦。

網(wǎng)線直連電腦

這里我們采用的是直連網(wǎng)絡(luò),即開發(fā)板通過網(wǎng)線直連電腦。

首先啟動(dòng) Ubuntu 虛擬機(jī),由于我們采用直連方式,所以虛擬機(jī)無法自動(dòng)獲取到 IP 地址,

需要我們手動(dòng)設(shè)置 IP 地址。

打開虛擬機(jī)的“/etc/network/interfaces”文件

linux@ubuntu:$ sudo vi /etc/network/interfaces

添加如下配置

auto ens33

iface ens33 inet static

address 192.168.100.240

netmask 255.255.255.0

gateway 192.168.100.1

dns-nameserver 192.168.100.1

這里“ens33”代表網(wǎng)卡名,可以通過 ifconfig 命令查看;

address 為要設(shè)置的靜態(tài) IP 地址;

netmask 為子網(wǎng)掩碼

gateway 為網(wǎng)關(guān)地址

設(shè)置完成后重啟網(wǎng)絡(luò)服務(wù)

linux@ubuntu:$ sudo reboot

設(shè)置完成后使用 ifconfig 命令查看當(dāng)前 ubuntu 的 IP 地址。

在開發(fā)板上電之前需將調(diào)試串口、網(wǎng)線接入網(wǎng)口 1。

之后給開發(fā)板上電,使程序停留在 u-boot 終端。

這里我們需要設(shè)置幾個(gè)與網(wǎng)絡(luò)相關(guān)的環(huán)境變量,以支持網(wǎng)絡(luò)傳輸。

在上面我們已經(jīng)設(shè)置好了 ubuntu 的網(wǎng)絡(luò)配置,這里 ubuntu 充當(dāng) TFTP 服務(wù)器。我們需要

按照 ubuntu 的配置來設(shè)置開發(fā)板的環(huán)境變量。

設(shè)置服務(wù)器 IP 地址(ubuntu ip)

u-boot=> setenv serverip 192.168.100.240

設(shè)置本機(jī) IP 地址(開發(fā)板 ip)

u-boot=> setenv ipaddr 192.168.100.241

設(shè)置網(wǎng)關(guān)

u-boot=> setenv gatewayip 192.168.100.1

設(shè)置子網(wǎng)掩碼

u-boot=> setenv netmask 255.255.255.0

設(shè)置網(wǎng)卡 1 MAC 地址

u-boot=> setenv eth1addr 00:04:9f:07:0b:a5

保存環(huán)境變量

u-boot=> saveenv

設(shè)置完成后可以使用 ping 命令來進(jìn)行測試

u-boot=> ping 192.168.100.240

下載 linux 內(nèi)核與設(shè)備樹

在進(jìn)行內(nèi)核下載之前,首先需要確認(rèn) TFTP 服務(wù)器是否已經(jīng)安裝完畢,如果還沒有安裝則需要根據(jù)前面章節(jié)的內(nèi)容進(jìn)行安裝,此外還需要將之前編譯好的 Image linux 內(nèi)核程序與設(shè)備樹文件 imx8mp-ai-robot.dtb 放入 TFTP 服務(wù)器,如果是按照前面教程搭建路徑為【/tftpboot/】

下面在 u-boot 中設(shè)置要下的鏡像名稱和設(shè)備樹名稱

u-boot=> setenv image Image

u-boot=> setenv fdt_file imx8mp-ai-robot.dtb

u-boot=> saveenv

如果希望將下載下來的鏡像文件存儲(chǔ)到指定的存儲(chǔ)設(shè)備,例如外部 sdcard 或者 eMMC,

則需要設(shè)置當(dāng)前存儲(chǔ)設(shè)備。

保存到 eMMC,在開發(fā)板執(zhí)行如下指令

u-boot=> mmc dev 2 0

保存到 SDcard,在開發(fā)板執(zhí)行如下指令

u-boot=> mmc dev 1 0

下載 linux 內(nèi)核文件

u-boot=> tftpboot ${loadaddr} ${image}

下載設(shè)備樹文件

u-boot=> tftpboot ${fdt_addr} ${fdt_file}

啟動(dòng)程序

u-boot=> run mmcargs

u-boot=> booti ${loadaddr} - ${fdt_addr}

通過路由器連接電腦

上小節(jié)講述了如何通過網(wǎng)路直連進(jìn)行 TFTP 服務(wù)器的數(shù)據(jù)傳輸,本小節(jié)則講述如何通過路由器連接。

通過路由器連接與直連其實(shí)差異并不大,只是通過路由器可以使用 DHCP 服務(wù)器,進(jìn)行自動(dòng) IP 地址獲取。

打開虛擬機(jī)的“/etc/network/interfaces”文件

linux@ubuntu:$ sudo vi /etc/network/interfaces

添加如下配置

auto ens33

iface ens33 inet dhcp

這里將“ens33”設(shè)置成了通過 DHCP 自動(dòng)獲取 IP 地址

設(shè)置完成后重啟網(wǎng)絡(luò)服務(wù)

linux@ubuntu:$ sudo reboot

設(shè)置完成后使用 ifconfig 命令查看當(dāng)前 ubuntu 的 IP 地址。

首先啟動(dòng)開發(fā)板,使程序停留在 u-boot 終端。

這里我們需要設(shè)置幾個(gè)與網(wǎng)絡(luò)相關(guān)的環(huán)境變量,以支持網(wǎng)絡(luò)傳輸。

在上面我們已經(jīng)設(shè)置好了 ubuntu 的網(wǎng)絡(luò)配置,這里 ubuntu 充當(dāng) TFTP 服務(wù)器。我們需要按照 ubuntu 的配置來設(shè)置開發(fā)板的環(huán)境變量。

設(shè)置服務(wù)器 IP 地址(ubuntu ip)?

u-boot=> setenv serverip 192.168.101.47

設(shè)置網(wǎng)卡 1 MAC 地址

u-boot=> setenv eth1addr 00:04:9f:07:0b:a5

保存環(huán)境變量

u-boot=> saveenv

下載 linux 內(nèi)核與設(shè)備樹

在進(jìn)行內(nèi)核下載之前,首先需要確認(rèn) TFTP 服務(wù)器是否已經(jīng)安裝完畢,如果還沒有安裝則需要根據(jù)前面章節(jié)的內(nèi)容進(jìn)行安裝,此外還需要將之前編譯好的 Image linux 內(nèi)核程序與設(shè)備樹文件 imx8mp-ai-robot.dtb 放入 TFTP 服務(wù)器,如果是按照前面教程搭建路徑為【/tftpboot/】

下面在 u-boot 中設(shè)置要下的鏡像名稱和設(shè)備樹名稱

u-boot=> setenv image Image

u-boot=> setenv fdt_file imx8mp-ai-robot.dtb

u-boot=> saveenv

這里與直連網(wǎng)路不同的是,不再需要指定本機(jī) ip、網(wǎng)關(guān)、子網(wǎng)掩碼等環(huán)境變量,這些信

息只需要通過 dhcp 獲取即可

下載 linux 內(nèi)核文件

u-boot=> dhcp ${loadaddr} ${image}

下載設(shè)備樹文件

u-boot=> dhcp ${fdt_addr} ${fdt_file}

啟動(dòng)程序

u-boot=> run mmcargs

u-boot=> booti ${loadaddr} - ${fdt_addr}

基于 busybox 的最小文件系統(tǒng)制作

busybox 源碼編譯及安裝

可以從 http://busybox.net/downloads/網(wǎng)站下載 busybox-1.29.3 源碼用于制作 Linux 文件系

統(tǒng),為了方便,已將源碼放進(jìn)了光盤。

安裝交叉編譯工具鏈。

linux@ubuntu:$ sudo apt-get install gcc-aarch64-linux-gnu

linux@ubuntu:$ sudo apt-get install g++-aarch64-linux-gnu

linux@ubuntu:$ sudo apt-get install libncurses5-dev libncursesw5-dev

驗(yàn)證開發(fā)工具是否安裝正確,顯示版本信息如下圖所示。

linux@ubuntu:$ aarch64-linux-gnu-gcc -v

建立源碼目錄

將【華清遠(yuǎn)見-I.MX8M Plus 開發(fā)資料-2021-06-02\程序源碼\busybox】下的 busybox-1.29.

3.tar.bz2 拷貝至該目錄。

linux@ubuntu:$ tar xvf busybox-1.29.3.tar.bz2 //解壓源碼

linux@ubuntu:$ cd busybox-1.29.3

配置 busybox 源碼:

將頂層目錄下的 Makefile 文件中的 CROSS_COMPILE 字段修改為“aarch64-linux-gnu-”

可以使用如下命令配置源碼

linux@ubuntu:$ make ARCH=arm64 menuconfig

選擇退出,選擇保存

編譯源碼:

linux@ubuntu:$ make

安裝:

busybox 默認(rèn)安裝路徑為源碼目錄下的_install

linux@ubuntu:$ make install

進(jìn)入安裝目錄可看到如下目錄:

linux@ubuntu:$ cd _install

linux@ubuntu:$ ls

bin linuxrc sbin usr

添加主要系統(tǒng)啟動(dòng)文件

創(chuàng)建其他需要的目錄:?

linux@ubuntu:$ cd _install

linux@ubuntu:$ mkdir dev etc mnt proc var tmp sys root

添加庫:

將工具鏈中的庫拷貝到_install 目錄下:

linux@ubuntu:$ cp –a /usr/aarch64-linux-gnu/lib/ .

刪除靜態(tài)庫:

linux@ubuntu:$ rm lib/*.a

添加系統(tǒng)啟動(dòng)文件:

在 etc 下添加文件 inittab,文件內(nèi)容如下:

注意:修改文件均為_install 目錄下

?etc/inittab

這里我們掛載的文件系統(tǒng)有三個(gè) proc、sysfs 和 tmpfs。

回到創(chuàng)建的文件系統(tǒng)處,在 etc 下創(chuàng)建 init.d 目錄,并在 init.d 下創(chuàng)建 rcS 文件,rcS 文件內(nèi)容為:etc/init.d/rcS

為 rcS 添加可執(zhí)行權(quán)限:

linux@ubuntu:$ chmod a+x init.d/rcS

在 etc 下添加 profile 文件,文件內(nèi)容為:etc/profile

此時(shí)一個(gè)最小文件系統(tǒng)就制作完成了,可以將_install 目錄下的文件復(fù)制到/source/rootfs 目

錄下用于 NFS 掛載。

linux@ubuntu:$ cp * /source/rootfs -a 當(dāng)前路徑為_install?

通過 NFS 掛載文件系統(tǒng)

NFS 方式是開發(fā)板通過 NFS 掛載放在主機(jī)(PC )上的根文件系統(tǒng)。此時(shí)在主機(jī)在文件系統(tǒng)中進(jìn)行的操作同步反映在開發(fā)板上;反之,在開發(fā)板上進(jìn)行的操作同步反映在主機(jī)中的根文件系統(tǒng)上。實(shí)際工作中,我們經(jīng)常使用 NFS 方式掛載系統(tǒng),這種方式對(duì)于系統(tǒng)的調(diào)試非常便。

在進(jìn)行本章實(shí)驗(yàn)前需首先確保 NFS 服務(wù)已經(jīng)按照前面章節(jié)安裝成功。本實(shí)驗(yàn)與 TFTP 實(shí)驗(yàn)相同,也分為直連和通過路由器兩個(gè)部分。其中 ip 地址設(shè)置部分參考《通過 TFTP 服務(wù)器下載內(nèi)核》章節(jié)設(shè)置即可,這里不在贅述。

在通過 NFS 啟動(dòng)網(wǎng)路文件系統(tǒng)之前,首先要確保 ubuntu 虛擬機(jī)目錄下【/source/】存在

rootfs 文件系統(tǒng),如果不存在該文件,則需要在【華清遠(yuǎn)見-I.MX8M Plus 開發(fā)資料-2021-06-

02\程序源碼/文件系統(tǒng)源碼】目錄下提取 rootfs.tar.xz 壓縮包,解壓到/source/目錄下,解壓完成之后會(huì)在/source/目錄下生成 rootfs 目錄。

在開發(fā)板上電之前需將調(diào)試串口、網(wǎng)線接入網(wǎng)口 1。

配置好環(huán)境之后啟動(dòng)開發(fā)板,在使程序停留在 u-boot 終端。

使用 NFS 啟動(dòng)這里同樣網(wǎng)路連接方式分為直連方式和路由器方式。

? 直連方式

設(shè)置 serverip

這里假設(shè)服務(wù)器 ip 為 192.168.103.100 和開發(fā)板 ip 地址 192.168.103.1

u-boot=> setenv serverip 192.168.103.100

u-boot=> setenv ipaddr 192.168.103.101

設(shè)置 nfsroot

nfsroot 為我們?cè)诜?wù)器上 nfs 服務(wù)器所在的工作目錄,在前面章節(jié)我們已經(jīng)將其設(shè)置為

“/source/rootfs”

u-boot=> setenv nfsroot /source/rootfs

設(shè)置 bootargs

u-boot=> setenv bootargs console=${console} root=/dev/nfs ip=${ipaddr}:::::eth0:off nfsr

oot=${serverip}:${nfsroot},v3,tcp

啟動(dòng)內(nèi)核

u-boot=> run loadimage

u-boot=> run loadfdt

u-boot=> booti ${loadaddr} - ${fdt_addr}

? 路由器方式

設(shè)置 serverip

這里假設(shè)服務(wù)器 ip 為 192.168.103.100

u-boot=> setenv serverip 192.168.103.100

設(shè)置 nfsroot

nfsroot 為我們?cè)诜?wù)器上 nfs 服務(wù)器所在的工作目錄,在前面章節(jié)我們已經(jīng)將其設(shè)置為

“/source/rootfs”

u-boot=> setenv nfsroot /source/rootfs

設(shè)置 bootargs

u-boot=> setenv bootargs console=${console} root=/dev/nfs ip=dhcp nfsroot=${serverip}:

${nfsroot},v3,tcp

啟動(dòng)內(nèi)核

u-boot=> run loadimage

u-boot=> run loadfdt

u-boot=> booti ${loadaddr} - ${fdt_addr}

這里需要注意的是直連方式和路由器方式,啟動(dòng)內(nèi)核部分都是加載外部存儲(chǔ)器中的程序進(jìn)行啟動(dòng)的,如果需要通過 TFTP 啟動(dòng)參考《通過 TFTP 服務(wù)器下載內(nèi)核》即可。

LED 驅(qū)動(dòng)開發(fā)之設(shè)備樹編寫

設(shè)備樹結(jié)構(gòu)分析

imx8mp uboot 設(shè)備樹位于“arch/arm/dts/”目錄下,linux 內(nèi)核設(shè)備樹位于

“arch/arm64/boot/dts/freescale/”目錄下。

imx8mp 設(shè)備樹結(jié)構(gòu)如下圖所示:

由上圖可知“imx8mp.dtsi”為設(shè)備樹的底層設(shè)備描述文件,主要描述了 SoC 級(jí)的控制器相關(guān)

信息,例如在開發(fā)中經(jīng)常用到的“I2C 總線控制器”、“SPI 總線控制器”等都是在該設(shè)備樹中描述,此外該文件中還添加了一些頭文件,這些頭文件是用于設(shè)備樹中對(duì)一些宏定義的支持。在 imx8mp.dtsi 的下級(jí)分別有“imx8mp-evk.dts”、“imx8mp-ai-robot.dts”、“imx8mpevk-rpmsg.dts”、“imx8mp-evk-dsp.dts”四個(gè)文件,其中 imx8mp-evk.dts 是默認(rèn)使用的設(shè)備樹文件,可提供板載設(shè)備全功能驅(qū)動(dòng);imx8mp-ai-robot.dts 是作為“工業(yè)及機(jī)器人領(lǐng)域”的擴(kuò)展設(shè)備樹,可以支持 ROS、xenomai 及 EtherCAT 等功能擴(kuò)展;imx8mp-evk-rpmsg.dts 主要用于 Cortex-A53 與 Cortex-M7 協(xié)同工作時(shí)使用的設(shè)備樹,該設(shè)備樹中將一部分外設(shè)資源分配給了 Cortex-A53 核心使用,一部分分配給 Cortex-M7 核心使用;imx8mp-evk-dsp.dts 主要是用于 DSP 相關(guān)功能支持。

IOMUXC 配置簡介

我們?cè)诳刂埔粋€(gè)外部設(shè)備時(shí),第一步通常都是在配置 SoC 上的引腳功能。對(duì)于 imx8mp

我們可以通過內(nèi)部的 IOMUX 控制器來配置管腳的電壓水平、驅(qū)動(dòng)強(qiáng)度和遲滯等屬性。具體引腳配置屬性可以參考 NXP 官方提供的《i.MX 8M Plus Applications Processor Datasheet for Industrial Products》手冊(cè)中的“External Signals and Pin Multiplexing”章節(jié)。IOMUX控制器的配置參考“IOMUX Controller (IOMUXC)”

IOMUX 控制器包含四組寄存器:

? 通用寄存器(IOMUXC_GPRx):由控制鎖相環(huán)頻率、電壓和其他通用配置的寄存器組成。

? Daisy Chain 控制寄存器(IOMUXC_<Instance_port>_SELECT_INPUT):使 IC 可以在一

個(gè) pad 上共享多個(gè)功能塊。這種共享是通過復(fù)用 pad 的輸入和輸出信號(hào)來實(shí)現(xiàn)的。

? MUX 控制寄存器(改變 pad 模式):

選擇使用 pad 的 8 種不同功能(ALT 模式)中的哪一種功能。

使用下列寄存器中單獨(dú)或分組設(shè)置 pad 功能:

IOMUXC_SW_MUX_CTL_PAD_<PAD NAME>

IOMUXC_SW_MUX_CTL_GRP_<GROUP NAME>

? Pad 控制寄存器(改變 Pad 特性)涉及以下寄存器:

IOMUXC_SW_PAD_CTL_PAD_<PAD_NAME>

IOMUXC_SW_PAD_CTL_GRP_<GROUP NAME>

可設(shè)置的特性

SRE: 速率設(shè)置,可配置為 FAST 或者 SLOW。

DSE: 管腳驅(qū)動(dòng)強(qiáng)度,可配置為 low, medium, high 或者 max

ODE: 可設(shè)置為開漏輸出或者 CMOS 輸出

HYS: 設(shè)置輸入觸發(fā)方式可配置為 CMOS 或者施密特

PUS: 設(shè)置管腳的內(nèi)部上拉或者下拉

PUE: 設(shè)置在低功耗模式下默認(rèn)的上拉或者下拉

PKE: 開啟或關(guān)閉低功耗模式上拉或者下拉

下面的示例演示如何在設(shè)備樹中使用 IOMUX XML Code

這里我們來分析第 7 行的配置,pinctrl 原理都是相同的這里以 7 行為例:

MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 本質(zhì)是一個(gè)宏定義,定義文件為 ar

ch/arm64/boot/dts/freescale/imx8mp-pinfunc.h,這里列出該定義的原型

#define MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x220 0x480 0x5E8 0x0

0x4這里可以看到該宏的值為 0x220 0x480 0x5E8 0x0 0x4,那么這組數(shù)字是什么含義呢?

關(guān)于這組數(shù)字在 imx8mp-pinfunc.h 文件的第 11 行有解釋“<mux_reg conf_reg input_reg mux_mode input_val>”這里的“mux_reg conf_reg input_reg”為三組 IOMUXC 控制器所對(duì)應(yīng)的

寄存器的偏移量。

mux_reg=0x220 所對(duì)應(yīng)的寄存器是 IOMUXC_SW_MUX_CTL_PAD_UART1_RXD

可以看到該寄存器的偏移量為 220h。同理我們可以得到另外兩個(gè)寄存器 conf_reg=0x480

和 input_reg=0x5E8 分別對(duì)應(yīng) IOMUXC_SW_PAD_CTL_PAD_UART1_RXD 和 IOMUXC_UA

RT1_UART_RXD_MUX_SELECT_INPUT 寄存器。這里例如 input_reg 所對(duì)應(yīng)的值為 0 則表

示沒有使用。

接下來看 mux_mode input_val 這兩個(gè)值,這兩個(gè)值分別表示 mux_reg 和 input_reg 這兩

個(gè)寄存器要設(shè)置的值。例如這里 mux_mode=0x0 則對(duì)應(yīng) IOMUXC_SW_MUX_CTL_PAD_UA

RT1_RXD 寄存器設(shè)置為 0;input_reg=0x4 對(duì)應(yīng)IOMUXC_UART1_UART_RXD_MUX_SELE

CT_INPUT 設(shè)置為 0x4。這里我們就將 MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX

這個(gè)宏所對(duì)應(yīng)的含義解釋清楚了。

對(duì)于上面對(duì) MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 宏的解釋其實(shí)還有一個(gè)問題,這個(gè)宏設(shè)置寄存器偏移量時(shí)我們?cè)O(shè)置了三個(gè)寄存器,但是這個(gè)宏里只指定了兩個(gè)寄存器的值,那么有一個(gè)寄存器的值沒有被設(shè)定,這個(gè)寄存器就是 conf_reg 所對(duì)應(yīng)的 IOMUXC_SW_PAD_CTL_PAD_UART1_RXD 寄存器,該寄存器的值在設(shè)備樹被指定,我們?cè)賮砜丛O(shè)備樹的第 7 行,MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x140 這里的 0x140即為 IOMUXC_SW_PAD_CTL_PAD_UART1_RXD 寄存器要設(shè)置的值。

這部分內(nèi)容可參考 linux 內(nèi)核中對(duì)應(yīng)的說明文檔:

Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt

Documentation/devicetree/bindings/pinctrl/fsl,imx8mp-pinctrl.txt

LED 驅(qū)動(dòng)開發(fā)之驅(qū)動(dòng)程序設(shè)計(jì)

platform 總線

要滿足 Linux 設(shè)備模型,就必須要有總線、設(shè)備和驅(qū)動(dòng)。但是有的設(shè)備并沒有對(duì)應(yīng)的物理總線,比如 LED、RTC 和蜂鳴器等。為此,內(nèi)核專門開發(fā)了一種虛擬總線——platform 總線,用來連接這些沒有物理總線的設(shè)備或者一些不支持熱插拔的設(shè)備,接下來我們要用到的

LED 設(shè)備就是掛接在這條總線上的。

平臺(tái)驅(qū)動(dòng)是用 struct platform_driver 結(jié)構(gòu)來表示的,他的定義如下。

C++ Code

驅(qū)動(dòng)開發(fā)者關(guān)心得主要成員如下。

probe:總線發(fā)現(xiàn)有匹配的平臺(tái)設(shè)備時(shí)調(diào)用。

remove:所驅(qū)動(dòng)的平臺(tái)設(shè)備被移除時(shí)或平臺(tái)驅(qū)動(dòng)注銷時(shí)調(diào)用。

shutdown、suspend 和 resume:電源管理函數(shù),在要求設(shè)備掉電、掛起和恢復(fù)時(shí)被調(diào)用。

內(nèi)嵌的 struct device_driver 的 pm 成員也有對(duì)應(yīng)的電源管理函數(shù)。

id_table:平臺(tái)驅(qū)動(dòng)可以驅(qū)動(dòng)的平臺(tái)設(shè)備 ID 列表,可用于和平臺(tái)設(shè)備匹配。

向平臺(tái)總線注冊(cè)和注銷的平臺(tái)驅(qū)動(dòng)的主要函數(shù)如下。

platform_driver_register(drv)

void platform_driver_unregister(struct platform_driver *);

因?yàn)樵隍?qū)動(dòng)中,經(jīng)常在模塊初始化函數(shù)中注冊(cè)一個(gè)平臺(tái)驅(qū)動(dòng),在清除函數(shù)中注銷一個(gè)平臺(tái)驅(qū)動(dòng),可以參考如下代碼片段。

C++ Code

代碼第 7 行至代碼第 14 行定義了一個(gè)平臺(tái)驅(qū)動(dòng),名字為 farsight-led;第 1 行至第 5 行是用于設(shè)備樹匹配,匹配設(shè)備樹中 compatible 的值為“farsight-led”的配置項(xiàng)當(dāng)著兩項(xiàng)匹配成功時(shí)執(zhí)行 led_drv_probe 函數(shù)。代碼第 19 行使用 platform_driver_register 向 platform 總線注冊(cè)一個(gè) platform driver 設(shè)備。

上面提到該驅(qū)動(dòng)匹配設(shè)備樹中 compatible 的值為“farsight-led”的配置項(xiàng),這里列出完整設(shè)備樹配置。

C++ Code

字符設(shè)備驅(qū)動(dòng)編寫

在正式學(xué)習(xí)字符設(shè)備驅(qū)動(dòng)的編寫之前,我們首先來看看相關(guān)的基礎(chǔ)知識(shí)。在類 UNIX 系

統(tǒng)中,有一個(gè)眾所周知的說法,即“一切皆文件”,當(dāng)然網(wǎng)絡(luò)設(shè)備是一個(gè)例外。這就意味著

設(shè)備最終也會(huì)體現(xiàn)為一個(gè)文件,應(yīng)用程序要對(duì)設(shè)備進(jìn)行訪問,最終就會(huì)轉(zhuǎn)化為對(duì)文件的訪問,

這樣做的好處是統(tǒng)一了對(duì)上層的接口。設(shè)備文件通常位于/dev 目錄下,使用下面的命令可以看到很多設(shè)備文件及其相關(guān)的信息。

root@imx8mp:# ls -l /dev

total 0

……

brw-rw---- 1 root disk 8, 0 Jul 4 10:07 sda

brw-rw---- 1 root disk 8, 1 Jul 4 10:07 sda1

brw-rw---- 1 root disk 8, 2 Jul 4 10:07 sda2

brw-rw---- 1 root disk 8, 5 Jul 4 10:07 sda5

……

crw--w---- 1 root tty 4, 0 Jul 4 10:07 tty0

crw-rw---- 1 root tty 4, 1 Jul 4 10:07 tty1

……

面列出的信息中,前面的字母“b”表示的是塊設(shè)備,“c”表示的是字符設(shè)備。比如上面的 sda、sda1、sda2、sda5 就是塊設(shè)備,實(shí)際上這些設(shè)備是筆者的 Ubuntu 主機(jī)上的一個(gè)硬盤和這個(gè)硬盤上的三個(gè)分區(qū),其中 sda 表示的是整個(gè)硬盤,而 sda1、sda2、sda5 分別是三個(gè)分區(qū)。tty0、tty1 就是終端設(shè)備,shell 程序使用這些設(shè)備來同用戶進(jìn)行交互。從上面的打印信息來看,設(shè)備文件和普通文件有很多相似之處,都有相應(yīng)的權(quán)限,所屬的用戶和組,修改時(shí)間和名字。但是設(shè)備文件會(huì)比普通文件多出兩個(gè)數(shù)字,這兩個(gè)數(shù)字分別叫主設(shè)備號(hào)和次設(shè)備號(hào)。這兩個(gè)號(hào)是設(shè)備在內(nèi)核中的身份或標(biāo)志,是內(nèi)核用于區(qū)分不同設(shè)備的唯一信息。通常內(nèi)核用主設(shè)備號(hào)區(qū)別一類設(shè)備,次設(shè)備號(hào)用于區(qū)分同一類設(shè)備的不同的個(gè)體或不同的分區(qū)。而路徑名則是用戶層用于區(qū)別設(shè)備的信息。

現(xiàn)在的 Linux 系統(tǒng)中,設(shè)備文件通常是自動(dòng)創(chuàng)建的。即便如此,我們還是可以通過 mknod

命令來手動(dòng)創(chuàng)建一個(gè)設(shè)備文件,如下所示。

root@imx8mp:# mknod /dev/vser0 c 256 0

root@imx8mp:# ls -li /dev/vser0

126695 crw-r--r-- 1 root root 256, 0 Jul 13 10:03 /dev/vser0

要實(shí)現(xiàn)一個(gè)字符設(shè)備驅(qū)動(dòng),其中最重要的事就是要構(gòu)造一個(gè) cdev 結(jié)構(gòu)對(duì)象,并讓 cdev 同

設(shè)備號(hào)和設(shè)備的操作方法集合相關(guān)聯(lián),然后將該 cdev 結(jié)構(gòu)對(duì)象添加到內(nèi)核的 cdev_map 散列表中。下面我們逐步來實(shí)現(xiàn)這一過程,首先就是在驅(qū)動(dòng)中注冊(cè)設(shè)備號(hào),代碼如下(完整的代碼請(qǐng)參見“”)。

在模塊的初始化函數(shù)中,首先在代碼第 38 行使用 MKDEV 宏將主設(shè)備號(hào)和次設(shè)備號(hào)合并成一個(gè)設(shè)備號(hào)。

第 5 行定義了一個(gè) struct cdev 類型的變量 cdev,在第 12 行到第 16 行定義了一個(gè) struct file_operations 類型的全局變量 dev_ops。我們知道,這兩個(gè)數(shù)據(jù)結(jié)構(gòu)是實(shí)現(xiàn)字符設(shè)備驅(qū)動(dòng)的關(guān)鍵。其中 cdev 代表了一個(gè)具體的字符設(shè)備,而 dev_ops 是操作該設(shè)備的一些方法。代碼第27 行調(diào)用了 cdev_init 函數(shù)初始化了 cdev 里面的部分成員,另外一個(gè)最重要的操作就是將 cdev里面的 ops 指針指向了 dev_ops,這樣在通過設(shè)備號(hào)找到 cdev 對(duì)象后,就能找到相關(guān)的操作方法集合,并調(diào)用其中的方法。cdev_init 函數(shù)的原型如下,第一個(gè)參數(shù)是要初始化的 cdev 地址,第二個(gè)參數(shù)是設(shè)備操作方法集合的結(jié)構(gòu)地址。

void cdev_init(struct cdev *cdev, const struct file_operations *fops);

代碼第 29 行將一個(gè) owner 成員賦值為 THIS_MUDULE,owner 是一個(gè)指向 struct module

類型變量的指針,THIS_MUDULE 是包含驅(qū)動(dòng)的模塊中的 struct module 類型對(duì)象的地址,類似于 c++中的 this 指針。這樣就能通過 cdev 或 dev_ops 找到對(duì)應(yīng)的模塊,在對(duì)前面兩個(gè)對(duì)象進(jìn)行訪問時(shí)都要調(diào)用類似于 try_module_get 的函數(shù)增加模塊的引用計(jì)數(shù),其目的是這兩個(gè)對(duì)象在使用的過程中,模塊是不能被卸載的,因?yàn)槟K被卸載的前提條件是引用計(jì)數(shù)為 0。cdev 對(duì)象初始化好以后,就應(yīng)該添加到內(nèi)核中的 cdev_map 散列表當(dāng)中,調(diào)用的函數(shù)是cdev_add,其函數(shù)原型如下。

int cdev_add(struct cdev *p, dev_t dev, unsigned count);

在初始化函數(shù)中添加了 cdev 對(duì)象,那么在清除函數(shù)中自然就應(yīng)該刪除該 cdev 對(duì)象,代碼第 85 行演示了這一操作,實(shí)現(xiàn)的函數(shù)是 cdev_del,其函數(shù)原型如下。

void cdev_del(struct cdev *p);

操作 GPIO 管腳

GPIO 應(yīng)該是每個(gè)嵌入式設(shè)備都避免不了的?,F(xiàn)在內(nèi)核里面多了 gpiod 的來控制 gpio 口,

相對(duì)于原來的形式,使用 gpiod 的好處是我們申請(qǐng)后不進(jìn)行 free 也沒有什么問題。

使用以下函數(shù)獲取 GPIO 設(shè)備,多個(gè)設(shè)備時(shí)需要附帶 index 參數(shù)。函數(shù)返回一個(gè) GPIO 描

述符,或一個(gè)錯(cuò)誤編碼,可以使用 IS_ERR()進(jìn)行檢查:

struct gpio_desc *gpiod_get_index(struct device *dev,

?const char *con_id, unsigned int idx,

?enum gpiod_flags flags)

如果要設(shè)置 GPIO 的輸入或者輸出模式,可以使用如下兩個(gè)函數(shù)實(shí)現(xiàn):

int gpiod_direction_input(struct gpio_desc *desc)

int gpiod_direction_output(struct gpio_desc *desc, int value)

如果要讀取 GPIO 口的電平狀態(tài)則使用下面的函數(shù):

int gpiod_get_value(const struct gpio_desc *desc);

如果要設(shè)置 GPIO 口的電平狀態(tài)則使用下面的函數(shù):

void gpiod_set_value(struct gpio_desc *desc, int value);

下面我們來分析 GPIO 控制邏輯。代碼如下:

C++ Code

這部分代碼比較簡單,這里我們只關(guān)注與 GPIO 相關(guān)程序,程序第 6 行是在獲取設(shè)備樹中對(duì) gpio 口的配置,第 21 行是將對(duì)應(yīng) IO 口設(shè)置為高電平,第 25 行的將對(duì)應(yīng) IO 口設(shè)置為低電平。

上層應(yīng)用程序開發(fā)

該驅(qū)動(dòng)我們通過 ioctl 函數(shù)來控制 LED 燈的狀態(tài)。ioctl 函數(shù)為了處理設(shè)備非數(shù)據(jù)的操作(這些可以同過 read、write 接口來實(shí)現(xiàn)),內(nèi)核將對(duì)設(shè)備的控制操作委派給了 ioctl 接口,ioctl 也是一個(gè)系統(tǒng)調(diào)用,其函數(shù)原型如下。

int ioctl(int d, int request, ...);

0x12345678 表示點(diǎn)燈,而 0x12345679 表示滅燈等。但是這個(gè)操作碼,或者更符合內(nèi)核的

說法是命令,應(yīng)該具有一定的編碼規(guī)則,這個(gè)我們?cè)诤竺鏁?huì)介紹?!?C 語言中實(shí)參個(gè)數(shù)可變的函數(shù)原型聲明形式,但在這里表示的是第三個(gè)參數(shù)可有可無。比如對(duì)于剛才的 LED 例子,第三個(gè)參數(shù)可以用于指定將哪個(gè) LED 點(diǎn)亮或熄滅,如 0 表示 LED0,1 表示 LED1 等。因?yàn)榈谌齻€(gè)形參是 unsigned long 類型的,所以除了可以傳遞數(shù)字值而外,還可以傳遞一個(gè)指針,這樣就可以和內(nèi)核空間交互任意多個(gè)字節(jié)的數(shù)據(jù)。

查看前面的 file_operations 結(jié)構(gòu)的定義,和 ioctl 系統(tǒng)調(diào)用對(duì)應(yīng)的驅(qū)動(dòng)接口函數(shù)是

unlocked_ioctl,另外還有一個(gè) compat_ioctl,compat_ioctl 是為了處理 32 位程序和 64 位內(nèi)核兼容的一個(gè)函數(shù)接口,和體系結(jié)構(gòu)相關(guān)。unlocked_ioctl 的函數(shù)原型如下。

long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

第一個(gè)參數(shù)還是是打開的文件的 file 結(jié)構(gòu)指針,第二個(gè)參數(shù)和系統(tǒng)調(diào)用的第二個(gè)參數(shù)

request 對(duì)應(yīng),第三個(gè)參數(shù)對(duì)應(yīng)系統(tǒng)調(diào)用函數(shù)的第三個(gè)參數(shù)之前說到用于 ioctl 的命令需要遵從一種編碼規(guī)則,那么這個(gè)編碼規(guī)則是怎樣的呢?在當(dāng)前的內(nèi)核源碼版本中,命令按照如下方式組成。

上述內(nèi)容摘自內(nèi)核文檔“Documentation/ioctl/ioctl-decoding.txt”。也就是說一個(gè)命令由 4個(gè)部分組成,每個(gè)部分有規(guī)定的意義和位寬限制。之所以這樣定義命令,而不是簡單的用 0、1、2、……來定義命令,是為了避免命令定義的重復(fù),從而導(dǎo)致應(yīng)用程序誤操作,把一個(gè)命令發(fā)送給本不應(yīng)該執(zhí)行他的驅(qū)動(dòng)程序,而驅(qū)動(dòng)程序又錯(cuò)誤地執(zhí)行了這個(gè)命令。采用這種機(jī)制,使得驅(qū)動(dòng)有機(jī)會(huì)來檢查這個(gè)命令是否屬于驅(qū)動(dòng),從一定程度上避免了這種問題的發(fā)生。理想的要求是比特 15 位到比特 8 位所定義的幻數(shù)在一種體系結(jié)構(gòu)下是全局唯一的,但很顯然,這很難做到。盡管如此,我們還是應(yīng)該遵從內(nèi)核所規(guī)定的這種命令定義形式。內(nèi)核提供了一組宏來定義命令、提取命令中的字段信息,代碼如下。

定義命令所使用的最底層的宏是_IOC,他將 4 個(gè)部分通過移位合并在一起。假設(shè)要定義一個(gè)設(shè)置串口幀格式的命令,那么按照前面的規(guī)則,這個(gè)命令要帶參數(shù),并且是將數(shù)據(jù)寫入到驅(qū)動(dòng),那么最高兩個(gè)比特是 01,如果要寫入的參數(shù)是一個(gè) struct option 的結(jié)構(gòu),而結(jié)構(gòu)占12 個(gè)字節(jié),那么比特 29 到比特 16 的 10 進(jìn)制值應(yīng)該是 12,如果定義幻數(shù)為字母 s,命令碼為2,最終就應(yīng)使用_IOC(1,‘s’,0,12)來定義該命令。不過內(nèi)核還提供了更方便的宏,剛才那個(gè)命令可以通過_IOW(‘s’,2,struct option)來定義。另外還有 4 個(gè)宏_IOC_DIR、_IOC_TYPE、

_IOC_NR 和_IOC_SIZE 來分別提取命令中的 4 個(gè)部分。

本程序中對(duì)于命令碼的定義如下:

該程序最終實(shí)現(xiàn)了 LED 燈的閃爍,每 1s 變化一次狀態(tài)

程序運(yùn)行

? 添加設(shè)備樹

首先我們需要在內(nèi)核源碼中,添加我們對(duì)應(yīng) LED 的設(shè)備樹文件。需要注意的是由于系統(tǒng)

默認(rèn)已經(jīng)設(shè)置好的 LED 的配置,所以我們需要先將原來的 leds 配置項(xiàng)屏蔽。

打開“arch/arm64/boot/dts/freescale/imx8mp-ai-robot-base.dts”文件,將 leds 配置項(xiàng)屏蔽。

添加 my_led 設(shè)備節(jié)點(diǎn),在設(shè)備樹“/”下添加如下配置

? 部署設(shè)備樹

重新編譯設(shè)備樹,此部分可參考《linux》編譯小節(jié),編程成功后會(huì)在“arch/arm64/boot/d

ts/freescale/”目錄下生成“imx8mp-ai-robot-base.dtb”文件,將該文件使用 tftp 方式下載到開

發(fā)板并啟動(dòng)系統(tǒng)。

? 編譯驅(qū)動(dòng)程序

將“華清遠(yuǎn)見-I.MX8M Plus 開發(fā)資料-2021-06-02\程序源碼”下的“gpio_demo”導(dǎo)入到虛擬機(jī)中

在進(jìn)行源碼編譯之前需要先導(dǎo)入交叉編譯工具鏈,之前章節(jié)已經(jīng)介紹過具體安裝過程,這里不再贅述,如果還沒有安裝可參考《交叉編譯工具鏈安裝》章節(jié)

linux@ubuntu:$ source /opt/fsl-imx-xwayland/5.4-zeus/environment-setup-aarch64-poky-lin

ux

linux@ubuntu:$ $CC --version

進(jìn)入到 gpio_demo 源碼中,修改 Makefile 文件,將 KERNELDIR 變量修改為內(nèi)核源碼所在路徑。修改完成后使用 make 命令編譯即可

linux@ubuntu:$ make

之后使用如下命令編譯應(yīng)用程序代碼

linux@ubuntu: $CC ledapp.c -o ledapp

編譯完成后會(huì)在當(dāng)前目錄生成“imx8mp_led_driver.ko”文件和“l(fā)edapp”文件,將著兩個(gè)文件復(fù)制到“/source/rootfs/”目錄下,使用 NFS 掛載啟動(dòng)即可,在目標(biāo)板中運(yùn)行了。

? 運(yùn)行應(yīng)用程序

首先需要先通過 tftp 啟動(dòng)的方式來更新設(shè)備樹配置,之后通過 NFS 網(wǎng)絡(luò)文件系統(tǒng)掛載方式掛載 rootfs。

啟動(dòng)成功之后進(jìn)入到“imx8mp_led_driver.ko”文件和“l(fā)edapp”文件所在的目錄下,按照如下命令安裝驅(qū)動(dòng)程序并運(yùn)行應(yīng)用程序。

linux@ubuntu: insmod imx8mp_led_driver.ko

linux@ubuntu: ./ledapp

基于imx8m plus開發(fā)板全體系開發(fā)教程4:Linux系統(tǒng)開發(fā)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
兰考县| 正宁县| 宜兴市| 读书| 日土县| 同德县| 金华市| 大竹县| 陵川县| 饶阳县| 襄垣县| 拉孜县| 读书| 大安市| 西青区| 泾源县| 龙陵县| 孟津县| 申扎县| 宜丰县| 平定县| 屏东县| 衡阳市| 义乌市| 揭东县| 洪泽县| 和林格尔县| 盐源县| 南京市| 大连市| 镇雄县| 绥棱县| 巧家县| 吉木乃县| 鲁甸县| 米脂县| 金坛市| 娄底市| 阿鲁科尔沁旗| 和田市| 奈曼旗|