荔枝派Nano交叉编译和wifi支持全记录

背景:本人从淘宝上买了一块荔枝派nano,意欲构建一个需要用到网络的服务。购买回来后,虽然提供了wifi模块,但是接进去后发现并不能连上网络。预装系统启动时也报了网络启动失败的错误,所以只好去官方尝试找支持wifi的firmware镜像,网上也有人说用官方firmware烧录时能正常连上wifi。结果是自己烧录后发现连系统都启动不了,最终一查发现我的flash用的是”xt25f128b”芯片,而官方的镜像默认是没有支持上的。最终只好自己去编译,过程中碰到不少问题,这里记录下来,以供后来者有个参考。

同时这里请注意本人主开发环境是mac,有些个别地方mac上需要特别处理,但大部分情况下你在ubuntu上操作是一样的,甚至更简单。对于有区别的地方,我会进行相应提示。

第一章 Docker容器编译环境搭建

Docker 镜像下载

不要用官网提供的

pull zepan/licheepi-nano``` 方式,我这边试过是没效的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

直接去官方提供的网盘上去下载:
[docker镜像](https://pan.baidu.com/s/1aYcGfzyz-g4CbxGSsVREGQ)

下载后解压
>gunzip nano.tar.gz

将获得
>nano.tar

下面将会用到

#### 创见大小写敏感分区(只需要在Mac环境下做)
这个我是听官方群的人说的,真实情况是否如此以及我是否有理解正确,我其实比较怀疑,不过我没有花时间去对比,所以直接就这样开干了。

> 在mac上使用docker编译时,会出现mac和linux文件系统不兼容的问题。所以需要创建独立大小写敏感分区作为共享文件夹来进行编译。

我们将会在启动docker容器时通过-v host路径:容器路径 来让容器和系统共享文件夹,这样在容器内编译好的东西,我们在mac上就能直接烧录

**创建5g磁盘名为DockerShare的分区**

>hdiutil create -size 5g -type SPARSE -fs "Case-sensitive HFS+" -volume DockerShare DockerShare.sparseimage

**挂载分区**

>hdiutil attach DockerShare.sparseimage

**检查分区**

>df -lh

/dev/disk2s2 4.7Gi 2.8Gi 1.8Gi 61% 171722 4294795557 0% /Volumes/DockerShare

1
2
3
4
5
6
7
#### 加载docker镜像

加载刚才解压的docker镜像
>sudo docker import nano.tar

查看docker image id
>sudo docker images

Kevins-MacBook-Pro:build kzhu$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE

808dbfca6929 45 hours ago 3.62GB

1
2
3
4
5
6
7
8

#### 运行容器

通过指定刚才获得的image id和本地的共享文件夹运行容器,同时默认打开sshd,好让我们可以通过ssh进去容器进行操作
>sudo docker run -d -v /Volumen/DockerShare:/data -p 6666:22 808dbfca6929 /usr/sbin/sshd -D

检查容器是否正确运行
>sudo docker ps

Kevins-MacBook-Pro:build kzhu$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
489c34f2215e 808dbfca6929 “/usr/sbin/sshd -D” 23 hours ago Up 23 hours 0.0.0.0:6666->22/tcp licheepai

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

检查ssh是否正常工作

>ssh -p 6666 root@127.0.0.1

输入密码,默认licheepi。注意buildroot时如果改了则用相应密码

#### 移动源码到共享目录
ssh进去通过root账号登录后,我们会发现里面已经准备好了以下源码
- linux
- u-boot
- buildroot-2017.08

如上面说的,我们会在共享文件夹中进行编译,所以需要将这些文件夹拷贝到上面挂载的/data/目录下。


#### 安装缺少的依赖包

ssh到容器后,我们会发现里面已经为我们准备好了linux,u-boot等的源码,在编译之前,我们需要安装缺少的几个包,我自己跑的时候缺的是以下一些,按照命令安装就好了。

>sudo apt install libusb-1.0-0-dev

>sudo apt install swig

>sudo apt install python-dev


### 第二章 编译uboot

#### 编译选项配置
首先进入u-boot源码目录,然后如官网上一样执行以下命令

此处告知make采用arm-linux-gnueabi下的所有交叉编译工具,目标架构为Arm,设定各项默认配置为 nano 的spiflash支持版

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- licheepi_nano_spiflash_defconfig

若不带spi-flash的板子,请换成 licheepi_nano_defconfig

进行可视化配置

make ARCH=arm menuconfig

1
2

然后开始进行编译配置,首先我用的是一块800x480的LCD屏,所以我需要勾选上:ARM architecture ‣ Enable graphical uboot console on HDMI, LCD or VGA, 然后统计的LCD panel timing details设置成:

x:800,y:480,depth:18,pclk_khz:33000,le:87,ri:40,up:31,lo:13,hs:1,vs:1,sync:3,vmode:0

1
2
3
4
5
6
7
然后将LCD panel backlight pwm pin设置成PE6

修改完LCD支持后,跟着配置启动参数, 勾选Enable boot arguments
console=ttyS0,115200 panic=5 rootwait root=/dev/mtdblock3 rw rootfstype=jffs2

然后是配置bootcmd,这里是可选的,你可以在这里配置,也可以通过修改源码进行配置。我选择在这里配。
首先勾选上Enable a default value for bootcmd,然后填上:

sf probe 0 50000000;sf read 0x80C00000 0x100000 0x4000;sf read 0x80008000 0x110000 0x400000;bootz 0x80008000 - 0x80C00000”

1
2
3
4
5
6
7
8
9
10

然后保存配置并退出

#### 源码修改以适配flash芯片
下一步我需要做的是让uboot支持上我的"xt25f128b"flash,这里特别要注意的是,如果你是在淘宝上买的荔枝派nano,那么很大可能你的flash芯片是“xt25f128b”, 因为据说原来不是这个芯片,后来芯片价格贵了,就找了这个芯片来替代。 如果我们不改的话,烧录新固件到flash后就会启动不了并报以下错误:
>SF: unrecognized JEDEC id bytes: 0b, 40, 18

首先我们进入u-boot源码下的drivers/mtd/spi/spi_flash_ids.c。

找到对应数据结构增加"xt25f128b"的信息定义,具体含义我也不知道,反正就照做

const struct spi_flash_info spi_flash_ids[] = {

{“w25q128fw”, INFO(0xef6018, 0x0, 64 1024, 256, RD_FULL | WR_QPP | SECT_4K) },
{“xt25f128b”, INFO(0x0b4018, 0x0, 64
1024, 256, RD_FULL | WR_QPP | SECT_4K) },

};

1
2

然后我们打开arch/arm/dts/suniv-f1c100s-licheepi-nano.dts这个文件,找到spi0,修改成我们的flash型号。

&spi0 {
pinctrl-names = “default”;
pinctrl-0 = <&spi0_pins_a>;
status = “okay”;
flash@0 {

        #address-cells = <1>;
        #size-cells = <1>;
        #compatible = "winbond,w25q128", "jedec,spi-nor";
        compatible = "winbond,xt25f128b", "jedec,spi-nor";
        reg = <0>;
        spi-max-frequency = <40000000>;
};

};

1
2

#### 开始编译

开始编译

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j8

1
2
3
4
5
6
7
8
9
10

编译完成后,可一看到目录下多了一堆以u-boot带头的文件,我们只需取 u-boot-sunxi-with-spl.bin 即可;


### 第三章 编译linux

#### dts修改
因为我们上面是通过uboot的bootargs传递给内核进行解析分区信息,所以这里我觉得应该不改写可以。但我是改了的,然后最终起来也没有报错,所以我就懒得去掉它重新测试了。

在linux源码目录下打开arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dts,并进行以下修改,注意我这里将芯片型号改成了我的”xt25f128b"

&spi0 {
pinctrl-names = “default”;
pinctrl-0 = <&spi0_pins_a>;
status = “okay”;
spi-max-frequency = <50000000>;
flash: xt25f128b@0 {

    #address-cells = <1>;
    #size-cells = <1>;
    compatible = "winbond,xt25f128b", "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 0x100000>;
            read-only;
        };

        partition@100000 {
            label = "dtb";
            reg = <0x100000 0x10000>;
            read-only;
        };

        partition@110000 {
            label = "kernel";
            reg = <0x110000 0x400000>;
            read-only;
        };

        partition@510000 {
            label = "rootfs";
            reg = <0x510000 0xAF0000>;
        };
    };
};

};

1
2
3
4
5


根据官方说的下载[.config](http://dl.sipeed.com/LICHEE/Nano/SDK/config)文件,然后替换掉linux目录下的.config

然后在linux目录下执行以下命令进行配置

make ARCH=arm menuconfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

进入 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*设备,不选会启动时找不到/dev/mtdblock3设备而报错

取消勾选 General setup -> initramfs support。

再进入Filesystem Drivers,选上JFFS2的支持。

然后打开drivers/mtd/spi-nor/spi-nor.c,检查自己的flash型号在该文件上是否有定义。

如果该文件上面没有你的芯片类型定义,那么加一个,比如我是在“w251i80"上加上了我的"xt25f128b"的信息。

{ “xt25f128b”, INFO(0x0b4018, 0, 64 1024, 256, 0) },
{ “w25q80”, INFO(0xef5014, 0, 64
1024, 16, SECT_4K) },

1
2


为了加快编译速度,请自行更改线程数

编译内核,生成zImage

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4

编译dts,生成dtb文件

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- dtbs -j4

编译内核模块,并输出到out目录

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- INSTALL_MOD_PATH=out modules
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- INSTALL_MOD_PATH=out modules_install

1
2
3
4
5
6
7
8
9
10
编译完成后会生成如下两个文件:
- ./arch/arm/boot/zImage
- ./arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dtb

和如下目录:
- ./out/lib/modules

### 第四章 编译esp8089 wifi驱动模块
如果你要连接网络,并且用的是相应的模块,则需要对esp8089驱动进行编译。
首先进入到我们的/data目录,执行以下命令拉取esp8089驱动源码

git clone https://github.com/Icenowy/esp8089.git

1
2

然后再次进入到linux目录下执行以下命令进行编译即可

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4 INSTALL_MOD_PATH=out modules
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4 INSTALL_MOD_PATH=out modules_install
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4 M=../esp8089 CONFIG_ESP8089=m INSTALL_MOD_PATH=out modules
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4 M=../esp8089 CONFIG_ESP8089=m INSTALL_MOD_PATH=out modules_install

1
2
3
4
5
6
7
8
9
10
11

最终将生成:
- esp8089/esp8089.ko。 生成的模块将会和linux自身模块一起打包到镜像中
- esp8089/firmware。这里的内容也必须打包,没有的话到时insmode esp8089模块时会失败

生成的模块将会和linux自身模块一起打包到镜像中

### 第五章 buildroot构建根文件系统
这里我通过官网提供的[.config](https://fdvad021asfd8q.oss-cn-hangzhou.aliyuncs.com/migrate/buildroot.config)构建出来的文件系统打包后rootfs.tar达到95兆之大,所以只能删掉该配置文件,只选取基本的包来进行编译。

首先,进入到buildroot-2017.08源代码,删除.config文件,然后执行

make menuconfig

1
2

然后对编译选项做相应配置。首先根据官网做最简单的配置

Target options —>

Target Architecture Variant (arm926t)  --->   // arm926ejs架构

[ ] Enable VFP extension support // Nano 没有 VFP单元,勾选会导致某些应用无法运行
Target ABI (EABI) —>
Floating point strategy (Soft float) —> // 软浮点

System configuration —>

(Lichee Pi) System hostname                   // hostname
(licheepi) Root password                      // 默认账户为root 密码为licheepi
[*] remount root filesystem read-write during boot  // 启动时重新挂在文件系统使其可读写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

因为我还需要用到一些网络工具来连接和测试wifi,所以我在Target Package->Networking applications下选上
- ifupdown scfripts
- iw
- wireless tools 这里会包含wlist这些工具
- wpa_supplicant

退出保存配置。然后执行make进行构建,第一次编译时,这个构建过程可比较漫长,大家有个心理准备。大家可以网上查下是否有其他办法缩短。

编译完成后生成的rootfs.tar将会保存到buildroot-2017.08/output/images/下


### 第六章打包生成镜像
到现在为止我们已经生成了所有我们构建flash版镜像需要的包:
- u-boot/u-boot-sunxi-with-spl.bin
-linux/arch/arm/boot/zImage
- linux/arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dtb
- esp8089/firmware
- buildroot-2017.08/output/images/rootfs.tar

这时我们可以在/data, 即linux,u-boot同层目录下创建脚本来进行打包。我这里的脚本参考的是:https://blog.csdn.net/u011847345/article/details/110727606

#!/bin/bash
curPath=$(readlink -f “$(dirname “$0”)”)
_IMG_FILE=firmware.bin
_UBOOT_FILE=$curPath/u-boot/u-boot-sunxi-with-spl.bin
_DTB_FILE=$curPath/linux/arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dtb
_KERNEL_FILE=$curPath/linux/arch/arm/boot/zImage
_ROOTFS_FILE=$curPath/buildroot-2017.08/output/images/rootfs.tar
_MOD_FILE=$curPath/linux/out/lib/modules
_ESP8089_FIRMWARE=$curPath/esp8089/firmware
_TEMP_FOLDER=~/_temp

if [ -f $_IMG_FILE ] ; then
echo “Image exist,rename it to .old”
mv $_IMG_FILE $_IMG_FILE.old -f
echo “Creating new an Image”
fi

rm -rf $_TEMP_FOLDER
mkdir $_TEMP_FOLDER &&\
cd $_TEMP_FOLDER &&\
echo “Generate bin…”
dd if=/dev/zero of=flashimg.bin bs=1M count=16 &&\
echo “Packing Uboot…”
dd if=$_UBOOT_FILE of=flashimg.bin bs=1K conv=notrunc &&\
echo “Packing dtb…”
dd if=$_DTB_FILE of=flashimg.bin bs=1K seek=1024 conv=notrunc &&\
echo “Packing zImage…”
cp $_KERNEL_FILE ./zImage &&\
dd if=./zImage of=flashimg.bin bs=1K seek=1088 conv=notrunc &&\
mkdir rootfs
echo “Packing rootfs…”
tar -xvf $_ROOTFS_FILE -C ./rootfs >/dev/null &&\
cp -r $_MOD_FILE rootfs/lib/modules/ &&\
cp -r $_ESP8089_FIRMWARE rootfs/lib/ &&\
mkfs.jffs2 -s 0x100 -e 0x10000 –pad=0xAF0000 -d rootfs/ -o jffs2.img &&\
dd if=jffs2.img of=flashimg.bin bs=1K seek=5184 conv=notrunc &&\
mv ./flashimg.bin $curPath/$_IMG_FILE &&\
echo “Bin update done!”
echo $(pwd)

1
2

我这里的_TEMP_FOLDER=~/_temp,这是打包时创建的临时目录,所有东西都在这下面进行解压和打包。注意我这里指定的是容器里面root的home目录,不能放在容器和mac的共享文件夹目录/data。因为共享的文件夹是osxfs文件系统,不支持moknod命令,而解压rootfs.tar时需要mknode ./dev/console。

root@489c34f2215e:/data# df -T .
Filesystem Type 1K-blocks Used Available Use% Mounted on
osxfs fuse.osxfs 10485760 5287532 5198228 51% /data

1
2
3
4
5

### 第七章 烧录

#### 安装烧录工具
首先在mac命令行中执行以下命令,从github上clone下来sunxi-tools的源码

git clone https://github.com/Icenowy/sunxi-tools.git -b f1c100s-spiflash

1
2

然后安装libs-usb依赖。 注意这里我是mac,如果你是ubuntu的话,请将brew换成apt-get

brew install libusb

1
然后link一下

brew link libusb

1
2

最后开始编译

make && make install

1
2
3
4
5
6
7
8
9

最终将会生成并安装好sunxi-fel工具

#### 进行烧录

拔掉usb转ttl于电脑的连接,短接flash的1,4两脚,注意,这里是flash的1,4脚,flash是靠近otg接口的那块芯片,上面写着"xt25f128b"之类型号的芯片。
接上usb与电脑的连接,然后松开1,4两脚的连接,这时应该就会进入到fel烧录模式,这时屏幕你观察下,不会再由人很启动或者uboot信息打印出来。

然后通过sunxi-fel工具可以检查是否进入了fel模式:

Kevins-MacBook-Pro:images kzhu$ sudo sunxi-fel version
AWUSBFEX soc=00001663(F1C100s) 00000001 ver=0001 44 08 scratchpad=00007e00 00000000 00000000

1
如果打印的是以下信息,代表没有进入到fel模式

Kevins-MacBook-Pro:build kzhu$ sudo sunxi-fel version
ERROR: Allwinner USB FEL device not found!

1
2

最后进行烧录

sudo sunxi-fel -p spiflash-write 0 /Volumes/DockerShare/firmware.bin
100% [================================================] 16777 kB, 96.3 kB/s
`

烧录完后拔掉usb重新上电,接上串口,即可启动并进入到系统,然后就开始愉快的玩耍了。

第八章 参考和感谢

整个过程参考了很多文章,同时感叹下荔枝派nano的资料真心是少,官方文档也应该是没有精力维护。所以非常感激那些编写了相应文章让我能有所参考的玩家们,这里列出一些引用到的文章,如果还有哪些我忘了写的,这里说声抱歉,你跟我说下,然后我添加上去。

我的更多作品
[三日清单] - 把握今天,放眼未来
[好学街] - 记录学习点滴、分享才艺人生
[techgogogo] - 本站公众号、关注了不迷路