资讯动态

Cyclone V SoC开发实战:硬件设计、Linux适配与HPS-FPGA桥接经验

发布时间:2026/10/17 0:35:51 来源:尧图企业网站定制
1. 项目背景与方案选型的几条经验这两年用 Cyclone V SoC 平台完整走完了一款产品的开发周期从立项评审、硬件设计、FPGA 逻辑、嵌入式 Linux 适配到产测落地整个链路都摸了一遍。回头再看这个选型在当时有很多争议但整体结果是让人满意的所以想把过程里的判断依据和踩过的坑整理出来。先交代一下背景产品是一台面向工业现场的边缘数据采集与协议转换设备需要同时处理多路高速模拟量采样、现场总线通信、以太网上行还要跑 Web 管理界面和远程配置。最初评估过两类方案一类是 MCU 独立 FPGA 的双芯片架构另一类是直接上高性能应用处理器。前者的痛点在于两套开发环境割裂MCU 和 FPGA 之间通过并行总线或 SPI 通信带宽有限且调试麻烦后者的痛点在于实时采样和多路并发协议处理的硬实时能力不够而且工业级型号成本偏高。Cyclone V SoC 把双核 Cortex-A9 和 FPGA 逻辑放在同一颗芯片里HPSHard Processor System和 FPGA 阵列之间通过片内的 AXI 高速桥互联这种架构恰好同时解决了带宽和实时性问题。选型时还重点比较了 Cyclone V SoC 的几个型号差异比如 5CSXFC6 和 5CSXFC4 的逻辑资源量差距、是否带 MMU、封装上的引脚数量差别。最终选择了中等级别的 5CSXFC6D6F31I7N它的逻辑单元数量足够容纳我们的数据预处理和通信协议栈DDR3 控制器集成在 HPS 侧设计上少了一颗外部内存芯片的布线压力。SE 和 SX 的另一个区别是 SoC 系列的 HPS 侧自带丰富外设——USB、UART、SPI、I2C、SDMMC、GMAC——很多板级功能不需要额外接芯片这对硬件面积和 BOM 成本都是实打实的优化。方案确定之后后续所有工作都围绕“FPGA 做实时预处理、HPS 做协议栈和业务逻辑”这条主线展开。FPGA 侧负责 ADC 数据的乒乓缓存、数字滤波、协议帧的编解码HPS 侧负责 TCP/IP 协议栈、Modbus 映射、配置管理、Web Server 和数据上报。两边需要的通信带宽并不算极端——采样率做到 200kSPS、16bit 深度加上多路总线协议并发有效数据吞吐大概在几十 MB/s 的级别——用 AXI 桥做 DMA 传输足够应付。这个架构现在看不算稀奇但在方案评审阶段需要说服团队里的几位老工程师放弃“MCU 管逻辑、FPGA 管采集”的传统分工方式。我的观点是分工的边界不应该是芯片边界而应该是任务属性边界。把“硬实时、并行性要求高”的任务放在 FPGA把“控制流、复杂协议、人类交互”的任务放在 A9 核通信问题用片内桥接解决整体的数据通路路径更短、延迟更低、板级干扰因素更少。当然也有个现实问题需要正视SoC 方案的学习曲线比传统 MCUFPGA 分开开发的模式陡峭得多。HPS 侧的启动流程涉及 Boot ROM、SPL、U-Boot、内核的多级引导FPGA 侧的配置时序又和 HPS 启动之间存在着严格的先后依赖关系硬件设计上还要处理 DDR3、时钟源、IO 复用等一系列新问题。这套复杂度在项目初期确实拖慢了节奏但长期看是值得的——产品迭代时只需更新 FPGA 逻辑或修改设备树不需要重新设计整个硬件平台。2. 硬件设计的关键决策与电源时序考量Cyclone V SoC 的硬件设计和普通 FPGA 板卡最大的不同在于不仅要管 FPGA 内核电压、IO 电压、配置电路还要管 HPS 侧的 DDR3、启动模式选择、复位时序、时钟树以及 HPS 和 FPGA 之间的电平标准匹配。这些环节环环相扣任何一处疏忽都会让系统卡在某个启动阶段而且是那种“看起来没坏、但就是跑不起来”的隐蔽故障。2.1 电源轨设计与上电顺序SoC 芯片的电源轨比纯 FPGA 多几路FPGA 内核 VCCINT0.85V/0.9V、FPGA IO VCCIO根据 bank 不同有 1.5V/1.8V/2.5V/3.3V 可选、HPS 侧 VCC_HPS0.9V、DDR3 VCCDDR1.5V、PLL 供电 VCCPT/VCCPD另外还有部分 I/O 和辅助电源。Cyclone V 要求 VCCINT 和 VCC_HPS 先上电然后是 VCCDDR再是 VCCIO最后是 PLL 电源完成整个启动序列。这个顺序不是靠单个芯片的上电时间差来碰运气而是要在电源电路设计时通过时序控制芯片或合理的 RC 延时电路来明确保证。我在这块踩过一次很深的坑做第一版样机时为了省一颗电源时序控制芯片想靠 DC-DC 的软启动时间和负载特性自然形成上电顺序。结果在低温环境下频繁出现 HPS 启动到一半死掉的现象——排查了很久才发现是低温让某一路 DC-DC 启动时间偏移了十几毫秒导致 DDR3 供电时序和 HPS 复位释放时序发生了竞争。从那以后我坚持在每次原型设计里都加入电源时序监控电路哪怕只是一颗简单的复位芯片加几个分压比较器也要确保“上电顺序有据可查、时序参数可测”。另外别忽略检流电阻和电流探头的预留位置——SoC 启动时瞬时电流很容易冲到 2A 以上如果在设计阶段没有预留测试点后期调试电源完整性会非常痛苦。2.2 启动配置的三种方式与引脚复用的取舍Cyclone V SoC 支持三种启动方式直接从 FPGA 配置FPGA-first、从 HPS 启动HPS-first、以及二者结合的两阶段启动。产品最终选择了 HPS-first理由很直接我们希望把 FPGA 的配置数据放在 Linux 文件系统里这样升级 FPGA 逻辑就可以像升级普通固件一样通过 Web 上传 .rbf 文件再触发重配置而不需要打开机箱去换 SPI Flash 内容。这个选择对产测和售后维护特别友好。启动相关引脚的关键之一就是 BSEL 引脚组它们决定 HPS 从哪种介质读取启动代码。我们在板子上预留了 4 组拨码开关方便开发阶段切换 SD 卡和 SPI Flash 两种启动介质量产版本再把拨码固定为焊锡跨线。另一个容易被忽略的是 SDMMC 引脚的 IO 电平标准——HPS 侧的 SDMMC 接口电平需要和 SD 卡供电电压匹配如果 VCCIO 设为 3.3V 却接了 1.8V 的 SD 卡轻则识别失败重则烧毁卡控制器的 IO。设计中我们统一把 SDMMC bank 的 VCCIO 定为 3.3V四线 SD 模式兼容市面上绝大多数 SDHC 卡。引脚复用方面HPS 外设功能在 SoC 里是高度复用的——同一组引脚可能是 SPI、I2C、UART 或 JTAG 功能。设计时用官方的 Pin Mux Tool 逐一确认每个功能对应的引脚分配和复用选项这个工具会直接生成 Qsys 系统里 HPS 外设的引脚配置 XML前期梳理得越清楚后期布线时越省心。我们最终分配的原则是高速接口GMAC、DDR3优先保证布局布线合理中速接口SDMMC、UART、USB兼顾连接器位置低速就用板内走线解决。UART0 一定保留了 debug 输出能力因为这是 HPS 启动阶段的唯一“眼睛”没有它U-Boot 阶段就完全是个黑盒。2.3 DDR3 布线的长度匹配细节HPS 的 DDR3 控制器是 SoC 片内集成的硬核数据速率跑到 800MT/sDDR3-800等效 400MHz 时钟左右布线方面必须严格控制。经历过一波教训后我在规则里定了三条硬性约束所有 DQ 信号同字节通道内的长度差控制在 0.5mm 以内DQS 比 DQ 长约 0.5mm 帮助读时序对齐地址和控制信号相对 CK 的等长控制在 1mm 以内。DDR3 的 VREF 需要干净的滤波我们给每个 VREF 引脚配了一个 0.1uF 的滤波电容并且保证 VREF 走线远离 DQS 和 CK 这些高速切换信号否则数据线上的串扰会直接反映在读写误码上。PCB 叠层上DDR3 信号尽量走在内层参考平面要连续尽量避免跨平面分割。这些细节单独看都不复杂但组合起来如果处理不当轻则 memtest 报错、重则系统随机死机而且这类问题极难复现和定位。3. U-Boot、Linux 与设备树的适配心得硬件平台稳定之后软件适配就成了主战场。Cyclone V SoC 的软件生态比较成熟官方维护的 Linux 内核分支和 U-Boot 版本基本能覆盖大多数需求但这不代表“拿来就能用”。设备树、U-Boot 环境变量、根文件系统、FPGA 重配置驱动这几个环节都需要针对产品实际做适配而且每个环节的错误排查方式都不一样。3.1 交叉编译环境与 SDK 选择SoC FPGA 的嵌入式 Linux 开发推荐使用官方提供的工具链但我不建议直接安装那个体积庞大的全套 EDS 图形界面版本——很多功能在命令行下几行命令就能完成没必要装一堆不常用的组件。实际工作中我只需要三样东西交叉编译器、U-Boot 源码、内核源码。交叉编译器选的是 arm-none-linux-gnueabihf 系列对应 Cortex-A9 硬浮点这里注意一定得带 hf 后缀否则内核空间浮点性能会大打折扣。U-Boot 和内核源码从官方仓库拉取对应分支编译配置里重点检查 HPS 平台相关的 defconfig 和设备树 dts 文件是否与我们的板卡匹配。官方默认配置对应的是自己的开发板外设地址、DDR 参数、引脚复用都可能和我们的设计不同必须要改。我们在项目里花在设备树适配上的时间比预想多出了不少但这是绕不开的——任何一处 pinmux 配置不对对应的外设就会注册失败或者中断无法触发。3.2 设备树中 HPS-FPGA 桥与 FPGA 节点的写法设备树里最关键的是三个 AXI 桥节点HPS-to-FPGA 桥、FPGA-to-HPS 桥、Lightweight HPS-to-FPGA 桥。它们分别对应不同地址段和不同性能特征的访问路径。设备树里首先要确保三个桥节点在 dts 中使能并且 compatible 属性正确然后把你生成的 Qsys 系统里自定义 IP 的寄存器地址空间挂载到对应桥节点下。这里有个常见误区很多人把自定义 IP 的地址写在 FPGA-to-HPS 桥下但这个桥主要用于 FPGA 主动发起访问比如 DMA 引擎或高速数据搬运如果逻辑上没有主动访问 HPS 内存的需求外设寄存器应该挂在 HPS-to-FPGA 或 LWHPS 桥上。我们在产品里用 LWHPS 桥做低速外设控制和状态查询——比如读取板卡温度、设置 LED、读取拨码开关状态这类控制操作频率低、数据量小用轻量级桥足够。而大数据量传输走的是 HPS-to-FPGA 桥配合 FPGA 内部的 DMA 模块或者反过来用 FPGA-to-HPS 桥由 FPGA 侧 DMA 直接搬走 HPS 侧内存里的数据。设备树里还有一类节点很少有人提但实际调试中很关键——复位控制器节点和时钟控制器节点。Cyclone V SoC 的很多外设时钟是 HPS 侧由片内时钟管理器统一配置的SPI、I2C、UART、GMAC 各自的时钟源可以不同设备树里的 clocks 属性必须和实际时钟频率对齐。我们遇到过 UART 波特率偏移 3% 导致通信偶发乱码的问题查了半天才发现是时钟控制器配置里把 UART 时钟设成了 100MHz 而实际 PLL 输出的是 96MHz。时钟频率的偏差对低速 UART 都这么明显对 GMAC 和 USB 这类高速外设的影响就更大适配时务必逐项核对。3.3 FPGA 重配置驱动的实现方式HPS-first 启动模式下FPGA 逻辑是由 U-Boot 或 Linux 在系统运行期间加载的。我们在内核里实现了两个重配置通道一是通过 /sys/class/fpga_manager/fpga0/ 接口直接写入 .rbf 文件这个适合开发阶段快速验证二是用自定义的字符设备驱动配合专门的分区工具将 .rbf 文件打包到固件升级包里通过 Web 上传并触发重配置面向量产场景。实现第二个通道时需要注意FPGA 重配置期间任何访问 FPGA 侧逻辑的驱动都会挂起或出错所以一定要保证先停掉相关服务再触发重配置否则系统可能进入不可恢复的卡死状态。我们在驱动里增加了一个状态机先把所有已被占用的中断源全部释放再去触发重配置完成后重新注册中断、恢复业务线程。整个重配置过程约耗时 200ms 到 500ms 不等取决于 .rbf 文件大小和配置时钟频率设计上要允许这段短暂的业务中断窗口。4. HPS 与 FPGA 数据交互的三种桥接实践SoC FPGA 相比传统 MCUFPGA 方案最大的红利就是片内 AXI 桥的带宽和低延迟。但带宽是“硬件上限”实际能跑多少取决于软件和逻辑侧怎么配合。我们做了三种不同路径的交互实现各有适用场景。4.1 LWHPS 桥低速寄存器访问最省心Lightweight HPS-to-FPGA 桥的数据位宽是 32 位地址空间映射在 HPS 的 0xFF20_0000 段访问延迟相对较高但胜在简单稳定不需要配置 DMA。我们把所有控制类寄存器都放在这个桥上采样开关、增益挡位、滤波模式切换、设备心跳计数。软件侧用 devmem 工具直接读写驱动里就是普通的 ioremap 后读写 32 位寄存器。这里有个细节LWHPS 桥访问 FPGA 侧寄存器时FPGA 逻辑里对读请求的响应必须在一个可预测的时间窗口内完成否则 AXI 总线会发生超时。因此 LWHPS 桥控制的逻辑模块必须设计成“纯组合逻辑 极浅流水线”不能有等待状态。我们在 FPGA 里给这些控制寄存器加了 AXI-Lite 的 ready 信号恒为高的设计虽然严格意义上不符合 AXI 规范但在 LWHPS 这种点到点的简单场景下实测非常稳定。4.2 HPS-to-FPGA 桥高带宽数据下行的主干道HPS 向 FPGA 大批量传数据用的是 HPS-to-FPGA 桥数据位宽可配置为 64 位或 128 位。我们配置成 64 位工作模式实测峰值带宽接近 1GB/s 的量级——这个数字已经远远超过产品所需的几十 MB/s。但在实际业务里我们刻意把传输速率控制在一个保守区间约 200MB/s原因有两方面一是高速传输会增加 FPGA 侧 FIFO 的存储压力特别是跨时钟域处理不当会出现亚稳态问题二是 HPS 侧的 CPU 参与 DMA 描述符填充时过高的中断频率会侵占 A9 核心的算力影响协议栈的处理吞吐。最终设计是 FPGA 侧做一个 4KB 深度的异步 FIFOHPS 侧通过 DMA 描述符链一次性下发大块数据FPGA 按帧解析后存入 DDR3 缓冲区再由逻辑侧完成后续处理。这套方案在长时间满负荷运行下也没有出现丢帧关键是把 DMA 描述符环的大小、中断合并阈值和 FIFO 深度三者匹配好。4.3 FPGA-to-HPS 桥FPGA 主动上行的最快路径上行数据采用的是 FPGA-to-HPS 桥这个方向对延迟的要求比下行苛刻得多采样数据从 ADC 进入 FPGA 到最终写入 HPS 侧 DDR3 的端到端延迟直接影响整个系统的实时性指标。我们的实现路径是ADC 采样数据进入 FPGA 逻辑后先经过数字滤波和格式转换存入 FPGA 内部的缓存区然后由一个自定义的 AXI Master 模块通过 FPGA-to-HPS 桥发起 DMA 写请求直接把数据写入 HPS 侧预先分配的 DMA 缓冲区写完触发中断通知 HPS 侧驱动取走数据。为了让这个过程稳定我们在 HPS 侧用 CMAContiguous Memory Allocator分配了一片物理连续的内存区域并且在设备树里将其预留、禁止常规页面分配器使用。CMA 的使用是这个方案的真正关键点——如果不用 CMA 而用普通 kmalloc物理内存不连续DMA 分散到多个页面里硬件侧描述符处理复杂度和出错概率都会显著上升。FPGA 侧 AXI Master 模块的跨时钟域处理也需要重点说明。我们模块的主时钟是 FPGA 侧的 100MHz 采样时钟但 AXI 总线时钟是 HPS 侧的 250MHz可配置。设计上使用异步 FIFO 作为跨时钟域缓冲并采用 AXI 总线标准的先写后读握手协议。实际调试中遇到过一个很有意思的问题AXI 的 awready 和 wready 信号是独立拉起的逻辑里如果把两者绑定成“都准备好才接受请求”等效于人为延长了写事务的持续时间反而降低了有效带宽。后来我按照 AXI 规范把地址通道和数据通道完全解耦允许地址请求先到达、数据后续跟上带宽利用率立刻提升了很多。4.4 三种桥的选型对照与适用场景桥类型地址段典型带宽延迟适用场景LWHPS-to-FPGA0xFF20_0000低高控制寄存器、状态读取HPS-to-FPGA0xC000_0000高中大批量下行数据、命令下发FPGA-to-HPS0x8000_0000高低实时采样数据、主动上行通知这个表格做出来之后团队在评审每个新 IP 时都会先问一句“这个模块挂哪个桥”逼着大家从数据方向、频率、延迟要求三个维度去思考架构合理性而不是随手把地址分配到某个桥下完事。5. 系统启动流程与启动时间优化SoC 的启动过程比普通 MCU 复杂很多Boot ROM 固化在芯片内部、无法修改它会根据 BSEL 引脚选择介质读取 SPLSPL 初始化 DDR3 后再加载 U-BootU-Boot 负责加载内核和设备树。每个阶段都有优化空间。5.1 启动各阶段的时间构成实测我们产品的完整启动时间从上电到 Linux 用户态登录大约为 3.2 秒分解开来看Boot ROM 耗时约 0.1s、SPL 初始化 DDR3 约 0.3s、U-Boot 加载内核镜像与设备树约 0.7s、内核启动到 rootfs 挂载约 1.0s、用户态业务进程和 FPGA 重配置约 1.1s。这 3.2s 在开发阶段完全不是问题但产品化之后客户会提“重启设备能不能快点”所以必须逐段优化。SPL 阶段的主要耗时在 DDR3 训练和初始化Cyclone V 的 DDR3 控制器硬件训练功能比较完善但默认的训练复杂度会根据配置而变化。可以适当降低 Verifier 阶段的字节数来缩短时间前提是板级 DDR3 布线质量足够稳定否则可能牺牲时序冗余。U-Boot 阶段的优化点是去掉用不到的驱动和命令比如多余的网络协议栈、USB 初始化、文件系统支持只保留 SD/MMC 和网络两个最关键的子系统。内核阶段的优化主要是裁剪内核把用不到的子系统音频、蓝牙、大量网络协议编译掉使用 initramfs 来代替外部 rootfs 挂载等。5.2 FPGA 重配置与 Linux 启动的并行笔直落点最理想的启动流程是U-Boot 阶段直接加载 .rbf 文件并配置 FPGA等内核启动后 FPGA 逻辑已经就位。这样业务线程起来后可以直接访问 FPGA 外设不需要等待单独的重配置过程。但实际产品里我们把 .rbf 放在了根文件系统分区里因为这样便于升级——如果放在 U-Boot 能读取的 boot 分区升级 FPGA 逻辑就需要同时更新 boot 分区内容产测和远程升级的复杂度都上去了。折中方案是U-Boot 阶段只配置 FPGA 里的 SDRAM 接口和 HPS 桥的桩模块让 HPS 侧能访问 FPGA 的基本地址空间Linux 启动后由一个用户态服务从 rootfs 分区读取完整 .rbf 并做一次热重配置。这样启动时间只多了约 300ms但换来了 FPGA 逻辑远程升级的极高灵活性。热重配置期间设备上的 LED 会以特定频率闪烁方便现场人员从视觉上确认重配置状态。5.3 启动失败时怎么定位启动失败是 SoC 开发中几乎无法回避的问题尤其是第一版样机。排查手段按顺序来先看 JTAG 能否连接——能连上说明 HPS 的电源和时钟基本正常Boot ROM 已经执行或至少 JTAG TAP 状态机是好的连接不上则优先检查 VCC_HPS、VCCDDR 和复位引脚电平。如果 JTAG 能连但 U-Boot 串口无输出多半是 SPL 卡在 DDR3 初始化上此时检查 DDR3 配置参数是否和实际颗粒型号匹配、等长走线是否达标如果 SPL 有输出但加载 U-Boot 时报 CRC 错误可能是 Boot ROM 读到的 SPL 文件不完整检查 SD 卡分区的起始扇区和 U-Boot 生成的镜像格式。内核启动阶段如果卡在“Uncompressing Linux...”之后无输出大概率是 DTB 里 UART 时钟配置不对或者控制台参数没有传入。这些问题的定位思路都离不开“逐级确认、每级留一口串口日志”的原则。开发阶段一定要保证 U-Boot 和内核的早期打印完整千万不要为了图省事把日志级别调低否则出了问题只能靠猜。6. 常见问题与排查技巧实录这一节内容来自开发过程中的真实问题记录既有硬件层面的也有软件层面的整理成一个速查表后面有人再做类似项目时可以直接对照排查。故障现象可能原因排查方法HPS 上电后 JTAG 连不上VCC_HPS 未达到目标电压检查电源轨输出和时序监控点U-Boot 串口无输出引脚复用配置错误或 UART 时钟偏差核对 Pin Mux 工具配置检查时钟树寄存器内核启动死循环DTB 里 DDR 参数和实际颗粒不匹配对比 dts 中的 DDR 配置和硬件颗粒型号FPGA 逻辑无法配置.rbf 文件 CRC 校验失败或配置时钟不稳定重新生成 .rbf检查配置时钟源的稳定度HPS 访问 FPGA 寄存器超时桥没有使能或 FPGA 侧逻辑应答超时检查设备树桥节点状态、逻辑侧 ENABLE 信号上传文件夹后 FPGA 卡死驱动释放中断时序不正确按状态机要求先停服务、释放中断再重配置SD 卡启动偶尔失败SDMMC 电平标准不匹配或走线过长检查 VCCIO 电平缩短 SD 信号走线网络偶发断连GMAC 的 RGMII 时序偏差用示波器测量 TXD 和 TX_CLK 相位关系长时间高负载后系统无响应散热不足导致热降频或程序死锁检查温度传感器读数审查持锁路径其中有两个问题值得单独展开说。一个是网络偶发断连开发后期遇到以太网在长时间高吞吐下偶发丢包和断连开始以为是协议栈问题排查了很久才发现是 GMAC 的 RGMII 接口在 PCB 上布线时 TX_CLK 和 TXD 的等长控制没做好加上链路伙伴的时钟源抖动稍大导致建立时间裕量不足。后来使用了一个非常简单有效的思路在 PHY 芯片配置寄存器里把 RGMII 的 TX 时钟延迟调整为 2ns硬件上不动一根线网络稳定性立刻明显好转。RGMII 规范里是接收端负责延迟时钟采样但很多 PHY 芯片实际实现是发送端要做相位调整遇到时钟沿不对的板子软件配置就可以救回来。另一个是 FPGA 重配置期间的上位机通信问题。我们产品支持远程升级Web 服务运行在 HPS 侧FPGA 重配置时 Web 服务不应被杀掉否则升级过程中断就麻烦了。实操中特意把重配置服务设计成“异步触发 状态查询”模式用户上传新固件后服务先校验文件完整性、把 .rbf 存到一个专用分区、标记待升级状态然后返回“升级已启动”的响应接下来进入重配置流程此时 Web 服务仍然运行HPS 本身没重启只是无法访问 FPGA 寄存器重配置完成后服务检测 FPGA 状态寄存器识别到版本号变化再返回“升级成功”并自动重启业务进程。这个模式经历了几轮更新后非常稳定现场从没出现过升级到一半变砖的情况——关键就是每个阶段都有状态寄存器可查而且 FPGA 侧始终保留一个固定版本号的“引导逻辑”作为最后一道保险。最后再分享一个开发流程上的心得Cyclone V SoC 这种异构平台的调试复杂度远超纯 FPGA 或纯 ARM 项目团队协作时一定要明确接口层的定义——比如 FPGA 逻辑和 HPS 驱动之间的寄存器地址分配表必须用文档固化下来任何一边修改都要同步更新文档。我们在项目中期吃过一次亏FPGA 工程师重排了寄存器地址但没有同步更新驱动里的宏定义结果出现了一段“逻辑跑得对、驱动读不对”的诡异 bug定位花了一整天。从那以后我们在版本管理里加入了一份强制审核项凡是涉及 HPS-FPGA 接口的改动必须同时提交驱动代码变更和寄存器映射表变更否则不允许合并。这套流程落地后接口相关的低级错误基本绝迹了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑