适合初学者的 AXI 总线教程:Zynq 实现 PS-PL-DDR 数据搬运

 根据之前设计的AXI读写模块,今天来实际应用一下,进行PL 与 PS 交互操作 DDR 全流程

制作不易,记得三连哦,给我动力,持续更新!!!

完整工程文件下载:https://pan.baidu.com/s/1pdf4YFe2XlmQQc5XVpEkJQ?pwd=6qhr(点击蓝色字体获取)


📌 项目背景

  • 平台:Xilinx Zynq-7000 ( ZedBoard )

  • 目的通过 PL 端 Verilog 逻辑发起 AXI Master 读写操作,访问 PS 端的 DDR 内存,实现数据交互。

  • 工具:Vivado2018.3 + Xilinx SDK

✅功能展示

在文章开始之前,首先来看看本篇文章具体做了什么

❶  通过PS端写1KB数据到DDR

❷  通过EMIO控制PL端读取DDR

❸  PL端将读取到的数据写到DDR另外一个地址

一、设计思路

        根据咱们之前的文章,相信大家已经完全掌握了AXI总线的读写功能,这篇文章将在上次的基础上,进行实际项目的使用,来设计一套基于ZYNQ芯片的PS与PL之间的数据交互demo。以后进行大规模数据处理的时候,就可以根据此设计进行改进,也可以用此项目进行学习AXI总线的使用。

废话不多说,直接上干货!!!

二、整体设计框图

本次设计的总体框图,如下所示

下面将给大家进行简单的讲解

框图展示了FPGA中的PL(Programmable Logic,可编程逻辑)和PS(Processing System,处理系统)之间的数据流和连接关系

  • PL部分
    • 包含AXI read module(AXI读模块)和AXI write module(AXI写模块),它们通过AXI4接口与SmartConnect模块连接。
    • SmartConnect是一个AXI互联模块,负责管理PL中的数据路由和传输。
    • PL通过“AXI HP”接口与PS通信。
  • PS部分
    • 包含ARM Cortex-A9处理器,负责运行用户应用程序(user APP)。
    • 配备EMIO(Extended Multiplexed I/O)和S_AXI_HP0接口,用于与PL通信。
    • DDR3内存通过PS与ARM Cortex-A9连接,用于数据存储。
  • 数据流
    • AXI read module和AXI write module通过AXI4接口与SmartConnect交换数据。
    • SmartConnect通过AXI4接口与PS的S_AXI_HP0接口连接,实现高性能数据传输。
    • PL与PS之间的控制和数据传输通过EMIO和AXI4接口完成。
    • 用户APP可以访问DDR3内存,并通过ARM Cortex-A9处理数据。

三、PL部分设计

PL端主要设计有对ZYNQ7 处理系统的配置,已经PL端读写PS端DDR的逻辑模块

3.1 zynq处理系统配置

通过vivado创建一个工程,然后创建一个block design设计,搜索ZYNQ7 Processing System并添加,然后双击进行一些主要功能的配置

配置MIO

 配置HP接口

配置一个时钟

主要配置的就是这三个部分,其他的没用到的,就先不配置了

3.2 PL端设计

整体采用block design进行设计,

其中的AXI读写代码,上一篇文章已经讲解过,不懂得可以去看上一篇文章

手把手教你verilog实现AXI总线协议读写(一)---- AXI读写模块设计

其介绍和整体设计框图的完全一致,大家可以按照那个介绍进行理解和学习。

3.3 PS端设计

PS端主要通过SDK来进行设计,其主要的设计流程图如下所示

通过用户输入指令,来控制是否进行DDR的读写和是否触发PL端DDR的读写操作,其部分代码如下所示

    while (1){
		xil_printf("请输入触发的方式:\n");
		xil_printf("1:仅仅触发EMIO。\n");
		xil_printf("2:写DDR,并触发EMIO模式。\n");
		xil_printf("3:从两块地址读出数据模式。\n");
		xil_printf("4:从两块地址读出数据,并比较\n");
		xil_printf("请输入指令:1-4\n");
		scanf(" %c", &j);

		xil_printf("你输入的值是:%c\n",j);
		switch (j) {
			case '1':
				// 触发 EMIO 信号以启动 PL 端操作
				xil_printf("触发 EMIO 信号...\n");
				trigger_emio(&Gpio, EMIO_GPIO_PIN + 54);
				break;

			case '2':
				xil_printf("写DDR并触发EMIO模式 \n");
				xil_printf("向 DDR 地址 0x%X 写入 %d 个 32 位数据\n", DST_ADDR, DATA_SIZE);
				// 写入DDR
				for (int i = 0; i < DATA_SIZE; i++) {
					Xil_Out32(DST_ADDR+i*4,i*2);
					xil_printf("addr = %X,data= 0x%X\n",DST_ADDR+i*4,i*2);
				}
				Xil_DCacheFlushRange(DST_ADDR, DATA_SIZE * sizeof(uint32_t));  // 刷新 Cache

				// 触发 EMIO 信号
				xil_printf("触发 EMIO 信号...\n");
				trigger_emio(&Gpio, EMIO_GPIO_PIN + 54);
				break;

			case '3':
				xil_printf("从两块地址读出数据模式  \n");
				Xil_DCacheInvalidateRange(SRC_ADDR, DATA_SIZE*4);
				Xil_DCacheInvalidateRange(DST_ADDR, DATA_SIZE*4);
				//读取0x10000000地址数据
				xil_printf("从 DDR 地址 0x%X 读取 %d 个 32 位数据\n", DST_ADDR, DATA_SIZE);
				for (int i = 0; i < DATA_SIZE; i++) {
					data_buffer0 = Xil_In32(DST_ADDR+i*4); // 读取 DDR
					xil_printf("addr = %X,data= %d\n",DST_ADDR+i*4,data_buffer0);
				}

				//读取0x11000000地址数据
				xil_printf("从 DDR 地址 0x%X 读取 %d 个 32 位数据\n", SRC_ADDR, DATA_SIZE);
				for (int i = 0; i < DATA_SIZE; i++) {
					data_buffer1 = Xil_In32(SRC_ADDR+i*4); // 读取 DDR
					xil_printf("addr = %X,data= %d\n",SRC_ADDR+i*4,data_buffer1);
				}
				break;

			case '4':
				xil_printf("从两块地址读出数据,并比较  \n");
				Xil_DCacheInvalidateRange(SRC_ADDR, DATA_SIZE*4);
				Xil_DCacheInvalidateRange(DST_ADDR, DATA_SIZE*4);
				xil_printf("从 DDR 地址 0x%X 读取 %d 个 32 位数据\n", DST_ADDR, DATA_SIZE);
				for (int i = 0; i < DATA_SIZE; i++) {
					data_buffer0 = Xil_In32(DST_ADDR+i*4); // 读取 DDR
					data_buffer1 = Xil_In32(SRC_ADDR+i*4); // 读取 DDR
					if (data_buffer0 != data_buffer1)
						xil_printf("数据不匹配,索引 %d: 预期 0x%X, 实际 0x%X\n", i, data_buffer0, data_buffer1);
					else
						xil_printf("数据匹配成功,索引 %d: 预期 0x%X, 实际 0x%X\n",i, data_buffer0, data_buffer1);
				}
				break;

			default:
				xil_printf("无效指令!\n");
				break;
		}
		xil_printf("\n");
		xil_printf("\n");
		xil_printf("\n");
    }

整体代码虽然相对简单,但作为本次的演示已经完全足够,因为它涵盖了PS端的DDR读写、PL端的代码读写以及PS与PL之间的交互机制。这使得它在未来的项目中可以直接拿来进行简单的修改和适配。

四、功能演示

大部分功能演示在文章开头的功能展示部分已经展示过了,这里我将用一个视频的形式,给大家演示本设计的所以功能和介绍。

至此,我们的PL 与 PS 交互访问 DDR 全流程就彻底验证完成了!!

下一节讲解如何在实际工程中调用并使用这AXI两个模块!!,大家有想看实现什么功能的也可以发到评论区,我给大家更新!!!!

制作不易,记得三连哦,给我动力,持续更新!!!

posted @ 2025-06-26 17:11  FPGAmaster  阅读(2942)  评论(0)    收藏  举报