荔枝派Nano全志F1C100s开发板实战:从uboot到buildroot的完整烧录指南
最近有不少朋友开始玩起了那些小巧又便宜的ARM开发板,其中全志F1C100s这颗芯片因为其极致的性价比和相对完整的生态,吸引了不少嵌入式爱好者和初学者的目光。荔枝派Nano作为一款搭载这颗芯片的经典开发板,以其小巧的尺寸和丰富的接口,成为了学习嵌入式Linux系统构建、驱动开发以及硬件交互的理想平台。不过,从拿到一块裸板到最终跑起一个完整的、带图形界面的Linux系统,这个过程对于新手来说,往往充满了各种“坑”:uboot编译不过、内核启动不了、屏幕点不亮、文件系统挂载失败……网上的资料虽然多,但常常是零散的记录,或者环境、版本稍有不同就会导致步骤失效。
这篇文章,我就想结合自己最近折腾荔枝派Nano的实际经历,为你梳理出一条清晰、可复现的路径。我们不只讲命令,更会解释每个步骤背后的逻辑,以及遇到常见问题时该如何排查。目标很明确:让你能亲手把uboot、Linux内核和buildroot构建的文件系统,完整地烧录到板载的SPI Flash中,并成功驱动一块800x480的LCD屏幕,最终看到一个可登录的Linux终端。无论你是想深入了解嵌入式系统启动流程的学生,还是希望为某个IoT项目快速搭建底层系统的开发者,这份指南都希望能为你节省大量摸索的时间。
1. 开发环境搭建与源码获取
工欲善其事,必先利其器。在开始编译任何代码之前,一个稳定、配置正确的交叉编译环境是成功的第一步。对于ARM架构的F1C100s,我们需要一套能在x86电脑上生成ARM可执行代码的工具链。
1.1 安装交叉编译工具链
我强烈推荐使用Linaro或ARM官方提供的GCC工具链,它们经过了广泛的测试,兼容性最好。这里我们选择arm-linux-gnueabi-这个前缀的工具链,它针对的是不带硬浮点单元的ARMv5架构(F1C100s的ARM926EJ-S核心正属于此)。
在Ubuntu或Debian系统上,安装非常简单:
sudo apt update sudo apt install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi安装完成后,可以通过以下命令验证:
arm-linux-gnueabi-gcc --version如果能看到类似gcc version 9.x.x (Ubuntu 9.x.x-0ubuntu1~20.04)的输出,说明工具链已就绪。
注意:不同Linux发行版的软件包名称可能略有差异。如果你使用的是Arch Linux,可以尝试
sudo pacman -S arm-linux-gnueabi-gcc。如果apt仓库中的版本太旧,你也可以从ARM官网直接下载预编译的工具链包,解压后将其bin目录添加到系统的PATH环境变量中。
1.2 获取并准备三大件源码
我们需要三份核心源码:U-Boot(系统引导程序)、Linux内核、以及Buildroot(用于构建根文件系统)。为了保证兼容性,最好使用针对荔枝派Nano优化过的版本。
U-Boot源码:
git clone https://gitee.com/LicheePiNano/u-boot.git cd u-boot git checkout nano-v2020.07 # 切换到一个稳定的、适配Nano的分支这里使用Gitee的镜像,速度会比GitHub快很多。nano-v2020.07是一个经过社区测试的相对稳定的分支,对SPI Flash启动支持较好。
Linux内核源码:
git clone https://gitee.com/LicheePiNano/Linux.git cd Linux # 通常主分支就是适配Nano的,可以查看一下有哪些tag或分支 git branch -a内核源码仓库包含了针对F1C100s的默认配置和设备树文件,这是我们能点亮屏幕的关键。
Buildroot源码: Buildroot我们选择官方发布的稳定版本,这样能避免开发版的一些不稳定问题。以2021.02.4这个长期支持版本为例:
wget https://buildroot.org/downloads/buildroot-2021.02.4.tar.gz tar xvf buildroot-2021.02.4.tar.gz cd buildroot-2021.02.4选择这个版本是因为其与较新的工具链和软件包兼容性平衡得比较好,社区资料也丰富。
2. U-Boot的配置、定制与编译
U-Boot是硬件上电后运行的第一段软件,它负责初始化最基础的硬件(如DRAM控制器、时钟、SPI Flash),然后加载并启动Linux内核。为荔枝派Nano编译U-Boot,有几个关键配置点需要特别注意。
2.1 基础配置与编译
进入U-Boot源码目录,首先应用针对Nano的默认配置。这里有两个常见的defconfig文件:
f1c100s_nano_uboot_defconfig: 针对板载SPI Flash启动的配置。licheepi_nano_defconfig: 更通用的配置,可能默认从SD卡启动。
如果你的板子焊接了SPI Flash并且打算从Flash启动,请使用第一个:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- f1c100s_nano_uboot_defconfig这条命令会基于预设的配置生成一个.config文件。
接下来,我们可能需要根据实际硬件进行微调,特别是屏幕参数。运行可视化配置菜单:
make ARCH=arm menuconfig这个基于ncurses的界面会让你更直观地修改配置。
2.2 关键配置项详解
在menuconfig中,你需要关注以下几个位置:
启用图形化控制台: 导航到
ARM architecture->Enable graphical uboot console on HDMI, LCD or VGA,将其设置为Y。这允许U-Boot在LCD上显示启动logo和命令行界面。设置LCD时序参数: 这是点亮屏幕的核心。找到
LCD panel timing details选项,其值是一个由逗号分隔的字符串。对于一块常见的800x480 RGB屏幕,参数可能如下: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让我解释一下这几个关键参数:
x,y: 分辨率,宽800像素,高480像素。depth: 色彩深度,18表示RGB666(每种颜色6位),这是F1C100s LCD控制器常用模式。pclk_khz: 像素时钟频率,单位KHz。33MHz是一个常用值,具体需参考屏幕数据手册。le(hback-porch),ri(hfront-porch),up(vback-porch),lo(vfront-porch): 行/场前后肩,用于信号同步。hs,vs: 行/场同步脉冲极性。1通常表示高电平有效。sync: 同步模式,3代表HSYNC和VSYNC都使能。
重要提示:这些时序参数必须与你的屏幕数据手册严格匹配!如果参数错误,可能导致无显示、花屏或闪屏。最可靠的方法是找到屏幕厂商提供的驱动代码或时序图。
SPI Flash驱动: 确保SPI Flash驱动已启用。通常路径在
Device Drivers->SPI Flash Support。默认配置应该已经包含。
配置完成后,保存退出。现在可以开始编译了:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j$(nproc)-j$(nproc)表示使用你电脑所有CPU核心并行编译,以加快速度。编译成功后,在源码根目录会生成关键文件u-boot-sunxi-with-spl.bin。这个文件包含了SPL(Secondary Program Loader,相当于U-Boot的前置引导)和主U-Boot,是我们要烧录到Flash最前端的镜像。
3. Linux内核的配置与设备树修改
内核是操作系统的核心,负责管理硬件资源、进程调度和提供系统调用。为F1C100s编译内核,重点是确保驱动齐全,尤其是显示和Flash驱动,并且设备树(Device Tree)要正确描述我们的硬件。
3.1 应用默认配置与基础编译
进入Linux内核源码目录,应用为Nano准备好的默认配置:
make ARCH=arm f1c100s_nano_linux_defconfig这个配置已经启用了F1C100s所需的大部分基本驱动。接下来,如果你需要对内核功能进行增删(比如增加某个文件系统支持、某个USB设备驱动),可以运行make ARCH=arm menuconfig进行可视化配置。对于首次尝试,建议先使用默认配置。
开始编译内核镜像和设备树:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j$(nproc)编译完成后,生成的两个关键文件是:
arch/arm/boot/zImage: 压缩的内核镜像文件。arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dtb: 设备树二进制文件,它描述了板子的硬件资源(如内存布局、外设地址、引脚复用等)。
3.2 修改设备树以适配屏幕
默认的设备树可能没有配置你的特定屏幕。我们需要修改设备树源文件(.dts),然后重新编译生成.dtb。
设备树源文件路径通常是:arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dts。
用文本编辑器打开它,找到描述显示接口的部分。它可能被包含在一个/{}根节点的子节点中,名字可能是panel或display。你需要修改或添加compatible属性来匹配你的屏幕驱动。例如,对于一款LG的LB070WV8屏幕,修改可能如下:
&lcd0 { status = "okay"; compatible = "lg,lb070wv8", "simple-panel"; ... };compatible属性是内核用来匹配驱动的关键字符串。第一个字符串"lg,lb070wv8"需要与内核中某个屏幕驱动(可能在内核源码的drivers/gpu/drm/panel/目录下)的of_match_table条目一致。第二个字符串"simple-panel"是一个通用面板驱动。
此外,你还需要在设备树中确认或添加屏幕的时序参数,这些参数应该与之前在U-Boot中设置的一致,或者由内核驱动解析。有时时序参数会直接写在驱动代码里。
修改保存后,必须重新编译设备树(单独编译设备树比编译整个内核快):
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- dtbs编译后,新的.dtb文件会覆盖原来的。
3.3 编译内核模块
很多驱动(如USB网卡、某些文件系统)是以模块形式存在的。为了在文件系统中使用它们,需要编译并安装内核模块:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- modules -j$(nproc) mkdir -p output/modules # 创建一个目录存放模块 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- INSTALL_MOD_PATH=./output/modules modules_install这会将编译好的模块(.ko文件)及其依赖关系安装到output/modules/lib/modules/<内核版本>/目录下。稍后我们需要将这些模块拷贝到构建的根文件系统中。
4. 使用Buildroot构建轻量级根文件系统
根文件系统包含了Linux启动后运行的所有用户空间程序、库、配置文件和目录结构。Buildroot是一个自动化工具,它能从零开始,下载、配置、编译并打包出一个完整的、可定制的根文件系统,非常适合嵌入式场景。
4.1 Buildroot基础配置
进入Buildroot目录,启动配置界面:
make menuconfig接下来进行一些关键配置:
| 配置类别 | 选项 | 设置值/说明 |
|---|---|---|
| Target options | Target Architecture | ARM (little endian) |
| Target Variant | arm926t (匹配F1C100s) | |
| Toolchain | Toolchain type | External toolchain (使用我们安装的) |
| Toolchain | Custom toolchain | |
| Toolchain path | /usr(如果工具链在系统路径) | |
| Toolchain prefix | arm-linux-gnueabi- | |
| External toolchain C library | glibc 或musl(更小) | |
| System configuration | System hostname | 可自定义,如licheepi |
| Init system | BusyBox(最常用) | |
| /dev management | Dynamic using devtmpfs + eudev | |
| Root filesystem overlay | 可指向一个目录,添加自定义文件 | |
| Enable root login | 务必勾选 | |
| Root password | 设置一个密码,如licheepi | |
| Filesystem images | 需要的文件系统格式 | 勾选jffs2 root filesystem(用于SPI Nor Flash) |
选择musl作为C库可以显著减小最终文件系统的体积,这对于只有32MB Flash的板子非常有益。BusyBox是一个集成了上百个常用Linux命令的单一可执行文件,是嵌入式系统的标配。
4.2 添加自定义软件包
Buildroot的强大之处在于可以轻松添加第三方软件包。在menuconfig中,进入Target packages子菜单,你可以按需开启:
BusyBox配置:可以进一步精简或增加命令。Networking applications: 如dropbear(SSH服务器)、iperf3(网络测试)。Hardware handling: 如alsa-utils(音频工具)。Interpreter languages and scripting: 如python3(但注意体积)。
对于初次使用,建议保持精简,只确保基本的命令行工具和网络功能即可。配置完成后保存退出。
4.3 编译与输出
开始漫长的编译过程(Buildroot会下载所有选中的软件包源码并编译):
make -j$(nproc)这个过程取决于你的网速和CPU性能,可能需要十几分钟到半小时。编译成功后,在output/images/目录下会生成我们需要的文件系统镜像。对于SPI Nor Flash,我们通常使用rootfs.jffs2(如果配置了生成jffs2镜像)或者一个rootfs.tar归档文件。
如果生成的是rootfs.tar,我们需要手动将其制作成JFFS2镜像,因为这是SPI Nor Flash最常用的可读写文件系统格式。首先解压:
sudo tar -xvf output/images/rootfs.tar -C /path/to/temp_rootfs/然后使用mkfs.jffs2工具制作镜像,关键参数需要匹配你的Flash擦除块大小(Erase Block Size)。对于常见的16MB SPI Nor Flash,擦除块大小可能是64KB或128KB。假设是128KB(0x20000字节):
sudo mkfs.jffs2 -s 0x100 -e 0x20000 --pad=0x1000000 -d /path/to/temp_rootfs/ -o rootfs.jffs2.img参数解释:
-s 0x100: 页大小(Page Size),通常256字节。-e 0x20000: 擦除块大小,128KB。--pad=0x1000000: 将镜像填充到16MB(0x1000000字节),这是Flash的总大小。-d: 输入目录。-o: 输出镜像文件。
务必根据你实际焊接的Flash型号和数据手册来确定正确的-e参数!错误的参数会导致系统无法挂载根文件系统。
5. 烧录工具使用与全系统烧写
所有组件都准备好后,就到了最激动人心的烧录环节。我们需要一个叫做sunxi-tools的工具,它包含了全志芯片特有的FEL模式烧写工具。
5.1 编译与安装sunxi-tools
首先获取针对F1C100s SPI Flash支持的sunxi-tools分支:
git clone https://github.com/Icenowy/sunxi-tools.git -b f1c100s-spiflash cd sunxi-tools安装编译依赖:
sudo apt install libusb-1.0-0-dev pkg-config编译并安装:
make sudo make install安装后,系统中会新增sunxi-fel等命令。
5.2 进入FEL模式与烧录
全志芯片有一种特殊的启动模式叫FEL模式,当芯片内部没有有效引导程序时,或者通过特定引脚触发,芯片会进入此模式,等待通过USB接收指令和数据进行编程。
对于荔枝派Nano,进入FEL模式的标准方法是:
- 找到板子上SPI Flash芯片的第一脚(通常有个小圆点标记)。
- 用杜邦线将此引脚与板子的GND(地)引脚短接。
- 保持短接状态,给板子上电(通过USB供电)。
- 上电后,断开短接。
此时,在电脑上执行sudo sunxi-fel ver,如果看到类似AWUSBFEX soc=00001663的芯片信息输出,说明板子已成功进入FEL模式并被电脑识别。
现在,按照以下顺序和地址烧录我们编译好的文件:
烧写U-Boot (到Flash起始地址0x000000):
sudo sunxi-fel -p spiflash-write 0 ../u-boot/u-boot-sunxi-with-spl.bin-p参数表示显示进度条。烧写设备树DTB (到地址0x0100000,即1MB偏移处):
sudo sunxi-fel -p spiflash-write 0x0100000 ../Linux/arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dtb烧写Linux内核zImage (到地址0x0110000,紧挨着DTB之后):
sudo sunxi-fel -p spiflash-write 0x0110000 ../Linux/arch/arm/boot/zImage烧写根文件系统JFFS2镜像 (到地址0x510000,约5MB偏移处,为内核和DTB留出足够空间):
sudo sunxi-fel -p spiflash-write 0x510000 ../path/to/rootfs.jffs2.img
地址规划说明:这些地址不是随意的。U-Boot在启动时会根据编译时设定的环境变量(或默认值)去固定的地址寻找内核和设备树。我们这里的地址布局(U-Boot在0,DTB在1MB,内核在1MB+64KB)是一种社区常用的约定,需要在U-Boot的环境变量中设置
bootcmd和bootargs来匹配。你也可以在U-Boot中通过printenv查看和修改这些变量。
烧录全部完成后,断开USB线再重新连接(无需短接),板子应该会从SPI Flash正常启动。如果一切顺利,你将首先在LCD屏幕上看到U-Boot的启动logo,接着是Linux内核解压和启动的信息滚动,最后出现登录提示符licheepi login:。输入root和你设置的密码(如licheepi),恭喜你,一个完整的嵌入式Linux系统已经在你的荔枝派Nano上运行起来了!
6. 常见问题排查与进阶调试
即使严格按照步骤操作,也可能会遇到问题。这里汇总几个我踩过的坑和解决方法。
问题一:屏幕无显示或显示异常。这是最常见的问题。
- 检查时序参数:再次核对U-Boot和内核设备树中的屏幕时序参数,确保与数据手册完全一致。一个像素时钟
pclk_khz的错误就足以导致无显示。 - 检查电压和背光:用万用表测量屏幕接口的供电电压(通常是3.3V或5V)和背光电压是否正常。背光不亮也会让人误以为屏幕没工作。
- 使用串口调试:在屏幕不亮时,串口输出是唯一的救命稻草。确保串口线(UART0,通常是板子上标有
U0TX/U0RX的引脚)正确连接,波特率设置为115200。通过串口日志可以判断系统是否运行到了显示初始化的阶段。
问题二:内核启动后卡住,提示“No working init found”或类似错误。这通常意味着根文件系统挂载失败。
- 检查烧录地址和大小:确认
bootargs内核参数中的root=地址是否正确指向了JFFS2镜像的起始地址(例如root=/dev/mtdblock3 rootfstype=jffs2)。同时,确保制作的JFFS2镜像大小没有超过分配给它的Flash分区大小。 - 检查文件系统格式:
bootargs中的rootfstype=jffs2必须指定。如果文件系统是其他格式(如squashfs),这里也要相应修改。 - 检查JFFS2参数:
mkfs.jffs2的-e参数(擦除块大小)必须与Flash物理擦除块大小一致。这是导致挂载失败的最常见原因之一。如果不确定,可以尝试常见的64KB(0x10000)或128KB(0x20000)。
问题三:系统启动后网络不可用。
- 检查驱动:首先通过
lsmod查看是否加载了网络驱动(如sunxi_emac)。如果没有,需要在内核配置中启用CONFIG_SUN4I_EMAC并编译进内核或作为模块。 - 检查设备树:确保设备树中启用了EMAC节点,并且引脚复用配置正确。
- 配置IP:使用
ifconfig eth0 up和udhcpc -i eth0(如果BusyBox编译了dhcp客户端)来获取IP地址。
进阶调试技巧:
- 修改U-Boot环境变量:在U-Boot启动倒计时时按任意键进入命令行,使用
setenv修改bootargs和bootcmd,然后用saveenv保存到Flash。这对于调试启动参数非常有用。 - 使用tftp加载内核:在开发阶段,频繁烧写Flash很耗时。可以配置U-Boot通过tftp从局域网电脑加载内核和DTB到内存并启动,极大加快调试速度。这需要先在U-Boot中设置
ipaddr、serverip,并使用tftp命令。 - 内核日志等级:在
bootargs中添加loglevel=8(或quiet相反),可以让内核打印更详细的启动信息,有助于定位问题。
折腾荔枝派Nano的过程,就像是在解一个层层递进的谜题。从最底层的硬件初始化,到操作系统的加载,再到最终人机交互的完成,每一步都充满了挑战和乐趣。当你第一次看到自己编译的系统在巴掌大的板子上跑起来,并且驱动了屏幕时,那种成就感是无可替代的。这份指南希望能为你铺平最初的道路,但嵌入式开发的深度远不止于此,后续你还可以尝试移植Qt图形界面、编写简单的硬件驱动、或者用它作为核心板去控制外设,那将是另一片广阔的天地。如果在实践中遇到了上面没覆盖到的问题,不妨去相关的开源社区和论坛搜索一下,很可能已经有先驱者遇到了同样的问题并分享了解决方案。