1. 项目概述为什么是RV1106最近在嵌入式视觉项目里RV1106这颗芯片的出镜率越来越高。如果你正在寻找一款能跑轻量级AI算法、支持高清编码、同时功耗和成本都控制得不错的SoC它大概率会进入你的候选名单。我手头几个安防和物联网的项目从门禁考勤机到智能猫眼都陆续用上了它。和之前常用的海思或全志方案相比RV1106在“性价比”和“开发生态”之间找到了一个不错的平衡点。简单来说RV1106是瑞芯微面向视觉物联网市场推出的一款芯片。它的核心是一个Cortex-A7处理器搭配一个独立的MCU这种“大小核”架构在低功耗场景下很实用——A7负责跑Linux系统和复杂的应用逻辑MCU则在系统休眠时处理简单的传感器唤醒和事件监听。最吸引人的是它集成了0.5TOPS算力的NPU虽然比不上那些动辄几T的大家伙但对于人脸检测、车牌识别、行为分析这类经典CV任务完全够用而且功耗和成本优势明显。再加上它原生支持H.264/H.265的5M30fps编码以及瑞芯微一直不错的ISP图像信号处理器让它成为了智能摄像头、可视门铃、执法记录仪等产品的热门选择。这篇文章我会结合自己从零搭建RV1106开发环境的实际经历把SDK获取、系统编译、烧录调试、驱动开发到应用部署的全流程拆解清楚。过程中踩过的坑、验证过的技巧都会毫无保留地分享出来。无论你是刚接触瑞芯微平台的新手还是从其他平台迁移过来的老鸟希望这些经验能帮你少走弯路。2. 开发环境搭建与SDK深度解析上手RV1106第一步就是把“武器库”准备好。这里的环境搭建不仅仅是装个编译器那么简单涉及到官方SDK的获取、编译工具链的配置、以及整个源码目录结构的理解。弄明白了这些后面的开发才能事半功倍。2.1 官方资源获取与初识SDK瑞芯微的开发者资源主要在其官方的Wiki平台和Git仓库。对于RV1106你需要关注的是RKNPU、RKISP以及RV1106 Linux SDK这几个部分。1. SDK获取途径通常你需要联系瑞芯微的销售或技术支持签署相关协议后才能获得完整的、带BSP板级支持包的Linux SDK。这个SDK包体积不小可能有好几十个G里面包含了U-Boot、Kernel、Buildroot/Yocto根文件系统、预编译的工具链、以及各种中间件和示例代码。对于个人学习或评估也可以先从其GitHub上的开源仓库入手例如rockchip-linux仓库里有一些核心的驱动和配置但完整的、能直接编译出可烧录镜像的SDK还是需要官方提供。2. SDK目录结构扫盲拿到SDK后别急着编译先花半小时浏览一下目录结构。一个典型的RV1106 SDK目录可能长这样sdk/ ├── app/ # 上层应用示例如摄像头预览、编码测试 ├── buildroot/ # Buildroot构建系统用于制作根文件系统 ├── device/rockchip/rv1106/ # 设备树文件板级硬件配置的核心 ├── docs/ # 开发文档非常重要但常被忽略 ├── external/ # 第三方库如rkmedia, mpp ├── kernel/ # Linux内核源码 ├── prebuilts/ # 预编译的工具链、库文件 ├── rkbin/ # Rockchip二进制工具和固件如DDR初始化、Miniloader ├── tools/ # 各种开发工具如烧录工具rkdeveloptool └── u-boot/ # Bootloader源码重点要关注device/下的板级配置和docs/下的文档。docs/里通常有《编译指南》、《烧录指南》和《硬件设计指南》是避坑的第一手资料。2.2 编译工具链与依赖安装RV1106的A7核心是armv7-a架构你需要对应的交叉编译工具链。SDK的prebuilts/gcc/目录下通常已经提供了。如果没有可以安装Linaro或Arm官方的arm-linux-gnueabihf-工具链。在Ubuntu 20.04/22.04 LTS系统上基础的依赖安装命令如下sudo apt-get update sudo apt-get install -y git-core gnupg flex bison gperf build-essential \ zip curl zlib1g-dev gcc-multilib g-multilib libc6-dev-i386 \ libncurses5-dev lib32ncurses5-dev x11proto-core-dev libx11-dev \ lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip \ device-tree-compiler libssl-dev bc这里有个关键点务必使用64位的主机系统。因为编译过程中尤其是构建Buildroot根文件系统时有些步骤需要处理大量的32位和64位库的兼容性问题在纯32位系统或某些旧版本系统上会非常棘手。实操心得Python版本管理瑞芯微的很多编译脚本是用Python 2.7或Python 3写的。现在Ubuntu 22.04默认是Python 3但有些旧脚本可能仍需要Python 2。建议使用update-alternatives来管理全局的python命令指向或者更推荐的是在编译时显式地指定解释器例如在调用./build.sh时查看其首行是否是#!/usr/bin/env python并根据需要修改。我个人的习惯是在系统里同时安装python2和python3并通过虚拟环境venv来为不同的SDK版本隔离Python环境避免污染系统。2.3 源码编译全流程实操RV1106 SDK通常使用一个顶层的build.sh脚本来控制编译。但理解其背后的分步过程对于调试至关重要。1. 编译U-BootU-Boot是硬件上电后运行的第一段主要代码负责初始化DDR、加载并验证下一阶段镜像。cd /path/to/sdk ./build.sh uboot这个过程会使用rkbin目录下的预编译二进制文件如DDR初始化代码rkbin/bin/rv11/rv1106_ddr_xxx.bin和U-Boot的源码最终生成uboot.img和trust.imgATFARM Trusted Firmware。编译前务必确认device/rockchip/rv1106/下选择的板级配置文件例如rv1106-evb.config与你手上的开发板匹配。2. 编译KernelLinux内核的配置和编译。./build.sh kernel # 或者进入kernel目录进行手动配置 cd kernel make ARCHarm rv1106_defconfig # 加载默认配置 make ARCHarm menuconfig # 图形化界面调整配置可选 make ARCHarm rv1106-evb.img -j$(nproc) # 编译并打包成内核镜像内核配置是性能优化的关键。对于RV1106你需要重点关注NPU驱动CONFIG_ROCKCHIP_RKNPU这是AI算力的基础。ISP驱动CONFIG_VIDEO_ROCKCHIP_ISP图像处理管线。视频编解码CONFIG_ROCKCHIP_MPP_VCODEC多媒体处理平台。具体的Sensor驱动如CONFIG_VIDEO_OVXXXX。3. 编译Rootfs使用Buildroot构建一个轻量级的根文件系统。./build.sh rootfs这一步会在output/rockchip_rv1106/目录下生成rootfs.ext4镜像。Buildroot的配置board/rockchip/rv1106/下的defconfig决定了根文件系统里包含哪些软件包。你可以在这里添加你需要的库如OpenCV、Python3、MQTT客户端等。4. 打包统一固件将前面编译出的所有镜像打包成一个方便烧录的update.img。./build.sh updateimg这个update.img包含了Loader、Parameter、Uboot、Kernel、Rootfs等所有分区镜像可以通过瑞芯微的升级工具如upgrade_tool一次性烧录。注意首次编译可能会非常耗时取决于主机性能可能长达数小时主要是Buildroot需要从网络下载并编译大量的软件包。建议保持网络通畅并可以使用dl目录缓存下载的包供后续编译复用。3. 系统烧录与硬件调试实战镜像编译出来只是第一步把它正确地“灌进”开发板并跑起来才是真正考验的开始。RV1106支持多种启动和烧录模式最常用的是Loader模式和MaskRom模式。3.1 两种关键烧录模式详解1. Loader模式正常升级模式这是最常用的模式。开发板正常启动进入U-Boot或系统后通过命令让芯片进入一个等待接收固件的状态。此时芯片内部的BootROM已经加载了第一级Loader通常是MiniLoaderAll.bin这个Loader会初始化USB或串口等待主机发送固件。进入方式在U-Boot命令行下执行rockusb 0 mmc 0命令或者在某些系统中通过upgrade_tool工具发送切换命令。优点无需拆机短接方便快捷适合日常开发和迭代。缺点需要系统能正常启动到U-Boot或能运行切换命令的环境。如果BootLoader损坏此模式将失效。2. MaskRom模式救砖模式这是芯片的终极恢复模式。当Flash为空、或Loader严重损坏时芯片上电后会直接运行固化在芯片内部ROM中的一小段代码。这段代码会检测特定引脚通常是eMMC的DATA0引脚是否被拉低如果被拉低则进入MaskRom模式并通过USB等待烧录。进入方式断开电源用镊子短接开发板上eMMC芯片的DATA0引脚与地GND然后上电保持短接约1-2秒后松开。具体短接点需要查阅开发板原理图。优点只要芯片物理没坏一定能进入是“救砖”的最后手段。缺点需要物理操作有一定风险。3.2 使用upgrade_tool进行烧录瑞芯微官方提供的upgrade_toolLinux版本或RKDevToolWindows版本是标准的烧录工具。这里以Linux下的命令行工具为例它更利于自动化脚本集成。1. 连接与识别让开发板进入Loader或MaskRom模式并通过USB线连接到主机。执行lsusb命令应该能看到一个ID为2207:350a或其他以2207开头的的Rockchip USB设备。sudo upgrade_tool ld如果连接成功这个命令会列出当前连接的设备。2. 烧录统一固件推荐这是最简单的方式直接烧录打包好的update.img。sudo upgrade_tool uf /path/to/update.img工具会自动解析update.img中的分区表parameter文件并将各个部分写入对应的Flash分区。3. 分步烧录用于调试有时我们需要单独更新某个分区比如只更新内核。首先查看分区表sudo upgrade_tool pl这会显示Flash中的分区布局例如0x00002000:0x00008000 uboot。然后烧录指定分区sudo upgrade_tool di -p parameter.txt # 烧录分区表谨慎 sudo upgrade_tool di uboot uboot.img sudo upgrade_tool di kernel kernel.img sudo upgrade_tool di rootfs rootfs.ext44. 擦除Flash在更换系统或遇到奇怪问题时可以尝试擦除整个FlashMaskRom模式下。sudo upgrade_tool ef /path/to/update.img # 擦除后写入 # 或单独擦除 sudo upgrade_tool el重要提示烧录parameter分区表和uboot是高风险操作一旦出错可能导致板子无法启动。务必在操作前确认镜像文件是正确的并且板子有进入MaskRom模式进行恢复的能力。3.3 串口调试与系统启动日志分析串口是嵌入式开发的“眼睛”。RV1106开发板通常会引出一个UART调试串口通常是UART2。1. 硬件连接你需要一个USB转TTL串口模块。连接时注意开发板TX-串口模块RX开发板RX-串口模块TX开发板GND-串口模块GND千万不要接VCC开发板需要独立供电。2. 软件配置在PC上使用minicom、picocom或screen等工具。常用配置为波特率1500000瑞芯微平台常用尤其是BootLoader阶段数据位8停止位1无校验。sudo picocom -b 1500000 /dev/ttyUSB0上电后你应该能在串口终端看到类似以下的启动日志U-Boot 2017.09 ... DRAM: 128 MiB ... Hit any key to stop autoboot: 3在U-Boot的倒计时阶段按任意键可以进入U-Boot命令行进行手动引导、设置环境变量等操作。3. 启动问题排查如果系统卡住串口日志是唯一的线索。卡在“Starting kernel ...”通常是内核镜像kernel.img损坏或者设备树dtb与硬件不匹配。检查编译出的内核镜像大小是否合理并确认U-Boot传递给内核的设备树地址和文件名是否正确。卡在“Kernel panic ...”内核崩溃。最常见的原因是根文件系统挂载失败。检查root内核启动参数是否正确指向了存放根文件系统的设备如root/dev/mmcblk0p5以及rootfs.ext4镜像是否完整。无法进入Loader模式检查USB线、驱动尝试不同的USB口。在Linux下可能需要sudo权限或配置udev规则。4. 外设驱动开发与配置要点系统跑起来后下一步就是让板子上的各种硬件“活”起来。RV1106的硬件功能大多通过Linux内核驱动来管理而配置的核心在于设备树Device Tree。4.1 设备树DTS配置精髓设备树是一种描述硬件拓扑和资源的数据结构替代了旧内核中大量的板级硬编码。对于RV1106设备树源文件.dts和.dtsi通常位于kernel/arch/arm/boot/dts/目录下。1. 核心文件结构rv1106.dtsi芯片级的通用定义包含CPU、内存、内部外设如GPIO控制器、时钟、Pinctrl的节点。一般不需要修改。rv1106-xxx.dtsi基于芯片的板级通用定义比如共用某款PMIC电源管理芯片的配置。rv1106-xxx-evb-v10.dts你的主战场。这是针对特定评估板EVB的最终设备树文件它通过#include引用了上面的.dtsi文件并覆盖或添加具体的硬件配置如LED、按键、摄像头接口、屏幕接口等。2. 关键配置示例假设我们要启用一个连接到I2C1总线、地址为0x3c的OLED屏幕。// 在 rv1106-evb.dts 的 i2c1 节点中添加 i2c1 { status okay; // 启用I2C1控制器 clock-frequency 400000; // 设置I2C时钟频率为400kHz oled_display: oled3c { // 定义设备节点标签为 oled_display compatible solomon,ssd1306; // 驱动匹配的关键字 reg 0x3c; // I2C设备地址 reset-gpios gpio2 RK_PC1 GPIO_ACTIVE_LOW; // 复位引脚使用GPIO2_C1低电平有效 vbat-supply vcc_3v3; // 电源引用 status okay; }; };compatible属性是灵魂它告诉内核用哪个驱动来匹配这个设备。这里的值必须和驱动代码里of_device_id表里的字符串一致。reg是设备在总线上的地址。reset-gpios使用了GPIO的Phandle格式。gpio2指向GPIO控制器RK_PC1是瑞芯微定义的一个宏表示GPIO2组的C1引脚具体换算需要查数据手册。vbat-supply引用了系统中定义的稳压器节点实现电源管理。3. Pinctrl引脚复用配置RV1106的引脚功能高度复用一个物理引脚可能是GPIO、UART的TX、I2C的SDA等等。这需要通过Pinctrl子系统在设备树中配置。pinctrl { // 定义一组引脚配置命名为 i2c1_xfer i2c1 { i2c1_xfer: i2c1-xfer { rockchip,pins 2 RK_PB5 1 pcfg_pull_none, // SDA, 复用功能1无上下拉 2 RK_PB6 1 pcfg_pull_none; // SCL }; }; // 定义OLED复位引脚为GPIO功能默认输出高电平 oled { oled_reset: oled-reset { rockchip,pins 2 RK_PC1 RK_FUNC_GPIO pcfg_output_high; }; }; }; // 然后在I2C1节点中引用这个pinctrl配置 i2c1 { pinctrl-names default; pinctrl-0 i2c1_xfer; ... };避坑指南GPIO编号的混乱。在设备树、驱动代码和用户空间/sys/class/gpio中GPIO的编号方式可能不同。设备树里用的是“组内序号”而Linux系统全局的GPIO编号是计算出来的。最可靠的方法是使用内核提供的gpio_get_desc()等API或者直接使用驱动中定义好的GPIO资源。在用户空间可以通过cat /sys/kernel/debug/gpio来查看当前所有GPIO的状态和全局编号。4.2 摄像头与ISP图像通路搭建RV1106的视觉能力离不开其ISP。连接一个摄像头并让系统识别需要驱动和设备树协同工作。1. 硬件连接与时钟常见的MIPI CSI摄像头需要连接正确的数据线和时钟线。在设备树中你需要配置csi2_dphy节点和具体的sensor节点。// 启用MIPI CSI DPHY硬件 csi2_dphy_hw { status okay; }; // 配置MIPI CSI DPHY通道 csi2_dphy0 { status okay; ports { port0 { csi_dphy_input: endpoint { remote-endpoint ov5647_out; // 与sensor的输出端点连接 ># 安装工具 sudo apt install v4l-utils # 查看拓扑 media-ctl -p -d /dev/media0 # 设置链路例如将sensor连接到ISP的输入 media-ctl -l ov5647 2-0036:0 - rockchip-mipi-csi2:0[1]在应用层通过标准的V4L2 APIioctl调用就可以打开设备如/dev/video0设置格式分辨率、像素格式如NV12并获取图像数据。4.3 NPU驱动与AI模型部署RV1106的0.5T NPU是其亮点。瑞芯微提供了RKNN-Toolkit模型转换工具和librknn_runtime运行时库。1. 驱动与内核配置确保内核配置了CONFIG_ROCKCHIP_RKNPU并且设备树中启用了NPU节点。npu { status okay; };系统启动后NPU设备通常会出现在/dev/rknpu。2. 模型转换RKNN-Toolkit这是一个在PC上进行的步骤。你需要将训练好的模型如TensorFlow Lite.tflite、PyTorch.pt、ONNX.onnx或Caffe.caffemodel转换成RKNN格式。from rknn.api import RKNN rknn RKNN() # 加载模型 ret rknn.load_tflite(model./mobilenet_v1.tflite) # 配置模型输入、输出、目标平台 ret rknn.build(do_quantizationTrue, dataset./dataset.txt, target_platformrv1106) # 导出RKNN模型 ret rknn.export_rknn(./mobilenet_v1.rknn) rknn.release()量化Quantization是关键步骤它能将FP32模型转换为INT8大幅减少模型体积并提升在NPU上的推理速度但可能会带来精度损失。dataset.txt里需要提供一批代表性的校准图片。3. 在RV1106上运行推理将转换好的.rknn模型文件放到板子上。使用C或Python API加载模型并推理。// C语言示例片段 #include rknn/rknn_runtime.h rknn_context ctx; int ret rknn_init(ctx, model_data, model_size, 0, NULL); // 初始化 // 设置输入 rknn_input inputs[1]; inputs[0].index 0; inputs[0].buf input_image_data; inputs[0].size input_size; inputs[0].pass_through 0; ret rknn_inputs_set(ctx, 1, inputs); // 运行推理 ret rknn_run(ctx, NULL); // 获取输出 rknn_output outputs[1]; outputs[0].want_float 1; ret rknn_outputs_get(ctx, 1, outputs, NULL); // ... 处理输出结果 outputs[0].buf rknn_outputs_release(ctx, 1, outputs); rknn_destroy(ctx);性能调优心得输入数据对齐NPU对输入数据的地址和尺寸可能有对齐要求如要求128字节对齐。使用posix_memalign分配内存可以避免性能问题。零拷贝如果可能让ISP处理后的图像数据直接送入NPU避免在CPU内存和NPU内存间来回拷贝。这需要深入了解rkmedia等中间件或直接使用V4L2 buffer与NPU API进行对接。多模型并发RV1106的NPU支持一定程度的多模型并发执行但需要仔细管理内存和计算资源官方示例中有相关演示。5. 应用开发与系统优化当底层驱动和硬件都调通后就到了开发上层应用并让整个系统跑得更快、更稳的阶段。5.1 使用RKMedia进行多媒体应用开发直接操作V4L2和NPU的API比较底层。瑞芯微提供的RKMedia中间件封装了这些复杂操作提供了更友好的音视频采集、编码、解码、显示和AI推理的管道PipelineAPI。1. RKMedia核心概念RKMedia将处理单元抽象为MODULE如VI视频输入、VENC视频编码、RGA图形处理、AI推理并通过LINK将它们连接起来形成数据流。例如一个简单的摄像头编码流程可以是VI - RGA缩放/裁剪 - VENC - FILE。2. 快速实现摄像头H.264编码存储#include rkmedia/rkmedia_api.h // 1. 初始化 RK_MPI_SYS_Init(); // 2. 配置视频输入VI通道从/dev/video0获取数据 VI_CHN_ATTR_S vi_attr; vi_attr.pcVideoNode /dev/video0; vi_attr.u32Width 1920; vi_attr.u32Height 1080; vi_attr.enPixFmt IMAGE_TYPE_NV12; vi_attr.enBufType VI_CHN_BUF_TYPE_MMAP; RK_MPI_VI_SetChnAttr(0, vi_attr); // 使用VI通道0 RK_MPI_VI_EnableChn(0); // 3. 配置视频编码VENC通道H.264编码 VENC_CHN_ATTR_S venv_attr; venv_attr.stVencAttr.enType RK_CODEC_TYPE_H264; venv_attr.stVencAttr.u32PicWidth 1920; venv_attr.stVencAttr.u32PicHeight 1080; venv_attr.stVencAttr.u32Bitrate 4000000; // 4 Mbps RK_MPI_VENC_CreateChn(0, venv_attr); // 4. 绑定数据流VI通道0 - VENC通道0 MPP_CHN_S src, dst; src.enModId RK_ID_VI; src.s32ChnId 0; dst.enModId RK_ID_VENC; dst.s32ChnId 0; RK_MPI_SYS_Bind(src, dst); // 5. 启动编码并获取码流例如写入文件 VENC_STREAM_S stStream; FILE *fp fopen(output.h264, wb); while(running) { RK_MPI_VENC_GetStream(0, stStream, -1); // 阻塞获取码流包 for(int i0; istStream.u32PackCount; i) { fwrite(stStream.pstPack[i].pu8Addr, 1, stStream.pstPack[i].u32Len, fp); } RK_MPI_VENC_ReleaseStream(0, stStream); // 释放流 } // 6. 反绑定、销毁通道、去初始化...使用RKMedia可以大大简化开发但需要注意其版本与SDK的匹配以及各模块属性的详细配置。5.2 系统性能调优与稳定性保障产品化过程中系统必须稳定高效。1. 内存优化RV1106内存不大常见128MB或256MB DDR。优化策略包括使用busybox精简根文件系统在Buildroot配置中只选择必要的软件包。静态链接 vs 动态链接对于关键应用静态链接可以避免动态库加载的开销和依赖问题但会增大单个可执行文件体积。需要权衡。监控内存使用使用free、top命令关注Slab和Cache的使用情况。内核slabtop命令可以查看内核对象缓存。防止内存泄漏长时间运行后使用cat /proc/meminfo观察MemFree和Buffers/Cached的变化趋势。Valgrind不适合资源受限的嵌入式环境更多的是依靠代码审查和压力测试。2. 启动速度优化U-Boot优化减少不必要的设备初始化关闭启动延迟。修改include/configs/rv1106_common.h中的CONFIG_BOOTDELAY。内核裁剪使用make menuconfig移除所有不需要的驱动和功能模块。特别是文件系统、网络协议、调试功能等。Initramfs对于简单应用可以考虑使用initramfs作为根文件系统直接打包进内核省去从存储设备加载根文件系统的时间。并行初始化利用systemd或Busybox init的并行启动能力如果支持。3. 电源管理RV1106的MCU核心可以在A7休眠时维持低功耗运行。CPU频率调节使用cpufreq子系统。echo performance /sys/devices/system/cpu/cpufreq/policy0/scaling_governor切换到性能模式echo powersave切换到省电模式。休眠与唤醒配置GPIO中断作为唤醒源。在设备树中为按键或传感器配置wakeup-source属性并在驱动中实现相应的中断处理。让系统进入休眠状态可以通过echo mem /sys/power/state实现。5.3 常见问题排查与解决实录开发过程中以下问题我遇到得最多1. 内核启动时卡住串口无输出。检查点1电源。用万用表测量核心电压如VDD_LOGIC和DDR电压是否稳定且在正常范围内。RV1106对电源纹波比较敏感。检查点2时钟。检查24MHz主晶振是否起振。可以用示波器探头高阻测量晶振引脚看是否有正弦波。检查点3Boot引脚。确认板子的Boot Mode引脚如eMMC vs SPI Flash电平设置是否正确与你的烧录介质匹配。检查点4DDR配置。这是最棘手的问题之一。rkbin里的DDR初始化二进制文件rv1106_ddr_xxx.bin必须与板上焊接的DDR颗粒型号和时序完全匹配。如果不对轻则不稳定重则无法启动。需要根据DDR颗粒的数据手册核对或重新生成这个bin文件。2. 摄像头不出图media-ctl报错。检查点1I2C通信。首先用i2cdetect -y 2假设I2C总线是2检查传感器地址如0x36是否能被探测到。探测不到检查电源、复位引脚、I2C上拉电阻和接线。检查点2时钟和MIPI信号。用示波器检查Sensor的MCLK主时钟是否正常。MIPI信号需要用高速示波器或MIPI协议分析仪查看难度较大。可以尝试降低分辨率或帧率看是否是信号完整性问题。检查点3设备树配置。反复核对设备树中的remote-endpoint链接、>