作者:bt(CSDN)
本文配套源码工程已上传至https://download.csdn.net/download/botao_li/10907037
AXI_STREAM的时序
AXI_STREAM接口一般用于大规模持续的无地址映射关系的流数据传输
数据从master单向流动至slave,
参考自定义IP生成的示例代码进行说明
master端接口如下:
// Master Stream Ports. TVALID indicates that the master is driving a valid transfer, A transfer takes place when both TVALID and TREADY are asserted. output wire M_AXIS_TVALID, // TDATA is the primary payload that is used to provide the data that is passing across the interface from the master. output wire [C_M_AXIS_TDATA_WIDTH-1 : 0] M_AXIS_TDATA, // TSTRB is the byte qualifier that indicates whether the content of the associated byte of TDATA is processed as a data byte or a position byte. output wire [(C_M_AXIS_TDATA_WIDTH/8)-1 : 0] M_AXIS_TSTRB, // TLAST indicates the boundary of a packet. output wire M_AXIS_TLAST, // TREADY indicates that the slave can accept a transfer in the current cycle. input wire M_AXIS_TREADY
slave端接口如下:
// Ready to accept data in output wire S_AXIS_TREADY, // Data in input wire [C_S_AXIS_TDATA_WIDTH-1 : 0] S_AXIS_TDATA, // Byte qualifier input wire [(C_S_AXIS_TDATA_WIDTH/8)-1 : 0] S_AXIS_TSTRB, // Indicates boundary of last packet input wire S_AXIS_TLAST, // Data is in valid input wire S_AXIS_TVALID
在master端:
M_AXIS_TDATA, M_AXIS_TSTRB, M_AXIS_TLAST信号全部与M_AXIS_TVALID同步,在M_AXIS_TVALID与M_AXIS_TREADY同时为1的情况下完成M_AXIS_TDATA的一次传输
M_AXIS_TLAST用于指示此次流传输的最后1个M_AXIS_TDATA
在slave端:
在S_AXIS_TREADY和S_AXIS_TVALID都为1时取用数据
S_AXIS_TSTRB用于指示当前S_AXIS_TDATA内的有效字节,S_AXIS_TLAST表示此次流传输结束,根据功能需要执行流传输结束的相应处理
代码实现时,master和slave主要通过tvalid和tready相互配合完成传输,可以在master端先设置tvalid为1等待slave端的tready,也可以slave端将tready设置为1等待master端的tvalid
注意:
• 由于PS模块的AXI接口是地址映射接口,如果PL需要通过axi_stream与PS进行数据传输,则需要经由dma模块进行axi_stream与axi_full传输协议的相互转化
• 在AXI术语中,TVALID指示有效的TDATA被正确响应表示一次Burst,多个Burst组成1个Packet,Packet中用TLAST表示最后1个Burst对应的TVALID位置
AXI Direct Memory Access
axi_dma用于实现axi_stream流传输的地址映射
在Block Design中加入axi_dma模块,进行如下图所示的配置
• Scatter Gather Engine用于散内存传输,使用连续的虚拟内存地址映射至非连续的物理内存地址,效率较低并且使用更复杂,暂不研究
• Micro DMA是简化的DMA,暂不研究
• Width of Buffer Length Register是DMA的32位传输长度寄存器中用于表示一次传输(Transfer)字节数目的位数,上图配置为10,表示调用传输函数一次最大传输的数据量为210-1字节
• Max Burst Size表示axi_dma模块所有AXI接口可接受的最大的Burst数目,只有小于该值的Burst数目的传输才能被axi_dma模块正确解析
在Block Design中的axi_dma端口如下:
• S_AXI_LITE:用于与PS端的AXI Master连接,接收PS的控制指令,执行DMA写入或者DMA接收
• S_AXIS_S2MM:axi_dma模块的写接口,将数据从PL发送给PS
• M_AXIS_MM2S:axi_dma模块的读接口,将数据从PS送入PL
• M_AXI_S2MM:与PS的AXI SLAVE连接,用于PL向PS写入数据
• M_AXI_MM2S:与PS的AXI SLAVE连接,用于PL读入PS数据
• s2mm_introut:完成一次数据从PL发送给PS的Transfer后产生的中断信号,连接PS的PL中断接口
• mm2s_introut:完成一次数据从PS送入PL的Transfer后产生的中断信号,连接PS的PL中断接口
注意:
mm表示memory mapped,即内存映射,代表AXI_FULL协议,对应PS端的AXI接口
s表示stream,代码AXI_STREAM协议
AXIS中的S表示Stream
数据由PL至PS的工作流程:S2MM
① PS通过S_AXI_LITE接口送入指令,指令包含目标内存地址,即memory map
② S_AXIS_S2MM的s_axis_s2mm_tready信号拉高,允许数据进入axi_dma模块,外部与之连接的MASTER可以通过该tready信号判断写入时机
③ M_AXI_S2MM按照AXI_FULL的协议,用写指令将数据送给PS模块
数据由PS至PL的工作流程:MM2S
① PS通过S_AXI_LITE接口送入指令,指令包含数据源内存地址,即memory map
② M_AXI_MM2S按照AXI_FULL的协议,用读指令从PS模块中读出数据
③ M_AXIS_MM2S将m_axis_mm2s_tvalid信号拉高,表示有数据可以送出,外部与之连接的SLAVE可以通过该tvalid信号判断读出时机
AXI4-Stream Data FIFO
axi_dma不具备数据缓冲的能力,高速数据传输时PL很难完全配合PS发送DMA指令的时机,因此需要使用FIFO进行数据缓冲
本实验对PL至PS的数据进行FIFO缓冲
在Block Design中加入AXI4-Stream Data FIFO模块,进行如下图所示的配置
• Enabele Packet Mode表示按Packet传输,见AXI_STREAM的时序说明
• Signal Porperties与FIFO出入数据的AXI接口对应就可以了
• TID,TDEST,TUSER暂不考虑
在Block Design中的模块端口如下:
• S_AXIS:数据写接口,FIFO可写入的情况下s_axis_tready信号会拉高,只要对端MASTER送入s_axis_tvalid高电平即可以进行数据写入
• M_AXIS:数据读接口,FIFO数据可读出的情况下m_axis_tvalid信号会拉高,只要对端SLAVE送入m_axis_tready高电平即可进行数据读取
• 读接口Packet中的Burst数目与写接口保持一致
自定义数据源IP
在Vivado的Tools菜单,选择Create and Package New IP,建立Create a new AXI peripheral
根据之前文档的说明建立AXI STREAM协议的Master接口模块
代码如下:注意第39行及其注释,见[Block Design中的说明](#完整Block Design)
关于上述代码有以下几点说明:
• module关键字后接#的方式声明parameter可以让parameter被Block Design识别,在Block Design双击模块可以对parameter进行数值设置
• 无论输入输出端口都必须加上wire关键字声明
• 上述代码第163行的cnt_burst与BURST_NUM_M1的比较不能在比较代码中用计算公式
- 使用(BURST_NUM-8’d1)进行比较,可以正确仿真,但是Block Design的解析可能对计算进行了扩位,导致比较永不成立,无法出现Packet要求的tlast
- tlast不存在,会导致axi_dma进行s2mm传输时出现Transfer指令后虽然可以接收数据但是无法结束的情况(在dma的状态寄存器SR中出现DMAIntErr),参考https://forums.xilinx.com/t5/Embedded-Processor-System-Design/AXI-DMA-wi...
配置PS模块
向Block Design添加Zynq模块,配置AXI端口
完整Block Design
上述设计有以下几点说明:
1. 各模块的AXI接口由于模块本身设计可能不完全匹配,不是Master连Slave就可以正确工作的。尤其对于tkeep或者tstrb之类的信号,前者表示Packet中最后1个Burst中tdata总线上哪几个字节有效,如果传输数据量并非tdata字节数的整数倍则需要使用;后者表示每个Burst中tdata总线上哪几个字节有效。比如:上述设计中FIFO模块的M_AXIS不包含tkeep信号,而axi_dma模块的S_AXIS_S2MM包含tkeep,因此需要将axi_dma模块的s_axis_s2mm_tkeep连接常数4’b1111
2. axi_dma模块2个传输完成中断合并后接入PS的PL中断输入接口,方便PS编程处理
3. S2MM传输的数据源和FIFO连接axi_dma模块的s2mm_prmry_reset_out_n复位信号(见Block Design中的紫色高亮信号线),理由如下:
① 注意注意:axi_dma模块S2MM传输的全部数据量对于其S_AXIS_S2MM端口而言必须是1个完整的Packet,完成的标志即s_axis_s2mm_tlast出现高电平,如果此时数据量不足PS传输指令的数据量,传输仍然结束并且通过dma的buffer length寄存器返回已传输的数据量
② axi_dma模块内部S2MM通道可以缓冲16字节的数据量,即复位结束后通过s_axis_s2mm_tready高电平可以收入16字节数据,如果数据源或者FIFO的复位与S2MM通道复位不同步,则axi_dma模块复位后数据可能丢失,而数据源却认为已经发送,导致数据量出错,从而S2MM传输错误
③ AXI4-Stream Data FIFO模块的输入输出接口的Packet格式完全一样,即S_AXIS进入数据的Packet中Burst数目与M_AXIS送出数据的Packet中的Burst数目一样。于是数据源送出的Packet中的tlast的位置必须精确控制到与PS传输指令要求的数据量一致
4. 在信号连线上右键选择Debug,可以将信号用于调试,如果根据Block Design的自动连接提示会将Debug信号连接至System ILA模块,与普通ILA模块的差别在于可以显示调试中AXI接口的状态
注意上图中红色的OVERFLOW提示,是由System ILA模块的Number Of Outstanding Read/Write Transactions决定的,传输Burst数目超过设置值即会出现,但是未发现调试数据出现异常
① axi_dma模块的M_AXIS_MM2S用于PS至PL的数据传输,由于数据仅用于查看,因此连接至ILA模块。为了保证数据持续输出,将m_axis_mm2s_tready信号连接常数1’b1
PS编程
完成BIT文件生成后在Vivado的File菜单选择Export Hardware,并勾选Include bitstream(如果不选中则配置FPGA时需要手动添加)
在File菜单选择Launch SDK,建立SDK工程
在SDK中建立APU0的helloworld模板工程
代码如下:
上述代码有几点需要注意的内容:
① 代码第12行:设置一次传输的数据量,[必须小于axi_dma的buffer length register的宽度所决定的数据量](#AXI Direct Memory Access)。并且[必须与PL端数据源发送的Packet大小一致](#完整Block Design)
② 代码第18行:中断响应函数中进行设置并且在main函数中使用的变量不能cache,必须加上volatile声明,否则可能判断出错
③ 代码第24行:手动复位axi_dma模块需要加上看门狗,保证复位结束才能正常工作
④ 代码第239至250行,277至288行:传输完成有2种方式,用XAxiDma_Busy函数Poll轮询或者中断响应,根据实际需要选择使用。需要特别说明的是轮询方式无论中断是否使能,以及使能以后是否响应都可以正常工作
⑤ 代码第218行和300行:Xil_DCacheFlushRange用于将cache中的数据flush冲入内存。之前没想到的是,XAXIDMA_DEVICE_TO_DMA传输时数据首先会进入cache
⑥ 注意:中断响应函数在debug模式下不会进入,只有run模式才能进入中断响应函数!!!!!
特别注意
AXI_DMA模块即使配置为同时使能mm2s和s2mm,但是在PS调用API进行传输的时候,无论传输方向是否相同,必须完成前一个transfer才能执行下一个transfer
由于transfer的API接口函数为异步操作,如果需要并行DMA传输,则有必要使用多个AXI_DMA
版权声明:本文为CSDN博主「bt_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/botao_li/article/details/86168384