ESC
输入关键词搜索文章标题和内容

嵌入式Linux新板子bring-up实战:RK3506B从零到驱动验证

本文由 linuxROS 整理发布,首发于 linuxros.cn,转载请注明出处。

嵌入式Linux新板子bring-up实战:RK3506B从零到驱动验证

导读:新板子回来怎么让它跑起来?本文以Rockchip RK3506B工业平台为例,覆盖从USB烧录、DDR初始化、U-Boot移植到内核启动的完整bring-up链路,附每一步关键命令和常见踩坑排雷。


一、原理简析

bring-up是什么?

嵌入式Linux新板子bring-up,本质是让软件逐层认识硬件的过程。芯片上电后,依次经历五个阶段,每一层都把下一层所需的环境准备好:

阶段 谁在工作 核心任务 运行位置
① ROM代码 芯片内置BootROM 从存储介质加载SPL 芯片内部ROM
② SPL/TPL U-Boot第一阶段 初始化DDR,加载完整U-Boot 芯片内部SRAM
③ U-Boot 完整Bootloader 初始化外设,加载内核 DDR
④ 内核 Linux Kernel 驱动全部硬件,挂载根文件系统 DDR
⑤ 用户空间 init + 应用程序 业务逻辑运行 DDR

Rockchip启动链

Rockchip平台有一条明确的启动链,这也是bring-up的检查清单:

flowchart TB A(["上电"]) --> B["BootROM<br/>芯片内置ROM代码"] B --> C{"找到<br/>SPL?"} C -->|"是"| D["SPL加载到SRAM<br/>初始化DDR"] C -->|"否"| M["进入MaskROM模式<br/>等待USB烧录"] D --> E{"DDR init<br/>done?"} E -->|"否"| F["卡死: 无任何输出"] E -->|"是"| G["U-Boot加载到DDR<br/>初始化eMMC/网络/USB"] G --> H{"内核能<br/>启动?"} H -->|"否"| I["检查设备树<br/>检查bootargs"] H -->|"是"| J["内核启动<br/>挂载rootfs"] J --> K(["进入Linux<br/>驱动验证"]) style A fill:#E3F2FD,stroke:#1976D2 style B fill:#E3F2FD,stroke:#1976D2 style M fill:#FFF8E1,stroke:#F57C00 style F fill:#FFEBEE,stroke:#D32F2F style E fill:#FFF8E1,stroke:#F57C00 style H fill:#FFF8E1,stroke:#F57C00 style K fill:#E8F5E9,stroke:#388E3C

关键认知:bring-up不是调试bug,而是验证硬件设计。软件没反应,优先查供电、时钟、复位,再查代码。

RK3506B平台概览

属性 说明
CPU 3×Cortex-A7 @ 1.5GHz + 1×Cortex-M0 @ 200MHz(多核异构)
架构 ARMv7-A 32bit
制程 22nm
内存 16bit DDR2/DDR3/DDR3L,最大512MB
存储 eMMC / NAND Flash / SPI Nor
网络 双路RMII 10/100M以太网
工业总线 双CAN-FD、6×UART、3×SPI、3×I2C、DSMC/FLEXBUS
SDK Buildroot 2024.02 + Linux 6.1 + U-Boot 2017.09
实时支持 PREEMPT_RT / Xenomai 3

二、启动流程与分区布局

Rockchip启动模式

Rockchip芯片支持多种启动模式,通过硬件引脚或eFuse配置:

flowchart LR subgraph 正常启动["正常启动"] ROM["BootROM"] --> SPL["SPL→DDR→U-Boot"] SPL --> Kernel["Linux Kernel"] end subgraph 烧录模式["烧录模式"] Mask["MaskROM<br/>按住BOOT键+复位"] --> USB["USB OTG"] USB --> Tool["RKDevTool/rkdeveloptool"] end subgraph 恢复模式["Loader模式"] Loader["已有SPL"] --> USB2["USB OTG"] USB2 --> Tool2["快速烧录"] end style 正常启动 fill:#E8F5E9,stroke:#388E3C style 烧录模式 fill:#FFF8E1,stroke:#F57C00 style 恢复模式 fill:#E3F2FD,stroke:#1976D2

分区布局

Rockchip使用GPT分区表,bring-up阶段需要知道每个镜像烧到哪个位置:

分区名 起始扇区(512B) 大小 内容
loader1 0x40 (64) 2.5MB idbloader.img = TPL/SPL合并镜像
loader2 0x4000 (16384) 4MB u-boot.itb (U-Boot + ATF/Trust)
trust 0x6000 (24576) 4MB trust.img (ATF/TEE,仅miniloader方案使用)
boot 0x8000 (32768) 112MB boot.img (内核+设备树+extlinux.conf)
rootfs 0x40000 (262144) 剩余空间 rootfs.img

分区表来自Rockchip官方wiki Partitions 和 Boot_option。实际分区大小可通过parameter_gpt.txt自定义。

U-Boot两种启动方案对比

Rockchip平台U-Boot有两套方案,bring-up时需要明确用的是哪套:

维度 U-Boot SPL/TPL方案 Rockchip Miniloader方案
DDR初始化 rkbin预编译DDR bin + U-Boot TPL加载 预编译DDR bin + miniloader(全部闭源)
源码可见 U-Boot部分开源,DDR bin闭源 全部闭源
idbloader内容 TPL(DDR bin) + SPL(U-Boot编译) DDR bin + miniloader
loader2内容 u-boot.itb (含U-Boot+trust) uboot.img (单独)
trust分区 不需要(含在u-boot.itb内) 需要单独trust.img @ 0x6000
主线上游 部分支持(U-Boot主线) 不支持
RK3506B ✅ SDK默认方案 ❌ 旧方案

RK3506B SDK使用SPL/TPL方案:rkbin/目录提供DDR初始化二进制 + U-Boot编译生成SPL。烧录时db命令将loader下载到SRAM执行DDR初始化,之后通过wl分别写入各分区镜像。


三、关键速查表

bring-up五阶段对照表

阶段 成功标志 失败表现 首要排查项
① BootROM USB设备识别(2207:xxxx) 电脑无任何反应 供电、BOOT引脚电平
② SPL/DDR 串口打印"DDR init done" 串口无任何输出 DDR型号与bin是否匹配
③ U-Boot 串口出现=>交互提示符 SPL后无输出或卡死 波特率、串口引脚mux
④ 内核 打印"VFS: Mounted root" Starting kernel后卡死 设备树、root=参数
⑤ 驱动验证 各外设功能正常 设备文件缺失、通信异常 逐个外设排查dts配置

烧录工具对比

工具 平台 适用场景
RKDevTool Windows(GUI) 量产烧录、新手友好
rkdeveloptool Linux(命令行) 开发调试、CI集成
upgrade_tool Linux(命令行) 官方闭源工具、功能最全
rkflash.sh Linux(脚本) SDK一键烧录
# rkdeveloptool 常用命令速查(SPL方案,RK3506B默认)
rkdeveloptool list                    # 列出USB设备
rkdeveloptool db rk3506_loader.bin    # 下载Boot代码到SRAM(DDR初始化)
rkdeveloptool wl 0x40 idbloader.img   # 写入idbloader到loader1分区
rkdeveloptool wl 0x4000 u-boot.itb    # 写入U-Boot+Trust到loader2分区
rkdeveloptool wl 0x8000 boot.img      # 写入内核到boot分区
rkdeveloptool wl 0x40000 rootfs.img   # 写入根文件系统
rkdeveloptool rd                      # 复位设备
# 注意:ul命令仅miniloader方案使用,SPL方案不需要

四、实战步骤

第一步:SDK环境搭建

# ===== 宿主机:Ubuntu 22.04 LTS 推荐 =====
sudo apt update
sudo apt install -y build-essential git make gcc g++ \
    python3 bc unzip dosfstools mtools parted \
    libncurses-dev libssl-dev bison flex p7zip-full \
    libudev-dev libusb-1.0-0-dev dh-autoreconf repo

# ===== 获取RK3506B SDK =====
mkdir -p ~/proj/rk3506 && cd ~/proj/rk3506

# 方式一:从SDK基础包解压
7z x rk3506_linux_release_v1.0.0a.7z.001
cd rk3506_sdk

# 方式二:repo同步(如有账号)
repo init -u <manifest_url> -b linux-6.1-stan-rkr4.1
repo sync -j16

SDK目录结构速览:

~/proj/rk3506/rk3506_sdk/
├── build.sh -> device/rockchip/common/scripts/build.sh  # 编译入口
├── rkflash.sh -> device/rockchip/common/scripts/rkflash.sh  # 烧录入口
├── u-boot/                    # U-Boot 2017.09源码
├── kernel/                    # Linux 6.1内核源码
├── buildroot/                 # Buildroot 2024.02根文件系统
├── rkbin/                     # Rockchip闭源二进制(RK3506_DDR_bin等)
├── device/rockchip/rk3506/    # 板级配置文件
├── prebuilts/                 # 交叉编译工具链(arm-linux-gnueabihf-)
└── docs/                      # 本地开发文档

第二步:USB烧录

RK3506B的MaskROM模式进入方式:

# ===== 进入烧录模式 =====
# 方法:按住BOOT/KEY2键 → 按复位键 → 松开复位 → 松开BOOT
# 或:按住USER1/KEY3键同上操作(部分板卡KEY3=Loader模式)

# ===== 确认设备识别 =====
# 在Linux开发机上
lsusb | grep 2207
# 输出: Bus 003 Device 005: ID 2207:3506 Fuzhou Rockchip Electronics Company

rkdeveloptool list
# 输出: DevNo=1   Vid=0x2207,Pid=0x3506, LocationID=xxx    Maskrom

完整烧录流程:

RK3506B使用SPL/TPL方案,烧录命令如下(与miniloader方案不同,不需要ul和trust.img):

来自 linuxros.cn · linuxROS
# ===== SPL/TPL方案:rkdeveloptool(RK3506B SDK默认)=====
# 编译安装 rkdeveloptool
git clone https://github.com/rockchip-linux/rkdeveloptool.git
cd rkdeveloptool
autoreconf -i && ./configure && make && sudo make install

# Step1: db命令下载loader到SRAM,初始化DDR
rkdeveloptool db rk3506_loader_v1.00.bin

# Step2: 写入idbloader(TPL+SPL)到loader1分区(LBA 0x40)
rkdeveloptool wl 0x40 idbloader.img

# Step3: 写入u-boot.itb(U-Boot+trust)到loader2分区(LBA 0x4000)
rkdeveloptool wl 0x4000 u-boot.itb

# Step4: 写入boot.img(内核+设备树)到LBA 0x8000
rkdeveloptool wl 0x8000 boot.img

# Step5: 写入根文件系统到LBA 0x40000
rkdeveloptool wl 0x40000 rootfs.img

# Step6: 复位设备启动
rkdeveloptool rd

# ===== Miniloader方案(旧方案,仅对比参考)=====
# rkdeveloptool db rkxx_loader_vx.xx.bin
# rkdeveloptool ul rkxx_loader_vx.xx.bin    # ul = 写入loader到idb区域
# rkdeveloptool wl 0x4000 uboot.img         # 注意:uboot.img ≠ u-boot.itb
# rkdeveloptool wl 0x6000 trust.img         # miniloader需要单独的trust分区
# rkdeveloptool wl 0x8000 boot.img
# rkdeveloptool wl 0x40000 rootfs.img
# rkdeveloptool rd

# ===== 方案三:rkflash.sh(SDK自带一键脚本,推荐量产)=====
sudo ./rkflash.sh

重要区分:rkdeveloptool db用于下载loader到SRAM做DDR初始化(两个方案都用)。ul命令仅miniloader方案使用,等价于wl 0x40 idbloader.img。SPL方案直接用wl 0x40 idbloader.img + wl 0x4000 u-boot.itb,不需要ul和单独的trust.img。参考Rockchip Boot_option

第三步:SPL阶段——DDR bring-up

SPL是整个bring-up最难的环节。成功时串口输出(以RK3506B SDK为例):

U-Boot SPL 2017.09 (Mar 19 2025 - 10:00:00 +0800)
DDRINFO: start DDR init
DDRINFO: ddr_rate = 1056MHz
DDRINFO: ddr_type = DDR3
DDRINFO: ddr_size = 256MB
DDRINFO: ddr init done
Trying to boot from MMC1

DDR适配三步法:

flowchart TB A(["新板子DDR不工作"]) --> B{"DDR颗粒<br/>与参考板相同?"} B -->|"是"| C["直接用SDK rkbin<br/>中的DDR bin"] B -->|"否"| D{"颗粒在Rockchip<br/>支持列表内?"} D -->|"是"| E["从rkbin仓库<br/>选择对应bin文件"] D -->|"否"| F["需重新生成<br/>DDR初始化bin"] C --> G["烧录测试"] E --> G F --> H["联系Rockchip FAE<br/>获取DDR初始化工具"] H --> G G --> I{"mtest<br/>通过?"} I -->|"是"| K(["DDR验证通过"]) I -->|"否"| J["降频测试<br/>检查电源纹波"] J --> G style A fill:#E3F2FD,stroke:#1976D2 style B fill:#FFF8E1,stroke:#F57C00 style C fill:#E8F5E9,stroke:#388E3C style D fill:#FFF8E1,stroke:#F57C00 style E fill:#E8F5E9,stroke:#388E3C style F fill:#FFEBEE,stroke:#D32F2F style G fill:#F3E5F5,stroke:#7B1FA2 style H fill:#FFEBEE,stroke:#D32F2F style I fill:#FFF8E1,stroke:#F57C00 style J fill:#FFEBEE,stroke:#D32F2F style K fill:#E8F5E9,stroke:#388E3C

DDR验证命令:

# U-Boot命令行下快速验证
=> mw.l 0x80000000 0xdeadbeef 1      # 写入测试数据
=> md.l 0x80000000 1                  # 读回验证
80000000: deadbeef                    # 一致则DDR读写正常

=> mtest 0x80000000 0x81000000        # 测试前16MB(快速检查)
# 通过标准: 无 "FAIL" 错误输出

# 全量DDR测试(需要较长时间)
=> mtest 0x80000000 0x90000000        # 256MB全量测试

# Linux下memtester(系统启动后)
memtester 200M 10                      # 200MB跑10轮

第四步:U-Boot启动与调试

DDR跑通后,U-Boot正常启动日志:

U-Boot 2017.09 (Jan 15 2026 - 10:00:00 +0800)
CPU:   rk3506 (3*Cortex-A7)
DRAM:  256 MiB
MMC:   mmc@ff490000: 0, mmc@ff4b0000: 1
In:    serial@ff0d0000
Out:   serial@ff0d0000
Err:   serial@ff0d0000
Model: Rockchip RK3506B EVB
Net:   eth0: ethernet@ff010000, eth1: ethernet@ff011000
Hit any key to stop autoboot:  0
=>

U-Boot下常用调试命令:

# 查看环境变量
=> printenv bootargs

# 查看eMMC信息
=> mmc info

# 网络加载内核(TFTP调试利器)
=> setenv serverip 192.168.1.100
=> setenv ipaddr 192.168.1.200
=> tftpboot 0x81000000 zImage
=> bootz 0x81000000

# 手动挂载根文件系统启动
=> setenv bootargs 'console=ttyS0,115200 earlycon root=/dev/mmcblk0p5 rw rootwait'
=> boot

第五步:内核启动

正确的内核启动日志:

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 6.1.99 (builduser@buildhost)
[    0.000000] CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7)
[    0.100000] Memory: 256MB total
[    2.500000] VFS: Mounted root (ubifs filesystem) on device 0:14
rk3506 login:

内核卡死排查矩阵:

卡住位置 典型日志 优先排查
无任何内核输出 Starting kernel ... 后无下文 设备树uart节点status、earlycon=参数地址
停在内存初始化 Memory policy: ... 后停 kernel与SPL的DDR容量配置是否一致
停在VFS阶段 VFS: Cannot open root device bootargs中root=路径
停在驱动加载 某驱动probe后无输出 initcall_debug参数,逐个禁用可疑驱动

设备树检查要点:

# 确认dts中关键节点
chosen {
    stdout-path = "serial0:115200n8";     # 确保调试串口
};

# bootargs中追加earlycon
earlycon=uart8250,mmio32,0xff0d0000       # 提前输出内核日志

第六步:驱动逐项验证

内核跑起来后,按外设类型逐项验证:

# ===== GPIO =====
cat /sys/kernel/debug/gpio
echo 24 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio24/direction
echo 1 > /sys/class/gpio/gpio24/value

# ===== I2C =====
i2cdetect -y 1                        # 扫描I2C-1上的设备
i2cget -y 1 0x48 0x00                 # 读传感器寄存器

# ===== 以太网 =====
ifconfig eth0 192.168.1.200 up
ping 192.168.1.1

# ===== CAN =====
ip link set can0 type can bitrate 500000
ip link set can0 up
candump can0                          # 接收CAN数据

# ===== WiFi/BT =====
ifconfig wlan0 up
hciconfig hci0 up

# ===== eMMC/SD =====
mount /dev/mmcblk0p5 /mnt
dd if=/dev/zero of=/mnt/test.bin bs=1M count=10

五、常见问题解决

SPL/DDR阶段

现象 根因 解决
串口完全无输出 DDR初始化卡死,SPL未执行 ① 确认BOOT引脚电平正确 ② 检查各路供电(1.1V/1.35V/1.8V/3.3V) ③ 示波器测时钟晶振是否起振
DDR init done打印后无反应 SPL加载U-Boot失败 检查存储介质(eMMC/NAND)焊接、loader2分区位置
烧录成功但不起动 SPL的DDR bin与颗粒不匹配 从SDK rkbin/换用正确颗粒的DDR bin;检查Rockchip_Support_List_DDR_Ver2.63.pdf确认颗粒是否在支持列表
烧录中途报错 USB传输中断或DDR缓存出错 rkdeveloptool db后等2秒再执行wl;换USB线或端口;确认进入MaskROM模式

U-Boot阶段

现象 根因 解决
串口乱码 波特率或时钟配置错误 RK3506B默认波特率115200(部分老版本SDK用1500000),确认后用对应波特率连接
=>提示符下输入无响应 串口流控问题 终端软件关闭硬件流控(RTS/CTS)
mmc init failed eMMC未识别 检查eMMC供电、CMD/DATA线焊接、dts中mmc节点
Net: No ethernet found 以太网PHY未识别 检查PHY的reset引脚、MDIO地址、dts中phy-handle

内核阶段

现象 根因 解决
Starting kernel ... 后无输出 内核与设备树不匹配或earlycon地址错 用SDK自带内核镜像先验证;检查UART物理地址是否与dts一致
Kernel panic - not syncing: VFS rootfs路径或文件系统类型错误 确认root=/dev/mmcblk0p5分区号,确认文件系统类型(ubifs/ext4)
内核启动到一半panic 驱动probe某外设时崩溃 在设备树中status = "disabled"逐个禁用可疑外设核验
启动后内存不足 DDR容量配置偏小 检查SPL中DDR容量配置和设备树memory节点是否一致

六、总结

推荐bring-up顺序

flowchart LR A["1. 供电/时钟<br/>示波器验证"] --> B["2. MaskROM<br/>USB识别"] B --> C["3. SPL/DDR<br/>串口有输出"] C --> D["4. U-Boot<br/>=> 交互"] D --> E["5. 内核<br/>rootfs挂载"] E --> F["6. 驱动<br/>逐外设验证"] style A fill:#E3F2FD,stroke:#1976D2 style B fill:#E3F2FD,stroke:#1976D2 style C fill:#FFEBEE,stroke:#D32F2F style D fill:#FFF8E1,stroke:#F57C00 style E fill:#FFF8E1,stroke:#F57C00 style F fill:#E8F5E9,stroke:#388E3C

经验总结

串口是唯一眼睛——DDR没通之前,除了串口你什么也看不见。first thing first: 让串口出字。

一次只改一个变量——先用参考板验证SDK镜像没问题,再换到新板子上。镜像和硬件分开排查。

DDR是最难的坎——SPL打印"DDR init done"才是真正的bring-up第一关。优先复用同颗粒的DDR bin,不要从零调时序。

稳定压倒一切——DDR通了马上跑memtester大范围长时间测试。不稳定就降频,性能后面再说。

版权声明

作者linuxROS
协议本作品采用 CC BY-NC-SA 4.0 许可协议:署名-非商业性使用-相同方式共享
关注欢迎关注微信公众号 linuxROS,获取更多机器人 / 嵌入式 / Linux 干货
返回首页