1. 前言
之前复刻了一下v3s linux的开发板,所以这里记录一下构建v3s镜像。
2.内存卡分区
内存卡一共建立俩个分区:fat16 和 ext4
fat16用于存储 kernel 和dtb (设备树), ext4 存放 rootfs。
这里注意建立fat16分区时,前面预留1M字节的空间,用于存储uboot(不用给uboot单独建立分区):


3.使用docker 环境
使用docker进行编译有很多好处:如 不会破坏本地的编译工具链,所需的代码在镜像容器中都存在,开盒即用,免去了下载源码以及编译工具链的步骤。
bash
docker pull zepan/licheepi
docker run -d zepan/licheepi #启动容器
进入容器:
bash
docker exec -it [CONTAINER ID] bash
所有待编译的资源都在容器内的root目录下:
bash
linux #编译 kernel
buildroot-2017.08 # 编译rootfs
u-boot # 编译u-boot
4. 编译uboot
在u-boot文件中有一个隐藏文件:.config
这个文件中存储着编译配置选项,可以通过:
bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
进行修改,然后需要Save , 后面编译 kernel 也可以使用这种方式对编译选项进行配置:

基本上不需要修改任何选项,除非有特殊情况,可以看到里面有一个选项可以设置 uboot 超时时间,默认为2秒。
编译:
bash
./rebuild.sh
| 文件名 | 性质与作用 |
|---|---|
| u-boot | ELF格式的可执行文件,包含调试符号、段信息。主要用于源码级调试(如配合GDB),不直接用于烧写。 |
| u-boot.bin | 由 u-boot 经过 objcopy 转换得到的纯二进制镜像,去除了所有符号和重定位信息。是U-Boot的核心本体,但通常不独立使用。 |
| u-boot.img | 在 u-boot.bin 前添加了固定大小(通常64字节)的头部。头部包含镜像长度、加载地址、校验等信息,用于满足某些特定ROM代码的加载要求。 |
| u-boot-sunxi-with-spl.bin | 这是用于全志芯片SD卡启动的"最终成品"。它已将SPL和U-Boot主镜像打包合并为一个文件。烧写时需用 dd 命令写入SD卡的特定扇区(如seek=8)。 |
| u-boot-dtb.bin | 已将对应的设备树二进制文件 .dtb 打包合并进主镜像的 u-boot.bin 变体。对于V3s这种设备树内嵌的SoC,它和普通 u-boot.bin 功能相同。 |
| u-boot.dtb | 单独编译出来的设备树二进制文件。它描述了V3s芯片及开发板的硬件资源信息。在U-Boot启动内核时,会将此设备树信息传递给内核。对于V3s,该文件通常已内嵌在主镜像中。 |
我们实际 使用的只有 u-boot-sunxi-with-spl.bin 这个文件
将其从容器内复制到本地,并写入到内存卡的 8K部分:
bash
docker cp [CONTAINER ID]:/root/u-boot/u-boot-sunxi-with-spl.bin .
sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/SD卡设备 bs=1024 seek=8 conv=fsync
写入uboot后,通过串口就可以看到一些信息了:

5. 编译 kernel
如果不想用内置的linux kernel 4.2版本也可以使用5.2
bash
sudo apt update
sudo apt install libssl-dev
rm -rf linux #删除这个库,从新拉取5.2版本内核
git clone -b zero-5.2.y --depth 1 https://github.com/Lichee-Pi/linux.git
bash
cd linux
rebuild.sh脚本内容:
bash
#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16 &&\
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16 INSTALL_MOD_PATH=out modules &&\
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16 INSTALL_MOD_PATH=out modules_install &&
cp arch/arm/boot/zImage ./
然后可以线生成.config文件:
bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- licheepi_zero_defconfig # 使用v3s默认配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
5.1.修改内核启动图片
bash
sudo apt-get install netpbm
convert your_logo.png -resize 80x80 logo.png
# 转换为ppm格式(224色)
pngtopnm logo.png > logo.pnm
pnmquant 224 logo.pnm > logo224.pnm
pnmtoplainpnm logo224.pnm > drivers/video/logo/logo_linux_clut224.ppm
将内核图片放到 drivers/video/logo/, 编译内核就可以使用到这个图片
内核图片配置项:
bash
Device Drivers --->
Graphics support --->
[*] Bootup logo --->
[*] Standard 224-color Linux logo
5.2 屏幕驱动
我这里用的屏幕是st7789v2, 不过内核驱动里面可以使用Staging drivers 中的 fbtft st7789v驱动成功
bash
Device Drivers --->
[*] Staging drivers --->
<*> Support for small TFT LCD display modules --->
<*> FB driver for the ST7789V LCD controller
Graphics support --->
<*> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) --->
<*> Frame buffer Devices --->
<*> Support for frame buffer devices --->
[*] Framebuffer Console Support
[*] SPI support --->
<*> Allwinner A10/A20 SPI controller
5.2.1 屏幕设备树
vi arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts
加入以下代码:
bash
&pio {
spi0-pins {
pins = "PC0", "PC1", "PC2"; // MOSI, MISO, CLK
function = "spi0";
};
};
&spi0 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&spi0_pins>;
display@0 {
compatible = "sitronix,st7789v";
reg = <0x00>;
status = "okay";
spi-max-frequency = <0x5b8d800>;
spi-cpol;
spi-cpha;
rotate = <0x5a>;
fps = <0x3c>;
buswidth = <0x08>;
dc-gpios = <0x0b 0x01 0x04 0x00>;
reset-gpios = <0x0b 0x01 0x05 0x00>;
debug = <0x00>;
};
};
编译成功后的设备树在:/root/linux/arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dtb
5.2.2 Staging drivers 与 主线驱动
Staging 驱动 vs. 主线驱动
| 特性 | Staging 驱动 (暂存区) | 主线驱动 (如 drivers/gpu/drm/) |
|---|---|---|
| 代码质量 | 可能包含"丑陋"的代码、非常规的API使用,编码风格不一致。 | 必须符合内核严格的编码规范和代码质量标准。 |
| 维护状态 | 维护可能不稳定,主要由提交者或小社区维护。 | 由内核社区和稳定的维护者团队共同维护。 |
| 内核API使用 | 可能使用过时或非标准的API。 | 必须使用正确、当前的内核API。 |
| 配置依赖 | 依赖关系可能不清晰或配置复杂。 | 有清晰的Kconfig配置依赖。 |
| 文档 | 通常缺乏完整文档。 | 通常有较好的文档和设备树绑定说明。 |
| 长期稳定性 | 不保证长期稳定,API或行为可能在清理过程中改变。 | API和行为保持稳定,遵循内核的稳定分支规则。 |
由于我的屏幕是 st7789v2 , 而内核驱动是st7789v, 我配置主线驱动一直失败,而且其对设备树的配置有很严格的要求。
所以最终使用staging driver fbtft的驱动。
5.2.3 修改屏幕驱动反色问题
st7789v驱动文件位置:
主线驱动:vi drivers/gpu/drm/panel/panel-sitronix-st7789v.c
暂存区驱动:vi drivers/staging/fbtft/fb_st7789v.c
由于我使用的是暂存区驱动,所以修改了暂存区驱动代码:
cpp
static int init_display(struct fbtft_par *par)
{
/* turn off sleep mode */
write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE);
mdelay(120);
/* set pixel format to RGB-565 */
write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
write_reg(par, PORCTRL, 0x08, 0x08, 0x00, 0x22, 0x22);
/*
* VGH = 13.26V
* VGL = -10.43V
*/
write_reg(par, GCTRL, 0x35);
/*
* VDV and VRH register values come from command write
* (instead of NVM)
*/
write_reg(par, VDVVRHEN, 0x01, 0xFF);
/*
* VAP = 4.1V + (VCOM + VCOM offset + 0.5 * VDV)
* VAN = -4.1V + (VCOM + VCOM offset + 0.5 * VDV)
*/
write_reg(par, VRHS, 0x0B);
/* VDV = 0V */
write_reg(par, VDVS, 0x20);
/* VCOM = 0.9V */
write_reg(par, VCOMS, 0x20);
/* VCOM offset = 0V */
write_reg(par, VCMOFSET, 0x20);
/*
* AVDD = 6.8V
* AVCL = -4.8V
* VDS = 2.3V
*/
write_reg(par, PWCTRL1, 0xA4, 0xA1);
//
write_reg(par, 0x21); //加入的代码
//
write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
return 0;
}
浅色过亮问题解决(设置新Gamma值):
cpp
#define DEFAULT_GAMMA \
"D0 08 0B 0C 11 12 28 40 4A 27 16 17 1D 1E\n" \
"D0 08 0B 0C 11 12 27 3F 4A 27 16 17 1D 1E"
5.3 USB设备树
vi arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts
bash
&usb_otg {
dr_mode = "host";
status = "okay";
};
正常情况下选择 dr_mode设置为otg时,可以根据ID 引脚自动进行主从切换,但是如果电路硬件方面不支持也就无法实现这个功能,所有这里就设置成主机,设置从机可以当做一个电脑的配件: USB串口 / 调试控制台 、大容量存储设备、USB网络适配器、其他Gadget。
5.4 开始编译kernel与dtb
bash
./rebuild.sh
copy到内存卡的 FAT16分区内:
bash
docker cp [CONTAINER ID]:/root/linux/zImage .
docker cp [CONTAINER ID]:/root/linux/arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dtb .
编写boot.cmd:
bash
setenv bootargs console=tty1 console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait panic=10 earlyprintk rw
load mmc 0:1 0x41000000 zImage
load mmc 0:1 0x41800000 sun8i-v3s-licheepi-zero.dtb
bootz 0x41000000 - 0x41800000
console=tty1 可以将内核日志输出到屏幕上,去掉此选项屏幕只显示内核图片
编译生成 boot.scr:
bash
mkimage -C none -A arm -T script -d boot.cmd boot.scr
将boot.scr也放到内存卡的FAT16分区。
所以最终FAT16分区一共有3个文件:boot.scr zImage sun8i-v3s-licheepi-zero.dtb
6.构建rootfs
这里我不使用 docker内的buildroot, 因为其构建的rootfs没有包管理,也过于精简,所以这里我构建一个相对完整linux系统。
使用debootstrap, 在宿主机上构建。
debootstrap 是Debian/Ubuntu官方工具,用于构建最小根文件系统。它在x86主机上运行,为ARM目标机下载并安装基础包。
binfmt-support 其包含一服务,其功能就是可以根据二进制magic byte 选择不同的qemu解释器去执行,比如如果是arm架构就会去调用qemu的arm执行, 可以通过 sudo service binfmt-support restart 进行服务重启,binfmt-support 也是一个内核模块。如果没有这个服务开启就不能实现chroot, 因为其bash是arm架构的,而内核不知道如何去执行这个文件。
bash
sudo apt update
sudo apt install debootstrap binfmt-support qemu-user-static debootstrap
# 创建一个目录,用于存放即将构建的根文件系统
sudo mkdir -p /path/to/v3s-rootfs
# ========== 第一阶段:下载和解包 ==========
# 使用国内镜像源(如清华源)加速,为 ARM 硬浮点 (armhf) 架构构建
sudo debootstrap --arch=armhf \
--foreign \
bookworm \
/path/to/v3s-rootfs \
https://mirrors.tuna.tsinghua.edu.cn/debian/
# 参数解释:
# --arch=armhf: 指定目标架构为 ARM 带硬浮点 (对应 V3s 的 Cortex-A7)
# --foreign: 仅进行第一阶段,不解压包内的配置脚本(因为宿主机架构不同)
# bookworm: Debian 12 的代号
# /path/to/v3s-rootfs: 目标目录
# 最后是镜像源 URL
# 在 chroot 环境中,使用 qemu 模拟 ARM 环境来执行所有的安装后配置脚本
sudo chroot /path/to/v3s-rootfs /debootstrap/debootstrap --second-stage
# 此过程会持续几分钟,会看到很多配置包的信息。
临时进入v3s分区,进行配置以及安装软件包:
bash
sudo chroot /path/to/v3s-rootfs /bin/bash
6.1 rootfs: 必要包安装及配置
bash
# 设置 root 密码
passwd
# 配置软件源(继续使用国内源)
cat > /etc/apt/sources.list << SRC_EOF
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm-updates main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian-security bookworm-security main contrib non-free
SRC_EOF
# 更新并安装一些必要工具
apt update
apt install -y sudo ssh net-tools ethtool iputils-ping vim wget kmod systemd-sysv htop wpasupplicant curl wireless-tools
# 设置主机名
echo "v3s-debian" > /etc/hostname
# 修改国内时区
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 配置 fstab (假设你的V3s从SD卡启动,根文件系统在第二个分区)
cat > /etc/fstab << FSTAB_EOF
/dev/mmcblk0p1 /boot vfat defaults,noatime 0 2
/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
FSTAB_EOF
EOF # 结束 chroot 内的命令块
6.2 rootfs: 配置swap分区
由于v3s只带只有64M内存,如果不使用swap, 基本上很多功能都无法使用
bash
fallocate -l 512M /swapfile
dd if=/dev/zero of=/swapfile bs=1M count=512
chmod 600 /swapfile
mkswap /swapfile
# swapon /swapfile 启用swap
设置开机自动挂载
vi /etc/fstab 加入
bash
/swapfile none swap sw 0 0
6.2 rootfs: 配置wifi
wifi 设备树配置:
vi arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts
bash
&mmc1 {
pinctrl-names = "default";
broken-cd;
bus-width = <4>;
vmmc-supply = <®_vcc3v3>;
status = "okay";
};
网卡使用sdio接口,开启mmc1即可,不过需要注意删除PG 引脚的其他引用否者会出现引脚冲突,导致
sunxi-mmc 1c10000.mmc: fatal err update clk timeout
bash
leds {
compatible = "gpio-leds";
blue_led {
label = "licheepi:blue:usr";
gpios = <&pio 6 1 GPIO_ACTIVE_LOW>; /* PG1 */
};
green_led {
label = "licheepi:green:usr";
gpios = <&pio 6 0 GPIO_ACTIVE_LOW>; /* PG0 */
default-state = "on";
};
red_led {
label = "licheepi:red:usr";
gpios = <&pio 6 2 GPIO_ACTIVE_LOW>; /* PG2 */
};
};
需要将这部分删除。
下载rtl8723bs_nic固件:
bash
cd /lib/firmware/rtlwifi/
wget https://raw.githubusercontent.com/jackeyt/RTL-8XXX-Serial-Firmware/refs/heads/master/rtl8723bs_nic.bin
生成wifi配置文件:
bash
sudo wpa_passphrase [网络SSID] [KEY秘钥] > /etc/wpa_supplicant.conf
设置网络接口:
vi /etc/network/interfaces
bash
auto wlan0
iface wlan0 inet dhcp
wpa-conf /etc/wpa_supplicant.conf
配置udev(固定为wlan0):
vi /etc/udev/rules.d/70-persistent-net.rules
bash
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="r8723bs", NAME="wlan0"
以上这些配置完成后,可以实现开机自动连接wifi。
这里还没有放入内核驱动,后面在 rootfs: 最终打包 时再将对应的ko文件放到lib目录下。
6.3 rootfs: 音频编解码器与多媒体软件安装
cat /proc/asound/cards
设备树配置:
bash
&codec {
status = "okay";
allwinner,audio-routing = "Headphone\0HP\0Headphone\0HPCOM\0MIC1\0Mic\0Mic\0HBIAS";
};
内核驱动部分:
bash
Device Drivers → Sound card support → ALSA for SoC audio support → Allwinner sun8i audio codec analog controls support
bash
apt install alsa-utils mplayer
进入系统后:
bash
# 列出所有控制项
amixer scontrols
# 解除耳机静音并设置音量
amixer set 'Headphone' 80% unmute
# 如果还有 Master 控制项,也一并设置
amixer set 'Master' 80% unmute
刷新内核模块加载位置:
bash
depmod -a
6.4 rootfs: 桌面安装
bash
apt install xinit dwm
echo "exec dwm" > ~/.xinitrc
xinit #启动图形化界面
6.5 rootfs: 最终打包
bash
# 清理 APT 缓存,减小根文件系统体积
apt-get clean && rm -rf /var/lib/apt/lists/*
# ========== 集成内核与驱动(针对V3s) ==========
# 将你之前为 V3s 编译好的内核模块安装到根文件系统
# 假设你的内核构建目录是 /path/to/linux-v3s
cd /path/to/linux-v3s
sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=/path/to/v3s-rootfs modules_install
# ========== 打包 ==========
# 将构建好的根文件系统打包,方便部署到SD卡
cd /path/to
sudo tar -czpf v3s-debian-rootfs.tar.gz -C v3s-rootfs .