DDR读写的方式进行PS与PL的数据交互

发布于 2025-02-04  410 次阅读


本次验证采用的基本思路为PL对PS端DDR进行读写验证(采用AXI协议),再PS端读取DDR数据存入数组,串口打印,参考黑金的教程
用到3个HDL代码(aq_axi_master.v mem_test.v top.v),aq_axi_master模块包括AXI协议主要的读写逻辑,mem_test模块用于控制产生测试数据进行循环读写,我对代码进行了详细的注释,有需要可以看看,AXI协议的简单原理跳转见[[5 PS与PL数据常用交互之DDR读写#AXI协议原理|AXI原理]]

注意:mem_test模块的数据读写和地址是以字(word)为单位,而AXI协议的地址是以字节(byte)为单位,1字的宽度和总线宽度相同,故1word=64bit,字节固定为8bit,DDR每个地址存储8位数据(1字节)

操作步骤为硬件环境搭建、PL端读写验证、PS读取验证
硬件环境搭建好后,进行一次综合,点击set up debug快速创建ILA(需要观察的信号已在代码中标记好)
导出xsa文件后,快速创建一个hello world工程,修改代码如下

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#define MEM_BASE_ADDR 0x10000000   // PL 写入数据的起始地址
#define DATA_SIZE 256              // 读取的数据量(128个64bit数据 == 256 个 32-bit 数据)

int main()
{
    init_platform();

    print("Hello Worldnr");
    print("Successfully ran Hello World application");

    //使用 volatile uint32_t * 指针 避免编译器优化,确保访问真实的硬件地址。
    volatile uint32_t *mem_ptr = (uint32_t *)MEM_BASE_ADDR; // 直接映射到 PL 的存储地址
    uint32_t data_array[DATA_SIZE];

    // 读取数据并存入数组
    for (int i = 0; i < DATA_SIZE; i++) {
        data_array[i] = mem_ptr[i];  // 逐个读取数据
    }

    // 打印部分数据以验证
    for (int i = 0; i < 10; i++) {
        printf("Data[%d] = 0x%08Xn", i, data_array[i]);
    }
    cleanup_platform();
    return 0; 
}

结果验证

PL端读写验证

写入数据如下
Pasted image 20250203213653
读出数据如下
Pasted image 20250203213721
整体读写循环,error信号一直拉低,并无报错
Pasted image 20250203213811

PS端读取验证

ps端串口打印数据如下
Pasted image 20250203220705

硬件环境搭建

  1. 创建zynq核,配置好串口(或者其他基本工程另存为)
  2. 基于“ps_hello”工程,在 vivado 的界面中 HP 的配置如下图(HP0~HP3),这里面有使能控制,数据位宽选择,可选择 32bit、64bit 或 128bit 的位宽。我们的实验启用 HP0 配置为 64bit 位 宽,使用的时钟是 150Mhz,HP 的带宽是 150Mhz * 64bit,对于视频处理,ADC 数据采集等 应用都有足够的带宽。不需要 AXI HPM0 LPD,取消选择。Pasted image 20250202172244Pasted image 20250202192124
  3. 添加复位模块,用于复位Pasted image 20250202213513
  4. 在空白处右键选择”Creat Port”,创建时钟端口并进行约束Pasted image 20250202213525配置如图Pasted image 20250202213552
  5. 选中引脚,点击 Make External,将信号导出Pasted image 20250202213621修改引脚名称如下图,其中pl_clk0引脚输出150M时钟,在顶层文件中将其与axi_hp_clk相连Pasted image 20250202213656选择总线同步时钟为 axi_hp_clkPasted image 20250202213714
  6. 点开 Address Editor,如果发现地址没有分配,点击自动分配地址按钮Pasted image 20250202213728分配后的结果,可以看到访问 DDR, QSPI, OCM 的地址空间Pasted image 20250202213743对比vitis中的结果Pasted image 20250203223145保存设计,重新 Generate Ouput Product
  7. 添加 hdl 文件Pasted image 20250202213831

AXI协议原理

AXI4 相对复杂,但 SOC 开发者必须掌握,对于 zynq 的开发者,笔者建议能够在一些已 有的模板代码基础上修改。AXI 协议的具体内容可参考 Xilinx UG761 AXI Reference Guide。 在这里我们简单了解一下。
AXI4 所采用的是一种 READY,VALID 握手通信机制,即主从模块进行数据通信前,先根 据操作对各所用到的数据、地址通道进行握手。主要操作包括传输发送者 A 等到传输接受者 B 的 READY 信号后,A 将数据与 VALID 信号同时发送给 B,这是一种典型的握手机制。
Pasted image 20250202222050
AXI 总线分为五个通道:
 读地址通道,包含 ARVALID, ARADDR, ARREADY 信号;
 写地址通道,包含 AWVALID,AWADDR, AWREADY 信号;
 读数据通道,包含 RVALID, RDATA, RREADY, RRESP 信号;
 写数据通道,包含 WVALID, WDATA,WSTRB, WREADY 信号;
 写应答通道,包含 BVALID, BRESP, BREADY 信号;
 系统通道,包含:ACLK,ARESETN 信号;

其中 ACLK 为 axi 总线时钟,ARESETN 是 axi 总线复位信号,低电平有效;读写数据与读 写地址类信号宽度都为 32bit;READY 与 VALID 是对应的通道握手信号;WSTRB 信号为 1 的 bit 对应 WDATA 有效数据字节,WSTRB 宽度是 32bit/8=4bit;BRESP 与 RRESP 分别为写回 应信号,读回应信号,宽度都为 2bit,‘h0 代表成功,其他为错误。
读操作顺序为主与从进行读地址通道握手并传输地址内容,然后在读数据通道握手并传输 所读内容以及读取操作的回应,时钟上升沿有效。如图所示:
Pasted image 20250202222656
写操作顺序为主与从进行写地址通道握手并传输地址内容,然后在写数据通道握手并传输 所读内容,最后再写回应通道握手,并传输写回应数据,时钟上升沿有效。如图所示:
Pasted image 20250202223128

代码

最后更新于 2025-03-03