
RV1126B这块板子我前前后后折腾了小两个月从拿到的第一块工程板只能点亮电源灯到最后USB烧写一把过中间踩的坑估计能装满一个行李箱。尤其DDR那段板子点不亮的时候真的是所有调试手段都试了一遍最后才发现问题比想象中简单得多。这篇文章就把我完整跑通的移植过程、DDR配置异常的具体排查逻辑、SDK编译环境的搭建以及USB固件烧写的细节全部分享出来希望能帮正在折腾同平台的朋友少走几个弯路。1. 项目背景与平台特点拆解1.1 RV1126B到底是什么定位、适合哪些场景RV1126B是瑞芯微RV1126的一个迭代版本核心卖点就是那颗算力2.0TOPs的NPU可以把它理解成一颗专门为IPC、智能摄像头、人脸识别门禁这类视觉产品定制的SoC。和RV1126相比RV1126B在集成度上做了优化编码能力、ISP效果和外围接口都有调整最关键的是它把内存总线、DDR控制器的兼容性做了改动这就导致很多原本在RV1126上能直接跑的DDR参数拿到RV1126B上就会出问题。从我实际使用的情况来看RV1126B最典型的应用场景就是带AI功能的IP Camera、边缘计算盒子这类产品有编码需求、有轻量级AI识别需求但功耗和成本控制又比较严格。它内置的ISP对常见Sensor比如GC2053、OS04A10这些支持比较好一个Sensor搭配一颗镜头就能快速出一个画面效果不错的摄像头方案。不过要注意的是这颗芯片在主线内核上的支持并不算完整SDK基本依赖瑞芯微维护的release分支所以做移植的时候SDK的选型和版本锁定非常关键。1.2 拿到一套SDK先搞清楚工程结构再动手瑞芯微RV1126B的SDK体量不小通常是通过repo方式管理多个git仓库。第一次拉完代码之后你可能会有一种“这到底该看哪个目录”的迷茫。这里先说清楚一个核心概念RV1126B的启动流程是固定的一套——BootROM加载SPLSPL初始化DDR和基础时钟然后加载U-Boot再由U-Boot引导内核最终挂载根文件系统。所以DDR配置并不在kernel代码里而是在SPL/U-Boot的DDR驱动初始化阶段完成的这一点特别容易被不熟悉这套架构的新手忽略。SDK根目录下几个关键的位置需要提前心里有数u-boot存放的是SPL和U-Boot源码kernel/arch/arm/boot/dts/下面放着设备树文件buildroot或者debian目录是根文件系统的构建方案而rockdev/则是最终打包镜像的输出目录。简单说你改DDR参数是在u-boot里改改外设配置是在dts里改改系统组件是在buildroot里改三者独立又互相配合。我在实际移植过程中最大的体会是先熟悉SDK的构建脚本再谈具体改动。SDK根目录有build.sh或者Makefile这类入口脚本编译量非常大第一次全量编译可能需要很长时间。建议先编译一次默认配置确认你的编译环境没问题然后再开始改DDR和烧写相关的部分。如果连默认配置都编不过先解决工具链、依赖库、Python版本之类的环境问题再往下走。2. DDR配置异常排查实录2.1 问题日志一出来基本就能锁定方向拿到RV1126B开发板之后我第一时间做的就是把SDK默认镜像烧进去结果串口日志卡在一半不动了。这里建议大家务必先接好串口RV1126B的调试串口默认配置一般是1.8V电平115200波特率通过UART2输出。我用的是一颗USB转串口芯片进行了电平转换避免直接接3.3V的TTL模块把引脚打坏。回传的日志里有一个非常典型的卡住位置U-Boot SPL board init U-Boot SPL booting from boot resource Trying to boot from MMC1如果你看到的日志停在这个位置基本可以判定是DDR初始化没跑过。SPL阶段的DDR初始化失败是不会详细报错的它就在卡在DDR训练或者内存检测那一步没办法继续加载U-Boot。还有一种更隐蔽的情况是日志正常跑完但U-Boot阶段kernel启动时频繁随机死机、校验CRC错误、内存访问不稳定这类问题通常也和DDR配置不当有关。碰到DDR问题我个人的排查顺序是这样的先确认板子上的实际DDR颗粒型号和容量再确认SDK里对应的DDR配置是否开启然后再看时序参数是否适配最后才考虑是不是硬件虚焊、走线等的问题。很多人一上来就怀疑硬件虚焊其实DDR参数不匹配的概率比虚焊高得多。2.2 DDR配置到底在改什么瑞芯微的DDR初始化在U-Boot的DDR驱动中完成核心配置文件通常在u-boot/configs/rockchip_rv1126b相关头文件里或者是通过一个单独的defconfig来区分不同内存颗粒的配置。这块芯片使用的是synopsys的DDR控制器它对DDR3和DDR4都支持但配置方式并不是“填一个频率”这么简单它需要一整套参数包括DDR类型、行地址数、列地址数、bank数、容量大小、时序参数CL/RCD/RP/RC等、驱动强度以及训练相关的使能开关。以DDR3 1GB8bit * 8颗或者16bit * 4颗为例容量计算的公式为总容量 行数 x 列数 x Bank数 x 位宽这个一定要根据实际颗粒Datasheet逐项核对。举个具体例子如果你的颗粒是512MBit x 168行、16列、8个Bank单颗是1Gbit4颗就是4Gbit也就是512MB。如果板子标注的是1GB但只识别出512MB那很可能就是地址位配置不对常见是Row地址少配了一位。瑞芯微DDR驱动内部支持通过参数列表自动检测但如果你的颗粒不在它默认支持的列表里就需要手动改参数。2.3 具体修改的实操步骤先说结论路径RV1126B的DDR频率和参数通常在U-Boot源码目录下的drivers/ram/rockfish/或者类似rockchip专用目录中管理。有些SDK版本会用DDR bin文件的方式在U-Boot编译时以二进制形式打进SPL里。如果你下载的DDR bin是固定支持的颗粒列表那你就得找到一个和你颗粒兼容的配置或者重新生成DDR bin。我当时用的颗粒是一颗国产DDR3L1Gb * 8bit4颗组成1GB容量实际颗粒是512MB总内存1GB两颗rank或者单颗容量大。在配置时我重点核对并修改了这几个地方/* 以DDR3类型为例 */ #define DDR_TYPE_DDR3 (1) #define DDR_ROW_ADDR 15 #define DDR_COL_ADDR 10 #define DDR_BANK_CNT 8 #define DDR_CAPACITY 1024这里的ROW_ADDR是行地址位数COL_ADDR是列地址位数BANK_CNT是bank数量。如果你确定DDR颗粒是8bit位宽的颗粒4颗并联就是32bit位宽8颗并联则是64bit位宽这里bank数量一般DDR3都是8个bank但某些特殊颗粒是16个bank一定要看颗粒手册确认不能想当然。改完DDR基础配置之后还需要检查SPL阶段的时钟配置。RV1126B的DDR频率一般有几种DDR3常见的有800MHz、1066MHz、1333MHzDDR3L作为低电压版本通常跑在1066MHz比较稳妥。很多人发现频率调高后系统直接起不来或者反复重启就是因为DDR控制器的驱动强度、ODT配置没有跟上。如果颗粒并非大牌的主流高速型号建议先从低频率开始跑稳定了再逐步往上升。这里详细讲一下我在修改时序参数时的一个实例。颗粒手册上会给出标准时序比如tRCDRAS to CAS Delay、tRPRow Precharge Time、tRASActive to Precharge Delay。DDR3常见的保守参数可以是CL9、tRCD9、tRP9对应实际延时计算为实际时间(ns) 周期数 / 内存频率如果跑1066MHz等效频率实时时钟533MHz一个时钟周期约1.875ns。所以tRCD9对应的实际延时约16.9ns只要大于颗粒手册的最小值就基本没问题。2.4 日志级别与调试手段改DDR配置最痛苦的就是没有图形界面、没有报错代码只能靠日志。瑞芯微这套DDR初始化代码里有debug开关一般在DDR驱动或者SPL的Makefile里可以打开详细日志。开启之后串口会输出DRAM类型、容量、频率、时序信息有一些版本还会输出每个PHY lane的训练结果这个对于手工调参实在是太有用了。如果你用的是瑞芯微官方的DDR调试工具从瑞芯微内部渠道或者线上资源亭获取的DDR Config工具那就更省事了。它可以让你在PC端图形化配置好参数生成一个DDR bin文件然后替换进U-Boot固件。不过这个工具对外未必容易拿到如果你手上没有手动改代码也是一样的效果只是要沉住气多试几轮。在这里我放一个我实际调试时使用的命令流程帮助你在无人指导的情况下快速缩小问题范围确认你开发板上的DDR颗粒型号拍照放大看清丝印搜索Datasheet在U-Boot defconfig或DDR配置文件中找到DDR_TYPE和频率相关的宏确认是否等于你的颗粒类型先关闭Training或者使用最保守的Timing参数把系统跑起来再说编译U-Boot和SPL生成新固件后烧录观察日志输出使用memtester或内核自带的内存压力测试工具跑满负载验证稳定性。2.5 内存稳定性测试要跑多久才算过关DDR配置调完之后很多人跑一个DDR stress test几分钟就宣布“搞定”这其实远远不够。我的建议是至少跑一整夜也就是8小时以上的压力测试。测试工具可以选择memtester这是最常见也最实用的内存压力测试工具。在文件系统起来之后执行类似下面的命令# 申请并且测试约700MB内存跑100个循环 memtester 700M 100或者用更狠一点的连续循环方式while true; do memtester 1G 1; done如果memtester跑半小时出现一个随机地址写入失败你很难判断到底是那块内存颗粒体质差、供电纹波大还是DDR时序参数余量不足。我的经验是先把频率降低一档验证硬件无问题再逐步提频每次提频后跑两个小时的测试确认稳定再继续。另外一个比较容易踩坑的点是当你修改了DDR容量或者频率后不但要重新编译u-boot还要确认对应的内核dts里的内存节点是否匹配。如果U-Boot识别出1GB但内核dts里写的是512MB那么内核就只能访问一半内存虽然系统能起来但容量就白白浪费了。RV1126B的dts内存配置通常在kernel/arch/arm/boot/dts/rv1126b*.dtsi文件里root节点下面有一个memory的reg属性memory { reg 0x00000000 0x20000000; /* 512MB */ };3. SDK移植过程中的关键环节3.1 编译环境和工程配置梳理SDK移植不是只改DDR就结束的整个编译链路的打通才是后续所有工作的基础。RV1126B SDK对编译环境要求比较苛刻不建议在Windows虚拟机里编译最好用干净的Ubuntu 18.04或20.04系统。装好必要的依赖包git、repo、python2、python3、gcc、g、make、cmake、libncurses5-dev、file、texinfo等缺什么就装什么最好根据SDK文档里的环境准备说明逐项对照。拉取SDK时注意使用repo工具和固定的manifest分支。我当时用的精简版SDK解压后大约16GB完整版的全量仓库可能超过30GB。所以建议在正式开始之前先确认你的磁盘空间充裕。编译时使用SDK根目录的build.sh脚本# 先选择板级配置 ./build.sh lunch # 然后编译U-Boot、内核、根文件系统 ./build.sh uboot ./build.sh kernel ./build.sh rootfs # 最后打包固件 ./build.sh firmware有一个容易忽略的细节第一次编译U-Boot时DDR bin文件会被一并打包入SPL所以如果你之前改了DDR参数那么一定要编译一次U-Boot并且确保编译日志里没有DDR配置相关的错误或警告。如果编译使用的是预先编译好的DDR bin而不是源码参数那你光改源码也没用必须把新的DDR bin替换到指定目录。3.2 内核DTS与外设适配DDR问题解决后、文件系统起来之前内核的设备树是另一个需要花大量时间的部分。RV1126B的SDK自带的DTS不一定对应你手上的具体板子因为不同方案商的引脚复用和供电配置有差异。你在移植时最需要关注的是串口、网口、SD卡/MMC、USB Host、Sensor的I2C。这些外设只要配置有一处不对系统就可能起不来或者设备无法枚举。这里我举一个我实际改配置的例子。我的板子把调试串口放在了UART2但SDK默认的DTS里配置的是UART0的复用。修改的位置在dtsi文件里uart2 { pinctrl-names default; pinctrl-0 uart2_xfer; status okay; };如果没有这组pinctrl配置内核启动时就不会正确配置引脚的复用功能串口自然没有输出但这个坑往往发生在你已经能看到开机logo之后症状比较隐蔽容易误以为是系统卡死。另外一个经常让人头大的是网络适配器很多板子用的是RMII接口的百兆PHY如果DTS里clock频率没有配置成50MHzRMII外部时钟或者25MHz内部模式网络就会频繁丢包甚至直接不通。3.3 根文件系统与Sensor调试前置条件DDR和内核都起来之后rootfs的适配相对轻松一些但也有一两个容易卡住的点。RV1126B的rootfs方案里buildroot是比较常见的选择它把BusyBox和可选组件打包在一起体积小适合嵌入式场景。我第一次编译buildroot时下载软件包就花了很长时间如果源速度慢建议提前配置好国内镜像源不然网络波动会让整个编译失败。另外编译rootfs时一定不要开太多并行任务经常报错的位置在网络下载环节重试和断点续传的体验不好。需要顺带提一下的是如果你要用这颗NPU跑AI模型SDK里对应的rknn-toolkit版本要提前确认好它和NPU驱动版本是严格对应的。我在移植时曾经把RKNN toolkit的版本弄高了一级NPU在初始化时直接出现权限问题跑模型就报各种奇怪的错误最后花了一个下午才排查清楚是版本不匹配。所以建议你在开始滴AI之前先把rknn-toolkit和驱动固件的版本锁定到同一套SDK release notes里对应的版本。4. USB固件烧写原理与实操4.1 烧写模式与识别机制解决完前面的移植问题接下来就是让板子进入可烧写状态。RV1126B的烧写方式和瑞芯微家族其他芯片一致核心原理就是通过BootROM检测USB下载模式然后由宿主机端的烧写工具通过USB协议把各个分区的镜像写入存储介质。这个模式和全志的烧写、联发科的烧写都不一样不需要额外连接JTAG只靠USB就能完成。具体来说RV1126B芯片内部有一小段BootROM代码上电后它会去探测外部存储介质eMMC、SD卡、SPI NOR如果探测不到合法的启动镜像或者通过特定方式触发就会进入Download模式。你可以通过按住板子上的RECOVERY键或者通过ADB命令reboot loader让U-Boot引导到RockUSB模式这时候USB设备在电脑上会显示为一个VID2207、PID350b的RockUSB设备如果没有显示说明驱动或者硬件有问题。需要注意的是不同板子的按键触发方式不太一样。有的板子是MaskRom按键下载模式有的板子是RECOVERY按键Loader模式这两种模式的区别主要体现在烧写能力和安全性上。Loader模式只能烧写已经签过名或没有签名校验的镜像而MaskRom模式则会强制使用最底层的下载协议可以烧写整个Flash。如果你的板子是全新的没有任何固件那么大概率只能进入MaskRom模式。4.2 驱动安装与开发工具使用烧写工具通常用的就是瑞芯微的Windows版烧写工具DriverAssitant和RKDevTool。如果你在Linux环境下也可以用SDK里带的upgrade_tool命令行工具。但无论哪种方式第一步都是确保USB驱动正确识别。Windows下安装好DriverAssitant之后插入板子在设备管理器里应该能看到一个RockUSB设备。如果你看到的设备一直是未知设备多半是线材问题或者USB接口是3.0兼容性问题。建议优先使用主机背板的USB 2.0口。这里分享一个我在实际烧写时遇到的最典型的坑Windows识别不到设备。当时换了好几个USB口、换了两根线都不行最后发现是板子供电不足导致USB枚举异常。RV1126B在烧写模式下芯片本身不运行主系统但是USB控制器是需要稳定供电的如果你的电源适配器输出电流不够或者电压偏低USB的D和D-信号就会不稳定导致枚举失败。解决方式是换一个质量靠谱的电源并且不要通过USB口给板子供电除非你的设计本来就支持这种模式。4.3 分区理解与打包烧写流程在烧写之前务必理解RV1126B的镜像分区构成。整个固件通常由以下几个部分组成SPL包含DDR初始化代码、U-Boot、boot.img内核和dts、rootfs.img根文件系统、parameter.txt分区表、以及可选的misc用于A/B分区或恢复逻辑。烧写工具默认按parameter.txt定义的偏移地址将各镜像写入eMMC对应的分区。在RKDevTool界面里你会看到一堆分区条目每个条目左边是分区名右边是镜像文件路径下面是偏移地址。每一个镜像都有它固定的烧写地址这些地址必须在parameter.txt和烧写工具里保持一致。如果你自己新加了一个分区但忘了在工具里补全地址它就会默认写到错误的位置轻则分区读不出来重则覆盖掉U-Boot直接变砖。一个我自己总结的安全操作习惯是无论做什么操作先备份原始的固件和分区表。尤其是原始parameter.txt不同厂商的板子flash偏移可能不一样。你用A厂商的parameter去烧B厂商的板子大概率会出问题。我自己前期就因为用了错误的分区表导致eMMC上U-Boot所在区域被覆盖不得不反复进入MaskRom模式重新烧写。烧写流程的大致步骤Windows环境如下安装DriverAssitant驱动确认板子通过双头USB线连接电脑打开RKDevTool如果配置正确左下角会显示“发现一个LOADER设备”导入parameter.txt核对各分区偏移和镜像路径点击“执行”开始烧写观察日志等待绿色成功提示拔掉USB线板子上电串口观察启动日志确认DDR、U-Boot、内核、rootfs都正常加载。4.4 固件烧写失败排查思路烧写失败的情况我遇到过不少总结下来比较常见的有三种一是设备枚举不稳定体现在烧写过程中途报“设备丢失”这基本就是USB线材、供电或者主控USB接口的问题二是某个分区写校验失败可能是镜像本身损坏也可能Flash存在坏块三是烧写时工具卡在低级格式化阶段多见于eMMC寿命或质量有问题。如果你已经成功烧写但板子上电后没有串口输出先别急着下结论。用示波器或者万用表确认DDR供电是否正常看SDK的Debug串口有没有收到数据检查启动选择引脚BOOT strap是否拨到了正确的启动介质上。RV1126B这类的启动选择不只有跳线还有可能被芯片内部的efuse锁死了Boot Order如果efuse配置成从SD卡启动而你烧在eMMC里那上电自然是黑的。这块如果你不熟悉建议优先通过SD卡启动来确认硬件本身没问题天长日久地排查下来一定会有收获。5. 常见问题速查表与避坑清单下面这张表是我在这次RV1126B移植中遇到的典型问题和对应的解决思路整理出来供你参考问题现象主要原因验证/解决方法SPL日志卡在DDR初始化DDR频率/时序/容量配置错误确认颗粒Datasheet核对容量、Row/Col/Bank降低频率尝试串口无输出板子无反应调试串口引脚复用错、电平不匹配换UART口测试确认DTS里pinctrl与板级一致U-Boot正常引导但内核随机死机DDR参数余量不足或供电不稳降低DDR频率跑memtester 8小时以上烧写工具识别不到设备驱动未装、USB枚举不稳、供电不足重装DriverAssitant换USB 2.0口和优质线材烧写后启动介质不对Boot引脚/efuse配置错误确认启动介质选择引脚检查eMMC/SD/SPI文件系统起不来kernel命令行root参数错误或rootfs损坏检查内核bootargs确认root指向实际分区避坑清单里我认为最重要的一条是在改动DDR配置、内核dts或者分区表之前一定要把原始版本备份好。你在默认配置下能跑起来说明整个平台的框架是正常的只是参数和你的具体板卡有出入。备份让你随时可以回退到上一个稳定版本不至于越改越乱、最后连问题出在哪里都找不到了。另外单次只改动一个变量比如这次只改DDR频率下次只改容量不要同时动多个变量。一旦出问题你就能立刻知道是哪个改动引起的否则你会陷入“明明改了很多还是不知道是哪一步导致问题”的泥潭里。还有一条很实用的经验是不要完全照搬RV1126的DDR配置到RV1126B上。虽然两者是兼容家族但DDR控制器内部的寄存器默认值、PHY的训练算法都有差异。你看着RV1126社区的帖子改RV1126B很可能方案就是错位互补浪费一整天排查。另外在SDK版本上尽量用和你的板卡配套的SDK release版本。如果方案商给你的是定制SDK请优先用它而不是自己去GitHub上拉一份“最新”的主线代码。很多方案商在瑞芯微官方SDK之上做了大量的裁剪和适配包括DDR配置、外设默认配置、Sensor接线等这些定制改动的价值比“最新版本”大得多。你要是手贱拉了一份新版SDK很可能出现各种奇奇怪怪的不兼容问题。最后关于USB烧写我想补充一个对新手朋友特别友好的做法遇到识别不出来的情况先把USB Host端的驱动卸载干净重启系统后再装一次。Windows的USB驱动有时候会有残留导致新设备无法正确加载驱动这个问题在公版驱动的设备上尤其常见。卸载的时候顺便把隐藏设备也清除一下然后再重新插板子往往就识别出来了。6. 几个比较隐蔽的细节踩过之后才明白细节一DDR电压的硬件确认。RV1126B的DDR3和DDR3L对供电电压要求不同DDR3L的额定电压是1.35V而普通DDR3是1.5V。如果你板子上用的DDR3L颗粒但供电模块输出的还是1.5V短期内可能没有问题长期运行就很容易出现随机位翻转、内存校验错误。第一次遇到这类问题时我花了一个上午查代码查日志最后用万用表量了一下DDR供电才发现电压不对。这个问题如果在硬件设计阶段发现的越早维护成本就越低。细节二串口工具的参数设置。RV1126B的调试串口大多数情况下是115200 8N1但也有SDK分支改成了1500000波特率的尤其是部分新版本bootloader提高了串口速度来加快日志输出。如果你看到乱码或者没有任何输出可以试试把波特率调到1500000再看看。这个信息在SDK里通常会有文档说明但往往容易被忽略。细节三eMMC烧写时间。烧写rootfs这种大分区时eMMC的写速度通常在20-40MB/s左右1GB的rootfs大约耗时半分钟到一分钟这属于正常范围。如果烧写速度慢得出奇比如只有几百KB/s检查一下工具设置里是否勾选了“校验”选项全量校验会大大拉长时间但换来的是稳定性首次烧写建议还是保持校验打开。细节四如果你用的是SDK里的upgrade_toolLinux命令行烧写工具它的参数和Windows工具不一致很多新手朋友在这里会卡一下。一个常见的操作方式是先在PC端进入loader模式再执行sudo upgrade_tool LD看看设备是否被识别。如果返回设备列表为空就是上电时序或者USB枚举的问题。细节五内核启动参数里的mem大小。有的SDK默认的bootargs把内存固定成512MB如果你的DDR识别为1GB这个固定参数会限制你用满内存。务必检查内核cmdline里是否有类似mem512M这样的参数有的话再后续调试中确认到底是谁加进去的是U-Boot传参、还是dtb里面定义、还是bootargs写死了。写在最后的一点心得整套RV1126B的移植跑通之后再回头看DDR那一段其实最折磨人不只技术上棘手更多是因为你根本不知道问题出在哪一环。U-Boot日志没有报错、DDR bin也是配好的、工具链也没问题可板子就是起不来。这种时候稳住心态特别重要按“硬件供电-时钟-复位-DDR参数-启动介质”这个顺序一项一项排除哪怕慢也不会走偏。我个人实际体验下来的核心心得就是“版本锁定参数核对”这两点做到位RV1126B的开发其实并没有想象中那么困难。SDK里很多默认配置依赖特定硬件环境而你的板子跟参考设计总有差异。与其大面积推翻重来不如精准定位差异、小步迭代每次只改一个变量做好记录。另外烧写工具和驱动能帮我们解决大部分问题但底层原理——比如怎么进入Loader模式、分区表怎么对齐、DDR时序怎么计算——这些知识才是最持久的生产力还是要花时间彻底搞明白。