今天我做了如下实验:axis stream data通过DMA S2MM写入DDR,PS读取DDR并通过串口打印,其中axis stream data的触发是通过按键完成,并且在调试过程中发现一个有意思的问题,即
“我首先在SDK点击Debug,包含program FPGA,然后我又在vivado重新Program device,出现了ila,我设置了key_pressed==1为trigger条件,在SDK端点击Run之前我按了按键,ila捕捉到source_tready在key_pressed==1之前一直为高电平(有效),之后source_tready有效持续4个时钟周期,然后又被拉低,此时我返回SDK点击Run,收到的是丢失前四个数据的结果。”
该错误操作下的ila抓包结果如下:
再次运行debug,并先在PS端启动DMA,后进行按键启动数据传输,ila抓包如下,此时PS串口也输出了完整的8个数据。
结论:一定要确保axis stream data在source_tready真正有效之后再进行传输。
其中PS端对DDR的配置和轮询程序如下:
#include "xparameters.h" #include "xaxidma.h" #include "xil_printf.h" #include "xil_cache.h" #include "sleep.h" #define DMA_DEV_ID XPAR_AXI_DMA_0_DEVICE_ID #define DDR_BUFFER_ADDR 0x10000000 #define TRANSFER_LENGTH 32 XAxiDma AxiDma; int main(void) { XAxiDma_Config *ConfigPtr; xil_printf("\r\n"); xil_printf("----- AXI DMA S2MM Test -----\r\n"); //1. 查找 DMA 配置 ConfigPtr = XAxiDma_LookupConfig(DMA_DEV_ID); //2. 初始化 DMA XAxiDma_CfgInitialize(&AxiDma, ConfigPtr); //3. 禁用 S2MM 中断,当前我们采用轮询方式 XAxiDma_IntrDisable( &AxiDma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA ); //4. 清空 DDR Buffer u32 *BufferPtr = (u32 *)DDR_BUFFER_ADDR; for (int i = 0; i < 8; i++) { BufferPtr[i] = 0xAAAAAAAA; } // 5. Flush Cache Xil_DCacheFlushRange( DDR_BUFFER_ADDR, TRANSFER_LENGTH ); xil_printf("\r\n"); xil_printf("DDR buffer initialized.\r\n"); XAxiDma_SimpleTransfer( &AxiDma, DDR_BUFFER_ADDR, TRANSFER_LENGTH, XAXIDMA_DEVICE_TO_DMA ); xil_printf("DMA S2MM is armed.\r\n"); xil_printf("Please press KEY to start PL data transmission.\r\n"); // 6. 等待 DMA 接收完成 while (XAxiDma_Busy( &AxiDma, XAXIDMA_DEVICE_TO_DMA )) {;} xil_printf("DMA transfer completed.\r\n"); // 7. Invalidate Cache Xil_DCacheInvalidateRange( DDR_BUFFER_ADDR, TRANSFER_LENGTH ); // 8. 读取 DDR xil_printf("\r\n"); xil_printf("DDR data:\r\n"); for (int i = 0; i < 8; i++) { xil_printf( "DDR[%d] = 0x%08lx\r\n", i, BufferPtr[i] ); } xil_printf("\r\n"); xil_printf("----- Test Finished -----\r\n"); return XST_SUCCESS; }PL中有一部分关于ILA的使用需要注意,这里我将自己的source文件作为RTL module加入到了block design中了,ila_0 不要作为一个独立 OOC 子设计处理,而是跟 pll_clock_top 一起综合。
module pll_clock_top( input clk, input rstn, input key, output [3:0] leds, output source_tvalid, output source_tlast, output [31:0]source_tdata, output [3:0] source_tkeep, input source_tready, //output key_pressed, //input start //input start ); //============================= // Key debounce //============================== wire key_state,key_pressed,key_released; key_debounce inst_key_debounce( .clk(clk), .rstn(rstn), .key(key), .key_state(key_state), .key_pressed(key_pressed), .key_released(key_released) ); //======================== // LED //============================ led_blink inst_led_blink( .clk(clk), .rstn(rstn), .key_pressed(key_pressed), .leds(leds) ); assign source_tkeep=4'b1111; axis_test_source inst_axis_test_source( .clk(clk), .rstn(rstn), .start(key_pressed), .m_tdata(source_tdata), .m_tvalid(source_tvalid), .m_tlast(source_tlast), .m_tready(source_tready) ); //set_property generate_synth_checkpoint 0 [get_files ila_0.xci] //这样告诉 Vivado:ila_0 不要作为一个独立 OOC 子设计处理,而是跟 pll_clock_top 一起综合。 ila_0 your_instance_name ( .clk(clk), // input wire clk .probe0(key_pressed), // input wire [0:0] probe0 .probe1(source_tvalid), // input wire [0:0] probe1 .probe2(source_tlast), // input wire [0:0] probe2 .probe3(source_tready), // input wire [0:0] probe3 .probe4(source_tdata) // input wire [31:0] probe4 ); endmodule