0. 教程完整目录
- 00 - 嵌入式Linux系统中Bootloader的作用和基本运行原理
- 01 - 下载uboot源码并使用VSCode远程查看源码、编译uboot(2012.04.01版本)
- 02 - 详细探索uboot启动过程(基于S3C2410处理器)
- 03 - 初步移植uboot 2012.04到JZ2440(修改时钟,配置串口)
- 04 - 移植uboot 2012.04到JZ2440(支持Nor Flash读写)
- 05 - 移植uboot 2012.04到JZ2440(支持Nand Flash读写)
- 06 - 移植uboot 2012.04到JZ2440(支持DM9000C网卡)
- 07 - 移植uboot 2012.04到JZ2440(裁剪uboot大小)
- 08 - 移植uboot 2012.04到JZ2440(设置mtd分区表)
- 09 - 移植uboot 2012.04到JZ2440(设置默认环境变量参数)
- 10 - 移植uboot 2012.04到JZ2440(烧写Linux内核、烧写yaffs2文件系统)
- 11 - 移植uboot 2012.04到JZ2440(移植完成,制作uboot补丁)
1. mtd分区规划及其作用
uboot支持各种设备之后,接下来的工作就是烧写内核、烧写文件系统,所以需要对整块Nand Flash的空间作以规划,大致分为以下四个空间即可:
- bootloader空间
- 内核参数空间
- 内核空间
- 文件系统空间
但是目前我们仅知道uboot.bin被裁剪到了217KB,而不知道其它三个空间的信息,而且是第一次移植,对内核参数占用空间、内核空间的大小没有概念,所以我们需要借助别人已经制作好的内核和文件系统来查看这个信息。
启动JZ2440官方提供的uImage_4.3
内核之后可以看到对整块Nand Flash的MTD分区信息:
Creating 4 MTD partitions on "NAND 256MiB 3,3V 8-bit":
0x00000000-0x00040000 : "bootloader"
0x00040000-0x00060000 : "params"
0x00060000-0x00260000 : "kernel"
0x00260000-0x10000000 : "root"
那么,mtd这样规划后有什么作用呢?
mtd的作用仅仅是给地址起个别名,方便使用,比如要烧写内核时要写0x00060000这个地址,就可以用 mtd2 这个名字代替,使代码变得更加通用。
2. 开启mtdparts命令支持
2.1. 添加宏CONFIG_CMD_MTDPARTS
mtdparts命令的相关实现在common/cmd_mtdparts.c
文件中,目前uboot命令中无此命令,所以查看其同目录的makefile文件,将此文件加入工程中编译。
makefile中的内容如下,需要定义 CONFIG_CMD_MTDPARTS 宏定义:
在单板配置文件中添加该宏定义:
2.2. 添加宏CONFIG_MTD_DEVICE
编译之后,发现报错信息如下:
在mtdparts命令的实现文件中调用了函数 get_mtd_device_nm,然而此函数没有定义,在VS Code中找到该函数定义在 drivers/mtd/mtdcore.c
文件中,说明此文件没有包含到工程中,继续查看mtdcore.c 文件目录中的makefile,可以看到需要定义宏CONFIG_MTD_DEVICE
:
继续在单板配置文件中添加该宏定义:
再次编译,编译成功,烧写到开发板,在串口终端中查看结果,已经支持mtdpars命令了:
2.3. 添加默认配置宏
再来查看一下是否能用:
使用时出现错误,提示mtdids没有定义,当前没有默认值。
搜索此mtdids,查找问题,果然在文件common/cmd_mtdparts.c
中找到结果:
在单板配置文件中,仿照其它单板文件的配置,添加这两个宏定义:
#define MTDIDS_DEFAULT "nand0=jz2440_nand.0"
#define MTDPARTS_DEFAULT "mtdparts=jz2440_nand.0:" \
"256k(uboot)ro," \
"128k(params)ro," \
"2m(kernel)," \
"-(filesystem)"
再次编译,下载到开发板进行测试:
这次mtd_parts正常打印出了刚刚设置的默认mtdids和mtdparts信息。
2.4. 测试mtdparts分区表是否可以正常使用
首先使用如下命令设置默认分区表:
mtdparts default
接着四个分区依次进行擦除测试:
nand erase.part uboot
nand erase.part params
nand erase.part kernel
nand erase.part filesystem
擦除没有问题,再进行内核烧写测试:
nand write 30000000 kernel
3. 自动执行mtdparts default命令
在之前的 2.4 节中,在使用mtd分区名称之前手动执行了mtdparts default命令设置分区表,但是在实际使用时,不可能每次在uboot命令行中手动执行这条命令,然后启动内核,所以在内核未启动之前,就要在代码中执行此命令。
在文件arch/arm/lib/board.c
中,在函数board_init_r
的最后,在main_loop之前添加这行代码,自动执行命令:
//手动加入需要执行的命令
run_command("mtdparts default", 0);
接着编译,下载到开发板中,测试。
上电之后执行mtdparts
查看分区表,分区表已经设置成功,正常打印:
再来测试使用mtd分区名称烧写内核:
接着重新上电,从nand flash中读取出内核:
接收更多精彩文章及资源推送,欢迎订阅我的微信公众号:『mculover666』。