ZYNQ QSPI flash分区设置&启动配置

摘要:sysfs接口,它提供有关系统中每个MTD设备的完整信息。 此接口易于扩展,并且鼓励开发人员尽可能使用sysfs接口,而不是较旧的ioctl或/proc/mtd接口。

一款基于zynq架构的产品,只有qspi Flash,并没有其他的存储设备,

现在的要求固化某个应用程序app,设置开机启动.

但是根据厂家提供的sdk,编译出的镜像重启后,文件系统的内容都会还原,

之前的方案是每次都要把程序放到buildroot下,

然后重新编译,将rootfs、内核镜像、设备树打包到image.ub.bin中,

然后用jtag重新烧录到flash中。

这很不合理,所以要我们需要对flash进行分区,

然后将需要固化的程序通过flashcp烧写到flash中,然后在用dd命令导出该文件。

该操作依赖linux的MTD子系统。

MTD(Memory Technology Device)是内存技术设备,它为原始闪存设备(例如NAND,OneNAND,NOR 等)提供了一个抽象层。

这些不同类型的Flash都可以使用相同的API。

通常内核都默认支持MTD驱动。

MTD字符设备-通常称为**/dev/mtd0,/dev/mtd1**等。

这些字符设备提供对原始闪存的I/O访问。

它们支持许多ioctl调用,用于擦除擦除块,将其标记为不良或检查擦除块是否不良,获取有关MTD设备的信息等。

sysfs接口,它提供有关系统中每个MTD设备的完整信息。 此接口易于扩展,并且鼓励开发人员尽可能使用sysfs接口,而不是较旧的ioctl或/proc/mtd接口。

mtd子系统的sysfs接口已在内核中进行了说明,当前可在Documentation/ABI/ testing/sysfs-class-mtd中找到。

/proc/mtd proc文件系统文件提供常规的MTD信息。 这是旧版界面,而sysfs界面提供了更多信息。

MTD子系统支持带有软件和硬件ECC的 raw NAND闪存,OneNAND闪存,CFI(通用闪存接口)NOR闪存以及其他类型的闪存。

进入uboot

fmsh> sf probe 0SF: Detected n25q256 with page size 256 Bytes, erase size 4 KiB, total 32 MiB

该命令式查看设备信息。

一口君使用的平台需要固化2个文件:cfg(存储配置信息)、app(可执行程序)

加上必须烧录的boot.bin、image.ub.bin,一共有4个文件,

所以我们需要配置4个分区。

image.ub.bin的地址通常厂家也会给出默认地址,

进入uboot打印环境信息:

fmsh> printenvfit_size=0x153f000flash_off=0x500000load_addr=0x2000000qspiboot=echo Copying FIT from SPI flash to RAM... && sf probe && sf read ${load_addr} ${flash_off} ${fit_size} && bootm ${load_addr}echo Copying FIT from SPI flash to RAM... :打印提示信息sf probe:查看设备硬件信息sf read ${load_addr} ${flash_off} ${fit_size},从flash地址flash_off开始读取fit_size个字节到ram地址load_addrbootm ${load_addr}:启动内核

可以看到flash地址是flash_off:0x500000

2) 分区划分

那现在我们就可以给这4个文件设置分区信息了

镜像文件实际大小(hex)起始地址offset块数boot.bin3D09000x000000x50000061-80image.ub.binD59F800x5000000x1100000214-272cfg.bin2000x16000000x100001app.bin78000x16100000x300003

注意:

offset大小必须是 0x10000整数倍,这个是擦除的最小单位-块。

每个分区大小结合要固化的程序,合理分配,既要考虑后面程序升级需要预留足够空间,也不要太大,造成浪费

分区划分不能超过flash最大值32M

flash分区设备树说明如下:

Documentation\devicetree\bindings\mtd\partition.txtFixed Partitions================Partitions can be represented by sub-nodes of a flash device. This can be usedon platforms which have strong conventions about which portions of a flash areused for what purposes, but which don't use an on-flash partition table suchas RedBoot.The partition table should be a subnode of the flash node and should be named'partitions'. This node should have the following property:- compatible : (required) must be "fixed-partitions"Partitions are then defined in subnodes of the partitions node.For backwards compatibility partitions as direct subnodes of the flash device aresupported. This use is discouraged.NOTE: also for backwards compatibility, direct subnodes that have a compatiblestring are not considered partitions, as they may be used for other bindings.#address-cells & #size-cells must both be present in the partitions subnode of theflash device. There are two valid values for both:: for partitions that require a single 32-bit cell to represent theirsize/address (aka the value is below 4 GiB): for partitions that require two 32-bit cells to represent theirsize/address (aka the value is 4 GiB or greater).Required properties:- reg : The partition's offset and size within the flashOptional properties:- label : The label / name for this partition. If omitted, the label is takenfrom the node name (excluding the unit address).- read-only : This parameter, if present, is a hint to Linux that thispartition should only be mounted read-only. This is usually used for flashpartitions containing early-boot firmware images or data which should not beclobbered.- lock : Do not unlock the partition at initializationtime (not supported onall devices)

我们只需要关注分区的子节点说明即可:

reg描述某个flash分区的offset和sizelabel(可选)分区名字read-only(可选)该分区只读

根据前面所有分析内容,最终我们修改设备信息如下:

&qspi0 {status = "okay";flash0: s25fl256s@0 {compatible = "spi-flash","spansion,s25fl256s1", "jedec,spi-nor";reg = ; /* chip select */spi-max-frequency = ;m25p,fast-read;page-size = ;block-size = ; /* 2^16, 64KB */cdns,read-delay = ;cdns,tshsl-ns = ;cdns,tsd2d-ns = ;cdns,tchsh-ns = ;cdns,tslch-ns = ;#address-cells = ;#size-cells = ;partition@boot {label = "boot";reg = ; };partition@uimage.ub {label = "uimage.ub";reg = ; }; partition@prm {label = "cfg";reg = ; }; partition@kk_ap {label = "app";reg = ; }; };};

重新编译rootfs打包后重新启动即可。

# cat /proc/mtd dev: size erasesize namemtd0: 00500000 00010000 "boot"mtd1: 01100000 00010000 "uimage.ub"mtd2: 00010000 00010000 "cfg"mtd3: 00030000 00010000 "app"# ls /dev/mtd* -lcrw------- 1 root root 90, 0 Jan 1 00:00 /dev/mtd0crw------- 1 root root 90, 1 Jan 1 00:00 /dev/mtd0rocrw------- 1 root root 90, 2 Jan 1 00:00 /dev/mtd1crw------- 1 root root 90, 3 Jan 1 00:00 /dev/mtd1rocrw------- 1 root root 90, 4 Jan 1 00:00 /dev/mtd2crw------- 1 root root 90, 5 Jan 1 00:00 /dev/mtd2rocrw------- 1 root root 90, 6 Jan 1 00:00 /dev/mtd3crw------- 1 root root 90, 7 Jan 1 00:00 /dev/mtd3robrw------- 1 root root 31, 0 Jan 1 00:00 /dev/mtdblock0brw------- 1 root root 31, 1 Jan 1 00:00 /dev/mtdblock1brw------- 1 root root 31, 2 Jan 1 00:00 /dev/mtdblock2brw------- 1 root root 31, 3 Jan 1 00:00 /dev/mtdblock3

/dev/mtd0,/dev/mtd0ro,/dev/mtdblock0代表的是同一个MTD分区,但是**/dev/mtd0,/dev/mtd0ro都是字符设备,其中/dev/mtd0ro是只读字符设备,/dev/mtdblock0是块设备。 常见的mtd-utils,nand_write等工具只能操作/dev/mtdX**字符设备,因为只有字符设备才支持ioctl操作。

擦除/dev/mtd0分区的第1块数据。

flash_erase /dev/mtd0 0x0 1写 MTD 分区 NOR Flashflashcp /tmp/mtd.bin /dev/mtdX写 MTD 分区 NAND Flashnandwrite /tmp/image.bin /dev/mtdX读 MTD 分区dd if=/dev/mtdX of=/tmp/mtd.bin

首先需要下载文件导开发板,可以用sd卡、网口(tftp)、串口(rz命令),根据自己的开发板资源。

执行下面命令烧录:

flash_erase /dev/mtd2 0x0 1flashcp cfg.bin /dev/mtd2

导出分区文件

dd if=/dev/mtd2 of=/mnt/cfg.binflash_erase /dev/mtd3 0x0 3flashcp app /dev/mtd3

导出分区文件

dd if=/dev/mtd3 of=/mnt/app.bin

注意导出的文件除了我们烧录的文件之外,

尾部还有多余FF,所以还需要去掉这些多余的部分,

所以我们必须要还原文件。

如下图所示:

【文件必须以二进制形式打开才能看到,彭老师用的Hex Editor Neo】

下载地址:

还原文件有很多方法,一口君自己写了个小程序,

原理:

逐字节读取文件,然后判断是否是0xFF,连续读取到16个0xff(防止文件中也由多个0XFF出现),

则认为读到了有效文件尾部,记录有效文件长度,然后根据该长度,复制成最终文件,该文件就是我们所需要的最终文件。

#include #include #include #include #include #include int main(int argc, char** argv){int fd_p;int fdw_p;unsigned char c;int count = 0;int pos = 0;int i;if(argc != 3){printf("argument error\n");for(int i = 0; i = 16){break;}}else{count = 0;}pos++;}lSEEK(fd_p, SEEK_SET, 0);for(i=0; i

可见写入到分区的文件和我们从分区读取后再还原的文件时一致的。

重启后,再验证

从MD5校验码可知,可执行程序还原正确。

将exportimg拷贝文件系统**/mnt**下,(目录有执行权限即可)设置开机子启动脚本sdk/buildroot-xxxxxx/output/target/etc/init.d/rcS

文件尾部添加:

dd if=/dev/mtd2 of=/mnt/cfg.bindd if=/dev/mtd3 of=/mnt/app.bintouch /mnt/apptouch /mnt/cfgchmod 777 /mnt/appchmod 777 /mnt/cfg/mnt/exportimg /mnt/app.bin /mnt/app/mnt/exportimg /mnt/cfg.bin /mnt/cfgrm /mnt/cfg.binrm /mnt/app.bin/mnt/app &

本例在复旦微fmsh平台测试通过。 zynq平台应该也没问题。

有了MTD驱动,就可以将挂载jffs2分区。

后续会继续更新文章。

来源:一口Linux

相关推荐