查看: 879|回复: 0

[分享] 【经验分享】i.MX6ULL开发:嵌入式Linux开发2-uboot移植实践

[复制链接]
  • TA的每日心情
    开心
    2020-12-18 12:56
  • 签到天数: 55 天

    [LV.5]常住居民I

    70

    主题

    220

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    1583
    最后登录
    2024-4-19
    发表于 2022-8-15 09:27:47 | 显示全部楼层 |阅读模式
    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文件
    将原始内容:
    1. # (C) Copyright 2015 Freescale Semiconductor, Inc.## SPDX-License-Identifier:      GPL-2.0+#
    2. obj-y  := mx6ullevk.o
    3. extra-$(CONFIG_USE_PLUGIN) :=  plugin.bin$(obj)/plugin.bin: $(obj)/plugin.o
    4.        $(OBJCOPY) -O binary --gap-fill 0xff [        DISCUZ_CODE_24        ]lt; $@
    复制代码

    其中的依赖项修改为:
    obj-y  := mx6ull_myboard.o
    图片 1.png
    这样才会编译mx6ull_myboard.c这个文件。
    2.3.2 修改imximage.cfg文件
    然后修改 board/freescale/mx6ull_myboard 目录下的imximage.cfg文件
    imximage.cfg中的下面一句:
    PLUGIN board/freescale/mx6ullevk/plugin.bin 0x00907000
    改为:
    PLUGIN board/freescale/mx6ull_myboard/plugin.bin 0x00907000
    图片 2.png
    2.3.3 修改Kconfig文件
    接着修改 board/freescale/mx6ull_myboard 目录下的Kconfig文件
    将原始内容:
    1. if TARGET_MX6ULL_14X14_EVK || TARGET_MX6ULL_9X9_EVK
    2. config SYS_BOARD
    3.        default "mx6ullevk"
    4. config SYS_VENDOR
    5.        default "freescale"
    6. config SYS_CONFIG_NAME
    7.        default "mx6ullevk"
    8. endif
    复制代码

    修改为:
    图片 3.png
    2.3.4 修改MAINTAINERS文件
    再接着修改 board/freescale/mx6ull_myboard 目录下的MAINTAINERS文件
    将原始内容:
    1. MX6ULLEVK BOARD
    2. M:      Peng Fan <peng.fan@nxp.com>
    3. S:      Maintained
    4. F:      board/freescale/mx6ullevk/
    5. F:      include/configs/mx6ullevk.h
    6. F:      configs/mx6ull_14x14_evk_defconfig
    7. F:      configs/mx6ull_9x9_evk_defconfig
    复制代码

    修改为:
    图片 4.png
    2.3.5 重命名板子的c文件
    board/freescale/mx6ull_myboard 目录下原来的mx6ullevk.c重命名为mx6ull_myboard.c
    图片 5.png
    2.4 修改U-Boot图形界面配置文件
    最后修改arch/arm/cpu/armv7/mx6/目录下的Kconfig文件
    注意这里的Kconfigboard/freescale/mx6ull_myboard目录下的Kconfig是不一样的。
    207行插入一些内容:
    1. config TARGET_MX6ULL_MYBOARD
    2.        bool "Support mx6ull_myboard"
    3.        select MX6ULL
    4.        select DM
    5.        select DM_THERMAL
    复制代码

    图片 6.png
    然后,在最后一行的endif的前一行添加如下内容:
    1. source "board/freescale/mx6ull_myboard/Kconfig"
    复制代码

    图片 7.png
    2.5 创建编译脚本
    uboot-imx-rel_imx_4.1.15_2.1.0_ga目录下新建一个名为build_myboard.sh shell 脚本,写入如下内容:
    1. 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"
    如果有很多文件都引用了这个头文件, 那就说明新板子添加成功:
    图片 8.png
    uboot进行编译并运行,实际的效果应该和原厂uboot的效果一样(LCD无法显示)
    图片 9.png
    总结一下刚才都有哪些修改:
    右端灰色的为原厂开发板的相关文件,黄色的为模仿原厂文件,新添加并修改的自己开发板的文件。
    图片 10.png
    下面进行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官方的开发板一致,也就是LCDIO和背光IO都是一样的, 所以IO部分就不用修改了,只需修改之后的LCD参数。
    3.1 修改c文件配置
    打开文件 mx6ull_myboard.c,需要修改下面这段内容:
    1. struct display_info_t const displays[] = {{
    2. .bus = MX6UL_LCDIF1_BASE_ADDR,
    3. .addr = 0,
    4. .pixfmt = 24,
    5. .detect = NULL,
    6. .enable = do_enable_parallel_lcd,
    7. .mode = {
    8. .name   = "TFT43AB",
    9. .xres           = 480,
    10. .yres           = 272,
    11. .pixclock       = 108695,
    12. .left_margin    = 8,
    13. .right_margin   = 4,
    14. .upper_margin   = 2,
    15. .lower_margin   = 4,
    16. .hsync_len      = 41,
    17. .vsync_len      = 10,
    18. .sync           = 0,
    19. .vmode          = FB_VMODE_NONINTERLACED} } };
    复制代码

    先来分析一下这段代码,该代码定义了一个变量displays,类型为display_info_t,这个结构体是LCD信息结构体,其中包括了LCD的分辨率,像素格式,LCD的各个参数等。
    display_info_t 定义在文件 arch/arm/include/asm/imx-common/video.h  中,定义如下:
    1. struct display_info_t {
    2. int bus;
    3. int addr;
    4. int pixfmt;
    5. int (*detect)(struct display_info_t const *dev);
    6. void (*enable)(struct display_info_t const *dev);
    7. struct fb_videomode mode;};
    复制代码

    这里的pixfmt是像素格式,也就是一个像素点是多少位,如果是RGB565的话就是16位,如果是RGB888的话就是24位,一般使用 RGB888
    结构体display_info_t还有个mode成员变量,此成员变量也是个结构体,为fb_videomode,定义在文件 include/linux/fb.h 中,定义如下:
    1. struct fb_videomode {
    2. const char *name; /* optional */
    3. u32 refresh;  /* optional */
    4. u32 xres;
    5. u32 yres;
    6. u32 pixclock;
    7. u32 left_margin;
    8. u32 right_margin;
    9. u32 upper_margin;
    10. u32 lower_margin;
    11. u32 hsync_len;
    12. u32 vsync_len;
    13. u32 sync;
    14. u32 vmode;
    15. 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_marginVBP(vertical back porch),垂直同步后肩
    lower_marginVFP(vertical front porch),垂直同步前肩
    hsync_len HSPW(horizontal sync pulse width),行同步脉宽
    vsync_lenVSPW(vertical sync pulse width),垂直同步脉宽

    vmode :大多数使用 FB_VMODE_NONINTERLACED,也就是不使用隔行扫描。
    这些参数需要与实用的LCDd的参数一致。
    野火的7RGB屏幕(GT911800x480)的一些参数如下:
    参数值width800height480HBP46HFP22VBP23VFP22HSW1VSW1
    注意像素时钟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屏幕的配置参数如下:
    1. struct display_info_t const displays[] = {{
    2. .bus = MX6UL_LCDIF1_BASE_ADDR,
    3. .addr = 0,
    4. .pixfmt = 24,
    5. .detect = NULL,
    6. .enable = do_enable_parallel_lcd,
    7. .mode = {
    8. .name   = "GT911",
    9. .xres           = 800,
    10. .yres           = 480,
    11. .pixclock       = 36496,
    12. .left_margin    = 46,  //HBPD
    13. .right_margin   = 22,  //HFPD
    14. .upper_margin   = 23,  //VBPD
    15. .lower_margin   = 22,  //VFPD
    16. .hsync_len      = 1,   //HSPW
    17. .vsync_len      = 1,   //VSPW
    18. .sync           = 0,
    19. .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
    图片 11.png
    但某些情况有可能还会遇到LCD 并没有工作,还是黑屏,这是什么原因呢?
    uboot 命令模式输入print来查看环境变量 panel 的值,会发现panel的值要是TFT43AB(或其他的,反正不是GT911):
    panel=TFT43ABscript=boot.scr

    Environment size: 2431/8188 bytes=>
    这是因为之前有将环境变量保存到EMMC中,uboot启动以后会先从EMMC中读取环境变量,如果EMMC中没有环境变量的话才会使用 mx6ull_alientek_emmc.h 中的默认环境变量。
    如果EMMC中的环境变量panel不等于GT911,那么LCD显示肯定不正常,我们只需要在uboot中修改panel的值为GT911即可,在uboot的命令模式下输入如下命令:
    setenv panel GT911
    saveenv
    上述命令修改环境变量panelGT911并保存后,按下复位键重启uboot,此时 LCD 驱动就工作正常了。
    4 网络测试
    I.MX6ULL内部有个以太网MAC外设,也就是ENET,需要外接一个PHY芯片来实现网络通信功能,也就是内部MAC+外部PHY芯片的方案。 I.MX6ULL有两个网络接口ENET1ENET2,野火的开发板提供了这两个网络接口,其中ENET1ENET2都使用是和原厂开发板一样的KSZ8081作为PHY芯片。
    因此,网络驱动部分的uboot不需要修改,下面就只是来测试一下网路功能。
    4.1 连接网线并查看启动情况
    首先将开发板通过网线连接到局域网的路由器中(自己的电脑也要在同一个局域网,这样ubuntu虚拟机则也在同一个局域网)。
    图片 12.png
    然后启动uboot,串口查看相关的打印信息,如下图,可以看到网络端口的FEC1(注意是uboot程序中默认设置的,不是因为网线插在了左边就自动识别FEC1),但是提示网络地址未设置。
    图片 13.png
    4.2 设置网络参数
    下面就来设置一下,首先是设置开发板的IP,在设置之前,先借助Windows电脑的cmdping+ip指令来测试某个IP是否被使用,如我的192.168.5.102未被使用,就可以设为开发板的IP
    图片 14.png
    除了设置开发板的IP,还要设置一些其它的网络参数,具体如下:
    1. setenv ipaddr 192.168.5.102 //开发板 IP 地址
    2. setenv ethaddr 00:04:9f:04:d2:35 //开发板网卡 MAC 地址
    3. setenv gatewayip 192.168.5.1 //开发板默认网关
    4. setenv netmask 255.255.255.0 //开发板子网掩码
    5. setenv serverip 192.168.5.101 //服务器地址,也就是 Ubuntu 地址
    6. saveenv //保存环境变量
    复制代码

    开发板的MAC地址是一个长度为48(6个字节)的地址,每个字节间通过冒号间隔,理论上只要局域网内各网络设备不冲突,该地址可任意设置。
    局域网的默认网关和子网掩码需要根据自己的实际情况设置(不知道是多少的,可以借助Windows电脑的cmd中的ipconfig指令来查看)
    服务器的地址就是ubuntu虚拟机的地址(可以通过linuxifconfig指令来查看)
    4.3 测试另一个网口
    打开 include/configs/mx6ull_alientek_emmc.h ,将CONFIG_FEC_ENET_DEV修改为 0, 重新编译uboot并烧写到SD卡中。
    图片 15.png
    将网线连接到开发板右边的网口上,按照之前的测试方法再次测试:
    图片 16.png
    5 uboot启动Linux内核测试
    uboot的最终目的就是启动Linux内核,所以需要通过启动Linux内核来判断uboot移植是否成功。
    启动Linux内核。我们测试两种启动Linux内核的方法:
    EMMC启动
    从网络启动
    EMMC启动也就是将编译出来的Linux镜像文件zImage设备树文件保存在EMMC中,ubootEMMC中读这两个文件并启动。 由于我们板子的EMMC中可能还没有linux镜像文件和设备树文件,所以先不测试这种方法。
    从网络启动,是指将linux镜像文件和根文件系统都放到Ubuntu下某个指定的文件夹中,然后通过nfs或者tftp等传输方式将系统文件(zImage和设备树文件)从Ubuntu中直接下载到开发板的内存中,EMMC中则不需要有系统文件。这种方式的作用就是方便调试,免去将代码固化到开发板的过程。当然,当开发板掉电,内存的系统文件就没了。
    下面就来通过网络调试的方法来测试uboot是否能正常启动Linux内核。
    在测试之前,先来介绍一下在ubuntu虚拟机上如何搭建tftp来传输文件
    5.1 tftp服务搭建
    Ubuntu上搭建TFTP服务器,需要安装tftp-hpatftpd-hpa,命令如下:
    sudo apt-get install tftp-hpa tftpd-hpa  sudo apt-get install xinetd
    TFTP也需要一个文件夹来存放文件,在用户目录下新建一个目录,示例命令如下:
    mkdir /home/xxpcb/myTest/tftpdir chmod 777 /home/xxpcb/myTest/tftpdir
    最后配置 tftp, 安装完成以后,新建文件/etc/xinetd.d/tftp 如果没有/etc/xinetd.d 目录的话自行创建,然后在里面输入如下内容:
    1. server tftp{
    2.     socket_type    = dgram
    3.     protocol       = udp
    4.     wait           = yes
    5.     user           = root
    6.     server         = /usr/sbin/in.tftpd
    7.     server_args    = -s /home/xxpcb/myTest/tftpdir/
    8.     disable        = no
    9.     per_source     = 11
    10.     cps            = 100 2
    11.     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文件下载到开发板DRAM0X80800000地址处,命令如下:
    tftp 80800000 zImage
    注:此次测试时,我的ubuntu虚拟机(作为tftp服务器)的IP变了,所以我又重新设置了ubuntuIP
    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
    通过tftpzImage和设备树下载到板子的RAM
    就是通过网路的方式(tftp)将系统文件下载到板子的内存中,这里使用的野火提供的yoctozImagedtb文件,将两个文件辅助到ubuntutftp服务器目录,依次输入如下指令:
    tftp 80800000 zImage tftp 83000000 imx6ull-14x14-evk-emmc.dtb
    启动内核
    bootz 80800000 - 83000000
    可以看到Starting kernel ...的字样,表示内核已经启动。
    再看看下板子,已经有启动画面了:
    图片 17.png
    在过一会儿,会出现系统的图形界面,只是现在还不能操作,触摸没反应。
    图片 18.png
    至此,uboot的移植基本完成,可以启动Linux内核。启动内核之后,uboot的使命就完成了。

    签到
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-20 12:12 , Processed in 0.115911 second(s), 20 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表