RK3568 Linux

Buildroot Debian Ubuntu

Posted by LXG on January 29, 2026

buildroot debian ubuntu

维度 Buildroot Debian Ubuntu
定位 固件生成器 通用 Linux 发行版 商业化通用发行版
目标 嵌入式量产 通用 + 嵌入式 桌面 / 服务器 / AI
rootfs 整体生成 包管理 包管理
包管理 ❌ 无 apt ✅ apt ✅ apt
系统体积 5~50MB 200MB+ 1GB+
启动速度 最快(秒级) 中等 最慢
可裁剪性 极高 很低
可控性 100% 70% 50%
量产友好 ⭐⭐⭐⭐⭐ ⭐⭐
学习成本 最低
适合你这种工程师 非常适合 调试舒服 偶尔用

RK3568 无人送货小车

RK3568 + 无人送货小车 + 2GB RAM / 16GB Flash

👉 首选:Buildroot 👉 调试期可用:Debian ❌ 不建议:Ubuntu

为什么不推荐 Debian 直接量产

维度 Debian Buildroot
出问题你能否“下死手”
强制复位 modem
USB 断电重枚举
OTA 可控
系统行为可预测

Buildroot 4G

/etc/ppp/peers/quectel-pppd.sh


#!/bin/sh
# ============================================================
# quectel-pppd.sh
# 用于通过 PPP 拨号连接 Quectel 4G 模块(ttyUSB3)
# 参数顺序:devname apn user password
# ============================================================

echo "quectel-pppd options in effect:"

# -----------------------------
# 默认值设置
# -----------------------------
QL_DEVNAME=/dev/ttyUSB1     # 4G 模块对应串口设备
QL_APN=3gnet                # 默认 APN,可根据运营商修改
QL_USER=user                # PPP 用户名(如果需要)
QL_PASSWORD=passwd          # PPP 密码(如果需要)

# -----------------------------
# 命令行参数覆盖默认值
# -----------------------------
if [ $# -ge 1 ]; then
	QL_DEVNAME=$1
	echo "devname   $QL_DEVNAME    # (from command line)"
else
	echo "devname   $QL_DEVNAME    # (default)"
fi

if [ $# -ge 2 ]; then
	QL_APN=$2
	echo "apn       $QL_APN    # (from command line)"
else
	echo "apn       $QL_APN    # (default)"
fi

if [ $# -ge 3 ]; then
	QL_USER=$3
	echo "user      $QL_USER   # (from command line)"
else
	echo "user      $QL_USER   # (default)"
fi

if [ $# -ge 4 ]; then
	QL_PASSWORD=$4
	echo "password  $QL_PASSWORD   # (from command line)"
else
	echo "password  $QL_PASSWORD   # (default)"
fi

# -----------------------------
# chat 命令,用于初始化 4G 模块并拨号
# -----------------------------
CONNECT="'chat -s -v ABORT BUSY ABORT \"NO CARRIER\" ABORT \"NO DIALTONE\" ABORT ERROR ABORT \"NO ANSWER\" TIMEOUT 30 \
\"\" AT OK ATE0 OK ATI\;+CSUB\;+CSQ\;+CPIN?\;+COPS?\;+CGREG?\;\&D2 \
OK AT+CGDCONT=1,\\\"IP\\\",\\\"$QL_APN\\\",,0,0 OK ATD*99# CONNECT'"

# 解释:
# - chat -s -v : 安静模式并打印调试信息
# - ABORT … : 遇到这些关键字就停止拨号
# - TIMEOUT 30 : 每步等待 30 秒
# - AT OK … : 发送 AT 指令初始化模块
#   - ATE0          : 关闭回显
#   - ATI / +CSUB…  : 查询模块信息、SIM 状态、信号质量
#   - &D2           : 设置 DTR 行断开模块复位
# - AT+CGDCONT=1,"IP","$QL_APN" : 设置 PDP Context
# - ATD*99#        : 拨号建立 PPP 链路
# - CONNECT        : 表示 chat 成功后进入 PPP 连接状态

# -----------------------------
# 启动 pppd
# -----------------------------
pppd $QL_DEVNAME 115200 user "$QL_USER" password "$QL_PASSWORD" \
connect "'$CONNECT'" \
disconnect 'chat -s -v ABORT ERROR ABORT "NO DIALTONE" SAY "\nSending break to the modem\n" "" +++ "" +++ "" +++ SAY "\nGood bay\n"' \
noauth               # 不要求对端认证
debug                # 输出调试信息到 stdout
defaultroute         # 将 PPP 网卡设置为默认路由
noipdefault          # 不使用默认 IP
novj novjccomp noccp  # 关闭压缩(Van Jacobson header & CCP)
ipcp-accept-local    # 接受对端配置的本地 IP
ipcp-accept-remote   # 接受对端配置的远端 IP
ipcp-max-configure 30 # 最大 IPCP 尝试次数
local                 # 强制本地模式(不使用调制解调器控制线)
lock                  # 锁定串口,防止并发访问
modem                 # 使用调制解调器控制信号
dump                  # 输出 PPP 协议调试信息
nodetach               # 不脱离终端,方便后台监控
nocrtscts              # 禁用硬件流控
usepeerdns             # 使用对端提供的 DNS
&                      # 后台执行 pppd

# ============================================================
# 注意事项(无人车量产需要考虑)
# 1. 脚本当前没有 watchdog,pppd 掉线不会自动重拨
# 2. PPP 模式效率低,QMI/MBIM 更现代且稳定
# 3. 日志 dump / debug 会频繁写 Flash,量产建议写内存盘
# 4. defaultroute 会覆盖系统默认路由,需要策略路由控制多网口环境
# 5. 建议结合 USB/GPIO 复位,实现模块掉线自愈
# ============================================================


4G 拨号过程


root@rk3568-buildroot:/# sh /etc/ppp/peers/quectel-pppd.sh
quectel-pppd options in effect:
devname   /dev/ttyUSB2    # (default) → 你选择的 PPP 数据口
apn       3gnet    # (default) → 使用的运营商 APN
user      user   # (default) → PPP 拨号用户名
password  passwd   # (default) → PPP 拨号密码

root@rk3568-buildroot:/# pppd options in effect:
debug		# (from command line) → 输出详细调试信息
nodetach	# (from command line) → 不后台运行,方便调试
dump		# (from command line) → 输出数据包内容
noauth		# (from command line) → 不要求对端认证
user user	# (from command line) → 用户名
password ??????	# (from command line) → 密码(隐藏显示)
/dev/ttyUSB2	# (from command line) → 物理串口
115200		# (from command line) → 波特率
lock		# (from command line) → 锁定串口
connect ''chat -s -v ABORT BUSY ABORT "NO CARRIER" ABORT "NO DIALTONE" ABORT ERROR ABORT "NO ANSWER" TIMEOUT 30 "" AT OK ATE0 OK ATI\;+CSUB\;+CSQ\;+CPIN?\;+COPS?\;+CGREG?\;\&D2 OK AT+CGDCONT=1,\"IP\",\"3gnet\",,0,0 OK ATD*99# CONNECT'' 
                # (from command line) → 拨号脚本,用 chat 执行 AT 指令和拨号
disconnect chat -s -v ABORT ERROR ABORT "NO DIALTONE" SAY "\nSending break to the modem\n" "" +++ "" +++ "" +++ SAY "\nGood bay\n"
                # (from command line) → 断开连接时执行的 chat 指令
nocrtscts	# (from command line) → 禁用 RTS/CTS 硬件流控
modem		# (from command line) → 使用 modem 模式
novj		# (from command line) → 禁用 Van Jacobson 压缩
novjccomp	# (from command line) → 禁用压缩
ipcp-accept-local	# (from command line) → 接受对端给本机分配的 IP
ipcp-accept-remote	# (from command line) → 接受对端要求分配给对方的 IP
noipdefault	# (from command line) → 不使用默认 IP
ipcp-max-configure 30	# (from command line) → IPCP 最大配置尝试次数
defaultroute	# (from command line) → 拨号成功后设置默认路由
usepeerdns	# (from command line) → 使用对端提供的 DNS
noccp		# (from command line) → 禁用压缩控制协议
abort on (BUSY)	# 遇到 BUSY 立即中止
abort on (NO CARRIER) # 遇到 NO CARRIER 立即中止
abort on (NO DIALTONE) # 遇到 NO DIALTONE 立即中止
abort on (ERROR) # 遇到 ERROR 立即中止
abort on (NO ANSWER) # 遇到 NO ANSWER 立即中止
timeout set to 30 seconds # 每个 expect 的超时时间

send (AT^M)
expect (OK)
^M
OK
 -- got it
                # 发送 AT 检查模块是否在线,收到 OK

send (ATE0^M)
expect (OK)
^M
^M
OK
 -- got it
                # 禁用回显 ECHO,收到 OK

send (ATI;+CSUB;+CSQ;+CPIN?;+COPS?;+CGREG?;&D2^M)
expect (OK)
^M
^M
Quectel^M
EC800M^M
Revision: EC800MCNLFR06A07M04^M
^M
SubEdition: V01^M
^M
+CSQ: 16,99^M
^M
+CGREG: 2,0^M
^M
+CPIN: READY^M
^M
+COPS: 0^M
^M
OK
 -- got it
                # 查询模块信息、信号质量、注册状态和 SIM 状态,模块返回 OK,SIM 就绪

send (AT+CGDCONT=1,"IP","3gnet",,0,0^M)
expect (OK)
^M
^M
OK
 -- got it
                # 配置 PDP Context,APN 为 3gnet,模块确认 OK

send (ATD*99#^M)
expect (CONNECT)
^M
^M
CONNECT
 -- got it
                # 拨号成功,模块返回 CONNECT,表示 PPP 链路可以建立

Script ''chat ... ATD*99# CONNECT'' finished (pid 2752), status = 0x0
                # 拨号脚本顺利完成,status=0 表示没有错误

Serial connection established.
using channel 1
Using interface ppp0
                # PPP 链路建立成功,使用 ppp0 接口

sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0xaa353776> <pcomp> <accomp>]
rcvd [LCP ConfReq id=0x1 <asyncmap 0x0> <auth pap> <magic 0x32d478c8> <pcomp> <accomp>]
sent [LCP ConfAck id=0x1 <asyncmap 0x0> <auth pap> <magic 0x32d478c8> <pcomp> <accomp>]
rcvd [LCP ConfAck id=0x1 <asyncmap 0x0> <magic 0xaa353776> <pcomp> <accomp>]
                # LCP 链路协商,双方交换 ConfReq/ConfAck 包

sent [PAP AuthReq id=0x1 user="user" password=<hidden>]
rcvd [PAP AuthAck id=0x1 "" 00]
PAP authentication succeeded
                # PPP 认证使用 PAP,认证成功

sent [IPCP ConfReq id=0x1 <addr 0.0.0.0> <ms-dns1 0.0.0.0> <ms-dns2 0.0.0.0>]
rcvd [LCP TermReq id=0x2]
LCP terminated by peer
                # 对端模块立即发送 LCP 终止请求,挂断 PPP 链路 → 模块拒绝 PPP

sent [LCP TermAck id=0x2]
rcvd [IPCP ConfReq id=0x0]
Discarded non-LCP packet when LCP not open
rcvd [IPCP ConfRej id=0x1 <ms-dns1 0.0.0.0> <ms-dns2 0.0.0.0>]
Discarded non-LCP packet when LCP not open
Modem hangup
Connection terminated.
                # PPP 链路彻底断开,无法分配 IP,最终连接失败

PPP 拨号 对比 QMI 拨号

项目 PPP QMI
年代 拨号时代 LTE 时代
数据通道 ttyUSB wwan0
稳定性
掉线恢复 手写脚本 模块自动
维护成本
运营商兼容
无人车量产 ❌ 不推荐 ✅ 强烈推荐

QMI 拨号


lxg@lxg:~/code/project/linux/rk3568_linux$ ls ./buildroot/board/rockchip/common/base/usr/bin/
4G_dialing.sh  5G_dialing.sh  create_ap  quectel-CM  rkisp_demo  rpdzkj-mobilenet.sh  video_camera.sh

4G_dialing.sh


#!/bin/bash

# =========================
# 4G 模块自动拨号脚本(Quectel EC20 / EC200 系列)
# 功能:
# 1. 遍历 USB 设备,识别 Quectel 4G 模块
# 2. 判断是否已有网络接口(usb0 / wwan0)
# 3. 若无接口或网络不通:
#    - 通过 AT 指令切换 usbnet 模式
#    - 启动 quectel-CM 进行 QMI/ECM 拨号
# =========================

# /dev/serial/by-id 下是 udev 创建的“稳定串口名”
DIRECTORY="/dev/serial/by-id"

# 保存最终选中的 AT 串口
Serial_port=""

# 计数器,用于选第 N 个 ttyUSB(Quectel 通常第 3 个是 AT 口)
counter=0


# =========================
# 函数:Switching_mode
# 作用:
#   1. 根据 USB 设备信息拼出 serial-by-id 名字
#   2. 在 /dev/serial/by-id 中找到对应 ttyUSB
#   3. 默认取第 3 个(counter == 2)
# =========================
Switching_mode()
{
    # USB 设备信息(来自 sysfs)
    PRODUCT_NAME=$(cat "$device_dir/product")
    MANUFACTURER=$(cat "$device_dir/manufacturer")
    SERIAL_NUMBER=$(cat "$device_dir/serial")

    # 生成 /dev/serial/by-id 的前缀名
    # 有些模块没有序列号,要兼容
    if [ "$SERIAL_NUMBER" == "" ];then 
        Serial="usb-${MANUFACTURER}_${PRODUCT_NAME}"
    else
        Serial="usb-${MANUFACTURER}_${PRODUCT_NAME}_$SERIAL_NUMBER"
    fi

    # 在 by-id 目录中查找对应的串口
    # Quectel 模块通常:
    # ttyUSB0/1: modem / diag
    # ttyUSB2:   AT 指令口(经验值)
    for file in $(ls "$DIRECTORY" | grep "$Serial" | sort); do
        if [ "$counter" -eq 2 ]; then
            Serial_port=$file
            echo "Serial_port:$Serial_port"
            break
        fi
        counter=$((counter+1))
    done
}

# =========================
# 主流程:遍历所有 USB 设备
# =========================
for device_dir in /sys/bus/usb/devices/*; do
    if [ -e "$device_dir/idProduct" ]; then

        # 读取 USB Product ID
        product_id=$(cat "$device_dir/idProduct")

        # ==================================================
        # EC200 系列(6001 / 6002 / 6005)
        # ==================================================
        if [ "$product_id" = "6002" ] || [ "$product_id" = "6001" ] || [ "$product_id" = "6005" ]; then
            echo "This is a EC200 module!"

            # 查找该 USB 设备下暴露的网络接口
            for interface in ${device_dir}/*/net/*; do
                name=$(basename $interface)
                echo "name:$name"
            done 

            # 如果系统中不存在该网络接口
            if [ ! -e "/sys/class/net/$name" ]; then
                echo "$name not found!!!"

                # 查找 AT 串口
                Switching_mode "$device_dir"

                if [ -e $DIRECTORY/$Serial_port ]; then
                    # 切换到 usbnet=1(ECM/QMI 模式)
                    echo -e "AT+QCFG=\"usbnet\",1" > $DIRECTORY/$Serial_port
                    sleep 1

                    # 启动 quectel-CM(后台)
                    /usr/bin/quectel-CM >> /tmp/4G.log 2>&1 &
                else
                    echo "The Serial_port not found!!!"
                fi

            else
                # 网络接口存在,进行连通性测试
                echo "This is EC200 Connection test"
                ping -c 2 -W 3 -I $name 8.8.8.8

                # ping 失败,认为 4G 掉线
                if [ ! "$?" == "0" ]; then
                    echo "EC200 Connect faile!!!"

                    Switching_mode "$device_dir"
                    if [ -e $DIRECTORY/$Serial_port ]; then
                        # 原厂这里注释掉了 usbnet=0
                        # 表示:不强制切回 PPP
                        sleep 1
                        /usr/bin/quectel-CM >> /tmp/4G.log 2>&1 &
                    else
                        echo "The Serial_port not found!!!"
                    fi
                else
                    echo "EC200 Connect success!"
                    exit 1
                fi
            fi
        fi

        # ==================================================
        # EC20 系列(0125)
        # ==================================================
        if [ "$product_id" = "0125" ]; then
            echo "This is a EC20 module!"

            for interface in ${device_dir}/*/net/*; do
                name=$(basename $interface)
                echo "name:$name"
            done

            if [ ! -e "/sys/class/net/$name" ]; then
                echo "$name not found!!!"

                Switching_mode "$device_dir"
                if [ -e $DIRECTORY/$Serial_port ]; then
                    # EC20 默认使用 usbnet=0(QMI)
                    echo -e "AT+QCFG=\"usbnet\",0" > $DIRECTORY/$Serial_port
                    sleep 1
                    /usr/bin/quectel-CM -d >> /tmp/4G.log 2>&1 &
                else
                    echo "The Serial_port not found!!!"
                fi

            else
                echo "This is EC20 Connection test"
                ping -c 2 -W 3 -I $name 8.8.8.8

                if [ ! "$?" == "0" ]; then
                    echo "EC20 Connect faile!!!"

                    Switching_mode "$device_dir"
                    if [ -e $DIRECTORY/$Serial_port ]; then
                        # 同样不强制切换 usbnet
                        sleep 1
                        /usr/bin/quectel-CM -d >> /tmp/4G.log 2>&1 &
                    else
                        echo "The Serial_port not found!!!"
                    fi
                else 
                    echo "EC20 Connect success!"
                    exit 1
                fi
            fi
        fi
    fi
done

quectel-CM

quectel-CM 是移远(Quectel)官方提供的 4G/5G 数据拨号与链路保持程序,主要用于 QMI / MBIM / ECM 等“非 PPP”拨号方式

查看当前网卡




root@rk3568-buildroot:/# ifconfig
dummy0    Link encap:Ethernet  HWaddr 9A:28:A9:0B:24:0E  
          inet addr:169.254.46.104  Bcast:169.254.255.255  Mask:255.255.0.0
          inet6 addr: fe80::e9f8:8c65:5e92:19e0/64 Scope:Link
          UP BROADCAST RUNNING NOARP  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:1432 (1.3 KiB)

eth0      Link encap:Ethernet  HWaddr A6:FC:A7:E6:8A:8F  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
          Interrupt:46 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

p2p0      Link encap:Ethernet  HWaddr 96:BA:06:E7:0E:34  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

usb0      Link encap:Ethernet  HWaddr AE:0C:29:A3:9B:6D  
          inet addr:100.89.144.41  Bcast:100.255.255.255  Mask:255.0.0.0
          inet6 addr: fe80::56c4:6eb9:9036:e032/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:29 errors:0 dropped:0 overruns:0 frame:0
          TX packets:45 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:2842 (2.7 KiB)  TX bytes:3954 (3.8 KiB)

wlan0     Link encap:Ethernet  HWaddr 94:BA:06:E7:0E:34  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)


root@rk3568-buildroot:/# ip route 
default via 100.89.144.214 dev usb0 proto dhcp src 100.89.144.41 metric 1006 
100.0.0.0/8 dev usb0 proto dhcp scope link src 100.89.144.41 metric 1006 
169.254.0.0/16 dev dummy0 scope link src 169.254.46.104 metric 1002 

Buildroot 系统启动脚本


lxg@lxg:~/code/project/linux/rk3568_linux$ ls buildroot/output/rockchip_rk3568/target/etc/init.d/
fuse3      S00mountall.sh       S02leds-trigger-config.sh  S20urandom         S40bluetoothd  S41dhcpcd    S50pulseaudio    S99-auto-reboot         S99input-event-daemon
ninfod.sh  S01boot-complete.sh  S02sysctl                  S30dbus            S40_ec801e     S49ntp       S50usbdevice.sh  S99_camera_node         S99_rpdzkj-mobilenet
rcK        S01syslogd           S05async-commit.sh         S35iptables        S40network     S49weston    S80dnsmasq       S99chromium-wayland.sh  socketcand
rcS        S02klogd             S10udev                    S36wifibt-init.sh  S40rkaiq_3A    S50dropbear  S98iodomain.sh   S99_config_soundcard

buildroot defconfig

rk3568_linux/buildroot/configs/rockchip_rk3568_defconfig


#include "base/base.config"               # 基础配置,必须保留,包含核心工具链和根文件系统基础
#include "chips/rk3566_rk3568_aarch64.config"  # RK3568/RK3566 平台配置,必须保留
#include "font/chinese.config"            # 中文字体支持,可根据需求保留或删除
#include "fs/exfat.config"                # exFAT 文件系统支持,如果不需要外部 exFAT SD/USB 可以删除
#include "fs/ntfs.config"                 # NTFS 文件系统支持,如果不使用 NTFS 外部盘可删除
#include "fs/vfat.config"                 # VFAT 文件系统支持,一般U盘必需,建议保留
#include "gpu/gpu.config"                 # GPU 驱动配置,RK3568 Mali GPU 必须保留
#include "multimedia/audio.config"        # 音频支持,可根据无人车场景决定是否保留
#include "multimedia/camera.config"       # 摄像头支持,如果无人车有摄像头必需保留
#include "multimedia/gst/audio.config"    # GStreamer 音频插件,可根据需求删除
#include "multimedia/gst/camera.config"   # GStreamer 摄像头插件,如果使用摄像头采集视频保留
#include "multimedia/gst/rtsp.config"     # GStreamer RTSP 流播放/推流插件,若无人车没有 RTSP 流可删除
#include "multimedia/gst/video.config"    # GStreamer 视频插件,保留与摄像头视频处理相关功能
#include "multimedia/mpp.config"          # RK3568 硬件多媒体编解码器配置,视频解码/编码必需
#include "wifibt/bt.config"               # 蓝牙支持,可删除如果无人车不使用蓝牙
#include "wifibt/wireless.config"         # Wi-Fi 支持,如果无人车不需要 Wi-Fi 可删除
#include "tools/benchmark.config"         # 测试/benchmark 工具,可删除生产环境
#include "tools/common.config"            # 常用工具/脚本,建议保留
#include "tools/test.config"              # 测试工具,可删除生产环境
#include "chromium.config"                # Chromium 浏览器,可删除,如果无人车不需要浏览器UI
#include "npu2.config"                    # NPU 支持,如果无人车有 AI 推理芯片保留,否则可删除
#include "powermanager.config"            # 电源管理,建议保留
#include "weston.config"                  # Weston 显示服务器,Qt 或 LVGL 全屏可选择保留或删除
#include "qt/qt5.config"                  # Qt5 库,做 GUI 必需
#include "qt/app.config"                  # Qt 应用,视具体项目保留
BR2_ROOTFS_OVERLAY+="board/rockchip/rk3566_rk3568/fs-overlay/"  # 文件系统 overlay,保留

buildroot Weston

Weston 不是“桌面 UI”,而是 Wayland 的显示与窗口合成基础设施。 在嵌入式里,它是“跑 UI 的地基”,不是“给人用的桌面”。

Weston 本身不是桌面环境,开机后你一般会 自动启动 Qt / LVGL 应用覆盖全屏

buildroot_weston

桌面图标


root@rk3568-buildroot:/# ls etc/xdg/weston/weston.ini.d/
01-launcher.ini  02-desktop.ini  03-desktop-launcher.ini  04-desktop-launcher-group.ini

编译报错分析


Running 10-os-release.sh for /home/lxg/code/project/linux/rk3568_linux/buildroot/output/rockchip_rk3568/target (buildroot init=busybox)...
Adding information to /etc/os-release...
Adding release_version to get version info
fatal: No names found, cannot describe anything.
ERROR: Running /home/lxg/code/project/linux/rk3568_linux/device/rockchip/common/post-hooks/10-os-release.sh - write_release_version failed!
ERROR: exit code 128 from line 20:
    SDK_VERSION=`git describe --tags $(git rev-list --tags --max-count=1)`
ERROR: call stack:
    10-os-release.sh: write_release_version(20)
    10-os-release.sh: main(58)
ERROR: Running /home/lxg/code/project/linux/rk3568_linux/device/rockchip/common/scripts/build.sh - run_hooks /home/lxg/code/project/linux/rk3568_linux/buildroot/output/rockchip_rk3568/target failed!
ERROR: exit code 128 from line 256:
    /home/lxg/code/project/linux/rk3568_linux/device/rockchip/common/post-hooks/10-os-release.sh /home/lxg/code/project/linux/rk3568_linux/buildroot/output/rockchip_rk3568/target
ERROR: call stack:
    build.sh: run_hooks(256)
    build.sh: run_post_hooks(288)
    build.sh: main(615)
    build.sh: main(660)


修改方案


diff --git a/device/rockchip/common/scripts/post-os-release.sh b/device/rockchip/common/scripts/post-os-release.sh
index 9d4d50574..27726c223 100755
--- a/device/rockchip/common/scripts/post-os-release.sh
+++ b/device/rockchip/common/scripts/post-os-release.sh
@@ -17,7 +17,8 @@ fixup_os_release()
 function write_release_version()
 {
     GIT_COMMIT=`git log --oneline -1 | awk {'print $1'}`
-    SDK_VERSION=`git describe --tags $(git rev-list --tags --max-count=1)`
+    # SDK_VERSION=`git describe --tags $(git rev-list --tags --max-count=1)`
+    SDK_VERSION="RK3568-K5-$(date +%Y%m%d)"
     BUILD_TIME=`date +"%Y-%m-%d %H:%M:%S"`
 
 {

固定CH341的串口编号

获取ID_PATH


root@rk3568-buildroot:/# udevadm info -n /dev/ttyUSB3
P: /devices/platform/usbhost/fd000000.dwc3/xhci-hcd.4.auto/usb5/5-1/5-1:1.0/ttyUSB3/tty/ttyUSB3
N: ttyUSB3
S: serial/by-id/usb-1a86_USB_Serial-if00-port0
S: serial/by-path/platform-xhci-hcd.4.auto-usb-0:1:1.0-port0
S: ttyCH341USB0
E: DEVLINKS=/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0 /dev/serial/by-path/platform-xhci-hcd.4.auto-usb-0:1:1.0-port0 /dev/ttyCH341USB0
E: DEVNAME=/dev/ttyUSB3
E: DEVPATH=/devices/platform/usbhost/fd000000.dwc3/xhci-hcd.4.auto/usb5/5-1/5-1:1.0/ttyUSB3/tty/ttyUSB3
E: ID_BUS=usb
E: ID_MODEL=USB_Serial
E: ID_MODEL_ENC=USB\x20Serial
E: ID_MODEL_FROM_DATABASE=HL-340 USB-Serial adapter
E: ID_MODEL_ID=7523
E: ID_PATH=platform-xhci-hcd.4.auto-usb-0:1:1.0
E: ID_PATH_TAG=platform-xhci-hcd_4_auto-usb-0_1_1_0
E: ID_REVISION=0264
E: ID_SERIAL=1a86_USB_Serial
E: ID_TYPE=generic
E: ID_USB_CLASS_FROM_DATABASE=Vendor Specific Class
E: ID_USB_DRIVER=ch341
E: ID_USB_INTERFACES=:ff0102:
E: ID_USB_INTERFACE_NUM=00
E: ID_VENDOR=1a86
E: ID_VENDOR_ENC=1a86
E: ID_VENDOR_FROM_DATABASE=QinHeng Electronics
E: ID_VENDOR_ID=1a86
E: MAJOR=188
E: MINOR=3
E: SUBSYSTEM=tty
E: USEC_INITIALIZED=117928515


编写Udev规则

rk3568_linux/buildroot/board/rockchip/common/base/etc/udev/rules.d/99-serial.rules


SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", ENV{ID_PATH}=="platform-xhci-hcd.4.auto-usb-0:1:1.0", SYMLINK+="ttyCH341USB0"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", ENV{ID_PATH}=="platform-fd8c0000.usb-usb-0:1:1.0", SYMLINK+="ttyCH341USB1"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", ENV{ID_PATH}=="platform-fd800000.usb-usb-0:1.1:1.0", SYMLINK+="ttyCH341USB2"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", ENV{ID_PATH}=="platform-fd800000.usb-usb-0:1.2:1.0", SYMLINK+="ttyCH341USB3"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", ENV{ID_PATH}=="platform-fd800000.usb-usb-0:1.4:1.0", SYMLINK+="ttyCH341USB4"

OTA 升级

Rockchip_Developer_Guide_Linux_Upgrade_CN.pdf

升级方式

  1. Recovery 模式,设备上有一个单独的分区(recovery)用于升级操作。
  2. Linux A/B 模式,设备上有两套固件,可切换使用。

Recovery升级


updateEngine --image_url=/userdata/update.img --misc=update --savepath=/userdata/update.img --reboot &

A/B 分区 OTA


┌───────────────┐
│ boot          │
├───────────────┤
│ rootfs_A  ← 当前运行 │
├───────────────┤
│ rootfs_B  ← OTA 写入 │
├───────────────┤
│ userdata      │
└───────────────┘

  1. 当前运行 A
  2. OTA 包写入 B 分区
  3. 修改 boot 参数 → 下次启动从 B
  4. B 启动成功 → 标记成功
  5. B 启动失败 → 自动回滚到 A

恢复出厂设置


root@rk3568-buildroot:/# update
update: Rockchip Update Tool
update: --wipe_all
command: --wipe_all
update: write command to command file: done
update: write command to misc file: done
update: reboot!