上篇文章,我们介绍了如何使用nxp原厂的uboot进行编译和烧写,将uboot运行在自己的开发板上。nxp原厂的uboot,直接烧录到我的开发板中,lcd的驱动是不正常的,需要进行修改。本篇我们就来继续研究uboot,使得uboot能匹配我们自己的开发板。
修改uboot以匹配开发板的方式有两种,一种是在nxp原厂开发板i.mx 6ull evk的文件上进行修改,另一种仿造nxp的开发板文件,添加自己的开发板文件。
为了能更多的了解uboot,我们使用代码改动较大的第二种方式进行uboot的移植。
在修改uboot之前,先来看一下uboot的源码结构。
1 uboot源码结构分析 uboot的源码如下,这里是源码编译后的结果,包含编译后的文件。
这里文件的含义如下:
2 uboot移植实践 2.1 添加开发板配置文件 首先是创建自己开发板的配置文件,该文件可参考原厂开发板的配置文件,在configs文件夹下,将原来的默认配置文件mx6ull_14x14_evk_emmc_defconfig复制一份,并重命名为mx6ull_myboard_defconfig,该文件即用于作为自己开发板的配置文件。
然后进行内容修改,将原始内容:
config_sys_extra_options=imx_config=board/freescale/mx6ullevk/imximage.cfg,mx6ull_evk_emmc_reworkconfig_arm=yconfig_arch_mx6=yconfig_target_mx6ull_14x14_evk=yconfig_cmd_gpio=y 修改为:
2.2 添加开发板对应的头文件 在目录 include/configs 下添加自己开发板对应的头文件,复制mx6ullevk.h,并重命名为mx6ull_myboard.h,将文件中的
#ifndef __mx6ullevk_config_h #define __mx6ullevk_config_h 修改为:
该文件里面有很多宏定义,这些宏定义基本用于配置uboot,如果我们自己要想使能或者禁止uboot的某些功能,那就要在这里面修改。
在ubuntu中,可以安装vs code软件来辅助查看代码,在ubuntu中安装vscode,需要先下载deb格式的安装包,然后使用类似如下的指令即可进行安装:
sudo dpkg -i code_1.58.0-1625728071_amd64.deb 安装完之后,我们可以将图标添加到ubuntu桌面上,ubuntu安装的所有软件图标都在目录/usr/share/applications中,找到 visual studio code 的图标,然后点击鼠标右键,选择复制到->桌面即可。
2.3 添加开发板对应的板级文件夹 uboot中每个板子都有一个对应的文件夹来存放板级文件(如开发板上外设驱动文件等)。nxp的i.mx系列芯片的所有板级文件夹都存放在 board/freescale/目录下,在这个目录下有个名为mx6ullevk的文件夹,原厂开发板的板级文件夹。
复制 mx6ullevk,将其重命名为mx6ull_myboard,进入mx6ull_myboard目录中, 将其中的mx6ullevk.c文件重命名为mx6ull_myboard.c。
2.3.1 修改makefile文件 首先是修改 board/freescale/mx6ull_myboard 目录下的makefile文件
将原始内容:
# (c) copyright 2015 freescale semiconductor, inc.## spdx-license-identifier: gpl-2.0+#obj-y := mx6ullevk.oextra-$(config_use_plugin) := plugin.bin$(obj)/plugin.bin: $(obj)/plugin.o $(objcopy) -o binary --gap-fill 0xff $ 修改为:
2.3.5 重命名板子的c文件 将 board/freescale/mx6ull_myboard 目录下原来的mx6ullevk.c重命名为mx6ull_myboard.c
2.4 修改u-boot图形界面配置文件 最后修改arch/arm/cpu/armv7/mx6/目录下的kconfig文件
注意这里的kconfig和board/freescale/mx6ull_myboard目录下的kconfig是不一样的。
在207行插入一些内容:
config target_mx6ull_myboard bool support mx6ull_myboard select mx6ull select dm select dm_thermal 然后,在最后一行的endif的前一行添加如下内容:
source board/freescale/mx6ull_myboard/kconfig
2.5 创建编译脚本 在uboot-imx-rel_imx_4.1.15_2.1.0_ga目录下新建一个名为build_myboard.sh的 shell 脚本,写入如下内容:
make arch=arm cross_compile=arm-linux-gnueabihf- distcleanmake arch=arm cross_compile=arm-linux-gnueabihf- mx6ull_myboard_defconfigmake v=1 arch=arm cross_compile=arm-linux-gnueabihf- -j8 至此,以上完成的工作,相当于将nxp原厂开发板相关的配置文件,重新复制了一份,并对板子名称修改为了自己板子的名字。
此时执行./build_myboard.sh,等待编译完成后输入如下命令:
grep -nr mx6ull_myboard.h 如果有很多文件都引用了这个头文件, 那就说明新板子添加成功:
将uboot进行编译并运行,实际的效果应该和原厂uboot的效果一样(lcd无法显示)。
总结一下刚才都有哪些修改:
右端灰色的为原厂开发板的相关文件,黄色的为模仿原厂文件,新添加并修改的自己开发板的文件。
下面进行lcd驱动的修改。
3 lcd驱动的修改 一般uboot中修改驱动都是在对应板子c文件和h文件,即board/freescale/mx6ull_myboard/mx6ull_myboard.c和 include/configs/mx6ull_myboard.h这两个文件。
一般修改 lcd 驱动重点注意以下几点:
lcd 所使用的 gpio,查看 uboot 中 lcd 的 io 配置是否正确
lcd 背光引脚 gpio 的配置
lcd 配置参数是否正确
正点原子以及野火的i.mx6ull开发板的lcd原理图和nxp官方的开发板一致,也就是lcd的io和背光io都是一样的, 所以io部分就不用修改了,只需修改之后的lcd参数。
3.1 修改c文件配置 打开文件 mx6ull_myboard.c,需要修改下面这段内容:
struct display_info_t const displays[] = {{ .bus = mx6ul_lcdif1_base_addr, .addr = 0, .pixfmt = 24, .detect = null, .enable = do_enable_parallel_lcd, .mode = { .name = tft43ab, .xres = 480, .yres = 272, .pixclock = 108695, .left_margin = 8, .right_margin = 4, .upper_margin = 2, .lower_margin = 4, .hsync_len = 41, .vsync_len = 10, .sync = 0, .vmode = fb_vmode_noninterlaced} } }; 先来分析一下这段代码,该代码定义了一个变量displays,类型为display_info_t,这个结构体是lcd信息结构体,其中包括了lcd的分辨率,像素格式,lcd的各个参数等。
display_info_t 定义在文件 arch/arm/include/asm/imx-common/video.h 中,定义如下:
struct display_info_t { int bus; int addr; int pixfmt; int (*detect)(struct display_info_t const *dev); void (*enable)(struct display_info_t const *dev); struct fb_videomode mode;}; 这里的pixfmt是像素格式,也就是一个像素点是多少位,如果是rgb565的话就是16位,如果是rgb888的话就是24位,一般使用 rgb888。
结构体display_info_t还有个mode成员变量,此成员变量也是个结构体,为fb_videomode,定义在文件 include/linux/fb.h 中,定义如下:
struct fb_videomode { const char *name; /* optional */ u32 refresh; /* optional */ u32 xres; u32 yres; u32 pixclock; u32 left_margin; u32 right_margin; u32 upper_margin; u32 lower_margin; u32 hsync_len; u32 vsync_len; u32 sync; u32 vmode; u32 flag;}; 结构体b_videomode里面的成员变量为lcd的参数,这些成员变量函数如下:
name :lcd 名字,要和环境变量中的 panel 相等
xres 、yres :lcd x 轴和 y 轴像素数量
pixclock:像素时钟,每个像素时钟周期的长度,单位为皮秒
left_margin :hbp(horizontal back porch),水平同步后肩
right_margin :hfp(horizontal front porch),水平同步前肩
upper_margin:vbp(vertical back porch),垂直同步后肩
lower_margin:vfp(vertical front porch),垂直同步前肩
hsync_len :hspw(horizontal sync pulse width),行同步脉宽
vsync_len:vspw(vertical sync pulse width),垂直同步脉宽
vmode :大多数使用 fb_vmode_noninterlaced,也就是不使用隔行扫描。
这些参数需要与实用的lcdd的参数一致。
野火的7寸rgb屏幕(gt911,800x480)的一些参数如下:
参数 值
width 800
height 480
hbp 46
hfp 22
vbp 23
vfp 22
hsw 1
vsw 1
注意像素时钟pixclock的计算方法:以野火的 7 寸rgb屏为例,屏幕要求的像素时钟为27.4mhz,因此:pixclock=(1/27400000)*10^12=36496
像素时钟就是 rgb lcd 的时钟信号,以 gt911这款屏幕为例,显示一帧图像所需要的时钟数就是: (vspw+vbp+line+vfp) * (hspw + hbp + hozval + hfp) = (1 + 23 + 480+ 22) * (1+ 46+ 800+ 22) = 526* 869 = 457094。 显示一帧图像需要457094个时钟数, 那么显示60帧就是: 457094* 60 = 27425640≈27.4m,所以像素时钟就是27.4mhz
由以上的屏幕参数,可以得出gt911屏幕的配置参数如下:
struct display_info_t const displays[] = {{ .bus = mx6ul_lcdif1_base_addr, .addr = 0, .pixfmt = 24, .detect = null, .enable = do_enable_parallel_lcd, .mode = { .name = gt911, .xres = 800, .yres = 480, .pixclock = 36496, .left_margin = 46, //hbpd .right_margin = 22, //hfpd .upper_margin = 23, //vbpd .lower_margin = 22, //vfpd .hsync_len = 1, //hspw .vsync_len = 1, //vspw .sync = 0, .vmode = fb_vmode_noninterlaced} } }; 3.2 修改h文件配置 另外还要修改include/configs/路径下的mx6ull_myboard.h,找到所有如下语句:
panel=tft43ab 修改为:
panel=gt911 //与mx6ull_myboard.c中修改的名称保持一致 修改完成以后重新编译一遍 uboot 并烧写到 sd 中启动。
3.3 编译测试 将修改后的uboot编译下载以后,lcd 驱动一般就会工作正常了,lcd 上会显示 nxp 的 logo。
但某些情况有可能还会遇到lcd 并没有工作,还是黑屏,这是什么原因呢?
在 uboot 命令模式输入“print”来查看环境变量 panel 的值,会发现panel的值要是tft43ab(或其他的,反正不是gt911):
panel=tft43abscript=boot.screnvironment size: 2431/8188 bytes=> 这是因为之前有将环境变量保存到emmc中,uboot启动以后会先从emmc中读取环境变量,如果emmc中没有环境变量的话才会使用 mx6ull_alientek_emmc.h 中的默认环境变量。
如果emmc中的环境变量panel不等于gt911,那么lcd显示肯定不正常,我们只需要在uboot中修改panel的值为gt911即可,在uboot的命令模式下输入如下命令:
setenv panel gt911 saveenv 上述命令修改环境变量panel为gt911并保存后,按下复位键重启uboot,此时 lcd 驱动就工作正常了。
4 网络测试 i.mx6ull内部有个以太网mac外设,也就是enet,需要外接一个phy芯片来实现网络通信功能,也就是内部mac+外部phy芯片的方案。 i.mx6ull有两个网络接口enet1和enet2,野火的开发板提供了这两个网络接口,其中enet1和enet2都使用是和原厂开发板一样的ksz8081作为phy芯片。
因此,网络驱动部分的uboot不需要修改,下面就只是来测试一下网路功能。
4.1 连接网线并查看启动情况 首先将开发板通过网线连接到局域网的路由器中(自己的电脑也要在同一个局域网,这样ubuntu虚拟机则也在同一个局域网)。
然后启动uboot,串口查看相关的打印信息,如下图,可以看到网络端口的fec1(注意是uboot程序中默认设置的,不是因为网线插在了左边就自动识别fec1),但是提示网络地址未设置。
4.2 设置网络参数 下面就来设置一下,首先是设置开发板的ip,在设置之前,先借助windows电脑的cmd的ping+ip指令来测试某个ip是否被使用,如我的192.168.5.102未被使用,就可以设为开发板的ip。
除了设置开发板的ip,还要设置一些其它的网络参数,具体如下:
setenv ipaddr 192.168.5.102 //开发板 ip 地址setenv ethaddr 00:04:9f:04:d2:35 //开发板网卡 mac 地址setenv gatewayip 192.168.5.1 //开发板默认网关setenv netmask 255.255.255.0 //开发板子网掩码setenv serverip 192.168.5.101 //服务器地址,也就是 ubuntu 地址saveenv //保存环境变量 开发板的mac地址是一个长度为48位(6个字节)的地址,每个字节间通过冒号间隔,理论上只要局域网内各网络设备不冲突,该地址可任意设置。
局域网的默认网关和子网掩码需要根据自己的实际情况设置(不知道是多少的,可以借助windows电脑的cmd中的ipconfig指令来查看)
服务器的地址就是ubuntu虚拟机的地址(可以通过linux的ifconfig指令来查看)
4.3 测试另一个网口 打开 include/configs/mx6ull_alientek_emmc.h ,将config_fec_enet_dev修改为 0, 重新编译uboot并烧写到sd卡中。
将网线连接到开发板右边的网口上,按照之前的测试方法再次测试:
5 uboot启动linux内核测试 uboot的最终目的就是启动linux内核,所以需要通过启动linux内核来判断uboot移植是否成功。
启动linux内核。我们测试两种启动linux内核的方法:
从emmc启动
从网络启动
从emmc启动也就是将编译出来的linux镜像文件zimage和设备树文件保存在emmc中,uboot从emmc中读这两个文件并启动。 由于我们板子的emmc中可能还没有linux镜像文件和设备树文件,所以先不测试这种方法。
从网络启动,是指将linux镜像文件和根文件系统都放到ubuntu下某个指定的文件夹中,然后通过nfs或者tftp等传输方式将系统文件(zimage和设备树文件)从ubuntu中直接下载到开发板的内存中,emmc中则不需要有系统文件。这种方式的作用就是方便调试,免去将代码固化到开发板的过程。当然,当开发板掉电,内存的系统文件就没了。
下面就来通过网络调试的方法来测试uboot是否能正常启动linux内核。
在测试之前,先来介绍一下在ubuntu虚拟机上如何搭建tftp来传输文件。
5.1 tftp服务搭建 ubuntu上搭建tftp服务器,需要安装tftp-hpa和tftpd-hpa,命令如下:
sudo apt-get install tftp-hpa tftpd-hpa sudo apt-get install xinetd tftp也需要一个文件夹来存放文件,在用户目录下新建一个目录,示例命令如下:
mkdir /home/xxpcb/mytest/tftpdirchmod 777 /home/xxpcb/mytest/tftpdir 最后配置 tftp, 安装完成以后,新建文件/etc/xinetd.d/tftp, 如果没有/etc/xinetd.d 目录的话自行创建,然后在里面输入如下内容:
server tftp { socket_type = dgram protocol = udp wait = yes user = root server = /usr/sbin/in.tftpd server_args = -s /home/xxpcb/mytest/tftpdir/ disable = no per_source = 11 cps = 100 2 flags = ipv4 } 完了以后启动tftp服务,命令如下:
sudo service tftpd-hpa start 打开/etc/default/tftpd-hpa文件,将其修改为如下所示内容:
# /etc/default/tftpd-hpa tftp_username=tftp tftp_directory=/home/xxpcb/mytest/tftpdir tftp_address=:69 tftp_options=-l -c -s tftp_directory就是我们上面创建的tftp文件夹目录,以后我们就将所有需要通过tftp传输的文件都放到这个文件夹里面,并且要给予这些文件相应的权限。
最后输入如下命令, 重启 tftp 服务器:
sudo service tftpd-hpa restart 至此,tftp服务器已经搭建好了,可以先来测试一下功能是否正常。
5.2 tftp文件传输测试 测试tftp功能是否正常,主要分为两步:
首先是将某个zimage镜像文件拷贝到ubuntu虚拟机的tftpboot文件夹中,并且给予 zimage 相应777的权限。
然后是通过开发板uboot的串口交互指令将文件从ubuntu传输到开发板的内存。
uboot串口交互指令中的tftp命令格式如下:
tftpboot [loadaddress] [[hostipaddr:]bootfilename] loadaddress是文件在dram中的存放地址,[[hostipaddr:]bootfilename]是要从ubuntu中下载的文件。
tftp传输文件,不需要输入文件在ubuntu中的完整路径,只需要输入文件名即可。
比如我们现在将tftpboot文件夹里面的zimage文件下载到开发板dram的0x80800000地址处,命令如下:
tftp 80800000 zimage 注:此次测试时,我的ubuntu虚拟机(作为tftp服务器)的ip变了,所以我又重新设置了ubuntu的ip
5.3 测试从网络启动linux 设置环境变量
这两个环境变量的具体含义先不展开讨论。
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw' setenv bootcmd 'tftp 80800000 zimage; tftp 83000000 imx6ull-14x14-evk-emmc.dtb; bootz 80800000 - 83000000' saveenv 通过tftp将zimage和设备树下载到板子的ram中
就是通过网路的方式(tftp)将系统文件下载到板子的内存中,这里使用的野火提供的yocto的zimage和dtb文件,将两个文件辅助到ubuntu的tftp服务器目录,依次输入如下指令:
tftp 80800000 zimagetftp 83000000 imx6ull-14x14-evk-emmc.dtb 启动内核
bootz 80800000 - 83000000 可以看到starting kernel ...的字样,表示内核已经启动。
再看看下板子,已经有启动画面了:
在过一会儿,会出现系统的图形界面,只是现在还不能操作,触摸没反应。
至此,uboot的移植基本完成,可以启动linux内核。启动内核之后,uboot的使命就完成了。
Gartner最新报告:安卓暂停合作,将限制华为增长空间
TPS25810用作USB-C端口控制器的特点及设计
调查显示消费者对5G和蜂窝网络的质量并不满意
火爆蓝牙手环芯片
人工智能落地之路怎么走
i.MX6ULL嵌入式Linux开发2-uboot移植实践
炬光科技和New Source Technology LLC签署代理协议
中国WJ-700新型无人机首飞成功,综合素质达到了世界先进的水平
统联精密:现有MIM产能在旺季已到高位运行状态
锂金属电池失效的主要原因在于非活性锂
上汽大众生产的大众帕萨特车型存在着碰撞不佳的问题
MMU内存管理单元的宏观理解
赛灵思推出世界最大FPGA芯片 拥有多达350亿个晶体管
高通在物联网市场走出了一条差异化道路
维修SMA100A信号发生器R&S罗德与施瓦茨信号源修理
mos管工作原理 mos管有什么用途和功能
3海底电缆故障 Vocus提前为ASC做好准备
技术不成熟,可穿戴设备尚未达到理想标准
特高压输电的特点_特高压输电的优缺点
水利安全监测方案——基于RTU200的解决方案