拓冰建站拓冰建站
首页 / 资讯中心 / 正文

FPGA+ARM64+Linux:自研DMA框架解决高速数据采集难题

搞高速数据采集的人多半都经历过这种尴尬FPGA侧ADC采得飞快数据堆在FIFO里快溢出了CPU却迟迟拿不走。要么拆成一次次中断搬运CPU占用率高得吓人要么绕开操作系统直接操作物理地址性能倒是上去了可驱动和上层应用又变成一团乱麻。hs_dma_framework这个项目就是专门来收拾这个局面的。它把FPGA、ARM64处理器和Linux系统串成一条完整的采集链路核心里是一套不依赖厂商闭源IP的DMA框架FPGA负责把高速数据灌进AXI4-Stream总线ARM64侧通过Linux驱动的描述符环形队列接管这批数据整个搬运过程CPU几乎不参与用户态拿到手的已经是规整的、可以直接丢给算法处理的数据块。这篇文章会把这套框架从硬件选型、FPGA逻辑、Linux驱动到ARM64适配从头拆一遍把你最关心的几个问题讲透DMA描述符环形队列到底怎么设计才算可靠、ARM64缓存一致性为什么和x86不一样、设备树里那几行配置为什么能坑你一整天。如果你是做FPGA数据采集、边缘计算网关或者软件无线电的工程师这篇可以直接当参考设计来读。1. hs_dma_framework到底解决了什么问题1.1 高速数据采集的常见痛点做采集类项目的朋友应该都有体会数据搬运往往是整个系统里最难啃的骨头。ADC采样率上去了数据率轻松到几百Mbps甚至上Gbps这时候如果还靠CPU一条条读寄存器取数据基本就是灾难。我见过不少项目组第一步用GPIO模拟接口第二步用简单FIFO加中断第三步发现中断太频繁CPU被打满第四步才开始想DMA。麻烦还不止这些。用厂商自带DMA IP的工程一般都能跑通但问题在于这些IP往往和具体芯片绑定换一颗FPGA或者换一个操作系统版本整个链路就得重新调试。而且底层细节被封装起来出了问题你根本不知道是描述符写错了还是地址翻译出了岔子。hs_dma_framework的思路是把DMA这套机制自己实现一遍从描述符管理到中断处理全部透明化出了问题能直接顺着链路排查。1.2 为什么选FPGA加ARM64加Linux这个组合先说FPGA。高速数据采集的前端必然是FPGA因为ADC的LVDS、JESD204B这类接口以及数据的预处理、滤波、触发逻辑用处理器做不现实。FPGA的并行架构决定了它天生适合做这种高吞吐的数据管道。再说ARM64。放在几年前很多人可能还在纠结用ARM Cortex-A9还是FPGA内嵌的软核。但现在嵌入式平台上ARM64已经非常成熟四核A53/A72的价格和功耗都控制得很好性能完全撑得起协议解析、FFT、存盘这类后续处理。更重要的是ARM64能跑完整版的Linux这意味着网络、文件系统、调试工具这些现成的生态都能直接用。最后是Linux。Linux带来的最大好处是把内存管理、中断处理、设备模型这些东西都标准化了。你不需要自己管物理内存的分配和释放不需要考虑怎么把物理地址暴露给用户态驱动框架已经把这些事情安排好了。平台选型本质上就是在实时性和生态之间找平衡FPGA兜底实时采集Linux兜底应用生态ARM64负责把这两者连接起来这套组合在数据采集场景里确实是最稳的。1.3 平台的总体架构整个平台的数据流是这样走的ADC采样数据经过前端接口进入FPGA逻辑FPGA内部做必要的格式转换和缓冲后以AXI4-Stream协议把数据送给DMA写引擎写引擎根据CPU预先配置好的描述符把数据直接写到ARM64侧的内存里写完一整块描述符指向的数据后写引擎产生中断驱动在中断里处理这块数据并归还描述符。反过来CPU要下发控制命令时通过AXI4-Lite接口走寄存器通道配置采样率、触发条件、DMA启动停止等参数。两条通道分开设计控制面低带宽高实时数据面高带宽低干预互不干扰。ARM64侧的Linux驱动注册成平台设备在设备树里匹配FPGA挂在总线上的设备节点。驱动负责分配DMA缓冲区、维护描述符队列、注册中断处理函数然后把缓冲区通过mmap暴露给用户态应用。用户态拿到的是物理连续的内存映射可以直接读写避免了内核态到用户态的一次拷贝。2. 硬件选型与数据通路设计2.1 FPGA侧的资源评估与选型FPGA的选型往往不是先定芯片而是先算资源。你需要先明确前端接口的类型和数据率再根据数据率反推内部需要的缓冲深度和处理逻辑复杂度。以我常用的配置为例前端是双通道250MSPS的ADC16bit位宽通过LVDS接口接入FPGA总数据率约1Gbps。FPGA内部需要做双通道的数据对齐、格式转换、然后打包成AXI4-Stream的64bit数据通路。加上DMA写引擎、寄存器控制模块以及后续可能加的滤波逻辑LUT大概要占到中端芯片的3成左右DSP Slice反而用得很少。这里有个容易被忽视的坑是FIFO深度。很多人想省资源把FIFO开得很浅结果DMA搬运稍微慢一点就开始溢出丢数。实际上只要DMA描述符队列设计合理写入侧FIFO只需要能扛住一次总线仲裁的延迟就够了不需要做得特别深。真正决定系统稳定性的是DMA引擎本身的背压处理——能不能在AXI4-Stream握手信号里正确地把FIFO满的状态反馈回采集前端。如果项目里要用到多Die的中大型FPGA还要特别注意跨Die走线的约束问题。数据通路尽量安排在同一个Die内跨Die的信号要手动约束到特定的Super Logic Region否则时序收敛会让你调到头秃。这个问题在后面的踩坑章节会展开说。2.2 ARM64主控的选型思路ARM64这边要考虑的东西不太一样。首先是接口必须得有PCIe或AXI总线和FPGA对接这不是USB和网口能替代的因为只有总线级接口才能提供足够带宽和低延迟。其次是内存带宽DMA要写内存四核A53如果配的是DDR4-2400单通道理论带宽已经足够但你要注意实际平台的内存分配策略别让DMA缓冲区和普通应用的内存互相抢占。操作系统支持也是硬指标。选主控的时候一定要确认它的BSP对Linux的支持程度比如主线内核是否已经包含对应的设备树和驱动还是需要厂商提供补丁。我吃过一次亏选了一颗很新的芯片主线内核根本不认识它的串口和网卡只能等厂商发布全量BSP前后拖了一个多月。所以宁可选成熟一两年的型号也不要追新。常见的搭配有两种一种是独立的ARM64核心板和FPGA板通过PCIe连接适合产品迭代和模块化设计另一种是SoC FPGAARM核和FPGA逻辑封装在同一颗芯片里比如Xilinx的Zynq UltraScale MPSoC这种方案集成度高、时序可控性好但灵活性差一些。hs_dma_framework在设计上对这两种模式都做了兼容核心区别只是总线接口的配置方式不同。2.3 前端采集接口的取舍前端接口的选择直接决定FPGA逻辑的复杂度也是最容易返工的地方。说几个我实际对比过的接口UART这个主要是低速调试场景。FPGA实现UART RX很简单但有几个细节要注意比如波特率时钟需要16倍过采样才能保证稳定的采样点FIFO深度至少要做成2的幂来配合DMA搬运。UART对hs_dma_framework来说更多是验证链路用的最小用例跑通它再切换到高速接口排查问题会舒服很多。SPI与ADCFPGA控制SPI接口的ADC非常常见。SPI模式决定数据字节序一般ADC都是MSB First如果你的FPGA逻辑没对齐时序采出来的数据会整体错位表现出来就是数值完全不对但波形形状又像。SPI数据率上到几十MSPS就已经很吃力了所以它适合中低速高精度的采集场景。LVDS中高速ADC的标准接口。LVDS接收端要注意动态对齐的问题采样时钟和数据之间的相位差会随温度和电压漂移所以要用FPGA内部的延迟链做自动训练。这个训练逻辑务必在数据采集前完成否则高低温环境下数据会随机错位。JESD204B吉比特采样率的ADC基本都用这个。它的链路层、传输层如果用厂商IP还好自己实现的话工作量巨大而且必须处理多通道的同步问题。hs_dma_framework的DMA部分不关心你前端是什么接口只要输出标准AXI4-Stream就行但不同接口的适配模块还是得单独写。这里给个建议不管前端用什么接口FPGA侧统一转成AXI4-Stream协议再送给DMA引擎这条规则能让你后续接任何ADC都不用改DMA核心逻辑。3. DMA框架的核心设计3.1 描述符环形队列是怎么工作的DMA框架的心脏是描述符环形队列。理解它之前先丢掉“DMA就是把数据从一个地址搬到另一个地址”这种简单认知。实际的高速DMA由一组描述符驱动每个描述符记载一段数据搬运任务的元信息源地址、目标地址、数据长度、控制标志、下一个描述符的地址等。CPU负责准备这组描述符DMA硬件按顺序执行它们。环形队列的意思是这个描述符数组在逻辑上是首尾相接的。CPU在队尾追加新的描述符DMA在队头取描述符执行两者通过一个硬件生产的“尾巴索引”和软件维护的“头索引”来同步。我设计hs_dma_framework的队列深度是256项每项描述符最大搬运1MB数据这样整个环最多可承载256MB的任务量实际项目中足够覆盖绝大多数突发采集场景。描述符环形队列相比传统链式描述符有个实在的好处分配和回收都是固定的内存块不会出现链表碎片化问题而且DMA引擎可以用简单的循环索引判断队列是否为空或已满。只要CPU追加描述符的速度跟得上DMA执行的速度系统就能稳定跑满带宽。3.2 为什么不用简单的FIFO加中断方式这是个值得展开的问题。很多FPGA采集项目用的是这种方式ADC数据不断写入FIFOFIFO水位超过阈值就拉高中断CPU响应中断后把FIFO数据搬走。看着没什么问题但数据率一高就露馅了。中断的代价是很高的一次完整的Linux中断处理包括硬件中断、中断线程化、上下文切换最少也要几十微秒。如果FIFO很浅数据会频繁触发中断CPU大部分时间都在响应中断真正处理应用的算力所剩无几。如果FIFO很深延迟又上去了对实时性要求高的场景根本不合格。DMA描述符方案的本质是用内存换中断次数。每执行完一个描述符才产生一次中断一次中断对应一整块数据的交接中断频率下降了两个数量级。实测下来同样是200MB/s的采集数据率FIFO加中断方式CPU占用大概在一核半左右而描述符环形队列方案只需要不到三分之一核而且数据块越大这个优势越明显。3.3 ARM64缓存一致性问题的处理这是整个项目里最阴险的坑x86平台上搞DMA的人很容易在这里翻车。x86的CPU缓存和DMA引擎之间有硬件缓存一致性协议DMA写进内存的数据CPU能看到CPU改过的数据DMA也能读到不需要软件介入。但ARM64平台的很多实现不具备完整的硬件缓存一致性DMA直接写物理内存时可能会绕过CPU的Cache导致CPU读到的还是旧数据。解决方案是在软件层面对DMA缓冲区的Cache操作做显式管理。Linux内核里对应的API是dma_map_single、dma_alloc_coherent这一族。dma_alloc_coherent分配的缓冲区保证了CPU视角和DMA视角的一致性但代价是该区域不能使用Cache读写性能会打折扣。dma_alloc_attrs可以灵活调整这个策略。hs_dma_framework里我做了个折中DMA描述符队列本身用dma_alloc_coherent分配因为描述符的读写频率不高一致性优先真正的数据缓冲区用dma_map_single动态映射配合DMA_BIDIRECTIONAL标志在DMA操作前执行dma_map_single操作完成后再dma_unmap_single。这样既保证了数据通路的高速缓存命中又避免了缓存一致性问题。驱动的每次DMA操作都要严格按我上面说的顺序执行漏掉一步采集数据就会出现“看起来没什么规律但偶尔跳变”的灵异现象。4. Linux驱动与用户态数据通路4.1 字符设备驱动还是UIO驱动架构的选择直接影响开发效率。两条常见的路线一是传统字符设备驱动二是UIOUserspace I/O。我用过两种各有适用场景。传统字符设备驱动的优势是符合Linux设备模型数据可以走内核网络栈、V4L2框架等成熟路径适合要对接现成应用框架的场合。缺点也很明显内核态编程风险高一个指针错误就是整个系统崩溃调试全靠printk和trace。而且每改一次需求可能就要重新编译内核模块加重启迭代效率低。UIO则把大部分驱动逻辑搬到了用户态。内核侧只需要一个极简的UIO驱动把物理地址映射到用户空间中断也通过poll机制暴露给用户态进程。这样DMA描述符的管理、缓冲区的处理全部可以用普通C代码完成出了问题可以直接用gdb调试不需要在驱动开发上耗太多时间。hs_dma_framework最终采用的是UIO方案纯属从工程效率出发的选择——DMA逻辑本来就很复杂把它放进用户态能省掉大量内核调试时间。需要注意的是UIO在Linux主线内的接口就是uio_pdrv_genirq配合设备树属性就能工作不需要自己写内核驱动。但如果你需要DMA缓冲区的缓存一致性管理最好自己在UIO驱动里补充dma_alloc_coherent的分配逻辑否则还得依赖用户态手动做cache flush很容易把ARM64的Cache操作API搞错。4.2 设备树里的配置要点ARM64平台上Linux通过设备树描述硬件FPGA在系统里的位置也要靠设备树交代清楚。设备树配错了驱动大概率直接加载失败而且报错信息不一定直观。我常用的设备树节点长这样fpga_engine: fpgaa0000000 { compatible hs,dma-framework-v1; reg 0x0 0xa0000000 0x0 0x10000; // 控制寄存器空间 reg-names control; interrupts 0 42 4; // SPI中断42号高电平触发 interrupt-parent gic; dma-buf-size 0x400000; // 单个DMA缓冲区4MB dma-ring-size 256; // 描述符队列深度 };设备树里最容易出错的是reg和interrupts的格式。ARM64平台PCI和平台设备的reg属性格式不完全一样平台设备通常需要两段地址来描述高32位和低32位漏了可能会被裁剪到32位地址空间。另一个坑是interrupts属性里的中断号填写前要确认中断控制器GIC的中断号分配写错一个字驱动就收不到中断DMA搬完数据无人知晓采集线程卡死。还有一点经验之谈设备树节点里加一条status属性默认设为disabled在需要启用的时候再通过bootargs或uboot环境变量改成okay。这样做的好处是批量部署时不用重新编译内核改一条设备树就能控制不同板卡上FPGA引擎的开关。4.3 mmap零拷贝与用户态环形缓冲驱动把物理缓冲区映射到用户态之后剩下的工作就是用户态数据的组织。最常用也是我推荐的结构是用户态环形缓冲它和内核侧的DMA描述符队列形成两级流水内核侧描述符环形队列负责“硬件到内核”的搬运用户态环形缓冲负责“内核到应用”的交付。mmap映射要注意对齐要求。Linux的mmap要求映射长度按页对齐如果你dma_alloc_coherent分配的缓冲区是1MB正好是256个页面的整数倍没问题。但如果你图省事分配了一个370KB的非对齐大小最后两个页面的映射就会出问题用户态访问时会触发段错误。用户态环形缓冲的容量通常做成DMA描述符队列容量的2到4倍这样即便用户态应用偶尔掉链子处理不过来缓冲也不会立刻溢出。缓冲区的读写指针采用生产者消费者模型驱动每提交一块数据就更新写指针应用消费完一帧更新读指针。这里有个性能优化点两个指针的更新操作要加内存屏障ARM64上用原子操作加RELEASE语义避免编译器乱序优化导致读写指针错位。5. ARM64平台适配与调试环境5.1 交叉编译环境的搭建ARM64的交叉编译是每个从x86主机过来的Linux开发者都要过的第一关。基本工具链是aarch64-linux-gnu-gcc各家发行版都有打包好的交叉编译器Ubuntu上直接装gcc-aarch64-linux-gnu就行。除此之外还得装交叉编译版的内核头文件和libc不然编译驱动模块时连基本的printk、kmalloc声明都找不到。驱动模块的编译用的是内核源码树必须先用ARCHarm64 CROSS_COMPILEaarch64-linux-gnu-配置好内核再进入驱动目录执行内核模块的make命令。这一步经常有人卡住宿主机上编译x86模块没问题但交叉编译时忘记导出ARCH和CROSS_COMPILE环境变量编译器还是主机工具链编出来的.ko文件在板子上insmod直接报格式错误。建议搭建环境时顺便把文件系统也准备好。ARM64的根文件系统直接用现成的发行版根文件系统也可以但裁剪过的会更轻量。我习惯用debootstrap或buildroot生成最小根文件系统然后通过NFS挂载到开发板上。这样每次改完驱动和应用重新编译后直接拷贝到NFS目录就能运行省去烧写SD卡和重启的漫长循环。5.2 QEMU模拟ARM64的加速开发板卡资源总是有限的而且大量驱动迭代会很磨硬件的寿命。hs_dma_framework开发过程中我在QEMU模拟的ARM64虚拟机上跑通了大部分用户态代码和部分内核模块的验证效率提升非常明显。QEMU的ARM64虚拟化支持已经很成熟用qemu-system-aarch64配合virt平台可以模拟出带GIC中断控制器、PCIe总线、网络和virtio磁盘的完整设备树环境。最关键的是它支持半虚拟化的串口和中断Linux跑起来和真机几乎没有区别。设备树节点里的interrupts配置在QEMU里就能验证语法是否正确中断是否能够触发这些做好了上板之后大概率直接能用。当然QEMU也有局限性它模拟不了FPGA的实际时序也模拟不了DMA引擎的AXI行为。所以我的使用方式是QEMU主要验证驱动加载流程、设备树解析、用户态环形缓冲逻辑、内存映射是否正确DMA硬件行为必须回到板子上用FPGA逻辑分析仪和Linux内核trace配合验证。两条腿走路开发速度能快一倍以上。5.3 启动流程与根文件系统ARM64平台的启动流程要理解清楚不然连“怎么把内核跑起来”都费劲。典型流程是上电后ROM代码加载引导程序U-BootU-Boot初始化DDR和基本外设加载设备树二进制文件dtb和内核镜像Image然后跳转到内核入口。内核启动后会根据设备树初始化各个平台设备挂载根文件系统最后启动init进程。调试启动阶段最常见的问题是串口没有输出。这个问题90%是设备树中串口节点的clock-frequency属性和实际串口时钟不一致导致的。很多人会怀疑内核镜像坏了或者U-Boot配置错了实际上查一下设备树里uart节点的时钟频率和板级原理图对比问题立刻暴露。根文件系统的选择上我只推荐两条路。开发阶段用NFS挂载方便快速迭代发布阶段用SD卡或eMMC上的ext4根文件系统加uboot的initramfs支持。hs_dma_framework的采集应用要做成系统服务通过systemd托管开机自动加载驱动、启动采集进程。arm64v8相关的容器镜像如果项目要用到也可以在ARM64平台直接跑省去很多依赖编译的麻烦。6. 仿真、实测与性能调优6.1 FPGA侧Testbench怎么搭FPGA逻辑的验证不能等到上板再发现问题。hs_dma_framework的FPGA部分我习惯在Vivado/Quartus里建一套规范的Testbench把AXI4-Stream的DMA写引擎、描述符队列维护逻辑、以及模拟ADC的数据源全部虚拟化。Testbench的核心思路是模拟AXI总线时序。写一个简单的AXI4-Stream主设备模型每隔几个时钟周期推出一拍数据模拟真实ADC的采样节奏。同时用AXI4-Lite从设备模型去配置DMA引擎的寄存器。仿真时用VCD波形文件记录关键信号重点关注write pointer、read pointer、FIFO水位这几个变量确保描述符队列不会出现空转或重复执行。带中断的仿真还有一个细节ARM侧的Linux驱动在仿真环境里跑不通所以Testbench要自己模拟中断的产生和清除流程。可以写一个自动检查描述符完成状态的逻辑发现描述符完成标志置位后自动拉高中断信号几个周期模拟真实驱动读取并清除中断寄存器的行为。这样上板之后驱动和FPGA配合的稳定性很大程度上已经被提前验证过了。6.2 实测吞吐率与CPU占用平台跑通之后一定要做量化测试不能只满足于“数据不丢”。我的测试方法是构造三档负载第一档用FPGA内部计数器生成固定格式的伪随机数据不接真实ADC第二档接信号发生器出正弦波通过ADC量化后再采集第三档接双通道真实传感器做长时间持续采集。实测数据供参考在四核ARM64主频1.5GHz的平台下DMA描述符队列深度256单块缓冲区1MB持续采集中断频率约200次每秒系统CPU占用率约三分之一核内存带宽占用约150MB/s时没有丢帧。把缓冲区改小到64KB时中断频率骤升到3000次每秒CPU占用率翻了差不多三倍。这说明DMA缓冲区大小对系统性能的影响是决定性的一定要根据实际采集数据率和突发特性来权衡。还要测长时间稳定性。我曾经碰到过连续跑两天后DMA突然停摆的现象后来原因定位到描述符队列索引溢出——软件侧搞混了无符号整数的环绕逻辑。这种问题在短时间测试中根本暴露不了所以稳定性测试至少要保持48小时以上。6.3 性能瓶颈定位与参数调整如果实测吞吐率上不去不要急着改代码。用Linux的perf top先看热点在哪里很多时候瓶颈根本不在DMA本身。我遇到过的瓶颈主要有三类。第一类是中断处理路径太长中断里做了太多内联处理解决办法是把工作量移交到中断线程里。第二类是用户态轮的太频繁应用为了尽快拿到数据用100%的CPU跑忙等办法是把轮询间隔和DMA中断频率对齐尽量让应用在数据就绪后才醒来。第三类最隐蔽是用户态到内核态的缓冲区同步操作太频繁ARM64上执行cache操作的代价其实很高进入DMA前如果还要对整块缓冲区做invalid操作数据率上去了开销就很可观。这种情况下宁可多留余量让DMA只write并信任DMA_BIDIRECTIONAL标志的处理也不要动不动全缓冲invalid。调参我是这样做的先固定描述符数量扫一遍缓冲区大小从64KB到4MB的性能曲线曲线平台期再反过来固定缓冲区大小扫描述符数量。这样两个维度扫完之后基本能找到当前平台的甜点参数。7. 踩过的坑和应对方法7.1 DMA地址对齐问题这个坑几乎是所有自研DMA框架的梦魇。AXI总线的DMA要求源地址和目标地址按burst长度对齐常见的是32字节或64字节对齐。如果你的描述符里填的目标地址没有对齐DMA写传输要么直接报错要么默默丢掉头部几个字节数据错位还不知道哪里错的。解决办法是驱动分配缓冲区时强制对齐。Linux的dma_alloc_coherent返回的地址本身就是对齐的但如果你在用户态通过mmap再偏移使用就要小心偏移量破坏了原始对齐。我后来索性用了页对齐的缓冲区池每次从池子里取整块4KB或64KB的区域确保任何分包组合都能保持对齐。7.2 中断风暴与NAPI思路DMA设计得越高效中断频率反而可能越低但如果遇到极端场景比如短促高频的突发数据中断频率就会瞬间飙升把系统卡死。Linux网络子系统有NAPI机制专门解决这个问题——中断到来时先关闭中断用轮询方式把一整批数据处理完处理清了再重新开启中断。hs_dma_framework的驱动也借鉴了这个思路。采集突发数据时中断处理函数只把当前的描述符链表挂到待处理队列然后立刻调度一个内核线程去批量处理。如果下一轮检查发现待处理队列还有数据就继续处理不需要再等新中断进来。效果非常明显突发场景的中断次数下降了将近一个数量级。7.3 多Die FPGA的约束问题用到中大型FPGA时跨Die布线会带来一系列让入时序收敛失败的问题。多Die芯片的每个Die都有独立的可编程资源和路由资源Die之间通过有限的Super Logic Region互连跨Die信号多了布线资源紧张时序自然崩。处理办法是提前在引脚规划阶段就把数据通路限定在单一Die内。DMA引擎和它对应的AXI总线接口、FIFO务必放在同一个Die跨Die的信号只保留低频率的控制信号和中断信号。这需要在工程的floorplanning阶段就做约束后期再改是非常痛苦的返工。另一个技巧是给跨Die信号加上同步寄存器打两拍再进逻辑避免亚稳态问题。7.4 板级调试的一点经验最后说一个容易忽略的细节电源质量对高速采集系统的影响。FPGA内部有大量高速翻转的逻辑如果电源纹波超标采样时钟的抖动会变大采集数据的信噪比会肉眼可见地变差。做hs_dma_framework实测时我试过把FPGA核心供电的DCDC开关频率调低采样底噪立刻抬高了将近3dB。所以平台调试时不要光盯逻辑模拟电源的余量也值得花时间检查。另外一个习惯是给每块板卡预留JTAG和逻辑分析仪的测试点FPGA侧的ILA核、ARM侧的trace工具都提前留好接口。项目进行到后期80%的时间都花在定位问题上不说瞎话尽早把调试基础设施准备全后面会感激现在的自己。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门