板子回来,代码烧进去,不工作。想抓几个内部信号看看,发现调试引脚不够用。BGA封装飞线不现实,重新改板更不现实。这时候,能不能把板上已有的调试引脚复用起来,往往决定了调试周期是三天还是三周。
复用debug pin的核心思路很简单:不增加新引脚,把已有引脚当成一个“通道”,用协议或时分复用的方式传输调试信息。下面按从易到难的顺序,说几种实际项目中常用的做法。
一、先盘点:板上到底有哪些“现成通道”
别急着写代码,先把板子上的资源列一遍。常见的可复用对象包括:
JTAG接口:最优先考虑,因为ILA和VIO根本不占用物理引脚
UART:很多板子预留了串口,哪怕只焊了排针
LED和按键:虽然原始,但信息量可以做得很大
SPI/I2C:如果系统里有这些总线,可以挂调试寄存器
未使用的IO或测试点:有些板子会留几个空焊盘
排针或扩展口:尤其是开发板,通常会引出不少IO
盘点之后你会发现,大多数项目其实不缺调试通道,缺的是提前规划。
二、用JTAG做虚拟引脚:最省事的一条路
如果板上有JTAG,优先用ILA和VIO。它们不需要额外引脚,通过JTAG就能实时观测和激励内部信号。
ILA适合抓波形,VIO适合读写寄存器、改参数、触发状态机。比如一个图像处理项目,上板后画面偶尔花屏。在Vivado里例化一个VIO,把行缓冲的写指针和读指针挂上去,再挂一个手动触发的复位。一边跑一边看指针差值,几分钟就定位到是复位释放时序不对。
VIO的缺点是会占用一些逻辑资源,而且依赖JTAG连接。但对于实验室调试来说,这是性价比最高的方式。
三、UART复用:把状态“打印”出来
如果JTAG不可用,或者需要长时间跑稳定性测试,UART是最实用的选择。很多FPGA项目本来就有UART,哪怕没有,两根线也能临时接出来。
复用UART的关键是:别让它干扰原有功能。如果UART是系统正常通信用的,可以加一个调试模式开关。调试模式下发状态,正常模式下走业务数据。或者用时分复用,在空闲间隙插入调试帧。
一个简单的状态上报模块大概长这样:
上位机用一个简单的串口助手就能看。如果嫌ASCII解析麻烦,直接发二进制,Python几行代码就能解析成曲线。
四、LED和按键:别看不起眼,信息量可以很大
只有LED的时候怎么办?用状态编码。比如8个LED,可以表示256种状态。把关键状态机的当前状态、错误码、计数器高位映射到LED上,上板后一眼就能看出卡在哪一步。
按键也可以复用为调试输入。比如按一下切换调试模式,按两下触发一次软复位。用边沿检测和计数器就能实现,代码量很小。
五、复用已有总线:把调试寄存器挂上去
如果系统里有SPI或I2C,可以挂一个调试从机。主控通过读写寄存器来获取内部状态。这种方式适合已经有一个处理器或MCU在管理系统的场景。
比如在I2C从机地址空间里划出几个寄存器:一个放状态机状态,一个放错误计数,一个放版本号。调试的时候用I2C工具读一下就行,不需要额外接线。
六、复用时的几个坑
复用引脚听起来简单,但有几个地方容易翻车。
第一,不能破坏原功能。调试逻辑必须在不需要的时候能完全移除,或者至少不影响原路径的时序。建议用宏定义或参数来控制是否综合调试逻辑。
第二,注意电平和驱动能力。原有引脚可能是1.8V,你接的调试工具可能是3.3V。直接连可能烧芯片。
第三,避免毛刺和冲突。如果调试信号和原功能信号共用同一个引脚,必须用多路选择器干净地切换,不能出现两个驱动同时打开的情况。
第四,时序约束要跟上。复用引脚上的调试信号如果跨时钟域,同样需要同步处理,不能因为是“调试”就随便写。
七、一点实际经验
在由你创科技参与的一些项目中,硬件工程师会在引脚规划阶段就留出复用可能。比如把UART的TX/RX同时接到排针和调试芯片,把几个LED接到状态机的关键位上。这些动作在画板阶段只多花几分钟,但调试阶段能省下大量飞线和改板时间。
调试引脚这件事,最怕的就是“等出问题了再想办法”。提前规划、复用已有通道、把调试逻辑做成可插拔的模块,才是真正节约时间的做法。如果你正在规划一块新板子,不妨在引脚分配表里多留一列:这个引脚,调试的时候能不能复用?