位置: IT常识 - 正文

基于imx8m plus开发板全体系开发教程4:Linux系统开发(imx6ul开源项目)

编辑:rootadmin
基于imx8m plus开发板全体系开发教程4:Linux系统开发

推荐整理分享基于imx8m plus开发板全体系开发教程4:Linux系统开发(imx6ul开源项目),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:imx8mmini,imx8mmini,imx8mmini,imx8x,imx8x,imx8 安卓,imx8开发板,imx8 gpu,内容如对您有帮助,希望把文章链接给更多的朋友!

前言:

i.MX8M Plus 开发板是一款拥有 4 个 Cortex-A53 核心,运行频率 1.8GHz;1 个 Cortex-M7 核心,运行频率 800MHz;此外还集成了一个 2.3 TOPS 的 NPU,大大加速机器学习推理。

全文所使用的开发平台均为与NXP官方合作的FS-IMX8MPCA开发板(华清远见imx8mp开发板),支持Weston、ubuntu20.04、Android11 等操作系统;同时支持 Xenomai 硬实时内核、EtherCAT 总线、TSN 时间敏感网络、ROS1.0、ROS2.0 等工业与机器人领域应用;可以用于工业互联网、人工智能、边缘计算、多屏异显等应用方向。华清远见研发中心编写了大量开发教程并录制了丰富视频教学资源免费提供给大家!

开发板更多资料可在下方评论区留言领取~~~

Linux 系统开发TF-A 编译配置交叉编译工具链

在进行源码编译之前需要先导入交叉编译工具链,之前章节已经介绍过具体安装过程,这里不再赘述,如果还没有安装可参考《交叉编译工具链安装》章节

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

ux

linux@ubuntu:$ $CC --version

编译 TF-A 编译

将当前工作目录切换到 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/目录下生成相关镜像

Bootloader 的编译与运行配置交叉编译工具链

在进行源码编译之前需要先导入交叉编译工具链,之前章节已经介绍过具体安装过程,

这里不再赘述,如果还没有安装可参考《交叉编译工具链安装》章节

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

ux

linux@ubuntu:$ $CC --version

Bootloader编译

将当前工作目录切换到 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 相关镜像,在根目录下生成 u-boot.img 镜像

制作 imx-boot

在我们前面编译的标准 u-boot 无法自动启动设备,imx8mp 需要通过 imx-mkimage 构建

imx-boot。

imx-boot 镜像包括 U-boot、tf-a、uboot spl 和 ddr 固件。因此我们需要将前面编译的 uboot-imx 镜像和 imx-atf 以及 ddr 固件复制到 imx-boot/iMX8M 目录下来制作 imx-boot 镜像。

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

⚫ 复制 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/

⚫ 复制 DDR 固件

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

⚫ 复制 tf-a 镜像

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

⚫ 编译生成 imx-boot

linux@ubuntu:$ make SOC=iMX8MP flash_ai_robot

编译成功之后会在 iMX8M 目录下生成 flash.bin 文件,使用此文件通过 uuu 工具烧录到

开发板便可使用自己编译的 u-boot 和 tf-a 镜像启动开发板。

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

u-boot 常用命令介绍linux 系统环境变量

linux 下的环境变量可以通过在 u-boot 阶段进行设置,在 u-boot 启动过程中倒计时结束之

前按任意键停在 u-boot 进行环境变量设置。

如果要查看当前环境变量可以使用“print”命令

如果想要恢复至出厂时的环境变量可以使用“env default -f -a”命令进行重置

如果想要保存当前的环境变量可以使用“saveenv”进行保存。

a) 设置 linux 内核加载地址

⚫ linux 内核加载地址

u-boot=> setenv loadaddr 0x80080000

⚫ 设备树加载地址

u-boot=> setenv fdtaddr 0x80f00000

⚫ 设备树文件名称

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

b) 显示设置

⚫ 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) 设置跟文件系统位置

⚫ 通过 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 行缓冲命令行,当我们向终端命令行输入命令的时候,这些命令没有立即被系统识别,而是被缓冲到一个缓存区(也就是系统认为我换没有输入完),当我们按下回车键(换行)后,系统就认为输入完了,然后将缓冲区中所有刚才输入的命令拿去处理。

⚫ 第一个命令:printenv/print

printenv 命令不用带参数,作用是打印出系统中所有的环境变量。

printenv 环境变量名 查看指定的环境变量值。

⚫ 常用环境变量

bootdelay uboot 启动后,倒计时多少秒后自动执行环境变量 bootcmd 的语句

bootcmd 倒计时到 0 后,自动执行里面的语句

bootargs 是用于提供给内核的启动参数语句

ipaddr 当前开发板的 IP 地址

⚫ 设置添加/更改环境变量:setenv/set

用法:set name value

例如:set bootdelay 3

⚫ 保存环境变量的更改:saveenv/save

saveenv/save 作用是将内存中的环境变量的值同步保存到 flash 中环境变量的分区

⚫ 网络测试指令:ping

用法:ping IP 地址

此命令需要先设置好开发板的网络环境,包括网关,子网掩码,本机 IP 地址。之后才可以使用该命令。

⚫ tftp 下载命令

用于通过 tftp 协议从 tftp 服务器上下载文件。

eg: tftp 0x40480000 Image 将 tftp 服务器上的 Image 文件下载到本地内存的

0x40480000 地址处。

⚫ 内存操作指令:mw、md

md 内存地址 用于查看内存地址上的值

md.b 0x40008000 100 从内存地址 0x40008000 开始,查看 0x100 个字节并输出值

md.w 0x40008000 100 从内存地址 0x40008000 开始,查看 0x100 个 16 位值并输出值

md.l 0x40008000 100 从内存地址 0x40008000 开始,查看 0x100 个 32 位值并输出值

mw 用于修改内存地址上的值

mw.b x40008000 0xab 100 从内存地址 0x40008000 开始的 0x100 字节空间,设值为 0xab

mw.w 0x40008000 0xabcd 100 从内存地址 0x40008000 开始的 0x200 字节空间,每 16 位值设为 0xabcd

mw.l 0x40008000 0xabcdef88 100 从内存地址 0x40008000 开始的 0x400字节空间,每 32 位值设为 0xabcdef88

⚫ 帮助指令

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

过 help 命令来查看具体描述及用法。

Linux 内核源码编译配置交叉编译工具链

在进行源码编译之前需要先导入交叉编译工具链,之前章节已经介绍过具体安装过程,

这里不再赘述,如果还没有安装可参考《交叉编译工具链安装》章节

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

ux

linux@ubuntu:$ $CC --version

linux 编译

将当前工作目录切换到 linux 内核源码目录下,这里为“~/workdir/imx8mp/imx-yocto-bsp

/bsp_source/ linux-imx” 

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

添加 nxp 官方标准 imx_v8 配置

linux@ubuntu:$ make imx_v8_defconfig

添加自定义配置

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

添加完配置后我们可以通过 menuconfig 进行内核配置和裁剪

linux@ubuntu:$ make menuconfig

编译内核文件

linux@ubuntu:$ make

编译成功后在 arch/arm64/boot/目录下生成 Image 内核镜像,在arch/arm64/boot/dts/freescale/目录下生成设备树镜像

单独编译设备树文件

linux@ubuntu:$ make dtbs

编译成功后在 arch/arm64/boot/dts/freescale/目录下生成设备树镜像

通过 tftp 服务器更新内核镜像

上面章节已经将 VMware 的桥接网络配置好了,本小节将要通过 TFTP 服务器来下载内核及设备树,我们分为两部分介绍,第一部分通过网线直连电脑的方式进行验收,第二部分通过路由器连接开发板和电脑。

网线直连电脑

这里我们采用的是直连网络,即开发板通过网线直连电脑。

首先启动 Ubuntu 虚拟机,由于我们采用直连方式,所以虚拟机无法自动获取到 IP 地址,

需要我们手动设置 IP 地址。

打开虚拟机的“/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”代表网卡名,可以通过 ifconfig 命令查看;

address 为要设置的静态 IP 地址;

netmask 为子网掩码

gateway 为网关地址

设置完成后重启网络服务

linux@ubuntu:$ sudo reboot

设置完成后使用 ifconfig 命令查看当前 ubuntu 的 IP 地址。

在开发板上电之前需将调试串口、网线接入网口 1。

之后给开发板上电,使程序停留在 u-boot 终端。

这里我们需要设置几个与网络相关的环境变量,以支持网络传输。

在上面我们已经设置好了 ubuntu 的网络配置,这里 ubuntu 充当 TFTP 服务器。我们需要

按照 ubuntu 的配置来设置开发板的环境变量。

设置服务器 IP 地址(ubuntu ip)

u-boot=> setenv serverip 192.168.100.240

设置本机 IP 地址(开发板 ip)

u-boot=> setenv ipaddr 192.168.100.241

设置网关

u-boot=> setenv gatewayip 192.168.100.1

设置子网掩码

u-boot=> setenv netmask 255.255.255.0

设置网卡 1 MAC 地址

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

保存环境变量

u-boot=> saveenv

设置完成后可以使用 ping 命令来进行测试

u-boot=> ping 192.168.100.240

下载 linux 内核与设备树

在进行内核下载之前,首先需要确认 TFTP 服务器是否已经安装完毕,如果还没有安装则需要根据前面章节的内容进行安装,此外还需要将之前编译好的 Image linux 内核程序与设备树文件 imx8mp-ai-robot.dtb 放入 TFTP 服务器,如果是按照前面教程搭建路径为【/tftpboot/】

下面在 u-boot 中设置要下的镜像名称和设备树名称

u-boot=> setenv image Image

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

u-boot=> saveenv

如果希望将下载下来的镜像文件存储到指定的存储设备,例如外部 sdcard 或者 eMMC,

则需要设置当前存储设备。

保存到 eMMC,在开发板执行如下指令

u-boot=> mmc dev 2 0

保存到 SDcard,在开发板执行如下指令

u-boot=> mmc dev 1 0

下载 linux 内核文件

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

下载设备树文件

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

启动程序

u-boot=> run mmcargs

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

通过路由器连接电脑

上小节讲述了如何通过网路直连进行 TFTP 服务器的数据传输,本小节则讲述如何通过路由器连接。

通过路由器连接与直连其实差异并不大,只是通过路由器可以使用 DHCP 服务器,进行自动 IP 地址获取。

打开虚拟机的“/etc/network/interfaces”文件

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

添加如下配置

auto ens33

iface ens33 inet dhcp

这里将“ens33”设置成了通过 DHCP 自动获取 IP 地址

设置完成后重启网络服务

linux@ubuntu:$ sudo reboot

设置完成后使用 ifconfig 命令查看当前 ubuntu 的 IP 地址。

首先启动开发板,使程序停留在 u-boot 终端。

这里我们需要设置几个与网络相关的环境变量,以支持网络传输。

在上面我们已经设置好了 ubuntu 的网络配置,这里 ubuntu 充当 TFTP 服务器。我们需要按照 ubuntu 的配置来设置开发板的环境变量。

设置服务器 IP 地址(ubuntu ip) 

u-boot=> setenv serverip 192.168.101.47

设置网卡 1 MAC 地址

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

保存环境变量

u-boot=> saveenv

下载 linux 内核与设备树

在进行内核下载之前,首先需要确认 TFTP 服务器是否已经安装完毕,如果还没有安装则需要根据前面章节的内容进行安装,此外还需要将之前编译好的 Image linux 内核程序与设备树文件 imx8mp-ai-robot.dtb 放入 TFTP 服务器,如果是按照前面教程搭建路径为【/tftpboot/】

下面在 u-boot 中设置要下的镜像名称和设备树名称

u-boot=> setenv image Image

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

基于imx8m plus开发板全体系开发教程4:Linux系统开发(imx6ul开源项目)

u-boot=> saveenv

这里与直连网路不同的是,不再需要指定本机 ip、网关、子网掩码等环境变量,这些信

息只需要通过 dhcp 获取即可

下载 linux 内核文件

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

下载设备树文件

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

启动程序

u-boot=> run mmcargs

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

基于 busybox 的最小文件系统制作busybox 源码编译及安装

可以从 http://busybox.net/downloads/网站下载 busybox-1.29.3 源码用于制作 Linux 文件系

统,为了方便,已将源码放进了光盘。

安装交叉编译工具链。

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

验证开发工具是否安装正确,显示版本信息如下图所示。

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

建立源码目录

将【华清远见-I.MX8M Plus 开发资料-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 默认安装路径为源码目录下的_install

linux@ubuntu:$ make install

进入安装目录可看到如下目录:

linux@ubuntu:$ cd _install

linux@ubuntu:$ ls

bin linuxrc sbin usr

添加主要系统启动文件

创建其他需要的目录: 

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/ .

删除静态库:

linux@ubuntu:$ rm lib/*.a

添加系统启动文件:

在 etc 下添加文件 inittab,文件内容如下:

注意:修改文件均为_install 目录下

 etc/inittab

这里我们挂载的文件系统有三个 proc、sysfs 和 tmpfs。

回到创建的文件系统处,在 etc 下创建 init.d 目录,并在 init.d 下创建 rcS 文件,rcS 文件内容为:etc/init.d/rcS

为 rcS 添加可执行权限:

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

在 etc 下添加 profile 文件,文件内容为:etc/profile

此时一个最小文件系统就制作完成了,可以将_install 目录下的文件复制到/source/rootfs 目

录下用于 NFS 挂载。

linux@ubuntu:$ cp * /source/rootfs -a 当前路径为_install 

通过 NFS 挂载文件系统

NFS 方式是开发板通过 NFS 挂载放在主机(PC )上的根文件系统。此时在主机在文件系统中进行的操作同步反映在开发板上;反之,在开发板上进行的操作同步反映在主机中的根文件系统上。实际工作中,我们经常使用 NFS 方式挂载系统,这种方式对于系统的调试非常便。

在进行本章实验前需首先确保 NFS 服务已经按照前面章节安装成功。本实验与 TFTP 实验相同,也分为直连和通过路由器两个部分。其中 ip 地址设置部分参考《通过 TFTP 服务器下载内核》章节设置即可,这里不在赘述。

在通过 NFS 启动网路文件系统之前,首先要确保 ubuntu 虚拟机目录下【/source/】存在

rootfs 文件系统,如果不存在该文件,则需要在【华清远见-I.MX8M Plus 开发资料-2021-06-

02\程序源码/文件系统源码】目录下提取 rootfs.tar.xz 压缩包,解压到/source/目录下,解压完成之后会在/source/目录下生成 rootfs 目录。

在开发板上电之前需将调试串口、网线接入网口 1。

配置好环境之后启动开发板,在使程序停留在 u-boot 终端。

使用 NFS 启动这里同样网路连接方式分为直连方式和路由器方式。

⚫ 直连方式

设置 serverip

这里假设服务器 ip 为 192.168.103.100 和开发板 ip 地址 192.168.103.1

u-boot=> setenv serverip 192.168.103.100

u-boot=> setenv ipaddr 192.168.103.101

设置 nfsroot

nfsroot 为我们在服务器上 nfs 服务器所在的工作目录,在前面章节我们已经将其设置为

“/source/rootfs”

u-boot=> setenv nfsroot /source/rootfs

设置 bootargs

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

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

启动内核

u-boot=> run loadimage

u-boot=> run loadfdt

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

⚫ 路由器方式

设置 serverip

这里假设服务器 ip 为 192.168.103.100

u-boot=> setenv serverip 192.168.103.100

设置 nfsroot

nfsroot 为我们在服务器上 nfs 服务器所在的工作目录,在前面章节我们已经将其设置为

“/source/rootfs”

u-boot=> setenv nfsroot /source/rootfs

设置 bootargs

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

${nfsroot},v3,tcp

启动内核

u-boot=> run loadimage

u-boot=> run loadfdt

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

这里需要注意的是直连方式和路由器方式,启动内核部分都是加载外部存储器中的程序进行启动的,如果需要通过 TFTP 启动参考《通过 TFTP 服务器下载内核》即可。

LED 驱动开发之设备树编写设备树结构分析

imx8mp uboot 设备树位于“arch/arm/dts/”目录下,linux 内核设备树位于

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

imx8mp 设备树结构如下图所示:

由上图可知“imx8mp.dtsi”为设备树的底层设备描述文件,主要描述了 SoC 级的控制器相关

信息,例如在开发中经常用到的“I2C 总线控制器”、“SPI 总线控制器”等都是在该设备树中描述,此外该文件中还添加了一些头文件,这些头文件是用于设备树中对一些宏定义的支持。在 imx8mp.dtsi 的下级分别有“imx8mp-evk.dts”、“imx8mp-ai-robot.dts”、“imx8mpevk-rpmsg.dts”、“imx8mp-evk-dsp.dts”四个文件,其中 imx8mp-evk.dts 是默认使用的设备树文件,可提供板载设备全功能驱动;imx8mp-ai-robot.dts 是作为“工业及机器人领域”的扩展设备树,可以支持 ROS、xenomai 及 EtherCAT 等功能扩展;imx8mp-evk-rpmsg.dts 主要用于 Cortex-A53 与 Cortex-M7 协同工作时使用的设备树,该设备树中将一部分外设资源分配给了 Cortex-A53 核心使用,一部分分配给 Cortex-M7 核心使用;imx8mp-evk-dsp.dts 主要是用于 DSP 相关功能支持。

IOMUXC 配置简介

我们在控制一个外部设备时,第一步通常都是在配置 SoC 上的引脚功能。对于 imx8mp

我们可以通过内部的 IOMUX 控制器来配置管脚的电压水平、驱动强度和迟滞等属性。具体引脚配置属性可以参考 NXP 官方提供的《i.MX 8M Plus Applications Processor Datasheet for Industrial Products》手册中的“External Signals and Pin Multiplexing”章节。IOMUX控制器的配置参考“IOMUX Controller (IOMUXC)”

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

⚫ 通用寄存器(IOMUXC_GPRx):由控制锁相环频率、电压和其他通用配置的寄存器组成。

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

个 pad 上共享多个功能块。这种共享是通过复用 pad 的输入和输出信号来实现的。

⚫ MUX 控制寄存器(改变 pad 模式):

选择使用 pad 的 8 种不同功能(ALT 模式)中的哪一种功能。

使用下列寄存器中单独或分组设置 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>

可设置的特性

SRE: 速率设置,可配置为 FAST 或者 SLOW。

DSE: 管脚驱动强度,可配置为 low, medium, high 或者 max

ODE: 可设置为开漏输出或者 CMOS 输出

HYS: 设置输入触发方式可配置为 CMOS 或者施密特

PUS: 设置管脚的内部上拉或者下拉

PUE: 设置在低功耗模式下默认的上拉或者下拉

PKE: 开启或关闭低功耗模式上拉或者下拉

下面的示例演示如何在设备树中使用 IOMUX XML Code

这里我们来分析第 7 行的配置,pinctrl 原理都是相同的这里以 7 行为例:

MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 本质是一个宏定义,定义文件为 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,那么这组数字是什么含义呢?

关于这组数字在 imx8mp-pinfunc.h 文件的第 11 行有解释“<mux_reg conf_reg input_reg mux_mode input_val>”这里的“mux_reg conf_reg input_reg”为三组 IOMUXC 控制器所对应的

寄存器的偏移量。

mux_reg=0x220 所对应的寄存器是 IOMUXC_SW_MUX_CTL_PAD_UART1_RXD

可以看到该寄存器的偏移量为 220h。同理我们可以得到另外两个寄存器 conf_reg=0x480

和 input_reg=0x5E8 分别对应 IOMUXC_SW_PAD_CTL_PAD_UART1_RXD 和 IOMUXC_UA

RT1_UART_RXD_MUX_SELECT_INPUT 寄存器。这里例如 input_reg 所对应的值为 0 则表

示没有使用。

接下来看 mux_mode input_val 这两个值,这两个值分别表示 mux_reg 和 input_reg 这两

个寄存器要设置的值。例如这里 mux_mode=0x0 则对应 IOMUXC_SW_MUX_CTL_PAD_UA

RT1_RXD 寄存器设置为 0;input_reg=0x4 对应IOMUXC_UART1_UART_RXD_MUX_SELE

CT_INPUT 设置为 0x4。这里我们就将 MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX

这个宏所对应的含义解释清楚了。

对于上面对 MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 宏的解释其实还有一个问题,这个宏设置寄存器偏移量时我们设置了三个寄存器,但是这个宏里只指定了两个寄存器的值,那么有一个寄存器的值没有被设定,这个寄存器就是 conf_reg 所对应的 IOMUXC_SW_PAD_CTL_PAD_UART1_RXD 寄存器,该寄存器的值在设备树被指定,我们再来看设备树的第 7 行,MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x140 这里的 0x140即为 IOMUXC_SW_PAD_CTL_PAD_UART1_RXD 寄存器要设置的值。

这部分内容可参考 linux 内核中对应的说明文档:

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

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

LED 驱动开发之驱动程序设计platform 总线

要满足 Linux 设备模型,就必须要有总线、设备和驱动。但是有的设备并没有对应的物理总线,比如 LED、RTC 和蜂鸣器等。为此,内核专门开发了一种虚拟总线——platform 总线,用来连接这些没有物理总线的设备或者一些不支持热插拔的设备,接下来我们要用到的

LED 设备就是挂接在这条总线上的。

平台驱动是用 struct platform_driver 结构来表示的,他的定义如下。

C++ Code

驱动开发者关心得主要成员如下。

probe:总线发现有匹配的平台设备时调用。

remove:所驱动的平台设备被移除时或平台驱动注销时调用。

shutdown、suspend 和 resume:电源管理函数,在要求设备掉电、挂起和恢复时被调用。

内嵌的 struct device_driver 的 pm 成员也有对应的电源管理函数。

id_table:平台驱动可以驱动的平台设备 ID 列表,可用于和平台设备匹配。

向平台总线注册和注销的平台驱动的主要函数如下。

platform_driver_register(drv)

void platform_driver_unregister(struct platform_driver *);

因为在驱动中,经常在模块初始化函数中注册一个平台驱动,在清除函数中注销一个平台驱动,可以参考如下代码片段。

C++ Code

代码第 7 行至代码第 14 行定义了一个平台驱动,名字为 farsight-led;第 1 行至第 5 行是用于设备树匹配,匹配设备树中 compatible 的值为“farsight-led”的配置项当着两项匹配成功时执行 led_drv_probe 函数。代码第 19 行使用 platform_driver_register 向 platform 总线注册一个 platform driver 设备。

上面提到该驱动匹配设备树中 compatible 的值为“farsight-led”的配置项,这里列出完整设备树配置。

C++ Code

字符设备驱动编写

在正式学习字符设备驱动的编写之前,我们首先来看看相关的基础知识。在类 UNIX 系

统中,有一个众所周知的说法,即“一切皆文件”,当然网络设备是一个例外。这就意味着

设备最终也会体现为一个文件,应用程序要对设备进行访问,最终就会转化为对文件的访问,

这样做的好处是统一了对上层的接口。设备文件通常位于/dev 目录下,使用下面的命令可以看到很多设备文件及其相关的信息。

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”表示的是块设备,“c”表示的是字符设备。比如上面的 sda、sda1、sda2、sda5 就是块设备,实际上这些设备是笔者的 Ubuntu 主机上的一个硬盘和这个硬盘上的三个分区,其中 sda 表示的是整个硬盘,而 sda1、sda2、sda5 分别是三个分区。tty0、tty1 就是终端设备,shell 程序使用这些设备来同用户进行交互。从上面的打印信息来看,设备文件和普通文件有很多相似之处,都有相应的权限,所属的用户和组,修改时间和名字。但是设备文件会比普通文件多出两个数字,这两个数字分别叫主设备号和次设备号。这两个号是设备在内核中的身份或标志,是内核用于区分不同设备的唯一信息。通常内核用主设备号区别一类设备,次设备号用于区分同一类设备的不同的个体或不同的分区。而路径名则是用户层用于区别设备的信息。

现在的 Linux 系统中,设备文件通常是自动创建的。即便如此,我们还是可以通过 mknod

命令来手动创建一个设备文件,如下所示。

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

要实现一个字符设备驱动,其中最重要的事就是要构造一个 cdev 结构对象,并让 cdev 同

设备号和设备的操作方法集合相关联,然后将该 cdev 结构对象添加到内核的 cdev_map 散列表中。下面我们逐步来实现这一过程,首先就是在驱动中注册设备号,代码如下(完整的代码请参见“”)。

在模块的初始化函数中,首先在代码第 38 行使用 MKDEV 宏将主设备号和次设备号合并成一个设备号。

第 5 行定义了一个 struct cdev 类型的变量 cdev,在第 12 行到第 16 行定义了一个 struct file_operations 类型的全局变量 dev_ops。我们知道,这两个数据结构是实现字符设备驱动的关键。其中 cdev 代表了一个具体的字符设备,而 dev_ops 是操作该设备的一些方法。代码第27 行调用了 cdev_init 函数初始化了 cdev 里面的部分成员,另外一个最重要的操作就是将 cdev里面的 ops 指针指向了 dev_ops,这样在通过设备号找到 cdev 对象后,就能找到相关的操作方法集合,并调用其中的方法。cdev_init 函数的原型如下,第一个参数是要初始化的 cdev 地址,第二个参数是设备操作方法集合的结构地址。

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

代码第 29 行将一个 owner 成员赋值为 THIS_MUDULE,owner 是一个指向 struct module

类型变量的指针,THIS_MUDULE 是包含驱动的模块中的 struct module 类型对象的地址,类似于 c++中的 this 指针。这样就能通过 cdev 或 dev_ops 找到对应的模块,在对前面两个对象进行访问时都要调用类似于 try_module_get 的函数增加模块的引用计数,其目的是这两个对象在使用的过程中,模块是不能被卸载的,因为模块被卸载的前提条件是引用计数为 0。cdev 对象初始化好以后,就应该添加到内核中的 cdev_map 散列表当中,调用的函数是cdev_add,其函数原型如下。

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

在初始化函数中添加了 cdev 对象,那么在清除函数中自然就应该删除该 cdev 对象,代码第 85 行演示了这一操作,实现的函数是 cdev_del,其函数原型如下。

void cdev_del(struct cdev *p);

操作 GPIO 管脚

GPIO 应该是每个嵌入式设备都避免不了的。现在内核里面多了 gpiod 的来控制 gpio 口,

相对于原来的形式,使用 gpiod 的好处是我们申请后不进行 free 也没有什么问题。

使用以下函数获取 GPIO 设备,多个设备时需要附带 index 参数。函数返回一个 GPIO 描

述符,或一个错误编码,可以使用 IS_ERR()进行检查:

struct gpio_desc *gpiod_get_index(struct device *dev,

 const char *con_id, unsigned int idx,

 enum gpiod_flags flags)

如果要设置 GPIO 的输入或者输出模式,可以使用如下两个函数实现:

int gpiod_direction_input(struct gpio_desc *desc)

int gpiod_direction_output(struct gpio_desc *desc, int value)

如果要读取 GPIO 口的电平状态则使用下面的函数:

int gpiod_get_value(const struct gpio_desc *desc);

如果要设置 GPIO 口的电平状态则使用下面的函数:

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

下面我们来分析 GPIO 控制逻辑。代码如下:

C++ Code

这部分代码比较简单,这里我们只关注与 GPIO 相关程序,程序第 6 行是在获取设备树中对 gpio 口的配置,第 21 行是将对应 IO 口设置为高电平,第 25 行的将对应 IO 口设置为低电平。

上层应用程序开发

该驱动我们通过 ioctl 函数来控制 LED 灯的状态。ioctl 函数为了处理设备非数据的操作(这些可以同过 read、write 接口来实现),内核将对设备的控制操作委派给了 ioctl 接口,ioctl 也是一个系统调用,其函数原型如下。

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

0x12345678 表示点灯,而 0x12345679 表示灭灯等。但是这个操作码,或者更符合内核的

说法是命令,应该具有一定的编码规则,这个我们在后面会介绍。…是 C 语言中实参个数可变的函数原型

本文链接地址:https://www.jiuchutong.com/zhishi/300522.html 转载请保留说明!

上一篇:最新版本 Stable Diffusion 开源AI绘画工具之部署篇(最新版本TVBox配置地址)

下一篇:React报错之map() is not a function(react错误处理)

  • 进项税额加计抵减会计分录
  • 小微企业税收优惠政策2023年房产税
  • 申报美元出口以欧元收汇
  • 银行利息月末结算方式
  • 货物和运费一起开票怎么开
  • 汽车保险专用发票怎么做账
  • 未及时扣除的分数怎么算
  • 记账凭证的具体审计目标
  • 汇兑损益在外币业务核算中有什么重要意义
  • 收到社保中心的生育经贴怎么做账
  • 广告制作需要交文化建设费吗
  • 购买设备送给客户帐务处理是怎样的?
  • 用实物资产注资给子公司需缴纳增值税吗?
  • 一般纳税人首次领票能领多少
  • 注册资本需要
  • 小规模纳税人自开专票
  • 小规模专票普票区别
  • 公司办公楼转让缴纳增值税的依据
  • 住房公积金业务挂起
  • 所得税费用属于损失吗
  • 硬盘损坏类型
  • 空调应该计入什么科目
  • 对公账户转到私人账户要手续费吗
  • 小微企业减免额怎么计算
  • services.exe
  • vue 模拟遥控按钮
  • 商业会计做账
  • php实现上传文件
  • php新手入门
  • 贷款的减值会计怎么做账
  • php file_get_contents smb
  • css 宽度 自适应 占满
  • 持有待售资产是流动还是非流动
  • thinkphp整合layui
  • json_server
  • js 跳转网页
  • phpcms视频教程
  • 企业的借款费用怎么入账
  • 收到专票不认证不抵扣可以吗
  • 购入固定资产预付款怎么做账
  • 公司分红给个人
  • 帝国cms中英
  • mysql日志文件在哪里
  • 费用报销单里的类别怎么填
  • 增值税买票卖票
  • 新准则制度体系的核心变化
  • 金蝶凭证汇总表怎么打印
  • 购进废旧物资进项税额
  • 抵扣的进项税如何做账
  • 债券到期收益率被定义为使债券的()
  • 计提的生产车间职工工资
  • 职工工伤住院期间的各项费用由谁负责
  • 公司没有销售收入
  • 专项储备 科目
  • 销货清单自己留哪一联
  • 两家公司的钱混着用怎么做账
  • 进项税转出企业所得税调减么
  • 交车辆购置税需要什么材料
  • 公司购买的商品质量问题能用12315投诉吗
  • 处置固定资产应通过什么账户核算
  • 银行账和实际金额对不上
  • 复式记账法的特点不包括
  • mysql联合索引生效原则
  • sql批量替换字符串
  • fedora使用
  • 隐藏的系统应用在哪找
  • win8如何安装win10系统
  • linux 图形
  • win8.1使用教程
  • react-native fetch的具体使用方法
  • 全面理解全面把握全面落实
  • 简介英文
  • unity 子弹效果 粒子
  • ajax按顺序执行
  • Python 正则表达式的高级用法
  • javascript面向对象精要
  • 辽宁省国家税务总局
  • 纳税申报的具体内容
  • 山西省地方税务局通用定额发票
  • 国家税务总局对税务助征员
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设