v3s镜像从零开始构建

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 = <&reg_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 .
相关推荐
Felven2 小时前
国产ZYNQ multiboot功能介绍与实现
linux·fpga开发·multiboot·国产zynq
脆皮炸鸡7552 小时前
进程通信----命名管道
linux·经验分享·笔记·算法·学习方法
Mapleay2 小时前
FE-BE 动态路机制之 DPCM 与 DAPM 协作
linux
IT大白鼠2 小时前
Linux故障分析与排查:系统日志、启动故障与文件系统修复
linux·运维·服务器
老詹图解IT3 小时前
统信 UOS 登录界面转圈闪退/卡登录等常见原因及处理
linux·服务器·网络
闫记康3 小时前
Linux学习笔记day1
linux·笔记·学习
轻颂呀3 小时前
进程间关系和守护进程
linux·网络
sbjdhjd3 小时前
02 (中)| K8s Pod 生产化落地:从配置到优化全流程
linux·运维·云原生·kubernetes·开源·podman·kubelet
皓月盈江3 小时前
Linux Ubuntu系统如何编辑Docker容器内的文件
linux·ubuntu·docker·容器·靶场·vulhub·编辑docker内文件