驱动开发、移植
一、任务明确:把创龙MX8的驱动 按照我们的要求 然后移植到 我们的板子
1.Linux系统启动卡制作,
sd卡 先按照 《用户手册—3-2-Linux系统启动卡制作及系统固化》
把创龙的Linux系统刷进去。
2. 把TLIMX8-EVM的板子过一遍
把刚刚烧好系统的sd卡插入 创龙TLIMX8-EVM
的板子,
用SecureCRT调试窗口 串口或者SSH远程登陆 创龙创龙TLIMX8-EVM
的板子
然后按照 《2-1-评估板测试手册》
把评估版创龙TLIMX8-EVM
下面这些功能测试一遍
3. 把TLIMX8-EVM的板子的Liunx系统编译一遍
按照 《3-1-Linux系统使用手册》
把创龙的TLIMX8-EVM的板子配套的Liunx系统下面图这些U-Boot、Linux内核编译一遍,也就是把刚刚刷进去SD卡的Linux系统内核编译一遍。(之后可以按照自己的需求对内核进行配置和裁剪)
4.按照我们的需求去修改、配置内核,编译成内核镜像文件,修改设备树dts,编译生成设备树dtb文件
按照我们的需求去修改、配置内核,编译成内核镜像文件,烧录到我们自己的板子;
之后我们就把创龙的TLIMX8-EVM 板 对应的Linux系统内核,也就是上面刷的那个系统内核 根据 我们这边的需求去修改、去配置内核,然后编译出来生成Linux系统镜像文件,然后把这个镜像文件烧进SD卡—Linux系统启动卡,然后把这个卡插到我们自己做的板子,启动这个系统。
修改设备树dts文件,重新编译生成设备树dtb二进制文件,拷贝到SD卡—Linux系统启动卡的BOOT分区。
然后在虚拟机上修改设备树dts文件,重新编译生成设备树dtb二进制文件,拷贝到SD卡—Linux系统启动卡的BOOT分区。
5.之后工作的任务步骤
在虚拟机上使用 创龙的TLIMX8-EVM 板 对应的SDK(里面有文件可以编译生成对应版本的Linux系统。可以编译生成U-Boot、内核、文件系统、设备树文件)编译生成对应版本的Linux系统,烧录到SD卡—Linux系统启动卡。
1.内核配置,内核编译
首先先在虚拟机使用官方提供的SDK按照我们的需求去修改、配置内核,编译成内核镜像文件,烧录到我们自己的板子;
2.驱动适配调式过程:
将烧录好系统的sd卡插入 创龙TLIMX8-EVM
的板子,板子使用SD卡里面的系统进行启动,
用SecureCRT调试窗口 串口连接或者SSH远程登陆 创龙TLIMX8-EVM
的板子去测试刚刚烧录到这个Linux系统跟板子的功能模块适不适配,参考资料《2-1-评估板测试手册.pdf》
,
如果这个系统的某个功能模块(例如LED指示灯)在创龙TLIMX8-EVM
板子上正常,说明原本的LDE指示灯驱动程序.c源文件
没有问题。这时候我们就要去对应自己的板子去简单的修改LED指示灯驱动程序.c源文件,让这个驱动程序去适配我们的板子上的LED指示灯,如果.c源文件没有问题,或者不需要修改了,这时候就要去修改创龙TLIMX8-EVM
板子对应的设备树文件,去修改成适配我们板子的设备树文件,然后拷贝到我们板子系统的BOOT分区(例如我们的板子使用的是SD卡—Linux系统启动卡,那我们就要插上这个卡连接到我们的PC机的虚拟机上,然后把这个设备树文件拷贝到SD卡—Linux系统的BOOT分区,然后在把这个卡拔掉,然后插到我们的板子,使用SD卡-Linux系统启动卡运行系统)。
除了LED指示灯功能模块,其他的功能模块的驱动也是类似进行开发,移植,
当自己的板子所有的功能模块的驱动都适配后,这时候就可以把SD卡-Linux系统启动卡中的系统 固化 到板子的 eMMC里面。
二、实战
1.虚拟机的账号和密码均是:Hugo
虚拟机开启root用户,设置了root用户密码
评估版的账号密码,都是root
遇到问题
共享文件夹的问题,cd 到 /mnt/hgfs/ 路径下,ls没有看到 Shared Folders 共享文件夹
系统自动挂载功能未启用,系统里面有这个共享文件夹,但是系统没有把这个文件夹自动挂载到/mnt/hgfs/下。
使用vmware-hgfsclient命令列出所有共享文件夹(在VM->setting->options->shared Folders里面设置的),可以看到所以共享文件夹都在系统中,只是没有自动挂载在 /mnt/hgfs/ 路径下。
我们手动挂载一下。先创建一个文件夹,然后把主机hots的共享文件夹SharedFolders 挂载到虚拟机这个文件夹 、mnt/hgfs/SharedFolders
1
- 根目录 / 是Linux文件系统的最顶层目录
- 是一个快捷方式,代表当前用户的主目录。这是一种方便的方式来引用主目录而不需要输入完整的路径。比如,如果用户 hugo 的家目录是 /home/hugo,那么 ~/IMX8 就相当于 /home/hugo/IMX8 。
- 总是指向执行命令的那个用户的家目录。
2
在每次打开U-Boot配置界面时,要先
export LINES=24
export COLUMNS=80
强制设定终端的高度为24行,宽度为80列。请注意,这种方法不一定总是有效,因为实际显示效果还取决于终端的实际大小。
三、BL360_X8M板驱动移植
1. 修改设备树的步骤和命令
如图所示:
先cd到NXP i.MX8系列处理器(IMX8)
的内核(kernel)
目录下的 Linux内核版本为5.4.70(Linux-5.4.70)
的内核源代码、配置文件、编译结果(内核源码)路径
。
cd IMX8/Kernel/Linux-5.4.70/
然后在这个路径下重新编译生成二进制设备树文件:
① 先使能SDK环境变量
② 在内核源码目录 IMX8/Kernel/Linux-5.4.70/
下编译生成二进制设备树 dtb 文件(生成的 dtb文件位于arch/arm64/boot/dts/freescale/
路径下)
source /home/hugo/SDK/environment-setup-aarch64-poky-linux
make freescale/tlimx8-evm.dtb
插上SD系统启动卡连接到PC机上的虚拟机,然后把生成的二进制dtb设备树文件拷贝到SD系统启动卡(Linux系统)的BOOT分区。
cd /media/hugo/BOOT
cp /home/hugo/IMX8/Kernel/Linux-5.4.70/arch/arm64/boot/dts/freescale/tlimx8-evm.dtb ./
2. 系统启动
问题描述(启动系统被卡住)
BL360_X8M板插入sd系统启动卡,插上电启动的过程的时候,调试器SecureCRT显示出串口打印的信息,有pcie 。。。time out
。 然后系统就一直卡在这里,进不去。
问题解决
BL360_X8M板插入sd系统启动卡,启动前要先把设备树的pcie
屏蔽掉。
1.首先把sd系统启动卡拿出来,通过读卡器插到pc机上,然后挂载到虚拟机上。
2.根据《3-1-Linux系统使用手册.pdf》的 《3.4 编译设备树文件》的提示,进入这个链接去修改tlimx8-evm.dts
。
hugo@hugo-virtual-machine:~/IMX8/Kernel/Linux5.4.70/arch/arm64/boot/dts/freescale$ vi tlimx8-evm.dts
3.然后切换回内核源码安装目录下,执行如下命令使能SDK环境变量,并在内核源码目录"arch/arm/boot/dts/"路径中编译生成 dtb 文件。
4.把这个生成的dtb文件拷贝至Linux系统启动卡BOOT分区。
5.然后把系统启动卡断开链接,然后拔出来,插到BL360_X8M板上,重新启动
3.LED驱动移植
问题描述(修改LED驱动)
把创龙MX8评估板的系统移植到 自己的板子BL360_X8M,修改调试LED驱动适配我们的板子。
问题解决
① 首先,led.c的源码不用动,先根据你的原理图,看到我们自己的板子的LED1和LED2分别连接到GPIO3_23和GPIO3_34,
直接修改设备树文件tlimx8-evm.dts
,找到leds节点,把GPIO的口改成我们板子的LED连接的GPIO口。
然后重新编译生成设备树,重新运行系统。
一般就这样修改,LED就会亮了,但是LED还是不亮,
解决看4.《【 遇到问题】(引脚功能被复用)》
4.【 遇到问题】(引脚功能被复用)
根据原理图修改成我们板子的LED的GPIO引脚号后,但是LED还是不亮
问题解决
② 然后有经验的工程师来教我,他先把led的pin_ctrl
给注释掉了,说不用写也可以
为什么不需要配置pinctrl_gpio_led
?
内核自动处理:
因为在LED节点中直接指定gpios = <&gpio3 23 ...>
时,
内核会自动去检查该引脚是否被其他模块占用,
如果没有冲突,自动将引脚配置为GPIO模式。
但需注意:
如果引脚被其他模块占用(如PDM),内核会拒绝配置,将不会自动将引脚配置为GPIO模式,从而导致LED失败,
此时必须手动释放冲突模块(如禁用PDM)。
③ 然后他通过NXP芯片官网提供的config tool软件找到了GPIO3_23引脚,对应AD13,找到了这个脚有其他的功能复用的可能,然后他通过这段代码在设备树上查找:MX8MM_IOMUXC_SAI5_RXD2_PDM_DATA2
确实在设备树找到了代码:MX8MM_IOMUXC_SAI5_RXD2_PDM_DATA2 0xd6,说明配置了这个功能,刚好这个功能占用的口跟GPIO3_IO23冲突。
④ 然后通过在设备树搜索 :pinctrl_pdm
找到了用这个功能的代码,把这个功能注释掉就行。
⑤ 重新编译设备树,启动系统,通过代码测试,LED灯正常亮:
- 可以先cd到
/sys/class/leds
路径下,然后ls
,看看有没有user-led0 和 user-led1
节点:
- 通过命令测试,观察LED指示灯的亮灭:
echo 0 > /sys/class/leds/user-led0/brightness
echo 1 > /sys/class/leds/user-led0/brightness
echo 0 > /sys/class/leds/user-led1/brightness
echo 1 > /sys/class/leds/user-led1/brightness
结果如下:
四、驱动移植的理解
1. 一个I2C总线挂载多个从设备
一个I2C总线理论上可以挂载的设备数量取决于所使用的地址空间。
对于标准7位地址空间,I2C协议允许最多128个不同的地址(从0x00到0x7F)。
然而,实际上有几个地址是保留用于特殊用途的,比如通用调用地址和起始字节地址,所以实际可用的地址略少一些。
所以一个I2C总线最多挂载的设备是少于128个的。
所以一个I2C总线可以挂载多个设备
比如下图的设备树可以看到,
一个i2c4的接口节点,有3个compatible,分别的设备为ds1307、isl1208、ov5640_mipi,这代表i2c-4上挂载了三种不同的设备:
一个兼容dallasds1307的实时时钟(RTC)设备(地址0x68);
一个兼容isil.isl1208的RTC设备(地址0x6f) ,
以及一个兼容ovti,ov5640 mipi的摄像头模块(地址0x3c) .
只要它们的reg属性不同(也就是12C的给他们分配的唯一的i2C地址),那这些设备挂载在一个i2C总线上就不会发生冲突,i2C总线是通过挂载在I2C的设备唯一的I2C地址识别是哪个设备,从而跟对应的设备通信,所以一个I2C总线接多个设备不会冲突。