# SPI Flash 系统编译
在一些低成本应用场景,需要在SPI flash上启动系统,这需要对Uboot和系统镜像做些适配。
本文介绍SPI Flash镜像的制作过程。
## Flash分区规划
这里 使用MX25L25645G, 32M SPI flash作为启动介质,规划分区如下:
|分区序号|分区大小|分区作用|地址空间及分区名|
|--|--|--|--|
|mtd0|1MB|spl+uboot|0x0000000-0x0100000 : "uboot"|
|mtd1|64KB|dtb文件|0x0100000-0x0110000 : "dtb"|
|mtd2|4MB|linux内核|0x0110000-0x0510000 : "kernel"|
|mtd3|剩余|根文件系统|0x0510000-0x2000000 : "rootfs"|
## Uboot编译配置
由于目前Uboot环境变量固定存放在1MB位置之内,所有留给uboot的空间固定到flash前1MB的位置不变。
每个分区的大小必须是擦除块大小的整数倍,MX25L25645G的擦除块大小是64KB。
### 准备uboot
下载包含spi驱动的体验版本uboot,该驱动目前尚未合并到主线
`git clone -b v3s-spi-experimental https://github.com/Lichee-Pi/u-boot.git`
### 配置Flash支持型号
执行`make ARCH=arm menuconfig`打开uboot菜单配置,进入到`Device Drivers > SPI Flash Support`
注意看一下自己flash的厂家名称,例如选上Macronix SPI flash support用来支持测试用的flash:MX25L25645G。
如果使用的是16MB以上的flash,需要勾选flash bank支持选项,否则最多只能读到16MB:**CONFIG_SPI_FLASH_BAR**
### 配置uboot默认环境变量
在文件`include/configs/sun8i.h`中添加默认bootcmd和bootargs的环境变量设置,注意添加的位置在“#include ”的前边。
![](https://box.kancloud.cn/b4cce3d6f353a3aabb326dab402d58a3_1642x622.jpg)
~~~
vi include/configs/sun8i.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"
~~~
> 环境命令解析:
> sf probe 0;//初始化Flash设备(CS拉低)
> sf read 0x41800000 0x100000 0x10000; //从flash0x100000(1MB)位置读取dtb放到内存0x41800000偏移处。//如果是bsp的bin,则是0x41d00000
sf read 0x41000000 0x110000 0x400000; //从flash0x110000(1MB+64KB)位置读取dtb放到内存0x41000000偏移处。
bootz 0x41000000 (内核地址)- 0x41800000(dtb地址) 启动内核
> 启动参数解析
> console=ttyS0,115200 earlyprintk panic=5 rootwait //在串口0上输出信息
> mtdparts=spi32766.0:1M(uboot)ro,64k(dtb)ro,4M(kernel)ro,-(rootfs) root=31:03 rw rootfstype=jffs2//spi32766.0是设备名,后面是分区大小,名字,读写属性。
> root=31:03表示根文件系统是mtd3;jffs2格式
### 编译uboot
`time make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- 2>&1 | tee build.log`
会在目录下生成 u-boot-sunxi-with-spl.bin
## linux内核编译配置
linux内核基于github上的版本https://github.com/Lichee-Pi/linux.git,分支为最新的zero-4.13.y
### 内核选项配置
执行`make ARCH=arm menuconfig`打开内核菜单配置,
进入到`Device Drivers > Memory Technology Device (MTD) support`,
确保选择上mtd的` Command line partition table parsing`支持,该项目用来解析uboot传递过来的flash分区信息。
以及SPI-NOR 设备的支持。
![](https://box.kancloud.cn/3ed4fd5d601aceb7f896521ba4c67cf6_1430x862.jpg)
添加对jffs2文件系统的支持,路径在`File systems > Miscellaneous filesystems-> Journalling Flash File System v2 (JFFS2) support`
![](https://box.kancloud.cn/3be64c60667c0aa3a906f095171d1fda_1396x746.png)
### 设备树配置
修改dts配置添加spi flash节点
` vi arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts`
添加spi节点配置:
~~~
&spi0 {
status ="okay";
mx25l25635e:mx25l25635e@0 {
compatible = "jedec,spi-nor";
reg = <0x0>;
spi-max-frequency = <50000000>;
#address-cells = <1>;
#size-cells = <1>;
};
};
~~~
![](https://box.kancloud.cn/611c8c327abb212991c3d0c02b0cf6d8_954x809.jpg)
这里的flash型号需要在下表之中,否则将无法识别:
(注意容量也一定要对应)
~~~
static const struct spi_device_id m25p_ids[] = {
/*
* Allow non-DT platform devices to bind to the "spi-nor" modalias, and
* hack around the fact that the SPI core does not provide uevent
* matching for .of_match_table
*/
{"spi-nor"},
/*
* Entries not used in DTs that should be safe to drop after replacing
* them with "spi-nor" in platform data.
*/
{"s25sl064a"}, {"w25x16"}, {"m25p10"}, {"m25px64"},
/*
* Entries that were used in DTs without "jedec,spi-nor" fallback and
* should be kept for backward compatibility.
*/
{"at25df321a"}, {"at25df641"}, {"at26df081a"},
{"mx25l4005a"}, {"mx25l1606e"}, {"mx25l6405d"}, {"mx25l12805d"},
{"mx25l25635e"},{"mx66l51235l"},
{"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q512a"},
{"s25fl256s1"}, {"s25fl512s"}, {"s25sl12801"}, {"s25fl008k"},
{"s25fl064k"},
{"sst25vf040b"},{"sst25vf016b"},{"sst25vf032b"},{"sst25wf040"},
{"m25p40"}, {"m25p80"}, {"m25p16"}, {"m25p32"},
{"m25p64"}, {"m25p128"},
{"w25x80"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"},
{"w25q80bl"}, {"w25q128"}, {"w25q256"},
/* Flashes that can't be detected using JEDEC */
{"m25p05-nonjedec"}, {"m25p10-nonjedec"}, {"m25p20-nonjedec"},
{"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"},
{"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"},
/* Everspin MRAMs (non-JEDEC) */
{ "mr25h256" }, /* 256 Kib, 40 MHz */
{ "mr25h10" }, /* 1 Mib, 40 MHz */
{ "mr25h40" }, /* 4 Mib, 40 MHz */
{ },
};
~~~
退出菜单配置并编译内核和dts
~~~
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j32
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs
~~~
## 准备镜像文件
### 下载根文件系统
首先选择rootfs文件系统,我是用的是群朋提供的最小根文件系统rootfs-brmin.tar.gz,大小只有3M左右,下载地址在
~~~
https://pan.baidu.com/share/link?
shareid=1432204556&uk=3658413294#list/path=%2F
Lichee Zero>zero_imager.zip
~~~
### 制作jffs2文件系统
Flash支持jffs2文件系统格式,所以需要使用此该rootfs制作jffs2文件系统镜像、
下载jffs2文件系统制作工具
`apt-get install mtd-utils`
解压 rootfs-brmin.tar.gz
`tar xzvf rootfs-brmin.tar.gz`
计算好jffs的大小,可以使用zero_imager里的make_jffs2.sh 32生成
总空间是32M-1M-64K-4M=0x1AF0000
`mkfs.jffs2 -s 0x100 -e 0x10000 -p 0x1AF0000 -d rootfs/ -o jffs2.img`
页大小0x100 256字节
块大小0x10000 64k
jffs2分区总空间0x1AF0000
jffs2.img是生成的文件系统镜像。
最后将uboot,dtb,kernel,rootfs打包成一个系统镜像,命令如下;
(即zero_imager里的make_spiflash.sh 32 dock)
~~~
#!/bin/sh
dd if=/dev/zero of=flashimg.bin bs=1M count=$1
dd if=u-boot-sunxi-with-spl-$2.bin of=flashim