书接上文,上次把U-Boot移植完成了,有兴趣的小伙伴可以通过传送门过去。
Linux系统的移植已经完成,但是果然还是移植没时间整理资料,没办法,2年级的娃真的很难辅导……
现在我对野火开发板的移植已经完成了纯净Linux系统、Busybox根文件系统、SDL+OpenGL、Python3.6,下一步开始移植音频、WIFI、蓝牙、以及按键系统,但是音频已经搞了两天了,移植找不到设备,看了无数遍源码,都无果,后来换上火哥提供的5月份的FullQt,依然是音频设备错误,技术客服回答可能是音频模块坏了,这两天会给我送一块新的板子来,希望一切顺利吧。
这篇里面先说说我的Linux和根文件系统的移植吧,以及关于Linux内核烧入eMMC和远程加载的几种方式,关于SDL的坎坷……先不挖坑了,有空再整理吧。
书归正传。
火哥提供的Linux没看,貌似集成的内容太多了,不够纯,因为我比较喜欢处,所以就从NXP官方已经准备好的系统开始移植吧。
其实NXP提供的系统源码基本是可以用的,要修改的东西比较少,那就直接动手烧录他的系统吧。
- NXP官方系统烧录测试
NXP的系统可以从官网下载,或者从我提供的连接中下载都可以。
命令如下:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16
第一行命令用于清除工程中之前编译的残留文件,最好这样做,否则有惊喜。
第二行命令用于指定配置文件使用imx_v7_defconfig,这是EVK板子自带的东西。
第三行用于编译内核文件,时间比较长,尤其在虚拟机里做,你可以先吃杯泡面,回来就好了。
之后就编译出了Linux的内核文件,在arch/arm/boot中,如果存在zImage和imx6ull-14x14-evk.dtb两个文件表示成功,否则肯定是出问题了。我分析问题可能出现以下几种:
- 没有安装交叉编译环境,但如果你做了U-Boot移植,问题应该不在这;
- 没有安装lzop,直接apt-get安装一下即可;
- 配置文件名称写错了,imx_v7_defconfig;
- CROSS_COMPILE=arm-linux-gnueabihf- 后面没加空格,这个错误很低级。
如果两个文件都出来了,那么恭喜你,第一关过了。
下一步开始启动,启动前要保证几件事:
- 已经做好了U-Boot的移植,并且能够正常启动,如果不知道这是啥,去传送门看,先把U-Boot移植好了再回来看这个;
- 服务器端(Ubuntu或其他Linux端)安装了tftp或者nfs,关于这个教程这里不写了,问度娘吧。
用U-Boot启动NXP的Linux内核
先用tftp启动,把两个文件拷贝到tftp的目录下,启动tftp服务器。
启动U-Boot进入命令行模式,修改bootargs参数
setenv bootargs“console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw”
saveenv
设置U-Boot网络参数:
setenv ipaddr 192.168.1.55 //开发板IP地址
setenv ethaddr 00:04:9f:04:d2:35 //开发板网卡MAC地址
setenv gatewayip 192.168.1.1 //开发板默认网关
setenv netmask 255.255.255.0 //开发板子网掩码
setenv serverip 192.168.1.128 //服务器地址,也就是Ubuntu地址
saveenv //保存环境变量
然后尝试用tftp加载内核和设备树文件,并启动。
tftp 80800000 zImage
tftp 83000000 imx6ull-14x14-evk.dtb
bootz 80800000 - 83000000
前两行是通过tftp命令把服务器端的两个文件拉下来放到指定位置,Linux内核放在80800000,设备树放在83000000,6ULL默认从80000000启动,但是这个位置已经放了U-Boot,而且我们U-Boot加载Linux的时候还需要用,所以位置要往后放,这个参数根据自己的喜好设置吧。
或者通过nfs启动也成,先把两个文件放到NFS的目录下,命令如下:
nfs 80800000 192.168.31.128:/home/mars/Linux/nfs/zImage
nfs 83000000 192.168.31.128:/home/mars/Linux/nfs/imx6ull-14x14-evk.dtb
bootz 80800000 - 83000000
通过我测试,我的NFS要比TFTP快很多。
另外就是可以设置bootcmd参数,把启动命令自动化,这样就不用每次进U-Boot启动Linux系统了。
setenv bootcmd “nfs 80800000 192.168.31.128:/home/mars/Linux/nfs/zImage; nfs 83000000 192.168.31.128:/home/mars/Linux/nfs/imx6ull-14x14-evk.dtb;bootz 80800000 - 83000000”
记得用saveenv保存参数。
这里有个小插曲,我觉得是大家可能会才到的坑,就是NFS加载的时候会出现ERROR:File lookup fail的错误,这是因为uboot中使用的NFS版本是V2,而ubuntu的NFS版本为V3或V4及以上版本,导致uboot不能在NFS服务器中找到文件,所以需要修改ubuntu中NFS的兼容。
打开/etc/default/nfs-kernel-server文件,改三行内容:
RPCNFSDCOUNT="-V 2 8"
RPCMOUNTDOPTS="-V 2 --manage-gids"
RPCSVCGSSDOPTS="--nfs-version 2,3,4 --debug --syslog"
改完之后重启nfs就可以了。
Linux内核启动后控制台会蹦出一堆的内核加载信息,但到了最后发现加载不过去了,提示“Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)”,这是没有根文件系统造成的,这个先忽略,后面会讲到。到了这里表示你的原始内核已经移植成功了,吃杯泡面奖励一下自己吧。
- 改造自己的Linux内核
这部分内容对于野火用户来说非常友好,因为野火的开发板基本参考了NXP官方的板子,要改的东西不是很多,也没有太深奥的地方,甚至比隔壁家的还好弄。
2.1 添加自己的开发板配置文件
配置之前,先用make distclean清理一下工程,否则看着太乱。
上一节中我们编译官方内核的时候使用的是imx_v7_defconfig这个配置,这个文件在arch/arm/configs中,我们直接复制一份,重命名为imx_embedfire_emmc_defconfig,这里面是一些模块配置项,后面在移植声卡网卡一类的东西的时候需要改动,在这我们先不动了,永远是的就可以。
复制设备树文件,Linux内核中所有的设备树都存放在arch/arm/boot/dts中,素有imx6ull-开头的都是关于我们这块CPU的设备树,也是NXP官方已经写好的东西,我们从imx6ull-14x14-evk.dts直接入手。
复制这个文件,改名为imx6ull-embedfire-emmc.dts,今后涉及到设备树修改的,都需要在这里进行,本小结中先不动丫。
设备树文件有了,我们还希望在Makefile中能够找到他。
打开arch/arm/boot/dts/Makefile文件,搜索一下dtb-$(CONFIG_SOC_IMX6ULL),在最下面加入我们设备树的名字即可,这样在进行编译的时候就会按照我们的设备树文件编译出imx6ull-embedfire-emmc.dtb文件了。
至此,配置文件基本全部搞定,重新编译并通过U-Boot远程启动测试一下。
记得,在编译的时候使用imx_embedfire_emmc_defconfig这个配置。
2.2 修改eMMC驱动
在Linux内核源码中,eMMC采用的是4线模式的,而野火iMX6ULL Pro开发板用的是8线的,不改变也能用,但既然人家提供了8车道,为啥还要在4车道堵车呢!改丫的!
打开imx6ull-embedfire-emmc.dtb设备树文件,找到&usdhc2标签,修改成一下内容:
pinctrl-names = "default" , "state_100mhz" , "state_200hmz";
pinctrl-0 = <&pinctrl_usdhc2_8bit>;
pinctrl-1 = <&pinctrl_usdhc2_8bit_100hmz>;
pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>;
bus-width = <8>;
non-removable;
status = "okay";
2.3 修改LCD驱动
LCD是在硬件开发中比较常用的一种设备,在U-Boot移植的文章中,我们已经做了野火7寸LCD的移植,在Linux下,可以搭配SDL、QT这样的GUI库制作出精美的UI界面。
在Linux中,应用程序是需要通过操作LCD实现字符、图片等内容的显示,在裸机开发中我们可以随意分配一块内存给LCD作为显存用,但是在Linux中,系统对内存管理是很严格的,对于系统内存和用户内存有着明确的划分,正常情况下是不予许随意访问的,而在我们的LCD编程中,我们的驱动程序和应用程序都需要访问同一款叫做“显存”的虚拟内存实现绘制,所以为了解决这个问题,FrameBuffer应运而生,系统内核通过FrameBuffer对显存进行控制,对界面操作最终都是基于FB进行编程的。在Linux一切接文件的中心思想引领下,我们可以在/dev目录下找到显存对应的fbX的一系列文件,我们今天要做的LCD显示用的是/dev/fb0。
LCD的驱动有很多,NXP官方和野火及隔壁家的开发板都是使用的RGB888的协议,驱动NXP官方已经写好了,会在/dev下面生成一个fb0的设备,如果有多个显示设备的话还会出现fb1、fb2…。
过多的理论性内容网上一大堆,不啰嗦了,开始实战。
在Linux配置外设,无非就是操作设备树文件,对于相同协议的LCD,驱动基本上都是一样的,只需要根据不同的LCD硬件调整参数。在移植U-Boot的时候,对于LCD的移植已经讲得很清楚了,就是修改类似控制器hspw、hbp、hfp等等一些时间相关的参数。
打开imx6ull.dtsi文件,找到cdif:lcdif@021c8000这个节点,这里所有的配置项就是用于控制LCD显示的,这个节点在I.MX6ULL平台中是通用的,既然是通用也就意味着丫是不完整的,所以还需要我们在自己的imx6ull-embedfire-emmc.dts中做更进一步的配置。
我们先看imx6ull.dtsi文件中关于LCD节点的描述。compatible,这个字段在配置文件中是通用的,表示兼容性,LCD的兼容属性是"fsl,imx6ul-lcdif"和"fsl,imx28-cldi",在原文件中搜索就可以看到相关适配驱动的信息,有兴趣的可以读读源码。
打开imx6ull-embedfire-emmc.dts,找到pinctrl_lcdif_dat段,这部分是关于LCD用到引脚的配置,野火开发板和NXP开发板的引脚结构是相同的,所以这里基本不用改,而且建议大家以后做实际项目的时候尽量也用这些官方推荐的引脚。
第二个要修改的是&lcdif段,这里是关于LCD具体参数的配置,这里改的东西比较多,大部分需要根据你手头上用到的屏幕主板参数进行配置。
这里再次招来GT911的数据手册。
Item | Symbol | Values | Unit | Remark | ||
Min. | Typ. | Max. | ||||
Horizontal Display Area | thd | - | 800 | - | DCLK |
|
DCLK Frequency | fclk | 26.4 | 33.3 | 46.8 | MHz |
|
One Horizontal Line | th | 862 | 1056 | 1200 | DCLK |
|
HS pulse width | thpw | 1 | - | 40 | DCLK |
|
HS Blanking | thb | 46 | 46 | 46 | DCLK |
|
Vertical Display Area | tvd | - | 480 | - | TH |
|
VS period time | tv | 510 | 525 | 650 | TH |
|
VS pulse width | tvpw | 1 | - | 20 | TH |
|
VS Blanking | tvb | 23 | 23 | 23 | TH |
|
VS Front Porch | tvfp | 7 | 22 | 147 |
|
|
- Pinctrl-0:这里面配置了引脚的具体情况,这里用不到复位,所以要删除pinctrl_lcdif_rest
- Bits-per-pixel:像素格式,我们采用的是RGB888的协议,所以宽度为24bit
- bus-width:线宽,根据自己板子的DATA信号线对应,野火7寸屏用的是DATA0~DATA23,所以我的是24线
- clock-frequency:像素时钟,搜侧重是33.3MHz,所以应该是33300000
- hactive:X轴像素数,800
- vactive:Y轴像素数
- hfront-porch,HFP,210
- hback-porch,HBP,46
- hsync-len,HSPW,1
- vback-porch,VBP,23
- vfront-porch,VFP,7
- vsync-len,VSPW,1
- hsync-active,HSYNC数据线极性,0
- vsync-active,VSYNC数据线极性,0
- de-active,DE数据线极性,1
- pixelclk-active,时钟数据线极性,0
这些参数设置好之后LCD就能正常显示了,如果出现花屏或者黑屏的情况,很有可能是某个参数写错了,尤其是宽高。
第二步就是配置背光。
NXP官方板子和野火用的都是GPIO1_IO08控制背光,所以关于pinctrl_pwm1这段也不需要修改,关于pwm1这个节点的信息,在imx6ull.dtsi文件中可以找到,如果找不到就直接在imx6ull-embedfire-emmc.dts中重写一个,尽量不要去改动imx6ull.dtsi,毕竟人家是通用的设备树信息。
在imx6ull-embedfire-emmc.dts文件中可找到&pwm1的段,status设置为okay启用背光,通过阅读Documentation/devicetree/indings/video/backlight/pwm-backlight.txt得知,节点backlight就是背光的设置段,compatible属性设置为pwm-backlight,对应的驱动文件是drivers/video/backlight/pwm_bl.c。背光的PWM频率官方推荐是5KHz,这个我们就不改他了,除非屏幕闪烁厉害。
brightness-levels属性描述了屏幕的亮度级别,原文件中只给出了几个值,我们把他扩展到0~255,0表示PWM占空比为0%,背光完全关闭,255表示背光占空比为100%,背光全亮。当然,这个值可以任意写,只要不超过255就行。
default-brightness-level表示当前亮度级别,随便设置啥都行,这个值表示的是brightness-levels的Index值。
调整完毕后重新编译,,启动新的内核,这时候如果屏幕上出现了小企鹅,恭喜你,LCD移植成功。
如果你的小企鹅没出来,看看menuconfig中Device Drivers -> Graphics support -> Bootup logo下面的三个选项是不是都选中了。
可以通过/sys/devices/platform/backlight/backlight/backlight下面的文件操作背光显示,需要注意的是,这个文件必须在开发板的系统下才能看到,在Ubuntu下是看不到这个文件系统的。当然,这是后话,因为这时候还没一直根文件系统涅。
这个目录下的max_brightness表示最大级别,也就是default-brightness-level的Index值,如果这里面我们设置了7个值,那max_brightness最大就是7,而不是255,不知道有没有表达清楚。
brightness表示当前的背光级别。
2.4 LCD的额外设置和LOGO修改
最喜欢的环节,改LOGO。
在你的Ubuntu系统中先装个软件爱你 netpbm,用apt-get可以直接下载安装。
做好你的LOGO,bmp和png都可以,然后用这个软件转换成ppm格式的。
具体命令如下:
bmptopnm rainbow.bmp > rainbow.pnm
pnmquant 224 rainbow.pnm > rainbow_224.pnm
pnmtoplainpnm rainbow_224.pnm > logo_linux_clut224.ppm
第一行可以换成pngtopnm,第二行命令要求源文件和目的文件不能重名,第三行尽量保持同名。
最后把 logo_linux_clut224.ppm复制到源码devices/video/logo/下替换原来的文件,并删除logo_linux_clut224.c和logo_linux_clut224.o。最好是在编译前清理一下工程,这样保证不会出问题。
这样LOGO就改成我们自己的了。
在U-Boot中,设置bootargs,加一个console=tty1的输出,即setenv bootargs 'console=tty1 console=ttymxc0,115200’,这样屏幕上就可以看到控制台输出内容了。
等移植完根文件系统之后,在修改etc/inittab文件,加入tty1::askfirst:-/bin/sh,这样我们的I.MX6ULL主板就可以接收到剪片的输入了。
在默认情况下,10分钟后LCD会黑屏,如果需要增长这个时间,或者是要设置永久亮屏,只需要修改源码drivers/tty/vt/vt.c文件中的blankinterval白能量即可,0表示常亮。
另外,进入系统后可以通过fbset查看屏幕的参数信息。
2.5 修改RTC
RTC也就是系统实时时钟,用于记录系统的时间,在野火I.MX6ULL Pro开发板上有一块纽扣电池专门用于在系统掉电后维持系统时间。而在Linux驱动中也已经写好了RTC的驱动程序,NXP已经帮我们最好了移植,所以这块我们就不用在动了,直接用就行。
进入系统后时间是错乱的,所以要通过date -s “2020-11-24 17:25:30”命令来设置系统时间,设置完毕后再用date命令查询时间,发现一切OK。
But,重启是否发现时钟有他娘的归零了!!
不要着急,吃桶泡面稳定一下情绪。
在date设置完之后,你还需要hwclock -w写入到RTC芯片中,这样你的时钟就保存下来了,而且他会自己运行。
Linux源码:https://download.csdn.net/download/suolong123/13507164
U-Boot移植:https://blog.csdn.net/suolong123/article/details/109905018