uboot的启动特性:稳定性;速度
uboot的简化版启动流程:
1、设置状态寄存器 cpsr ,使CPU进入 SVC 特权模式,并且禁止 FIQ 和 IRQ;
2、关闭看门狗、中断、MMU、Cache;
3、初始化部分寄存器和外设(时钟、串口、Flash、内存);
4、自搬移uboot到内存中运行;
5、设置栈空间并初始化global_data;
6、剩余大部分硬件的初始化;
7、搬移Linux内核到内存;
推荐学习博客:Linux驱动开发:uboot启动流程详解_uboot启动linux_混分巨兽龙某某的博客-CSDN博客
二、uboot移植教学
嵌入式工程必备的技能就是贯通,需要从一种开发板的学习去学会其他开发板的大致开发流程(以一窥视万物)。
2.1 NXP官方uboot移植
为了保证产品研发的速度以及降低研发过程中错误率,公司产品一般都会以半导体厂商的开发板作为 ”蓝本“。自然地,uboot 的移植和使用肯定也是可以直接借鉴该 ”蓝本“。
NXP 官方原版的 Uboot 发送到 Ubuntu 中并解压,然后创建 VSCode 工程。
在 NXP 官方原版的 Uboot 中的 configs 中提供了很多的默认配置文件,其中以 mx6ul 开头的是 I.MX6UL 芯片的,mx6ull 开头的是 I.MX6ULL 开发板的。我们以关联性最强的 mx6ull_14x14_evk_emmc_defconfig 作为默认配置文件。
为了方便后续进行修改编译,作者建议编写如下的 shell 脚本(详情见代码注释),shell 脚本名为 mx6ull_14x14_emmc.sh,代码如下:
#!/bin/bash
#清理工程,每次编译uboot之前都清理一下工程
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
#配置uboot,选择与自己开发板最接近的uboot配置文件进行编译,方便后期修改
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_defconfig
#“make -j12”也就是使用 12 核来编译 uboot;v=1是设置编译过程的信息输出级别,1完全输出,0/无简化
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12
通过命令行:chmod 777 mx6ull_14x14_emmc.sh 赋予 shell 脚本可执行权限!通过下述命令运行该 shell 脚本:
./mx6ull_14x14_emmc.sh
编译完成以后会生成 u-boot.bin、u-boot.imx 等文件,但是这些文件是 NXP 官方 I.MX6ULL EVK 开发板。
将 imxdownload 软件拷贝到 uboot 源码根目录下,然后使用 imxdownload 软件将 u-boot.bin 烧写到 SD 卡中,烧写命令如下:
chmod 777 imxdownload //给予 imxdownload 可执行权限
./imxdownload u-boot.bin /dev/sdb //烧写到 SD 卡中,不能烧写到/dev/sda 或 sda1 里面
友情提示:SD 卡在 Linux 系统下的设备名称不一定是sdd亦或是sdb,通过:sudo fdisk -l 命令去检查一下 SD 卡到底是什么之后再进行烧入!
烧写完成以后将 SD 卡插入 I.MX6U-ALPHA 开发板的 TF 卡槽中,最后设置开发板从 SD 卡启动。打开 MobaXterm,设置好开发板所使用的串口并打开,复位开发板,MobaXterm 接收到如下图所示信息:
uboot 成功加载之后通常需要检查:(1)、SD 卡和 EMMC 驱动是否正常(常规情况下都是正常的),(2)、LCD 屏幕驱动是否正常(问题不大);(3)、网络驱动是否正常(核心部分)
考虑到后续需要通过网络加载 Linux 内核镜像等,所以网络驱动是必不可缺的部分!
uboot 启动的时候提示 “Board Net Initialization Failed” 和 “No ethernet found.” 这两行,说明网络驱动存在大问题。
作者概述:实际工作中, 一般情况下 SD 卡和 EMMC 等内存驱动都不会存在太大问题,核心部分的问题还是出现在网络驱动部分(比如:S3C2440)!!!
2.2 修改NXP官方uboot
先在 configs 目录下创建默认配置文件,复制 mx6ull_14x14_evk_emmc_defconfig,然后重命名为 mx6ull_alientek_emmc_defconfig,命令如下:
cd configs
cp mx6ull_14x14_evk_emmc_defconfig mx6ull_alientek_emmc_defconfig
然后将文件 mx6ull_alientek_emmc_defconfig 中的内容改成下面的:
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ull_alientek_emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK"
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MX6ULL_ALIENTEK_EMMC=y
CONFIG_CMD_GPIO=y
可以看出,mx6ull_alientek_emmc_defconfig 基本和 mx6ull_14x14_evk_emmc_defconfig 中的内容一样,只是第 1 行和第 4 行做了修改。修改的 2 行就是编译 uboot 配置时可以根据自己复制的副本进行配置编译了!
2.2.1 添加开发板对应的头文件
在目录 include/configs 下添加 I.MX6ULL-ALPHA 开 发 板 对 应 的 头 文 件 , 复 制 include/configs/mx6ullevk.h,并重命名为 mx6ull_alientek_emmc.h,命令如下:
cp include/configs/mx6ullevk.h mx6ull_alientek_emmc.h
修改防止重定义的 #ifndef 和 #define 的预处理代码:
mx6ull_alientek_emmc.h 里面有很多宏定义,这些宏定义基本用于配置 uboot,也有一些 I.MX6ULL 的配置项目。如果我们自己要想使能或者禁止 uboot 的某些功能,那就在 mx6ull_alientek_emmc.h 里面做修改即可。
2.2.2 添加开发板对应的板级文件夹
uboot 中每个板子都有一个对应的文件夹来存放板级文件,比如开发板上外设驱动文件等等。NXP 的 I.MX 系列芯片的所有板级文件夹都存放在 board/freescale 目录下,在这个目录下有个名为 mx6ullevk 的文件夹,这个文件夹就是 NXP 官方 I.MX6ULL EVK 开发板的板级文件夹。复制 mx6ullevk,将其重命名为 mx6ull_alientek_emmc,命令如下:
cd board/freescale/
cp mx6ullevk/ -r mx6ull_alientek_emmc
进入 mx6ull_alientek_emmc 目录中 , 将 其 中 的 mx6ullevk.c 文 件 重 命 名 为 mx6ull_alientek_emmc.c,命令如下:
cd mx6ull_alientek_emmc
mv mx6ullevk.c mx6ull_alientek_emmc.c
我们还需要对 mx6ull_alientek_emmc 目录下的文件做一些修改:
1、修改 mx6ull_alientek_emmc 目录下的 Makefile 文件
将 mx6ull_alientek_emmc 下的 Makefile 文件内容改为如下所示:
第 6 行的 obj-y,改为 mx6ull_alientek_emmc.o,这样才会编译 mx6ull_alientek_emmc.c 这个文件。
2、修改 mx6ull_alientek_emmc 目录下的 imximage.cfg 文件
将 imximage.cfg 中的下面一句:PLUGIN board/freescale/mx6ullevk/plugin.bin 0x00907000
改为:PLUGIN board/freescale/mx6ull-alientek_emmc/plugin.bin 0x00907000
3、修改 mx6ull_alientek_emmc 目录下的 Kconfig 文件
修改 Kconfig 文件,修改后的内容如下:
if TARGET_MX6ULL_ALIENTEK_EMMC
config SYS_BOARD
default "mx6ull_alientek_emmc"
config SYS_VENDOR
default "freescale"
config SYS_CONFIG_NAME
default "mx6ull_alientek_emmc"
endif
4、修改 mx6ull_alientek_emmc 目录下的 MAINTAINERS 文件
修改 MAINTAINERS 文件,修改后的内容如下:
MX6ULLEVK BOARD
M: Peng Fan <peng.fan@nxp.com>
S: Maintained
F: board/freescale/mx6ull_alientek_emmc/
F: include/configs/mx6ull_alientek_emmc.h
F: configs/mx6ull_alientek_emmc_deconfig
2.2.3 修改 U-Boot 图形界面配置文件
uboot 是支持图形界面配置。修改文件 arch/arm/cpu/armv7/mx6/Kconfig (如果用的 I.MX6UL 的话,应该修改 arch/arm/Kconfig 这个文件),在 207 行加入如下内容:
config TARGET_MX6ULL_ALIENTEK_EMMC
bool "Support mx6ull_alientek_emmc"
select MX6ULL
select DM
select DM_THERMAL
在最后一行的 endif 的前一行添加如下内容:
source "board/freescale/mx6ull_alientek_emmc/Kconfig"
上述操作都是为了能够创建出自己制作的开发板的编译和配置文件,这样以后就可以在自己创建的副本中改动,不需要在半导体厂商提供的 ”蓝本“ 代码上改动!
2.3 LCD驱动修改
一般 uboot 中修改驱动基本都是在 xxx.h 和 xxx.c 这两个文件中进行的,xxx 为板子名称,比如 mx6ull_alientek_emmc.h 和 mx6ull_alientek_emmc.c 这两个文件。
一般修改 LCD 驱动重点注意以下几点:
**①、**LCD 所使用的 GPIO,查看 uboot 中 LCD 的 IO 配置是否正确。
**②、**LCD 背光引脚 GPIO 的配置。
**③、**LCD 配置参数是否正确。
正点原子的 I.MX6U-ALPHA 开发板 LCD 原理图和 NXP 官方 I.MX6ULL 开发板一致,也就是 LCD 的 IO 和背光 IO 都一样的,所以 IO 部分就不用修改了。需要修改的是 LCD 参数,打开文件 mx6ull_alientek_emmc.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 的各个参数等。 我们需要根据自己 LCD 屏幕的参数去修改该 displays 变量内的数据,作者是 7 寸屏幕,修改后如下:
struct display_info_t const displays[] = {{
.bus = MX6UL_LCDIF1_BASE_ADDR,
.addr = 0,
.pixfmt = 24,
.detect = NULL,
.enable = do_enable_parallel_lcd,
.mode = {
.name = "TFT7016",
.xres = 1024,
.yres = 600,
.pixclock = 19531,
.left_margin = 140,
.right_margin = 160,
.upper_margin = 20,
.lower_margin = 12,
.hsync_len = 20,
.vsync_len = 3,
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED
}
}
};
打开 mx6ull_alientek_emmc.h,找到所有如下语句:
panel = TFT43AB 改为 panel = TFT7016
2.4 网络驱动修改
网络驱动的修改是非常繁琐且重要的,因为后续 Linux 内核的加载,虚拟根文件系统 rootfs 都离不开网络驱动的支持。
2.4.1 I.MX6U-ALPHA 开发板网络简介
I.MX6UL/ULL 内部有个以太网 MAC 外设,也就是 ENET,需要外接一个 PHY 芯片来实现网络通信功能,也就是内部 MAC+外部 PHY 芯片的方案。大家可能听过 DM9000 这个网络芯片,在一些没有内部 MAC 的 CPU 中,比如三星的 2440,4412 等,就会采用 DM9000 来实现联网功能。DM9000 提供了一个类似 SRAM 的访问接口,主控 CPU 通过这个接口即可与 DM9000 进行通信,DM9000 就是一个 MAC+PHY 芯片。
I.MX6UL/ULL 有两个网络接口 ENET1 和 ENET2,正点原子的 I.MX6U-ALPHA 开发板提供了这两个网络接口,其中 ENET1 和 ENET2 都使用 LAN8720A 作为 PHY 芯片(正点的外部 PHY 芯片与 NXP 官方的 IMX6ULL 不一样)。
网络驱动的匹配需要根据硬件的 PCB 原理图来进行分析,需要把握住根据 PHY 芯片的连接引脚与芯片驱动进行修改!
正点原子 IMX6ULL 的 ENET1:
ENET1 的网络 PHY 芯片为 LAN8720A,通过 RMII 接口与 I.MX6ULL 相连,正点原子 I.MX6U-ALPHA 开发板的 ENET1 引脚与 NXP 官方的 I.MX6ULL EVK 开发板基本一样,唯独复位引脚不同。从上图可以看出,正点原子 I.MX6U-ALPHA 开发板的 ENET1 复位引脚 ENET1_RST 接到了 I.M6ULL 的 SNVS_TAMPER7 这个引脚上。I.MX6U-ALPHA 开发板 ENET1 上连接的 LAN8720A器件地址为 0X0,所示我们要修改 ENET1 网络驱动的话重点就三点:
①、ENET1 复位引脚初始化。
②、LAN8720A 的器件 ID。
③、LAN8720 驱动
正点原子 IMX6ULL 的 ENET2:
关于 ENET2 网络驱动的修改也注意一下三点:
①、ENET2 的复位引脚,从上图可以看出,ENET2 的复位引脚 ENET2_RST 接到了 I.MX6ULL 的 SNVS_TAMPER8 上。
②、ENET2 所使用的 PHY 芯片器件地址,从上图可以看出,PHY 器件地址为 0X1。
③、LAN8720 驱动,ENET1 和 ENET2 都使用的 LAN8720,所以驱动肯定是一样的。
2.4.2 网络 PHY 地址修改
首先修改 uboot 中的 ENET1 和 ENET2 的 PHY 地址和驱动,打开 mx6ull_alientek_emmc.h 这个文件,找到如下代码并进行如下修改:
如果要使用 LAN8720A,那么就得将 CONFIG_PHY_MICREL 改为 CONFIG_PHY_SMSC,也就是使能 uboot 中的 SMSC 公司中的 PHY 驱动,因为 LAN8720A 就是 SMSC 公司生产的。
通过宏定义:CONFIG_FEC_ENET_DEV 的 0 或 1 决定是选择启用 ENET1 和 ENET2;
需要修改的代码部分如下:
**1、**修改 ENET1 网络 PHY 的地址。
**2、**修改 ENET2 网络 PHY 的地址。
**3、**使能 SMSC 公司的 PHY 驱动。
2.4.3 删除 uboot 中 74LV595 的驱动代码
uboot 中网络 PHY 芯片地址修改完成以后就是网络复位引脚的驱动修改了,打开 mx6ull_alientek_emmc.c,找到如下代码进行如下修改:
ENET1 的复位引脚连接到 SNVS_TAMPER7 上,对应 GPIO5_IO07,ENET2 的复位引脚连接到 SNVS_TAMPER8 上,对应 GPIO5_IO08:
/* #define IOX_SDI IMX_GPIO_NR(5, 10)
#define IOX_STCP IMX_GPIO_NR(5, 7)
#define IOX_SHCP IMX_GPIO_NR(5, 11)
#define IOX_OE IMX_GPIO_NR(5, 8) */
#define ENET1_RESET IMX_GPIO_NR(5,7)
#define ENET2_RESET IMX_GPIO_NR(5,8)
继续在 mx6ull_alientek_emmc.c 中找到如下代码也删除:
static iomux_v3_cfg_t const iox_pads[] = {
/* IOX_SDI */
MX6_PAD_BOOT_MODE0__GPIO5_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL),
/* IOX_SHCP */
MX6_PAD_BOOT_MODE1__GPIO5_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL),
/* IOX_STCP */
MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
/* IOX_nOE */
MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
};
继续在 mx6ull_alientek_emmc.c 中找到函数 iox74lv_init,iox74lv_init 函数是 74LV595 的初始化函数,iox74lv_set 函数用于控制 74LV595 的 IO 输出电平,将这两个函数全部删除掉!
在 mx6ull_alientek_emmc.c 中找到 board_init 函数,此函数是板子初始化函数,会被 board_init_r 调用,board_init 会调用 imx_iomux_v3_setup_multiple_pads 和 iox74lv_init 这两个函数来初始化 74lv595 的 GPIO,将这两行删除掉。至此,mx6ull_alientek_emmc.c 中关于 74LV595 芯片的驱动代码都删除掉了,接下来就是添加 I.MX6U-ALPHA 开发板两个网络复位引脚了。
2.4.4 添加 I.MX6U-ALPHA 开发板网络复位引脚驱动
在 mx6ull_alientek_emmc.c 中存在结构体数组 fec1_pads 和 fec2_pads 是 ENET1 和 ENET2 这两个网口的 IO 配置参数,在这两个数组中添加两个网口的复位 IO 配置参数,完成以后如下所示:
/*
* pin conflicts for fec1 and fec2, GPIO1_IO06 and GPIO1_IO07 can only
* be used for ENET1 or ENET2, cannot be used for both.
*/
static iomux_v3_cfg_t const fec1_pads[] = {
MX6_PAD_GPIO1_IO06__ENET1_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
MX6_PAD_GPIO1_IO07__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_DATA0__ENET1_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_DATA1__ENET1_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_EN__ENET1_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),
MX6_PAD_ENET1_RX_DATA0__ENET1_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_RX_DATA1__ENET1_RDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_RX_ER__ENET1_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET1_RX_EN__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
};
static iomux_v3_cfg_t const fec2_pads[] = {
MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET2_TX_DATA0__ENET2_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET2_TX_DATA1__ENET2_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
MX6_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),
## 最后
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**
**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
![img](https://img-blog.csdnimg.cn/img_convert/a1c135a3c9dfa2f719e38fb4cfd44417.png)
![img](https://img-blog.csdnimg.cn/img_convert/a9e99e429593c531918c17456f4ca75d.jpeg)
![img](https://img-blog.csdnimg.cn/img_convert/0457eb191bca1845cb451bf14582beef.png)
![img](https://img-blog.csdnimg.cn/img_convert/eb8f624be60a188fd0d1c90d24799088.png)
![img](https://img-blog.csdnimg.cn/img_convert/560224d2fb4d2461585790e17369ae53.png)
![img](https://img-blog.csdnimg.cn/img_convert/a48400c725d54d884acdf59ae9454c74.png)
![](https://img-blog.csdnimg.cn/img_convert/5a17f780e9b8650c5d17fc5c44feb80f.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!
全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
[外链图片转存中...(img-FwdOmk4B-1715587302042)]
[外链图片转存中...(img-tUpZojju-1715587302043)]
[外链图片转存中...(img-Mt09rFIe-1715587302044)]
[外链图片转存中...(img-jitOFRp0-1715587302044)]
[外链图片转存中...(img-qAZvtIAE-1715587302045)]
[外链图片转存中...(img-kQnMwGA2-1715587302045)]
[外链图片转存中...(img-bWjpknk6-1715587302046)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!