zynq PS端通过AXI-DMA 轮询读取PL端发送的数据
之后是测试PL端发送数据给DATA FIFO的模块,这里使用的是使用AXI4-stream接口的一个循环计数器。因为pl端写入的是4byte,而ps端读取使用的是1byte,所以会有三个0。(使用的vivado和vitis的版本为2021.2)
在使用ultraScale+RFSoc设计通信系统时,缺少上位机进行数据验证,所以尝试将PL端产生的数据发送到PS端,之后通过串口打印数据,进行数据读取,首先尝试使用了PS端与PL端通过AXI-Lite协议进行寄存器的读写交互,但发现读写速度有限,存在数据丢失的情况,于是采用AXI-DMA进行直接内存访问,以下是在学习PS通过DMA轮询读取PL端发送的数据时的一些学习记录:
(使用的vivado和vitis的版本为2021.2)
如图,搭建block design:

MPSoc IP核的axi配置如下图:

AXI-dma仅用于向ps发送数据,所以仅开启了AXI-S2MM写端口,其余使用默认最简配置:

AXI Stream Data Fifo使用最简配置:

之后是测试PL端发送数据给DATA FIFO的模块,这里使用的是使用AXI4-stream接口的一个循环计数器。

module cyclic_counter#(
parameter FRAME_SIZE = 32'd128
)(
input wire clk,
input wire resetn,
// AXI4-Stream Master Interface
output wire [31:0] m_axis_tdata,
output wire [3:0] m_axis_tkeep,
output wire m_axis_tlast,
output wire m_axis_tvalid,
input wire m_axis_tready
);
assign m_axis_tkeep = 4'b1111; // 4 字节全部有效
// 计数器
reg [31:0] count;
reg tvalid_reg;
reg tlast_reg;
always @(posedge clk or negedge resetn) begin
if (!resetn) begin
count <= 32'd0;
tvalid_reg <= 1'b0;
tlast_reg <= 1'b0;
end else begin
if (m_axis_tready || !tvalid_reg) begin
tvalid_reg <= 1'b1; // 持续输出
if (count == FRAME_SIZE - 1) begin
count <= 32'd0;
tlast_reg <= 1'b1;
end else begin
count <= count + 1;
tlast_reg <= 1'b0;
end
end
end
end
assign m_axis_tdata = count;
assign m_axis_tvalid = tvalid_reg;
assign m_axis_tlast = tlast_reg;
endmodule
生成bitstream后导出hardware,导入vitis生成工程:
这里使用的dma_simple_poll例程进行修改,以下是修改的两个函数 XAxiDma_SimplePollExample和check data:

int XAxiDma_SimplePollExample(u16 DeviceId)
{
XAxiDma_Config *CfgPtr;
int Status;
int Tries = NUMBER_OF_TRANSFERS;
int Index;
u8 *TxBufferPtr;
u8 *RxBufferPtr;
u8 Value;
TxBufferPtr = (u8 *)TX_BUFFER_BASE ;
RxBufferPtr = (u8 *)RX_BUFFER_BASE;
/* Initialize the XAxiDma device.
*/
CfgPtr = XAxiDma_LookupConfig(DeviceId);
if (!CfgPtr) {
xil_printf("No config found for %d\r\n", DeviceId);
return XST_FAILURE;
}
Status = XAxiDma_CfgInitialize(&AxiDma, CfgPtr);
if (Status != XST_SUCCESS) {
xil_printf("Initialization failed %d\r\n", Status);
return XST_FAILURE;
}
if(XAxiDma_HasSg(&AxiDma)){
xil_printf("Device configured as SG mode \r\n");
return XST_FAILURE;
}
/* Disable interrupts, we use polling mode
*/
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DEVICE_TO_DMA);
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DMA_TO_DEVICE);
/* Flush the buffers before the DMA transfer, in case the Data Cache
* is enabled
*/
Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, MAX_PKT_LEN);
for(Index = 0; Index < Tries; Index ++) {
Status = XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR) RxBufferPtr,
MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
while(XAxiDma_Busy(&AxiDma,XAXIDMA_DEVICE_TO_DMA));
Status = CheckData();
printf("CheckData Status %d\r\n",Status);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
}
/* Test finishes successfully
*/
return XST_SUCCESS;
}
static int CheckData(void)
{
u8 *RxPacket;
int Index = 0;
RxPacket = (u8 *) RX_BUFFER_BASE;
/* Invalidate the DestBuffer before receiving the data, in case the
* Data Cache is enabled
*/
Xil_DCacheInvalidateRange((UINTPTR)RxPacket, MAX_PKT_LEN);
for(Index = 0; Index < MAX_PKT_LEN; Index++) {
printf("%u\r\n",RxPacket[Index]);
}
return XST_SUCCESS;
}
上板测试:

因为pl端写入的是4byte,而ps端读取使用的是1byte,所以会有三个0
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)