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

DSP与FPGA的XINTF异步通信:时序收敛与跨时钟域设计实战

简介这是一份面向DSP与FPGA协同开发者的XINTF异步通信完整工程资料适用于需要实现TMS320C6x系列DSP与FPGA高速数据交互相关的硬件工程师、嵌入式软件工程师及电子类专业学生。内容深入讲解XINTF接口配置、跨时钟域同步、握手协议、FIFO缓冲和验证方法可帮助读者快速搭建稳定通信框架规避异步传输中的常见问题。压缩包内共308个文件约5.39MB以Quartus工程文件为主包含97个cdb工程数据库文件、12个tdf设计文件、4个v/vho硬件描述文件、4个txt说明文档以及sof、qsf、qpf、bdf等FPGA配套工程与配置文件便于直接打开工程查看顶层设计与仿真结果。当前已有1367人学习下载资源内还提供readme说明和详细工程目录适合正在调试DSP与FPGA通信、希望从工程实例入手理解XINTF时序与同步机制的中高级开发者参考使用。1. 一片板子上DSP与FPGA为什么要用XINTF异步通信之前拆过一套DSP和FPGA协同处理的板卡DSP跑控制算法FPGA管前端采样和IO扩展两者之间的通信既没用PCIe也没用串口而是走了TI的XINTF。这是一种典型的本地并行异步总线DSP侧直接按地址读写FPGA侧只需要把总线时序解析成内部寄存器或FIFO操作。相比SPI、UARTXINTF一拍能传16位或32位延迟可以做到纳秒级而且不需要复杂协议栈。这套方案的核心难点不在“把线连上”而在异步时钟下的时序收敛。DSP的XINTF输出时钟、FPGA内部逻辑时钟通常来自两个晶振跨时钟域读写很容易出现偶发错字。工程里通用的做法是FPGA侧用一个同步状态机把XRD/XWE时序转换成读写脉冲再通过握手信号和异步FIFO与内部模块对接。这也是本次拆解的重点。如果你正被“DSP写进FPGA的数据偶尔不对”“FPGA回的FIFO空满标志跳变”这类问题困扰下面会从时序寄存器配置、FPGA侧读写桥、跨时钟域处理、Quartus工程约束和整机调试五个环节完整说一遍。适合正在做C2000/C6000与FPGA联调的硬件工程师也适合刚入门并行总线设计的同学。2. XINTF总线时序拆解与FPGA侧读写桥设计2.1 XINTF引脚定义与FPGA侧信号映射XINTF的引脚在DSP端是一组并行总线FPGA端看到的基本可以归纳为几类数据线、地址线、片选、读写选通和等待信号。下面这张表是一个16位XINTF从设备最常见的信号集合也是Quartus工程里BDF顶层图上实际出现的端口。信号名方向以FPGA为参考作用XD[15:0]输入/输出16位数据总线读写共用XA[15:0]输入地址总线DSP通过它访问FPGA内部寄存器或FIFOXZCS0n/XZCS6n/XZCS7n输入片选信号对应DSP映射的不同ZoneXRDn输入读选通低有效XWEn输入写选通低有效XREADYn输出等待信号低有效会让DSP插入等待周期XCLKOUT输入XINTF参考时钟可用于FPGA侧同步总线信号FPGA端的设计思路很明确XRDn和XWEn都是异步输入不能直接当成寄存器时钟沿。项目里DSP_XINTF.v这个源文件做的事情就是把异步总线翻译成FPGA内部时钟域下的单周期读写脉冲并维护一组地址映射。需要注意DSP访问的地址是Zone基地址加偏移量FPGA只关心偏移地址部分比如XA[7:0]剩下的高位地址用于片选译码FPGA内部可以不关心。2.2 DSP侧时序寄存器lead、active、trail三个参数决定总线波形XINTF是异步接口DSP侧的访问时序由一组时序寄存器控制。以C2000系列常见的Zone2为例需要配置读和写各自的XRDLEAD、XRDACTIVE、XRDTRAIL以及对应的写参数。这三个值分别对应选通信号拉低前后的建立时间、低电平脉宽、恢复时间单位是XINTF外设时钟周期。// 以TMS320F28335的XINTF Zone2配置为例 // 头文件中的位域名以TI官方DSP2833x_GlobalPrototypes.h为准 XintfRegs.XTIMING2.bit.XRDLEAD 3; // 读选通拉低前的建立周期 XintfRegs.XTIMING2.bit.XRDACTIVE 7; // 读选通低电平保持周期 XintfRegs.XTIMING2.bit.XRDTRAIL 3; // 读选通拉高后的恢复周期 XintfRegs.XTIMING2.bit.XWRLEAD 3; XintfRegs.XTIMING2.bit.XWRACTIVE 7; XintfRegs.XTIMING2.bit.XWRTRAIL 3; XintfRegs.XTIMING2.bit.X2TIMING 1; // 使用XTIMING2寄存器这段代码的含义是每次读操作XRDn先保持高电平3个周期再拉低7个周期再拉高3个周期写操作同理。FPGA侧设计读写桥时要保证自己的状态机在这组时间窗口内完成数据采样和输出。XRDACTIVE太短FPGA可能来不及把数据送上总线太长则会拖慢整机访问速度。实际调试时我一般先用较大的XRDACTIVE跑通功能再用逻辑分析仪逐步压小。提示如果FPGA侧逻辑比较复杂读数据需要多个周期才能准备好不要盲目加大XRDACTIVE应该使用XREADY信号通知DSP插入等待。后面第四章会讲怎么接。2.3 FPGA侧读写桥同步、沿检测、三态数据总线FPGA侧拿到XRDn、XWEn之后第一件事是把它们用本地时钟打两拍避免亚稳态。第二件事是检测下降沿和上升沿产生单周期读写脉冲。第三件事是控制XD双向引脚读操作时输出数据写操作时释放总线。module xintf_bridge #( parameter AW 8, parameter DW 16 )( input wire clk, // FPGA采样时钟由PLL产生 input wire rst_n, input wire xcs_n, // XINTF片选低有效 input wire xrd_n, // 读选通低有效 input wire xwe_n, // 写选通低有效 input wire [AW-1:0] xa, // 地址 inout wire [DW-1:0] xd, // 双向数据总线 output reg [AW-1:0] wr_addr, // 写地址 output reg [DW-1:0] wr_data, // 写数据 output reg wr_pulse, // 写脉冲 output reg rd_pulse // 读脉冲 ); reg xrd_n_s1, xrd_n_s2; reg xwe_n_s1, xwe_n_s2; // 两级同步消除跨时钟亚稳态 always (posedge clk or negedge rst_n) begin if (!rst_n) begin xrd_n_s1 1b1; xrd_n_s2 1b1; xwe_n_s1 1b1; xwe_n_s2 1b1; end else begin xrd_n_s1 xrd_n; xrd_n_s2 xrd_n_s1; xwe_n_s1 xwe_n; xwe_n_s2 xwe_n_s1; end end // 下降沿读申请开始 wire xrd_fall xrd_n_s2 ~xrd_n_s1; // 上升沿写数据在此时已经稳定 wire xwe_pos xwe_n_s1 ~xwe_n_s2; always (posedge clk or negedge rst_n) begin if (!rst_n) begin wr_addr {AW{1b0}}; wr_data {DW{1b0}}; wr_pulse 1b0; rd_pulse 1b0; end else begin wr_pulse 1b0; rd_pulse 1b0; if (!xcs_n xwe_pos) begin wr_pulse 1b1; wr_addr xa; wr_data xd; // 上升沿时XINTF数据总线已稳定 end if (!xcs_n xrd_fall) begin rd_pulse 1b1; end end end // 读数据输出直接组合逻辑送三态总线 wire [DW-1:0] rd_data 16hA5A5; // 实际工程中根据xa地址读取寄存器 assign xd (!xcs_n !xrd_n_s2) ? rd_data : {DW{1bz}}; endmodule这段代码里xrd_n_s1/xrd_n_s2和xwe_n_s1/xwe_n_s2是打拍后的同步信号后续所有判断都基于同步信号不再直接使用异步引脚。xrd_fall用于检测DSP开始读xwe_pos用于检测DSP写结束这时数据总线上的写数据已经过了DSP侧保持时间FPGA采集最稳。rd_data在示例中直接返回常量真实项目里应该根据xa地址译码出FPGA内部寄存器或FIFO读取结果。需要注意的是读数据输出用的是组合逻辑FPGA内部寄存器信号经过组合逻辑后送到XD引脚路径延迟会叠加如果XINTF总线速率高建议在rd_data路径上加一级寄存器并通过增大XRDACTIVE或使用XREADY补偿这一拍延迟。3. 跨时钟域处理握手协议、两级同步器与异步FIFO3.1 为什么必须处理时钟域DSP与FPGA的相位关系XINTF异步通信最容易被忽略的部分就是时钟域。DSP的XCLKOUT和FPGA逻辑时钟来自不同晶振时两个时钟的上升沿位置会缓慢漂移严格来说不是固定的相位关系。如果FPGA直接拿本地时钟去采样总线上的地址、数据和控制信号就可能采到正在翻转的中间电平进而产生亚稳态导致偶发错误。解决思路分两路控制类信号用同步器打拍处理数据类信号用异步FIFO隔离。控制信号比如片选、读写选通它们变化频率低打两拍就能大幅降低亚稳态概率。数据信号比如XD总线如果DSP写入的数据直接进FPGA内部逻辑数据位之间还可能有skew多位数据不适合单纯打拍最好通过异步FIFO或双口RAM过渡。3.2 两级同步器处理单bit控制信号的亚稳态项目中最常用的同步单元就是两级寄存器。第一级寄存器输出可能仍处于亚稳态但经过一个时钟周期后第二级寄存器采到稳定值的概率已经足够高。对XINTF这类低速异步总线两级同步器完全够用。module sync_cell #( parameter DW 1 )( input wire clk, input wire rst_n, input wire [DW-1:0] async_in, output wire [DW-1:0] sync_out ); reg [DW-1:0] sync_reg1; reg [DW-1:0] sync_reg2; always (posedge clk or negedge rst_n) begin if (!rst_n) begin sync_reg1 {DW{1b0}}; sync_reg2 {DW{1b0}}; end else begin sync_reg1 async_in; sync_reg2 sync_reg1; end end assign sync_out sync_reg2; endmodule这里async_in来自XINTF总线信号sync_out进入FPGA内部逻辑。注意两级同步器只适合单bit信号。如果要对多位地址总线做同步不能直接套这个模块否则多个bit在跨时钟时变化时刻不一致采样结果会组合出非法值。实际项目中地址和控制信号经过同步后再译码数据走FIFO这是最不容易出问题的组合。3.3 异步FIFO数据跨时钟域的可靠通道当DSP连续向FPGA写入一批数据或者FPGA要向DSP回传采集结果时FIFO是标准解。异步FIFO的读写时钟完全独立读指针和写指针分别在自己的时钟域变化通过格雷码跨时钟同步空满状态。参数上最关心的只有两个数据宽度和深度。参数典型值说明DSIZE16 / 32与XINTF数据总线宽度一致ASIZE9 ~ 12地址位宽FIFO深度为2^ASIZE写侧时钟XINTF读写桥时钟DSP访问时产生的写脉冲作为winc读侧时钟FPGA内部业务时钟消费数据的模块时钟满标志wfull同步到写时钟域防止写溢出空标志rempty同步到读时钟域防止读空下面是工程里的例化模板端口命名对应常见的Xilinx/Quartus异步FIFO IPxintf_fifo #( .DSIZE(16), .ASIZE(11) ) u_fifo ( .wclk (clk_xintf_bridge), // 写时钟来自XINTF读写桥 .wrst_n (rst_n), .winc (fifo_wr_en), // XINTF写脉冲有效时拉高 .wdata (xintf_wr_data), // DSP写入的数据 .rclk (clk_fpga_core), // 读时钟FPGA业务模块时钟 .rrst_n (rst_n), .rinc (fifo_rd_en), // 业务模块读使能 .rdata (fifo_rd_data), .wfull (fifo_wfull), .rempty (fifo_rempty) );winc信号一般直接接XINTF桥产生的wr_pulse每来一个脉冲写一个数据。rinc则由FPGA内部消费模块产生取出数据后根据FIFO空标志决定是否继续读。调试时最容易出现的错误是忽略空满标志的同步延迟wfull从读时钟域同步到写时钟域需要几个周期所以写侧看到wfull0只代表FIFO大概率还没满保守做法是在快满时提前停写或者预留深度余量。提示DSP访问FPGA寄存器时每次读写的数据量很小不建议用FIFO。这时应该用寄存器堆加握手协议。只有批量数据搬运才走异步FIFO。项目里一般把两类地址分区低地址映射寄存器高地址映射FIFO。4. 在Quartus工程中把XINTF控制器、PLL和约束文件接起来4.1 从工程文件还原可编译的BDF项目压缩包里出现的文件其实是一个完整的Quartus工程在某个中间版本留下的产物。DSP_FPGA.bdf是顶层原理图DSP_XINTF.v是Verilog源文件DSP_XINTF.bsf是它的原理图符号pll.bsf是PLL的可调用符号.ammdb和.cmp.ammdb是Quartus自动生成的工程数据库和编译数据库。拿到这些文件后直接打开DSP_FPGA.bdf可能因为缺少工程配置而报错正确步骤是先新建工程再添加源文件。我一般这样还原新建Quartus工程顶层实体名设为DSP_FPGA将DSP_XINTF.v复制到工程目录并添加到工程如果DSP_XINTF.v只有.v.bak备份需要改名为DSP_XINTF.v再添加。然后打开DSP_FPGA.bdf确认里面调用的元件符号是否存在。PLL部分必须重新生成双击bdf里的PLL符号在Megawizard中重新配置参数输出pll.v和pll.bsf否则编译流程会在Analyze时提示找不到宏功能模块。4.2 PLL参数设置与采样相位选择FPGA侧采样DSP总线信号时采样时钟频率不必和XCLKOUT完全一致但至少要保证在一个读或写周期内有足够的采样点数。常见做法是把板载晶振通过PLL倍频到100MHz左右然后用这个时钟驱动XINTF桥逻辑。PLL参数可以参考下表参数建议值说明输入时钟50MHz板载有源晶振或DSP输出的XCLKOUT倍频系数2 ~ 4输出100MHz或200MHz相移0° / 90°0°采样90°用来避开数据翻转窗口c0输出100MHz驱动XINTF桥和异步FIFO写侧为什么要单独关注相移DSP在XRDn下降沿后过一段时间才把数据驱动到XD总线FPGA如果恰好在这个翻转点采样就会采到毛刺。把采样时钟相位移到数据稳定区间比单纯提高频率更有效。实际调整时用SignalTap II观察XD总线和内部采样寄存器的相对关系找到最安全的相位即可。4.3 时序约束set_input_delay 与 set_output_delayXINTF总线不约束也能编译但时序分析结果不可信。Quartus工程里可以添加一个SDC文件把XINTF桥相关引脚约束成跨时钟域接口。下面是简化版SDC只覆盖核心路径# 定义两个异步时钟FPGA本地时钟与XINTF桥采样时钟 create_clock -name xc_clk -period 20.0 [get_ports {clk_50m}] create_clock -name xintf_samp_clk -period 10.0 [get_ports {pll_c0}] # 两个时钟之间没有固定相位关系设为异步 set_clock_groups -asynchronous \ -group [get_clocks {xc_clk}] \ -group [get_clocks {xintf_samp_clk}] # 输入信号相对采样时钟的延迟窗口 set_input_delay -clock xintf_samp_clk -max 14.0 [get_ports {xa[*] xrd_n xwe_n xcs_n}] set_input_delay -clock xintf_samp_clk -min 2.0 [get_ports {xa[*] xrd_n xwe_n xcs_n}] # 输出数据总线相对采样时钟的延迟 set_output_delay -clock xintf_samp_clk -max 10.0 [get_ports {xd[*]}] set_output_delay -clock xintf_samp_clk -min 1.0 [get_ports {xd[*]}]set_input_delay告诉时序分析工具外部信号在采样时钟沿前多久到达。最大值根据DSP输出时序和PCB走线估算一般取10~15ns。set_output_delay约束FPGA输出到DSP的数据路径XD是三态总线这里的约束同时影响输出使能路径。如果编译后时序报告显示这些路径slack为负不要盲目改约束值先回头检查PLL相位和上一章的同步器设计。4.4 三态总线与多驱动问题的排查XD数据总线在FPGA内部只能有一个模块驱动。容易犯的错误是XINTF桥模块内部定义了assign xd ...而BDF顶层原理图又把XD引脚直接连到了另一个模块的输出。Quartus在Compilation期间会报“Multiple driver”或“pin has multiple drivers”错误。解决办法是把XD总线在顶层只连接一个inout端口XINTF桥模块内部通过三态门控制驱动方向。使用{DW{1bz}}释放总线时要确保读写选通和片选条件同时成立后再驱动数据否则FPGA引脚会与DSP总线上的其他驱动源冲突严重的会损坏引脚。调试时用万用表量XD引脚电压若出现零伏或半电平基本就是多个驱动同时使能了。5. 用SignalTap、CCS和连读连写验证XINTF时序拿到可以编译的工程后先不要急着写业务逻辑。把DSP当作一个主设备FPGA当作一个寄存器从设备做一轮最基础的连读连写验证。在Quartus里用SignalTap II抓xrd_n_s2、xwe_n_s2、xa、xd、wr_pulse、rd_pulse这几个信号触发条件设为xcs_n 0就能看到DSP访问FPGA的完整波形。重点看两个地方写数据是否在xwe上升沿稳定读数据是否在xrd下降沿后及时出现在xd总线上。DSP侧用CCS写一段简单的回环测试对固定地址写一个特征值再读回来连续循环1024次。下面是常用模板volatile Uint16 *xintf_zone2 (volatile Uint16 *)0x00200000; Uint16 test_val 0x55AA; Uint16 rd_val; Uint32 err_cnt 0; for (Uint32 i 0; i 1024; i) { *(xintf_zone2 0x100) test_val; rd_val *(xintf_zone2 0x100); if (rd_val ! test_val) { err_cnt; } test_val ~test_val; }这段代码每次改变pattern如果读回值和写入值不一致说明时序或者地址映射有问题。最容易出现的现象是偶数次错误这往往不是FPGA逻辑错误而是XRDACTIVE太短导致读数据还没稳定。此时应该先调整DSP侧XINTF时序寄存器再把FPGA侧采样时钟相位调整到数据窗口中央。现象可能原因调整方向写寄存器偶发失败xwe上升沿采样点偏早增加XWRACTIVE或把采样时钟相位后移读数据回读全为0rd_data输出路径太慢增大XRDACTIVE或读数据加一级流水前几次读写正常突发后错乱FIFO写满被覆盖检查wfull是否接入写使能门控系统上电后第一次访问卡死同步器复位状态不对确认rst_n覆盖所有同步寄存器最后一轮调试时如果固定地址的单次访问已经稳定可以继续对连续地址做incr读写把FPGA内部的地址译码错误和FIFO读写指针问题暴露出来。比如让DSP从0x100到0x10F依次写递增数FPGA收到后通过另一个寄存器回读在CCS里比对连续值。这样能同时验证aw addr锁存和wr_pulse时序。真正的高频偶发错误建议把XINTF的XREADYn信号接上而不是完全靠时序参数硬扛。FPGA里用同步后的xrd/xwe产生一个准备信号XREADY拉低让DSP自动插入等待周期。这样即使FPGA逻辑增加了一个周期的处理时延DSP总线也能保持稳定比反复缩小参数要省事得多。本文还有配套的精品资源点击获取
分享:

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

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