PS端对DDR进行读写(一)
- 0 DDR原理
- 1 硬件部分
- 1.1、建立工程
- 1.2、点击“Create Block Design”,创建一个 Block 设计,也就是图形化设计
- 1.3、点击“Add IP”快捷图标,搜索ZYNQ,然后双击。
- 1.4、双击 Block 图中的“processing_system7_0”,配置相关参数
- 1.5、点击“Run Block Automation”,vivado 软件会自动完成一些导出端口的工作.
- 1.6、按照默认点击“OK”.
- 1.7、连接 FCLK_CLK0 到 M_AXI_GP0_ACLK,按 Ctrl+S 保存设计
- 1.8、选择 Block 设计,右键“Create HDL Wrapper...”,创建一个 Verilog 或 VHDL 文件,为 block design生成 HDL 顶层文件。
- 1.9、选择 block 设计,右键“Generate Output Products”,此步骤会生成 block 的输出文件,包括IP,例化模板,RTL 源文件,XDC 约束,第三方综合源文件等等。供后续操作使用。
- 1.10、在菜单栏“File -> Export -> Export Hardware...”导出硬件信息,这里就包含了 PS 端的配置信息。
- 1.11、在弹出的对话框中点击“OK”,因为实验仅仅是使用了 PS 的串口,不需要 PL 参与,这里就没有使能“Include bitstream”
- 2 软件部分
- 2.1、点击 Vivado 菜单“File -> Launch SDK”,启动 SDK
- 2.2、在 SDK 的菜单“New -> Application Project”,建立一个 APP 工程。“Project name”填写“hello”,其他默认,点击“Next”
- 2.3、 模板选择“Hello World”,点击“Finish”
- 2.4、在hello world模板编写代码
- 2.5、上电。并连接 JTAG 线到开发板、UART 的 USB 线到 PC
- 2.6、使用 PuTTY 软件做为串口终端调试工具,PuTTY 是一个免安装的小软件。选择serial---选择串口号----speed
- 2.7、 选择“hello”,右键,可以看到很多选项,本实验要用到这里的“Run as”,就是把程序运行起来,“Run as”里又有很对选项,选择第一个“Launch on Hardware (System Debuger) ”,使用系统调试,直接运行程序。
- 2.8 结果
0 DDR原理
DDR3的地址
// Canonical definitions for DDR MEMORY
#define XPAR_DDR_MEM_BASEADDR 0x00000000U
#define XPAR_DDR_MEM_HIGHADDR 0x3FFFFFFFU
等会我们要使用这个地址,对DDR3进行读写操作
读写操作函数
//从某个地址读数据
u8 Xil_In8(INTPTR Addr);
u16 Xil_In16(INTPTR Addr);
u32 Xil_In32(INTPTR Addr);
//向某个地址写数据。
void Xil_Out8(INTPTR Addr, u8 Value);
void Xil_Out16(INTPTR Addr, u16 Value);
void Xil_Out32(INTPTR Addr, u32 Value);
1 硬件部分
1.1、建立工程
create Project----------Next------工程命名为p_led,并选择文件保存路径
-----------Next
-----------Next-----------Next--------器件选择(按照直接的开发板信号进行选择)
-----------Next-----------finish
1.2、点击“Create Block Design”,创建一个 Block 设计,也就是图形化设计
“Design name”这里不做修改,保持默认“design_1”,这里可以根据需要修改,不过名字
要尽量简短,否则在 Windows 下编译会有问题。
1.3、点击“Add IP”快捷图标,搜索ZYNQ,然后双击。
1.4、双击 Block 图中的“processing_system7_0”,配置相关参数
1.4.1、首先出现的界面是 ZYNQ 硬核的架构图,可以很清楚看到它的结构,可以参考 ug585 文档,里面有对 ZYNQ 的详细介绍。图中绿色部分是可配置模块,可以点击进入相应的编辑界面,当然也可以在左侧的窗口进入编辑。下面对各个窗口的功能一一介绍。
1.4.2、PS 端外设配置
(1)从原理图中我们可以找到串口连接在 PS 的 MIO48-MIO49 上,所以在“Peripheral I/O Pins”选项中使能 UART1(MIO48 MIO49),PS 端 MIO 分为两个 Bank,Bank 0 ,也就是原理图中的 BANK500,电压选择“LVCMOS 3.3V”,Bank 1,也就是原理图中的 BANK501,电压选择“LVCOMS 1.8 V”。 如果不配置 Bank1 电平标准,可能导致串口无法接收
(2)配置 QSPI,QSPI 可以作为 ZYNQ 的启动存储设备,ZYNQ 可以通过读取 QSPI 中存储的启动文件加载 ARM 和 FPGA,从原理图得知,我们选择 Quad SPI Flash 为 Single SS 4bit IO
(3)配置以太网,在 PS 端设计有以太网接口,根据原理图选择 Ethernet 0 到 MIO16-MIO27。MDIO 为以太网 PHY 寄存器配置接口,选择 MDIO 并配置到 MIO52-MIO53
(4)配置 USB0 到 MIO28-MIO39
(5)除了 QSPI 启动 ZYNQ,还有 SD 卡模式启动 ZYNQ,选择 SD 0,配置到 MIO40-MIO45,选择
Card Detection MIO47,用于检测 SD 卡的插入。
(6)打开 GPIO MIO,PS 便可以控制剩余未分配的 MIO,用作 GPIO。在 GPIO MIO 中选择 MIO46 作为 USB PHY 的复位。
(7)外设配置结束。
1.4.3、MIO 配置
修改 Enet0 的电平标准为 HSTL 1.8V,Speed 为 fast,这些参数非常重要,如果不修改,网
络可能不通。其他部分保持默认。
1.4.4、时钟配置
在“Clock Configuration”选项卡中我们可以配置PS时钟输入时钟频率,这里默认是33.333333,和板子上一致,不用修改,CPU 频率默认 666.666666Mhz,这里也不修改。同时 PS 还可以给 PL 端提供 4 路时钟,频率可以配置,这里不需要,所以保持默认即可。还有 PS 端外设的时钟等也可以进行配置,这里保持默认。
1.4.5、DDR3 配置
在“DDR Configuration”选项卡中可以配置 PS 端 ddr 的参数,AX7010 配置 DDR3 型号为
“MT41J128M16 HA-125”, 这里 ddr3型号并不是板子上的 ddr3 型号,而是参数最接近的型号 。Effective DRAM Bus Width”,选择“32 Bit”
其他部分保持默认,点击 OK。至此 ZYNQ 核的配置结束。
1.5、点击“Run Block Automation”,vivado 软件会自动完成一些导出端口的工作.
1.6、按照默认点击“OK”.
点击“OK”以后我们可以看到 PS 端导出一些管脚,包括 DDR 还有 FIXED_IO,DDR 是 DDR3的接口信号,FIXED_IO 为 PS 端固定的一些接口,比如输入时钟,PS 端复位信号,MIO 等。
1.7、连接 FCLK_CLK0 到 M_AXI_GP0_ACLK,按 Ctrl+S 保存设计
1.8、选择 Block 设计,右键“Create HDL Wrapper…”,创建一个 Verilog 或 VHDL 文件,为 block design生成 HDL 顶层文件。
保持默认选项,点击“OK”
展开设计可以看到 PS 被当成一个普通 IP 来使用。
1.9、选择 block 设计,右键“Generate Output Products”,此步骤会生成 block 的输出文件,包括IP,例化模板,RTL 源文件,XDC 约束,第三方综合源文件等等。供后续操作使用。
点击“Generate”
1.10、在菜单栏“File -> Export -> Export Hardware…”导出硬件信息,这里就包含了 PS 端的配置信息。
1.11、在弹出的对话框中点击“OK”,因为实验仅仅是使用了 PS 的串口,不需要 PL 参与,这里就没有使能“Include bitstream”
2 软件部分
2.1、点击 Vivado 菜单“File -> Launch SDK”,启动 SDK
2.2、在 SDK 的菜单“New -> Application Project”,建立一个 APP 工程。“Project name”填写“hello”,其他默认,点击“Next”
2.3、 模板选择“Hello World”,点击“Finish”
2.4、在hello world模板编写代码
//使用PS控制DDR3的读写
/*
Canonical definitions for DDR MEMORY
#define XPAR_DDR_MEM_BASEADDR 0x00000000U
#define XPAR_DDR_MEM_HIGHADDR 0x3FFFFFFFU
//从某个地址读数据
u8 Xil_In8(INTPTR Addr);
u16 Xil_In16(INTPTR Addr);
u32 Xil_In32(INTPTR Addr);
//向某个地址写数据。
void Xil_Out8(INTPTR Addr, u8 Value);
void Xil_Out16(INTPTR Addr, u16 Value);
void Xil_Out32(INTPTR Addr, u32 Value);
*/
#include "stdio.h"
#include "platform.h"
#include "xparameters.h"
#include "xparameters_ps.h"
#include "xil_printf.h"
#include "xil_io.h"
#define DDR_BASEARDDR XPAR_DDR_MEM_BASEADDR + 0x10000000
int main()
{
init_platform();
int i;
int value;
// 写数据
for(i=0; i<32; i++)
{
//Xil_Out32(DDR_BASEARDDR+i*4,0xFF);//向某个地址写数据。
Xil_Out32(DDR_BASEARDDR+i*4,i);//向某个地址写数据。
// 第一个参数:写入数据的地址 第一个参数:待写入的数据
}
// 读数据
for(i=0; i<32; i++)
{
value = Xil_In32(DDR_BASEARDDR+i*4);//从某个地址读数据
// 第一个参数:写入数据的地址
printf("the address at %x data is : %x \n\r" ,DDR_BASEARDDR+i*4, value);
}
printf("finish write and read!\n");
cleanup_platform();
return 0;
}