最近在调RV1126B的SDK移植,从DDR配置一路折腾到USB调试,整个过程踩了不少坑,也把整个启动链路从底层到应用层摸了一遍。这篇文章就围绕这次移植实战展开,把DDR参数怎么定、SDK怎么改、USB调试口怎么从零配出来这些关键环节拆开讲清楚,适合正在搞瑞芯微平台、或者刚拿到新板子准备做系统移植的嵌入式开发朋友参考。
RV1126B这颗芯片主打IPC和AI视觉方向,双核A7加上RISC-V协处理器,拿来做摄像头、门锁、边缘盒子之类的产品很常见。SDK移植本身并不只是把代码拉下来编译一把就能跑,真正的难点在于适配板子的硬件差异,尤其是DDR初始化、设备树裁剪、外设驱动加载这几个环节。下面从整体思路上开始拆解。
1. 移植前需要想清楚的事:SDK选择与整体启动链路
1.1 RV1126B SDK里到底装了什么
瑞芯微的SDK是一个包含完整系统方案的代码仓库,拿RV1126B来说,核心目录大致有U-Boot、Kernel、Buildroot、external、rkbin、tools这几块。U-Boot负责引导,Kernel负责驱动和系统调用,Buildroot负责用户态根文件系统,external里面是瑞芯微自己的多媒体和ISP相关库,rkbin存放着DDR初始化二进制和ATF固件,tools里是烧录、打包、调试用的PC端工具。
第一次拿到SDK的人很容易被这些目录搞晕,但其实理解每个模块的作用之后,整个移植路径就清晰了:先让DDR和时钟初始化跑通,U-Boot能起来,再去调内核和设备树,最后才是文件系统和外设功能。很多人移植失败,往往是因为没弄明白“现在卡在哪一层”,一上来就改内核,结果板子连DDR都没过去。
1.2 一次完整移植要过哪几关
从板上电到系统能登录,实际要经过ROM代码、DDR初始化、U-Boot、内核、根文件系统这几个阶段。ROM代码是芯片出厂固化好的,我们不用动;DDR初始化由rkbin里的DDR bin完成;U-Boot负责加载内核和设备树;内核启动后再挂载根文件系统。
对应到SDK移植上,大致就是四件事:适配DDR参数、修改板级配置和设备树、裁剪内核驱动、制作根文件系统。这次移植的核心堵点就集中在两个地方——DDR初始化和USB调试,前者决定板子能不能从“死机”变成“活着”,后者决定你后续调试效率能有多高。所以我把这两个部分单独展开讲。
2. DDR配置实操:内存颗粒决定你起不起得来
2.1 DDR3 1GB方案怎么选颗粒
现在很多RV1126B的产品为了控成本,走的都是DDR3 1GB方案。市面上的DDR3颗粒型号五花八门,但选择时主要看几个硬指标:单片容量、位宽、速度等级、温度等级。RV1126B的DDR控制器支持16bit和32bit总线配置,常见的1GB方案有两条路线,一是用2颗512MB×16bit的颗粒组成32bit总线,另一条是用4颗256MB×16bit的颗粒组成32bit总线,具体取决于原理图怎么布线。
挑选颗粒时有一点特别容易被忽略——同容量同封装的颗粒,时序参数很可能不一样。比如有的颗粒标称DDR3-1600,但CL、tRCD、tRP这些参数由厂家的speed grade决定,直接拿去用默认配置不一定会死机,但稳定性就没法保证。稳妥的做法是在PCB定版之前,先到芯片原厂或瑞芯微官方支持的DDR列表里核对一下颗粒型号,选已经被验证过的方案,能省掉大量调试时间。
2.2 DDR参数从哪里来:频率、时序与容量计算
DDR配置核心是三件事:频率、时序、容量。频率方面,RV1126B的DDR控制器一般跑在DDR3-1066或DDR3-1600,对应的时钟频率是533MHz和800MHz,具体跑多高取决于颗粒速度等级和PCB走线质量,不必盲目追求高频,稳定优先。
时序参数需要从DDR颗粒的datasheet里查,关键项包括CL(CAS Latency)、tRCD、tRP、tRFC、tRC等,这些数值决定了内存控制器访问颗粒的节奏。SDK里通常有一份DDR配置头文件或dts中的频率表,移植时先把颗粒手册里的时序填进去,再通过DDR压力测试验证,不要想当然沿用其他型号的参数。
容量识别则是由行列bank和位宽共同决定的,比如一颗256MB×16bit的颗粒,内部组织结构大概是Row=15、Col=10、Bank=8,总线位宽配置成32bit时,4颗颗粒组合出1GB空间。如果容量算错,系统起来后要么只识别到一半内存,要么直接崩溃。瑞芯微的U-Boot在DDR初始化时会打印一行类似下面这样的日志:
DDR Version 1.09 20210425 In DDR3 Bus Width=32 Col=10 Bank=8 Row=15 CS=1 Die BW=16 Size=1024MB看到Size=1024MB且和硬件实际容量一致,说明DDR容量识别正常,如果显示512MB或256MB,就要回头检查行列配置和片选信号。
2.3 把DDR配置写进SDK的完整步骤
在瑞芯微SDK里,DDR初始化代码并不需要自己写,SDK的rkbin目录里已经编译好了二进制,我们只需要告诉U-Boot“这块板子用的是哪组DDR参数”。实际操作分几步:
- 在U-Boot的board目录下新建或复制一块板级配置,参考同系列EVB板;
- 在DDR配置头文件里找到颗粒参数表格,把本板颗粒的时序、容量、位宽填进去;
- 确认dts中的内存节点内存大小与实际容量一致;
- 重新编译U-Boot,用烧录工具把新U-Boot烧进去;
- 观察串口输出的DDR初始化日志,确认频率、容量、总线位宽无误;
- 进入系统后跑DDR压力测试,验证长时间稳定性。
第4步编译的时候要注意,瑞芯微的U-Boot编译命令通常是./make.sh rv1126b,编译产物是uboot.img,烧录时要连同idblock一起烧。只更新uboot.img而没更新idblock,可能会导致DDR初始化还是旧参数,这是新手很容易踩的坑。
2.4 DDR问题排查:起不来、报错、压力测试不通过
DDR初始化失败的现象通常有三类。第一类是板子完全没反应,串口没有任何输出,这种情况大概率是DDR颗粒没有被正确初始化,可能原因是rkbin里缺少该颗粒的配置,或者PCB走线问题导致颗粒没被识别。第二类是U-Boot能起来,但系统内存容量不对,或者随机死机,这种多半是行列地址配置错误、片选信号问题、以及CS1颗粒未正确配置。第三类是DDR压力测试跑不过,表现为高负载下重启或报ECC错误,这通常是时序太紧或者电源纹波偏大。
可以整理成一张排查表:
| 现象 | 可能原因 | 排查手段 |
|---|---|---|
| 完全没有串口输出 | rkbin配置缺失、DDR颗粒未被识别 | 检查颗粒型号是否在支持列表;用示波器看DDR时钟 |
| U-Boot起来但内存容量不对 | 行列地址、片选、总线位宽配置错误 | 核对dts与U-Boot DDR配置;检查CS引脚连接 |
| 运行时随机死机/重启 | 时序参数过紧、供电不足、走线质量差 | 降频测试;核对颗粒手册时序;用稳压电源观察纹波 |
| 高负载崩溃或报ECC错误 | tRFC/tRC等参数异常、散热不够 | 适当放宽时序参数;加强散热;换颗粒验证 |
我自己这次遇到的坑是DDR容量显示只有512MB,排查到最后发现是原理图上CS1的地址线被接到了NC,但软件里没有关掉第二个片选,导致初始化时多访问了不存在的颗粒,把CS配置改掉后问题消失。所以DDR配置出问题时,不要只盯着软件参数,先对着原理图确认硬件连接,再看软件的配置是否和硬件一致。
3. 内核、设备树与sensor移植
3.1 设备树裁剪:不是谁的板子都能直接跑
DDR起来之后,接下来就是内核启动。RV1126B的SDK默认支持自家的EVB板,如果你的板子跟EVB不完全一样,设备树必须改,否则很可能出现串口没输出、网口不通、USB不识别等各种“看起来正常但就是不对”的问题。
设备树里需要重点关注的节点有:内存节点(memory)、调试串口(uart)、以太网(gmac)、USB PHY、SD/MMC控制器、I2C外设、sensor节点和相关的pinctrl。比如串口调试口,如果原理图上用的是UART2,设备树里就要确认uart2节点状态为okay,同时引脚复用要选对,否则串口只会出乱码。
有个经验值很值得分享:拿到一块新板子,先把SDK自带的EVB设备树复制一份,然后对照原理图把差异点逐项修改,每改完一项就编译烧录验证一次。不要一次性改几十个节点,不然出问题根本定位不到是哪里引起的。改设备树用的是dts/dtsi文件,编译是在内核目录下make dtbs,然后用烧录工具把resource.img或boot.img烧进去,具体看SDK分区设计。
3.2 sensor移植:RV1126B的核心应用场景
RV1126B天生就是做视觉产品的,sensor驱动移植是绕不开的环节。这次项目里用的是OV5640,一颗很常见的500万像素sensor,但也有用SC3336、GC2053的方案,移植思路基本一致。
sensor移植分三块:设备树配置、内核驱动、ISP tuning文件。设备树里需要配置sensor的I2C地址、MCLK时钟频率、reset和pwdn引脚、以及MIPI CSI的lane数量和频率。比如OV5640的I2C地址一般是0x36或0x3c,MCLK常用24MHz,具体要以sensor手册和原理图为准。内核驱动方面,SDK默认带了一批sensor驱动,只要在内核配置里启用对应的CONFIG即可,比如CONFIG_VIDEO_OV5640。ISP tuning文件则是瑞芯微rkaiq体系下的XML参数,决定了成片效果,通常放在SDK的external/aiq或类似路径下,产品化阶段需要对着实际效果反复调。
调试时最实用的命令是i2cdetect和v4l2-ctl。先用i2cdetect -y -r 总线号确认sensor在I2C总线上能探测到地址,再查看/dev/video*节点是否正确生成,最后用v4l2-ctl --list-devices确认ISP链路注册情况。如果i2cdetect检测不到地址,先检查sensor供电、reset引脚电平和MCLK有没有波形,这类硬件问题的比例其实很高。
3.3 串口日志与启动异常排查
系统起不来的问题,大部分靠串口日志就能定位。RV1126B的调试串口一般是UART2,波特率很特殊,是1500000,也就是1.5M波特率,电脑端用minicom或MobaXterm配置时要选对,否则看到的全是乱码。还有一个小技巧,用TTL转USB模块调试时,供电要干净,最好用带隔离的模块,否则板子功耗一大,串口工具容易自己复位。
如果串口卡在U-Boot阶段,通常是DDR或存储介质初始化没过;如果过了U-Boot但内核没起来,看看是死在dtb解析、驱动probe还是控制台还没有注册;如果内核起来了但进不了系统,多半是根文件系统或者分区表问题。把启动分成这几个阶段来排查,效率会高很多。为了调试方便,我习惯在文件系统没调好之前先用initramfs启动内核,或者通过NFS挂载根文件系统,这样改文件系统内容不需要反复烧写Flash。
4. USB调试全解析:从host到device
4.1 硬件先看明白:板子上的USB口长什么样
RV1126B的USB调试,说到底就是让芯片的USB OTG口在device模式下工作,让PC端能够枚举到板子。常见的板子会设计一个Micro USB或者Type-C口专用于调试,也可能是USB OTG口复用,具体看原理图。调试前先把硬件看明白,确认这个口是不是真的连到了支持OTG的USB控制器上,VBUS检测、ID检测是怎么处理的,如果硬件上没有把ID脚拉对,后面软件怎么配都白搭。
另一个硬件细节是USB PHY的供电和参考时钟。RV1126B的USB PHY一般有独立的供电引脚,还要一个24MHz晶振提供参考时钟,如果时钟不对,USB就会出现时好时坏、枚举不稳定这类封闭问题。用示波器测量DP/DM信号和PHY供电波形是比较直接的验证手段。
4.2 加载USB gadget驱动:RNDIS和ADB是怎么配出来的
Linux下USB device模式的标准做法是透过configfs配置gadget。先用这个方式把RNDIS网卡配出来,操作流程大致是:
# 挂载configfs mount -t configfs none /sys/kernel/config # 创建gadget目录 mkdir /sys/kernel/config/usb_gadget/rk1126 cd /sys/kernel/config/usb_gadget/rk1126 # 设置VID/PID,0x2207是瑞芯微常用的VID echo 0x2207 > idVendor echo 0x0010 > idProduct # 添加字符串描述 mkdir strings/0x409 echo "rockchip" > strings/0x409/manufacturer echo "rv1126b" > strings/0x409/product # 创建配置 mkdir configs/c.1 # 创建RNDIS function mkdir functions/rndis.usb0 ln -s functions/rndis.usb0 configs/c.1/ # 绑定UDC控制器,具体名称以/sys/class/udc下为准 echo ci_hdrc.0 > UDC执行完上面的命令,PC端应该能枚举出一个RNDIS网卡,给板子配一个静态IP,比如192.168.1.10,PC端设192.168.1.2,两边就能ping通,这样就算有了一个“USB有线网络”,后续SSH、传输文件都方便了。如果还需要ADB调试,SDK的Buildroot默认可以开启adbd服务,但需要确保内核开启了对应的USB gadget功能,并且/system分区或者根文件系统里有adbd可执行文件和相关的dev节点权限。
有一件事必须提醒:上面这些操作每次重启后都会丢失。产品化的时候要把配置gadget的过程写成开机自启脚本,放在/etc/init.d或者使用systemd服务来管理,这样才能做到开机自动进入device模式,不用每次手动敲命令。
4.3 USB枚举问题速查:为什么插上没反应
USB调试不成功,现象千奇百怪,核心原因却往往很集中。下面这张表是我这次和以前项目里积累的排查经验:
| 现象 | 可能原因 | 排查手段 |
|---|---|---|
| PC完全没有枚举反应 | 硬件供电/DP/DM接反/USB线是充电线 | 换线,用示波器量DP/DM;检查USB PHY供电 |
| 枚举成功后反复断开 | VBUS检测信号不稳、驱动电流不足、接触不良 | 检查VBUS脚和ID脚;改用短而粗的USB线 |
| 识别为Unknown Device | 描述符读取失败、VID/PID冲突、USB PHY时钟异常 | 看dmesg报错;重新配置gadget描述符;检查晶振 |
| RNDIS网卡不出现 | 内核没有打开RNDIS功能、Windows缺少驱动 | 检查内核配置;在设备管理器里手动更新驱动 |
| 传输大文件时断连 | 供电不足、信号质量差、地弹影响 | 加强供电,缩短线材长度,检查GND连接 |
最常用的排查命令就是dmesg和lsusb。板子端执行dmesg | grep usb看重定向和错误,PC端插拔瞬间看lsusb输出。如果PC端完全没反应,优先怀疑硬件,不要一上来就改软件;如果在不同的PC上表现不同,那多半是gadget描述符问题或者USB线材的兼容性问题。
4.4 提升USB调试效率的小技巧
等RNDIS或者ADB跑通之后,USB调试口的作用就不只是“能连上”了,而是要让整个开发流程更顺。我习惯在板子起来后自动给RNDIS网卡配置好固定IP,这样每次开机直接SSH进去,不用每次重新找IP、配网络。ADB的话,也可以通过网络adb connect指定板子的IP来连接,省去插拔USB线的麻烦。
还有一个比较实用的技巧是,保留一个串口调试口的同时,把USB gadget做成多功能组合:一个RNDIS网卡加一个ACM串口再加一个UVC摄像头。这样PC端既能通过网络访问板子,又能通过虚拟串口看系统日志,还能直接预览sensor图像,调试体验会好很多。瑞芯微的SDK里面其实已经有这套组合的参考实现,搬过来改改VID、PID和脚本路径就能用。
5. 几个实测中容易踩的坑
这次RV1126B移植下来,有几个坑是反复出现的,专门列出来说一下。
5.1 SDK版本和烧录工具必须配套
瑞芯微的SDK会不断更新,烧录工具、U-Boot、内核可能都会跟着变。如果SDK是从旧版本升级上来的,编译工具链最好也一起升级,否则可能出现编译通过但运行崩溃的问题。我这次就碰到过一次,SDK更新后旧的RKDevTool不识别新固件的打包格式,烧录总是卡在下载阶段,后来换成新版工具才解决。
5.2 先让系统跑起来,再调外设
很多新手拿到板子喜欢上来就把所有外设节点全部配好,结果系统起不来,很难排查。正确做法是先用最简配置把系统跑起来,串口能登录、USB能调试,然后再逐个打开功能模块。这样每次只增加一个变量,出了问题很容易定位。
5.3 DDR参数不能只看容量
DDR参数里频率和时序才是稳定性的关键,容量只是冰山一角。有些颗粒虽然容量和位宽匹配,但tRFC差异很大,在DDR3-1600下长时间跑压力测试很容易报错,这时调低频率或者放宽时序往往能快速验证是不是时序问题。DDR这块没有捷径,数据手册一定要看,每一行参数都要有出处。
5.4 USB调试的硬件基础要先确认
最后再说一次,USB调试不成功的时候先怀疑硬件,换USB线、换电脑、量DP/DM波形、检查PHY供电,这些物理层面的排查往往比自己调半天内核配置更有效。我这次卡了两天的USB枚举问题,最后发现是USB线是那种只能充电的线,换了一根数据线直接就好。
这次移植从DDR配置到USB调试全跑通,最大的体会是:SDK移植表面上看是代码的事,实际上是硬件和软件交叉验证的过程,每一层都有它自己的“通关条件”。先把DDR这关过了,系统才算活着;再把USB调试配好,后面的开发效率才能上去。希望这篇能把你们要走的路提前铺平一点,少踩几个我踩过的坑。