在使用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

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐