百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

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

gudong366 2025-04-08 12:23 7 浏览

需求:

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

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

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

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

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

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

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

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

0. MTD基础

该操作依赖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闪存以及其他类型的闪存。

1. 查看qspi flash大小

进入uboot

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

该命令式查看设备信息。

可以看到qspi flash容量为32MB,即0x1E84800

2. 需要固化镜像分区地址设置

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

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

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

1) boot.bin、image.ub.bin地址

其中boot.bin包含了fpga的ip核和启动必要的文件信息,地址固定为0

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

进入uboot打印环境信息:

fmsh> printenv

fit_size=0x153f000
flash_off=0x500000
load_addr=0x2000000
qspiboot=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_addr
bootm ${load_addr}:
 启动内核

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

2) 分区划分

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

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

注意:

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

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

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

3. 设备树

flash分区设备树说明如下:

Documentation\devicetree\bindings\mtd\partition.txt


Fixed Partitions
================

Partitions can be represented by sub-nodes of a flash device. This can be used
on platforms which have strong conventions about which portions of a flash are
used for what purposes, but which don't use an on-flash partition table such
as 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 are
supported. This use is discouraged.
NOTE: also for backwards compatibility, direct subnodes that have a compatible
string 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 the
flash device. There are two valid values for both:
<1>: for partitions that require a single 32-bit cell to represent their
     size/address (aka the value is below 4 GiB)
<2>: for partitions that require two 32-bit cells to represent their
     size/address (aka the value is 4 GiB or greater).

Required properties:
- reg : The partition's offset and size within the flash

Optional properties:
- label : The label / name for this partition.  If omitted, the label is taken
  from the node name (excluding the unit address).
- read-only : This parameter, if present, is a hint to Linux that this
  partition should only be mounted read-only. This is usually used for flash
  partitions containing early-boot firmware images or data which should not be
  clobbered.
- lock : Do not unlock the partition at initialization time (not supported on
  all devices)

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

  1. reg描述某个flash分区的offset和size
  2. label(可选)分区名字
  3. read-only(可选)该分区只读

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

&qspi0 {
    status = "okay";
    flash0: s25fl256s@0 {
        compatible = "spi-flash","spansion,s25fl256s1", "jedec,spi-nor";
        reg = <0>;      /* chip select */
        spi-max-frequency = <50000000>;
        m25p,fast-read;
        page-size = <256>;
        block-size = <16>;  /* 2^16, 64KB */
        cdns,read-delay = <2>;
        cdns,tshsl-ns = <0>;
        cdns,tsd2d-ns = <0>;
        cdns,tchsh-ns = <0>;
        cdns,tslch-ns = <0>;

        #address-cells = <1>;
        #size-cells = <1>;
        partition@boot {
            label = "boot";
            reg = <0x0000000 0x500000>;   
        };
        partition@uimage.ub {
            label = "uimage.ub";
            reg = <0x500000 0x1100000>;   
        }; 
        partition@prm {
            label = "cfg";
            reg = <0x1600000 0x10000>;   
        }; 
        partition@kk_ap {
            label = "app";
            reg = <0x1610000 0x30000>;   
        };          
    };
};

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

4. 查看分区信息

# cat /proc/mtd 
dev:    size   erasesize  name
mtd0: 00500000 00010000 "boot"
mtd1: 01100000 00010000 "uimage.ub"
mtd2: 00010000 00010000 "cfg"
mtd3: 00030000 00010000 "app"
# ls /dev/mtd* -l
crw-------    1 root     root       90,   0 Jan  1 00:00 /dev/mtd0
crw-------    1 root     root       90,   1 Jan  1 00:00 /dev/mtd0ro
crw-------    1 root     root       90,   2 Jan  1 00:00 /dev/mtd1
crw-------    1 root     root       90,   3 Jan  1 00:00 /dev/mtd1ro
crw-------    1 root     root       90,   4 Jan  1 00:00 /dev/mtd2
crw-------    1 root     root       90,   5 Jan  1 00:00 /dev/mtd2ro
crw-------    1 root     root       90,   6 Jan  1 00:00 /dev/mtd3
crw-------    1 root     root       90,   7 Jan  1 00:00 /dev/mtd3ro
brw-------    1 root     root       31,   0 Jan  1 00:00 /dev/mtdblock0
brw-------    1 root     root       31,   1 Jan  1 00:00 /dev/mtdblock1
brw-------    1 root     root       31,   2 Jan  1 00:00 /dev/mtdblock2
brw-------    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操作。

5. 拷贝读取 MTD 分区

  • 查看 MTD 分区cat /proc/mtd
  • 擦除 MTD 分区flash_eraseall /dev/mtdX

擦除/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

a) 烧写cfg.bin文件到mtd2

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

执行下面命令烧录:

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

导出分区文件

dd if=/dev/mtd2 of=/mnt/cfg.bin

b) 烧写app.bin到mtd3

flash_erase /dev/mtd3 0x0 3
flashcp app /dev/mtd3

导出分区文件

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

6. 还原文件

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

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

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

如下图所示:

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

下载地址:

https://hhdsoftware.com/free-hex-editor

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

原理:

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

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

源码:

#include 
#include 
#include 
#include 
#include <sys/stat.h>
#include <sys/types.h>

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 < argc ; i++)
  {
   printf("argv[%d] = %s\n", i, argv[i]);
  }
 }

 fd_p = open(argv[1], O_RDWR);
 if(fd_p < 0){
  printf("open file  %s failed\n", argv[1]);
  return -1;
 }

 fdw_p = open(argv[2], O_RDWR | O_CREAT);
 if(fdw_p < 0 printfopen file s failed\n argv2 return -1 while1 readfd_p c 1 ifc='= 0xff){' count ifcount>= 16){
    break;
   }
  }
  else{
   count = 0;
  }
  pos++;
 }

 lseek(fd_p, SEEK_SET, 0);
 for(i=0; i<pos-15; i++){
  read(fd_p, &c, 1);
  write(fdw_p, &c, 1);
 }
 return 0;
}

测试:

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

重启后,再验证

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

7. 开机自动还原文件

要想开机后自动还原该文件,并启动程序app,步骤如下:

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

文件尾部添加:

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

touch /mnt/app
touch /mnt/cfg

chmod 777 /mnt/app
chmod 777 /mnt/cfg

/mnt/exportimg /mnt/app.bin /mnt/app
/mnt/exportimg /mnt/cfg.bin /mnt/cfg

rm /mnt/cfg.bin
rm /mnt/app.bin

/mnt/app & 

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

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

后续会继续更新文章。

相关推荐

一文讲清怎么利用Python实现Linux系统日志检索分析管理系统

摘要:在现代IT运营与开发中,日志分析早已成为不可或缺的核心环节。无论是排查系统故障、进行安全审计,还是优化服务性能,日志文件始终是最真实、最权威的信息来源。Linux系统作为主流的服务器操作系统,其...

Linux 思维导图整理(建议收藏)(linux知识点总结思维导图)

今天整理了一下收集的Linux思维导图。Linux学习路径Linux桌面介绍FHS:文件系统目录标准Linux需要特别注意的目录Linux内核学习路线地址:https://www.jiansh...

什么是操作系统(什么叫做操作系统)

Linux也是众多操作系统之一,要想知道Linux是什么,首先得说一说什么是操作系统。计算机是一台机器,它按照用户的要求接收信息、存储数据、处理数据,然后再将处理结果输出(文字、图片、音频、视频...

Windows操作系统和Linux操作系统有什么不同?

每天一分钟,关注我学更多今天的内容是Windows操作系统和Linux操作系统在多个方面存在显著差异,主要体现在用户界面、开源性、稳定性和安全性等方面。用户界面:Windows操作系统提供直观高效的图...

每日学习“IT”是什么呢?(it学习网站)

IT是信息技术(InformationTechnology)的简称,它是一个广泛的领域,涉及到利用计算机、网络通信技术、软件等来存储、处理、传输和获取信息。计算机硬件硬件组成部分:包括中央处理器(...

CAD是什么?如何选择最适合你的CAD软件?

CAD(计算机辅助设计)是建筑、机械、电子等行业的核心工具,通过数字化手段实现高精度设计与协作。传统CAD软件如AutoCAD功能强大,但操作复杂、成本高昂,而轻量化工具又难以满足专业需求。元图CAD...

Linux是什么?(linux是什么意思)

在今天的时代,计算机系统已经成为了我们生活中不可或缺的一部分。而Linux则是目前世界上最为流行和免费的操作系统之一,它以其自由和开放源代码的特点,吸引了全球大量的程序员和开发者前来使用和修改。那么,...

牛人带你通透理解高可用网络基础架构的关键组件:负载均衡机制

上篇给大家介绍的内容是微服务网关:Zuul源码解析,相信大家已经领会并且贯通了;那么本文将给大家介绍的内容是负载均衡:负载均衡机制。负载均衡负载均衡(LoadBalance)是分布式网络环境中的重要...

Linux运维网络篇(linux运维网站)

Linux运维过程中,我们会遇到各种形形色色的网络问题,今天我们就常见的检测手段以及处理办法给大家做一下统一分享。第一节:网络探测首先,我们需要通过各种命令来探测网络是否畅通,进而跟踪锁定到实际...

Nginx正向代理、反向代理、负载均衡及性能优化

一、Nginx是什么Nginx是一款高性能的HTTP和反向代理服务器,由俄罗斯人IgorSysoev(伊戈尔·赛索耶夫)为俄罗斯网站Rambler.ru开发的,在Rambler.ru网站平稳的运...

nginx负载均衡配置(nginx负载均衡配置教程)

Nginx是什么没有听过Nginx?那么一定听过它的“同行”Apache吧!Nginx同Apache一样都是一种WEB服务器。基于REST架构风格,以统一资源描述符(UniformResources...

Springmvc使用Nginx负载均衡session共享

上一节,我们讲到nginx的结构组成,已经把模块、还有之前谈及负载均衡知识时候遗留的东西进行了讲解,那么今天我们继续把使用nginx做负载均衡的时候,如何处理session的方法做个解析,如何有需要对...

Linux 系统卡顿问题的排查思路(linux系统突然非常卡)

#Linux系统卡顿问题排查思路当Linux系统出现卡顿问题时,可以按照以下系统性排查思路进行分析和解决:##1.快速检查系统整体状态###查看系统负载```bashuptimetophto...

一文搞懂LVS负载均衡工作原理 :NAT、DR、TUN模式

大家好,我是IT售前工程师Bernie。LVS(LinuxVirtualServer)是企业中常用的负载均衡方案,是一种基于Linux虚拟服务器,也是Linux标准内核的一部分。它能够实现高性...

从零构建高性能 LVS + Keepalived 四层负载均衡集群实战指南

一、前言在大型网站架构中,四层负载均衡是流量调度的第一道防线。相比七层(如Nginx、HAProxy),四层(基于IP/端口转发)在性能上更具优势。LVS(LinuxVirtualServer...