1. 全志V3s与NOR Flash开发板简介
第一次拿到全志V3s开发板时,我注意到板子上那颗不起眼的XT25F128B NOR Flash芯片。这种16MB容量的存储介质在嵌入式领域非常典型——价格低廉但性能有限,就像给跑车装了个小油箱。与常见的NAND Flash不同,NOR Flash允许直接执行代码(XIP),但写入速度较慢且容量较小。这种特性决定了我们必须精打细算地规划存储空间。
荔枝派Zero开发板的硬件布局很紧凑,SPI接口的NOR Flash直接连接在V3s的SPI0控制器上。实测发现,这颗XT25F128B的擦除块大小是64KB,这意味着我们所有的分区设计都必须以64KB为最小单位对齐。就像装修时要考虑瓷砖尺寸一样,不当的分区规划会导致大量存储空间浪费。
2. 嵌入式Linux四大件与存储妥协
2.1 系统必备组件
在NOR Flash上部署Linux系统就像玩俄罗斯方块,需要巧妙安排几个关键组件:
- U-Boot:系统引导程序,我通常预留1MB空间
- 设备树(dtb):硬件描述文件,64KB足够
- Linux内核:经过裁剪后4MB空间绰绰有余
- 根文件系统:剩下的约10.9MB空间全部分配给它
2.2 NOR Flash的特殊考量
由于NOR Flash的特性,我们必须做出一些妥协:
- 文件系统必须选择JFFS2这种专为Flash设计的类型
- 内核需要特别配置MTD和SPI-NOR驱动支持
- U-Boot环境变量必须放在前1MB空间内
- 所有分区起始地址必须按擦除块大小对齐
我曾尝试使用ext4文件系统,结果系统启动时直接卡死。后来发现是因为ext4的日志特性会频繁擦写Flash,导致寿命急剧下降。
3. U-Boot编译与配置实战
3.1 获取特殊版本U-Boot
全志芯片的SPI驱动尚未合并到主线U-Boot,需要克隆实验分支:
git clone -b v3s-spi-experimental https://github.com/Lichee-Pi/u-boot.git cd u-boot3.2 Flash型号配置技巧
执行menuconfig时有个坑要注意:
make ARCH=arm menuconfig进入Device Drivers > SPI Flash Support后,虽然列表里没有芯天下的选项,但实测选择Macronix的驱动可以兼容XT25F128B。如果Flash容量大于16MB,记得勾选CONFIG_SPI_FLASH_BAR选项。
3.3 环境变量关键配置
在include/configs/sun8i.h中添加启动参数时,一定要在包含sunxi-common.h之前添加:
#define CONFIG_BOOTCOMMAND "sf probe 0; " \ "sf read 0x41800000 0x100000 0x10000; " \ "sf read 0x41000000 0x110000 0x400000; " \ "bootz 0x41000000 - 0x41800000" #define CONFIG_BOOTARGS "console=ttyS0,115200 earlyprintk panic=5 rootwait " \ "mtdparts=spi32766.0:1M(uboot)ro,64k(dtb)ro,4M(kernel)ro,-(rootfs) root=31:03 rw rootfstype=jffs2"这里有几个关键点:
root=31:03表示使用mtdblock3作为根文件系统rootfstype=jffs2指定文件系统类型- 内存地址0x41000000用于加载内核,0x41800000用于设备树
4. Linux内核定制化编译
4.1 获取适配内核源码
使用Lichee Pi维护的内核分支更稳定:
git clone https://github.com/Lichee-Pi/linux.git cd linux git checkout zero-4.13.y4.2 内核关键配置项
必须确保以下选项启用:
make ARCH=arm menuconfig路径:
Device Drivers > Memory Technology Device (MTD) support > Command line partition table parsingDevice Drivers > Memory Technology Device (MTD) support > SPI-NOR device supportFile systems > Miscellaneous filesystems > Journalling Flash File System v2 (JFFS2) support
4.3 设备树修改要点
在arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts中添加SPI节点:
&spi0 { status = "okay"; xt25f128b: xt25f128b@0 { compatible = "jedec,spi-nor"; reg = <0>; spi-max-frequency = <50000000>; #address-cells = <1>; #size-cells = <1>; }; };注意Flash型号必须在内核支持的m25p_ids[]列表中,否则无法识别。如果型号不在列表中,可以尝试使用通用的"spi-nor"兼容性标签。
5. 文件系统与镜像打包
5.1 JFFS2镜像生成
首先安装制作工具:
sudo apt-get install mtd-utils假设已有rootfs目录,计算JFFS2分区大小:
16MB(总空间) - 1MB(uboot) - 64KB(dtb) - 4MB(kernel) = 0xAF0000(10.9MB)生成镜像命令:
mkfs.jffs2 -s 0x100 -e 0x10000 -p 0xAF0000 -d rootfs/ -o jffs2.img参数说明:
-s 0x100:页大小256字节-e 0x10000:擦除块大小64KB-p 0xAF0000:分区总空间
5.2 完整镜像打包脚本
创建打包脚本package.sh:
#!/bin/sh dd if=/dev/zero of=flashimg.bin bs=1M count=16 dd if=u-boot-sunxi-with-spl.bin of=flashimg.bin bs=1K conv=notrunc dd if=sun8i-v3s-licheepi-zero.dtb of=flashimg.bin bs=1K seek=1024 conv=notrunc dd if=zImage of=flashimg.bin bs=1K seek=1088 conv=notrunc dd if=jffs2.img of=flashimg.bin bs=1K seek=5184 conv=notrunc执行后会生成16MB的flashimg.bin文件,包含所有系统组件。这种打包方式就像制作多层蛋糕,每层食材必须精确放置在指定位置。
6. 烧录与启动技巧
6.1 进入FEL模式的方法
全志芯片的FEL模式有三种进入方式:
- 不插SD卡且Flash为空
- 使用特殊SD卡启动镜像
- 上电时将SPI_MISO引脚拉低
最可靠的方法是先清空Flash,然后通过USB连接电脑:
sudo sunxi-fel version正常连接会显示类似AWUSBFEX soc=00001681(V3s)的信息。
6.2 镜像烧录命令
全盘烧录最简单:
sudo sunxi-fel -p spiflash-write 0 flashimg.bin如果想单独更新某个组件,比如只更新内核:
sudo sunxi-fel -p spiflash-write 0x110000 zImage烧录完成后复位开发板,通过串口可以看到启动日志。如果遇到问题,建议先检查:
- U-Boot是否能正确识别Flash
- 内核启动参数中的root参数是否正确
- JFFS2镜像是否完整无误
在实际项目中,我发现NOR Flash的写入速度较慢,频繁烧录会降低开发效率。因此建议先在SD卡上调试系统,稳定后再移植到NOR Flash。