荔枝派nano(f1c100s)的SPI-Flash系统编译创建全过程
前言
本文的目标是创建一个运行在SPI-Flash上的精简系统,附带填一些前人没有提及的坑。在开始之前,请先通读官方教程的即食部分(U-Boot)、Linux编译和SPI-Flash系统的创建部分的教程,并搭建好编译工具链。以下我假设你已经按照上面的教程下载好了U-Boot和Linux内核,并且到Buildroot的官网下载好了Buildroot(但没按教程创建config文件)。
SPI-Flash的分区结构
以下是我这里的分区结构。你可以自由的分配后面两个分区的大小。
ID SIZE USAGE ADDR 0 448kb U-boot 0x0000 0000 - 0x0007 0000 1 64kb dtb 0x0007 0000 - 0x0008 0000 2 4mb kernel 0x0008 0000 - 0x0048 0000 3 7.5mb rootfs 0x0048 0000 - 0x00c0 0000 4 4mb overlay 0x00c0 0000 - 0x0100 0000
U-Boot的编译和填坑
按照上面的U-Boot的编译教程来编译基本上是没有什么太大问题。我这里就说一下上面教程里面没有说的配置:
设置内核启动参数
勾上
Enable boot arguments
,然后在下面填上:
panic=5 rootwait root=/dev/mtdblock3 rw rootfstype=squashfs
其中,root=/dev/mtdblock3指定了第3分区为rootfs所在分区,rootfstype=squashfs指定了这个分区的格式是squashfs。
设置Bootcmd
勾上
Enable a default value for bootcmd
,然后在下面填上:
sf probe 0 60000000; sf read 0x80c00000 0x70000 0x10000; sf read 0x80008000 0x80000 0x400000; bootz 0x80008000 - 0x80c00000
0x70000和0x80000分别是分区1和2的起始地址。
减小U-Boot体积
默认配置下,U-Boot的体积是接近1M的,但实际上U-Boot本体才270k左右。多余的空间实际上是被环境配置所占据了。
进入Environment菜单,找到Environment Offset。这个Offset就是配置的偏移地址,只要它比U-Boot本体大就可以了。这里我设置成0x68000,并将Environment Size设置成0x8000,这样编译出来的U-Boot大小就正好是0x70000,也就是448kb。
设置显示输出日志
勾上Console下的 Enable console multiplexing 和 Select console devices from environment,就可以在屏幕上看到启动日志了。
Linux的编译和填坑
Linux的坑就稍微有些多了。在做接下来的东西之前,你最好先载入官方的配置文件。
SPI-Flash的支持
进入 Device Drivers -> SPI support,将 Allwinner A10 SoCs SPI controller取消勾选,然后勾上下面的Allwinner A31 SPI Controller。这是为了修正配置文件中SPI驱动不正确的问题。
勾上并进入 Device Drivers -> Memory Technology Device (MTD) support,选上下面两项:
Command line partitioning table parsing #为了解析内核参数传过来的分区信息,如果用设备树应该可以不选 Caching block device access to MTD devices #为了生成/dev/mtdblock*设备,不选会报错
取消勾选 General setup -> initramfs support (存疑)。
再进入Filesystem Drivers,选上JFFS2和SquashFS的支持。
然后打开drivers/mtd/spi-nor/spi-nor.c,检查自己的flash型号的参数是否含有SECT_4K,如果有则改为0。例如对于w25q128,需要将
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
改为
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, 0) }
。
最后修改设备树文件中的分区信息,可以参考前面官方教程里面的dts修改章节。
flash@0 { #address-cells = <1>; #size-cells = <1>; compatible = "macronix,mx25l12805d", "jedec,spi-nor"; reg = <0>; spi-max-frequency = <50000000>; partitions { compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; partition@0 { label = "u-boot"; reg = <0x000000 0x70000>; read-only; }; partition@70000 { label = "dtb"; reg = <0x70000 0x10000>; read-only; }; partition@80000 { label = "kernel"; reg = <0x80000 0x400000>; read-only; }; partition@480000 { label = "rootfs"; reg = <0x480000 0x780000>; }; partition@c00000 { label = "overlayfs"; reg = <0xc00000 0x400000>; }; }; };
USB Gadget的支持
为了方便调试,需要启用USB Gadget。
转到 Device Driver -> USB support -> USB Gadget support,勾上 Usb gadget functions configurable through configfs,和上面的Serial gadget console support,以及下面的CDC ACM、CDC ECM、RNDIS、FunctionFS,再取消USB Gadget precomposed configurations的勾选。(具体原因和操作方法可以看我前面的文章)
对文件drivers/clk/sunxi-ng/ccu-suniv.c应用下面这个补丁,修正USB驱动问题
--- ../linux/drivers/clk/sunxi-ng/ccu-suniv.c 2019-01-15 22:48:18.824587965 +0800 +++ drivers/clk/sunxi-ng/ccu-suniv.c 2019-01-23 09:05:17.959348454 +0800 @@ -238,7 +238,7 @@ /* The BSP header file has a CIR_CFG, but no mod clock uses this definition */ static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", - 0x0cc, BIT(8), 0); + 0x0cc, BIT(1), 0); static SUNXI_CCU_GATE(dram_ve_clk, "dram-ve", "pll-ddr", 0x100, BIT(0), 0);
Wifi支持
我这里用的是rtl8723bs,所以在drivers->staging里面启用相关的驱动就可以了。
Buildroot的使用和rootfs的编译
下载Buildroot后解压,不要使用官方的配置文件,应当自己从零开始编译。
基础设置
Target options -- Target Architecture (ARM (little endian)) -- Target Variant arm926t Toolchain -- C library (musl) # 使用musl减小最终体积 System configuration -- Use syslinks to /usr .... # 启用/bin, /sbin, /lib的链接 -- Enable root login # 启用root登录 -- Run a getty after boot # 启用登录密码输入窗口 -- remount root filesystem # 重新挂载根文件系统到可读写 -- Install Timezone info # 安装时区信息。我的程序需要所以就打开了这个玩意 -- timezone list (asia) -- default local time (Asia/Shanghai) Target Packages -- mount/umount # 如果要用overlayfs,那就要用这个挂载
网络部分软件包
这里我给出包名然后自己搜素就好了
ifupdown scripts
iw # 用做无线网络管理的,可不要
wpa_supplicant # 无线网络管理需要这个玩意
linux-firmware -> rtl87xx # 无线网卡的固件
其他可能需要的软件包
lrzsz # rz/sz命令,用于传输文件
gawk # 用于解析iw命令的输出
dialog # 用于wifish管理的图形界面的生成
Busybox的设置
有一些软件包在busybox内是自带的,可以到使用busybox的menuconfig进行配置。需要先运行一次make生成busybox的构建文件夹,然后再使用 make busybox-menuconfig 配置。每次clean后都需要重新配置一次,因为在clean的时候这个配置会被清除。
可能需要的软件包:
ntpd # 网络自动校正时间
udhcpc # dhcp客户端
烧写镜像的生成和其他设置
下面所说的所有操作都包含在这个打包脚本里面了:licheepi-nano-image-master
镜像的生成
这里有个脚本可以一键生成镜像。
OUT_FILENAME="flashimg.bin" UBOOT_FILE=../u-boot-new/u-boot-sunxi-with-spl.bin KERNEL_DIR=../linux KERNEL_MODULES_DIR=$KERNEL_DIR/out/* DTB_FILE=$KERNEL_DIR/arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dtb KERNEL_FILE=$KERNEL_DIR/arch/arm/boot/zImage ROOTFS_FILE=../buildroot-2018.11.1/output/images/rootfs.tar SPEC_FILE=./custom/* SCRIPTES=./scripts/*.sh dd if=/dev/zero of=$OUT_FILENAME bs=1M count=16 dd if=$UBOOT_FILE of=$OUT_FILENAME bs=1K conv=notrunc dd if=$DTB_FILE of=$OUT_FILENAME bs=1K seek=448 conv=notrunc dd if=$KERNEL_FILE of=$OUT_FILENAME bs=1K seek=512 conv=notrunc mkdir rootfs tar xf $ROOTFS_FILE -C ./rootfs cp -r $KERNEL_MODULES_DIR rootfs/usr/ cp -r $SPEC_FILE rootfs/ # add some custom modify for f in $SCRIPTES; do ROOTFS_PATH=./rootfs bash "$f" -H done fakeroot mksquashfs rootfs/ rootfs.img -no-exports -no-xattrs -all-root fakeroot mkfs.jffs2 -s 0x100 -e 0x10000 --pad=0x400000 -o jffs2.img -d overlay/ dd if=rootfs.img of=$OUT_FILENAME bs=1K seek=4608 conv=notrunc dd if=jffs2.img of=$OUT_FILENAME bs=1M seek=12 conv=notrunc rm -rf rootfs rootfs.img jffs2.img
启用Gadget与串口
需要增加一个开机启动脚本,指向前面文章的USB gadget的配置脚本。
需要修改/etc/inittab,增加ttyGS0的getty。
sed -i 's/\# Put a getty on the serial port/\# Put a getty on the serial port\nttyGS0::respawn:\/sbin\/getty -L ttyGS0 0 vt100 # GENERIC_SERIAL/g' $ROOTFS_PATH/etc/inittab
配置网络
修改/etc/network/interface,增加wlan0
auto wlan0 iface wlan0 inet dhcp pre-up wpa_supplicant -i wlan0 -c /overlay/etc/wpa_supplicant.conf -B wait-delay 15 hostname $(hostname) post-down killall -q wpa_supplicant
为了使wpa_supplicant.conf可写,故我将其放在了overlay分区上。
配置挂载点
修改/etc/fstab,增加一行
/dev/mtdblock4 /overlay jffs2 defaults 0 0
这就将第四分区挂载到了/overlay上。需要注意这个文件夹需要预先创建
配置wpa_supplicant
在overlay分区创建etc/wpa_supplicant.conf,内容如下:
ctrl_interface=/var/run/wpa_supplicant ctrl_interface_group=wheel update_config=1 eapol_version=1 ap_scan=1 fast_reauth=1
增加的update_config=1是为了让wpa_cli能够修改这个文件,保存wifi的配置。
创建/etc/wpa_supplicant/wpa_cli-action.sh,内容见:
https://git.yoctoproject.org/cgit/cgit.cgi/meta-intel-edison/plain/meta-intel-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_cli-actions.sh
增加一个启动脚本,命令行为:
/usr/sbin/wpa_cli -a /etc/wpa_supplicant/wpa_cli-action.sh -B
。
上面的两个脚本的作用是让wpa_cli在Wifi连接上后调用wpa_cli-action.sh,从而自动调用udhcpc获取ip地址。
wifish
按照安装脚本将wifish的文件复制到它们应该在的地方。启动后就可以调用wifish来配置WiFi了。