FPGA和USB3.0通信知识记录(6)——基于特权同学图书《Xilinx FPGA伴你玩转USB3.0与LVDS》(基于UART的DDR3数据读写实验)

上一节实现了FPGA串口通信,这一节继续跟着特权同学的例程,记录一下基于UART的DDR3数据读写实验。本文全部基于书本《Xilinx FPGA伴你玩转USB3.0与LVDS》,我是新人请多多关照,一起进步!

一、功能概述

上电之后,自动向DDR3写256*32*【128bits】数据,PC通过串口助手发8位数据(地址)给串口接收模块,串口接收模块存储地址数据并且发送给data_source模块,从而确定了从哪个地址读DDR3,然后将读出的512byte数据发给PC端。

二、所有模块及顶层文件(.V)代码及注释

2.1 data_source.v

我自己补充的一些注释,我自己的理解...写的不一定对。

/
//特权同学 精心打造 Xilinx FPGA开发板系列
//工程硬件平台: Xilinx Artex7 FPGA 
//开发套件型号: SF-AT7 特权打造
//版   权  申   明: 本例程由《深入浅出玩转FPGA》作者“特权同学”原创,
//				仅供SF-AT7开发套件学习使用,谢谢支持
/
module data_source(
			input clk,      //在生成DDR3 IP的界面中有选择1/4还是1/2模式,本工程选择的1/4,所以是DDR3时钟(400MHz)的1/4,即100MHz
			input rst_n,	//复位信号
			
			//----------------DDR3控制器IP的用户接口信号:这部分时序与   命令和地址    相关----------------------------------//
			output reg[27:0] app_addr,	    //DDR3地址总线
			output reg[2:0]  app_cmd,	    //DDR3命令总线,3‘b000--写;3'b001--读;
			output reg app_en,	            //DDR3操作请求信号,高电平有效
			input app_rdy,	                //DDR3操作响应信号,表示当前的app_en请求已经获得响应,可以继续操作
			
			//----------------DDR3控制器IP的用户接口信号:这部分时序与   向DDR3写数据  相关----------------------------------//
			output reg[127:0] app_wdf_data,	//DDR3写入数据总线
			output reg app_wdf_wren,		//DDR3写入数据使能信号,表示当前写入数据有效
			output app_wdf_end,	            //关于 app_wdf_end 信号,该信号表示:当前突发写的最后一个数据。
			                                //在A7 DDR3 的控制器IP核中,只存在突发长度为 8 地址的形式 ,1 个地址能存放的数据是 16bit
											//因此每一次的地址突发带来的数据突发为 8*16=128 bit(对外接口为128bit)。
											//本次 DDR3 IP 核调取时,我们选取的 “物理层 - 用户端” 的速率为 4:1,每次发送的有效数据为 128 bit
											//因此只需1 次突发写就完成了数据的写入,故app_wdf_end 和 app_wdf_en 时序上同步了。
			input app_wdf_rdy,	            //DDR3可以执行写入数据操作,该信号拉高表示写数据FIFO已经准备好接收数据
			
			//----------------DDR3控制器IP的用户接口信号:这部分时序与   从DDR3读数据  相关----------------------------------//
			input[127:0] app_rd_data,	    //DDR3读取数据总线
			input app_rd_data_end,	        //类比app_wdf_end信号
			input app_rd_data_valid,	    //DDR3读出数据使能信号,表示当前读出数据有效
			
			//用户逻辑读写DDR3接口
			input user_ddr3_rden,			//串口接收模块输出的rx_rdy接收有效信号连接user_ddr3_rden端口,拉高时代表进入读取DDR3数据状态,并
											//同时将数据缓存至FIFO,通过串口发给PC机
			input[7:0] user_ddr3_addr,		//用户规定的首地址
			output user_ddr3_rddata_vld,	//DDR3 IP读数据有效信号输出给fifo的wr_en写使能端口,代表从DDR3读出的数据即将进入FIFO缓存
			output[127:0] user_ddr3_rddata	//DDR3中存储的数据进FIFO
		);
/********************************功能描述****************************************/
//上电后,从0地址开始遍历写256*32*【128bits数据】到DDR3的地址0-(256*32-1)中
//外部信号可以指定读某个地址数据,连续读出32*【128bits数据】
/********************************功能描述****************************************/
parameter BURST_WR_128BIT = 9'd32;	//burst写数据数量
parameter BURST_RD_128BIT = 9'd32;	//burst读数据数量

	
//2.?us定时计数逻辑    时钟为100MHz(10ns) 
reg[7:0] scnt; 
reg[8:0] times;		
always @(posedge clk or negedge rst_n)
	if(!rst_n) 
		scnt <= 8'd0;
	else if(scnt < 269)
		scnt<=scnt+1'b1;
	else	
		scnt<=0;

wire timer_wrreq = (scnt == 8'd100);	//定时DDR3写数据信号,每过两点多微妙就会产生timer_wrreq有效信号

always @(posedge clk or negedge rst_n)
	if(!rst_n) times <= 9'd0;
	else if(scnt == 8'd200) begin
		if(times < 9'd256) times <= times+1'b1;
		else ;
	end
	

//产生读写DDR3操作的状态
parameter SIDLE = 4'd0;
parameter SWRDB = 4'd1;
parameter SRDDB = 4'd2;
parameter SSTOP = 4'd3;
	
reg[3:0] nstate,cstate;
reg[8:0] num;
reg[8:0] wrnum;

always @(posedge clk or negedge rst_n)
	if(!rst_n) cstate <= SIDLE;
	else cstate <= nstate;

//数据读写仲裁控制状态机
always @(cstate or timer_wrreq or times or user_ddr3_rden or num or app_rdy or app_wdf_rdy) begin
	case(cstate)
		SIDLE: begin
			if(timer_wrreq && (times < 9'd256)) nstate <= SWRDB;
			else if(user_ddr3_rden) nstate <= SRDDB;								 //PC给串口发送地址之后,状态才会跳到SRDDB
			else nstate <= SIDLE;
		end
		SWRDB: begin	//写数据
			if((wrnum > BURST_WR_128BIT) && (num > BURST_WR_128BIT)) nstate <= SSTOP;//一个单位数据32*128bits=4096bits=512byte,
																					 //这里就是保证一个timer_wrreq有效之后
																					 //在下一个timer_wrreq有效来之前32个【128bits数据】都写完
			else nstate <= SWRDB;
		end
		SRDDB: begin	//读数据
			if(num > BURST_RD_128BIT) nstate <= SSTOP;								 //这里就是保证32个128bits都读完
			else nstate <= SRDDB;
		end
		SSTOP: nstate <= SIDLE;
		default: nstate <= SIDLE;
	endcase
end

	
//读或写数据控制信号计数器

always @(posedge clk or negedge rst_n)
	if(!rst_n) num <= 9'd0;
	else if(cstate == SWRDB) begin
		if(app_rdy) num <= num+1'b1;
		else ;
	end
	else if(cstate == SRDDB) begin
		if(app_rdy) num <= num+1'b1;
		else ;
	end
	else num <= 9'd0;
	
	
//写数据控制信号计数器

always @(posedge clk or negedge rst_n)
	if(!rst_n) wrnum <= 9'd0;
	else if(cstate == SWRDB) begin
		if(app_wdf_rdy) wrnum <= wrnum+1'b1;
		else ;
	end
	else wrnum <= 9'd0;	
	

//读写数据控制时序产生
//reg[27:0] app_addr,	//DDR3地址总线
//reg[2:0] app_cmd,		//DDR3命令总线,3‘b000--写;3'b001--读;3‘b011--wr_bytes(With ECC enabled, the wr_bytes operation is required for writes with any non-zero app_wdf_mask bits.)
//reg app_en,	//DDR3操作请求信号,高电平有效
			
always @(posedge clk or negedge rst_n)
	if(!rst_n) begin
		app_cmd <= 3'd0;
		app_en <= 1'b0;
		app_addr <= 28'd0;		
	end
	else if(cstate == SWRDB) begin
		app_cmd <= 3'b000;	//状态机现态为写数据时,用户接口app_cmd=3'b000	
		
		if(app_rdy) begin
			if(num < BURST_WR_128BIT) app_en <= 1'b1;//保证这32个周期内,app_en都置1,让所有32*128bits数据全部写入
			else app_en <= 1'b0;
		end
		else ;
		
		{app_addr[27:11],app_addr[2:0]} <= {4'd0,times[7:0],5'd0,3'd0};	  //地址随着时钟更新,第一个time,num更新32次
		                                                                  //第二个time,num再更新32次
		                                                                  //如此,有种256次,每次512byte数据传输的感觉
		if(app_rdy) app_addr[10:3] <= num[7:0];//app_addr[10:3]+1'b1;
		else ;		
	end
	else if(cstate == SRDDB) begin
		app_cmd <= 3'b001; //状态机现态为读数据时,用户接口app_cmd=3'b001

		if(app_rdy) begin		
			if(num < BURST_RD_128BIT) app_en <= 1'b1;//保证这32个周期内,app_en都置1,让所有32*128bits数据全部读入	
			else app_en <= 1'b0;
		end
		else ;
		
		{app_addr[27:11],app_addr[2:0]} <= {4'd0,user_ddr3_addr,5'd0,3'd0};	//写入数据有256组【32*128bits】,但读数据只会
																			//读出user_ddr3_addr规定的这一组
																			//user_ddr3_addr等于多少,由PC端发送的数据决定																
		if(app_rdy) app_addr[10:3] <= num[7:0];//app_addr[10:3]+1'b1;
		else ;			
	end
	else begin
		app_cmd <= 3'd0;
		app_en <= 1'b0;
		app_addr <= 28'd0;	
	end
	
	

//写数据控制时序产生
//reg[127:0] app_wdf_data,	//DDR3写入数据总线
//reg app_wdf_end,	//DDR3最后一个字节写入指示信号,与app_wdf_data同步指示当前操作为最后一个数据写入
//reg app_wdf_wren,	//DDR3写入数据使能信号,表示当前写入数据有效
//input app_wdf_rdy,	//DDR3可以执行写入数据操作,该信号拉高表示写数据FIFO已经准备好接收数据
			
always @(posedge clk or negedge rst_n)
	if(!rst_n) begin
		app_wdf_wren <= 1'b0; 	
		app_wdf_data <= 128'd0;	
	end
	else if(cstate == SWRDB) begin
		
		if(app_wdf_rdy) begin
			if(wrnum < BURST_WR_128BIT) app_wdf_wren <= 1'b1; 	
			else app_wdf_wren <= 1'b0;
		end
		else ;
		
		if(app_wdf_rdy) begin
			app_wdf_data[7:0]     <= times[7:0]+{wrnum[3:0],4'd0}+8'd15;//
			app_wdf_data[15:8]    <= times[7:0]+{wrnum[3:0],4'd0}+8'd14;//
			app_wdf_data[23:16]   <= times[7:0]+{wrnum[3:0],4'd0}+8'd13;//
			app_wdf_data[31:24]   <= times[7:0]+{wrnum[3:0],4'd0}+8'd12;//
			app_wdf_data[39:32]   <= times[7:0]+{wrnum[3:0],4'd0}+8'd11;//
			app_wdf_data[47:40]   <= times[7:0]+{wrnum[3:0],4'd0}+8'd10;//
			app_wdf_data[55:48]   <= times[7:0]+{wrnum[3:0],4'd0}+8'd9;	//
			app_wdf_data[63:56]   <= times[7:0]+{wrnum[3:0],4'd0}+8'd8;	//
			app_wdf_data[71:64]   <= times[7:0]+{wrnum[3:0],4'd0}+8'd7;	//
			app_wdf_data[79:72]   <= times[7:0]+{wrnum[3:0],4'd0}+8'd6;	//
			app_wdf_data[87:80]   <= times[7:0]+{wrnum[3:0],4'd0}+8'd5;	//
			app_wdf_data[95:88]   <= times[7:0]+{wrnum[3:0],4'd0}+8'd4; //
			app_wdf_data[103:96]  <= times[7:0]+{wrnum[3:0],4'd0}+8'd3;	//
			app_wdf_data[111:104] <= times[7:0]+{wrnum[3:0],4'd0}+8'd2;	//
			app_wdf_data[119:112] <= times[7:0]+{wrnum[3:0],4'd0}+8'd1;	//
			app_wdf_data[127:120] <= times[7:0]+{wrnum[3:0],4'd0}+8'd0;	//wrnum会加32次,每次都把128bits给一个地址;32次之后就给了32*128bits
																		//32次作为一个单元,即为256次512byte
		end
		else ;

	end
	else begin
		app_wdf_wren <= 1'b0; 
		app_wdf_data <= 128'd0;
	end 
	
assign app_wdf_end = 1'b1;	
	

//读数据控制时序产生
//input[127:0] app_rd_data,	//DDR3读取数据总线
//input app_rd_data_end,	//DDR3最有一个字节读取指示信号,与app_rd_data同步指示当前操作为最后一个数据读出
//input app_rd_data_valid	//DDR3读出数据使能信号,表示当前读出数据有效
/*reg ram_we_en;
reg[7:0] ram_addr;
reg[127:0] ram_data;

always @(posedge clk or negedge rst_n)
	if(!rst_n) begin
		ram_we_en <= 1'b0;
		ram_addr <= 8'd0;
		ram_data <= 128'd0;
	end
	else if(timer_rdreq) begin
		ram_we_en <= 1'b0;
		ram_addr <= 8'd0;
		ram_data <= 128'd0;	
	end
	else if(app_rd_data_valid) begin
		ram_we_en <= 1'b1;
		ram_addr <= ram_addr+1'b1;
		ram_data <= app_rd_data;			
	end

	//RAM例化,256*128bit
dist_mem_gen_0 	onchip_ram_ddr3_rddb (
  .a(ram_addr),        // input wire [7 : 0] a
  .d(ram_data),        // input wire [127 : 0] d
  .clk(clk),    // input wire clk
  .we(ram_we_en),      // input wire we
  .qspo()  // output wire [127 : 0] qspo
);	*/

assign user_ddr3_rddata_vld = app_rd_data_valid;
assign user_ddr3_rddata = app_rd_data;
	

//在线逻辑分析仪例化
		
ila_0 	ila_chipscope_for_dubug (
	.clk(clk), // input wire clk

	.probe0(app_en), // input wire [0:0]  probe0  
	.probe1(app_cmd), // input wire [0:0]  probe1 
	.probe2(app_addr), // input wire [0:0]  probe2 
	.probe3(app_rdy), // input wire [0:0]  probe3 
	.probe4(app_wdf_end), // input wire [0:0]  probe4 
	.probe5(app_wdf_wren), // input wire [0:0]  probe5 
	.probe6(app_wdf_rdy), // input wire [0:0]  probe6 
	.probe7(app_wdf_data), // input wire [0:0]  probe7 
	.probe8(app_rd_data_end), // input wire [0:0]  probe8 
	.probe9(app_rd_data_valid), // input wire [0:0]  probe9 
	.probe10(app_rd_data), // input wire [0:0]  probe10 
	.probe11(timer_wrreq), // input wire [0:0]  probe11 
	.probe12(user_ddr3_rden),
	.probe13(user_ddr3_addr)
);


	

endmodule

2.2   uart_tx_source.v模块

我自己补充的一些注释,我自己的理解...写的不一定对。

/
//特权同学 精心打造 Xilinx FPGA开发板系列
//工程硬件平台: Xilinx Artex7 FPGA 
//开发套件型号: SF-AT7 特权打造
//版   权  申   明: 本例程由《深入浅出玩转FPGA》作者“特权同学”原创,
//				仅供SF-AT7开发套件学习使用,谢谢支持
//官方淘宝店铺: http://myfpga.taobao.com/
//最新资料下载: http://pan.baidu.com/s/1c2iTPra
//公                司: 上海或与电子科技有限公司
/
module at7(
			// DDR3接口
			inout [15:0]       ddr3_dq,
			inout [1:0]        ddr3_dqs_n,
			inout [1:0]        ddr3_dqs_p,
			output [13:0]     ddr3_addr,
			output [2:0]        ddr3_ba,
			output            ddr3_ras_n,
			output            ddr3_cas_n,
			output            ddr3_we_n,
			output            ddr3_reset_n,
			output [0:0]       ddr3_ck_p,
			output [0:0]       ddr3_ck_n,
			output [0:0]       ddr3_cke,
			output [1:0]     ddr3_dm,
			output [0:0]       ddr3_odt,
			//系统时钟、外部复位
			input       sys_clk_i,
			input		ext_rst_n,	
			//UART接口
			input uart_rx,		// UART接收数据信号
			output uart_tx,		// UART发送数据信号
			//LED指示灯接口
			output[0:0] led		//用于测试的LED指示灯	PIN_L5
    );


//PLL例化
wire clk_200m;
wire sys_rst_n;
	
  clk_wiz_0 	uut_clk_wiz_0
   (
    .clk_in1(sys_clk_i),   
	
    .clk_out1(clk_200m),  

    .reset(!ext_rst_n), 
    .locked(sys_rst_n));      
	

//DDR3 controller例化

wire ui_clk;	        //时钟信号,是DDR3时钟(400MHz)的1/4,即100MHz,ui_clk是DDR3IP输出的一个时钟,供后面所有模块使用
wire ui_clk_sync_rst;	//复位信号,也是DDR3IP输出的一个信号,供后面所由模块使用

/*地址、命令*/
wire[27:0] app_addr;		//DDR3地址总线
wire[2:0] app_cmd;			//DDR3命令总线,3‘b000--写;3'b001--读;
wire app_en;	        	//DDR3操作请求信号,高电平有效
wire app_rdy;	        	//DDR3操作响应信号,表示当前的app_en请求已经获得响应,可以继续操作
wire init_calib_complete;	//校准初始化完成标志信号,高电平有效

/*向DDR3写数据*/
wire[127:0] app_wdf_data;	//DDR3写入数据总线
wire app_wdf_end;	        //DDR3最后一个字节写入指示信号,与app_wdf_data同步指示当前操作为最后一个数据写入
wire app_wdf_wren;	        //DDR3写入数据使能信号,表示当前写入数据有效
wire app_wdf_rdy;	        //DDR3可以执行写入数据操作

/*从DDR3读数据*/
wire[127:0] app_rd_data;	//DDR3读取数据总线
wire app_rd_data_end;	    //DDR3最有一个字节读取指示信号,与app_rd_data同步指示当前操作为最后一个数据读出
wire app_rd_data_valid;	    //DDR3读出数据使能信号,表示当前读出数据有效,这个信号会使能uart_tx_source模块中的fifo,DDR3读出的数据会进入fifo缓存

/*DDR3控制器IP的用户接口信号:刷新请求与响应*/
wire app_ref_req = 1'b0;	//DDR3刷新请求信号,高电平有效,该信号拉高必须保持到app_ref_ack拉高表示刷新请求已经响应
wire app_ref_ack;	        //DDR3刷新响应信号,高电平有效,该信号拉高表示已经执行DDR3的刷新操作

/*DDR3控制器IP的用户接口信号:ZQ校准请求与响应*/
wire app_zq_req = 1'b0;	    //DDR3 ZQ校准命令请求信号,高电平有效,该信号拉高必须保持到app_zq_ack拉高表示刷新请求已经响应
wire app_zq_ack;	        //DDR3 ZQ校准响应信号,高电平有效,该信号拉高表示已经执行DDR3的ZQ校准操作

/*DDR3控制器IP的用户接口信号*/
wire app_sr_req = 1'b0;
wire app_sr_active;
		  
		  
mig_7series_0 		u1_mig_7series_0 (
    // Memory interface ports
    .ddr3_addr                      (ddr3_addr),  // output [13:0]		ddr3_addr
    .ddr3_ba                        (ddr3_ba),  // output [2:0]		ddr3_ba
    .ddr3_cas_n                     (ddr3_cas_n),  // output			ddr3_cas_n
    .ddr3_ck_n                      (ddr3_ck_n),  // output [0:0]		ddr3_ck_n
    .ddr3_ck_p                      (ddr3_ck_p),  // output [0:0]		ddr3_ck_p
    .ddr3_cke                       (ddr3_cke),  // output [0:0]		ddr3_cke
    .ddr3_ras_n                     (ddr3_ras_n),  // output			ddr3_ras_n
    .ddr3_reset_n                   (ddr3_reset_n),  // output			ddr3_reset_n
    .ddr3_we_n                      (ddr3_we_n),  // output			ddr3_we_n
    .ddr3_dq                        (ddr3_dq),  // inout [15:0]		ddr3_dq
    .ddr3_dqs_n                     (ddr3_dqs_n),  // inout [1:0]		ddr3_dqs_n
    .ddr3_dqs_p                     (ddr3_dqs_p),  // inout [1:0]		ddr3_dqs_p
    .init_calib_complete            (init_calib_complete),  // output			init_calib_complete
      
    .ddr3_dm                        (ddr3_dm),  // output [1:0]		ddr3_dm
    .ddr3_odt                       (ddr3_odt),  // output [0:0]		ddr3_odt
    // Application interface ports
    .app_addr                       (app_addr),  // input [27:0]		app_addr
    .app_cmd                        (app_cmd),  // input [2:0]		app_cmd
    .app_en                         (app_en),  // input				app_en
    .app_wdf_data                   (app_wdf_data),  // input [127:0]		app_wdf_data
    .app_wdf_end                    (app_wdf_end),  // input				app_wdf_end
    .app_wdf_wren                   (app_wdf_wren),  // input				app_wdf_wren
    .app_rd_data                    (app_rd_data),  // output [127:0]		app_rd_data
    .app_rd_data_end                (app_rd_data_end),  // output			app_rd_data_end
    .app_rd_data_valid              (app_rd_data_valid),  // output			app_rd_data_valid
    .app_rdy                        (app_rdy),  // output			app_rdy
    .app_wdf_rdy                    (app_wdf_rdy),  // output			app_wdf_rdy
    .app_sr_req                     (app_sr_req),  // input			app_sr_req
    .app_ref_req                    (app_ref_req),  // input			app_ref_req
    .app_zq_req                     (app_zq_req),  // input			app_zq_req
    .app_sr_active                  (app_sr_active),  // output			app_sr_active
    .app_ref_ack                    (app_ref_ack),  // output			app_ref_ack
    .app_zq_ack                     (app_zq_ack),  // output			app_zq_ack
    .ui_clk                         (ui_clk),  // output			ui_clk
    .ui_clk_sync_rst                (ui_clk_sync_rst),  // output			ui_clk_sync_rst
    .app_wdf_mask                   (16'h00/*app_wdf_mask*/),  // input [15:0]		app_wdf_mask不确认高低有效
    // System Clock Ports
    .sys_clk_i                       (clk_200m),  // input			sys_clk_i
    .sys_rst                        (sys_rst_n) // input sys_rst
    );	
	

//产生数据源,用于测试DDR2的读写
	//用户逻辑读写DDR3接口
wire user_ddr3_rden;
wire[7:0] user_ddr3_addr;
wire user_ddr3_rddata_vld;
wire[127:0] user_ddr3_rddata;
			
data_source		u2_data_source(
					.clk(ui_clk),
					.rst_n(!ui_clk_sync_rst & init_calib_complete),
					.app_addr(app_addr),
					.app_cmd(app_cmd),
					.app_en(app_en),
					.app_rdy(app_rdy),
					.app_wdf_data(app_wdf_data),
					.app_wdf_end(app_wdf_end),
					.app_wdf_wren(app_wdf_wren),
					.app_wdf_rdy(app_wdf_rdy),
					.app_rd_data(app_rd_data),
					.app_rd_data_end(app_rd_data_end),
					.app_rd_data_valid(app_rd_data_valid),
					.user_ddr3_rden(user_ddr3_rden),
					.user_ddr3_addr(user_ddr3_addr),//串口调试助手发送的8位地址数据通过u5_my_uart_rx的rx_data输出给user_ddr3_addr端口
													//这8位地址数据将成为一个地址起点,从此地址开始往后的所有数据再通过串口返回给PC端
					.user_ddr3_rddata_vld(user_ddr3_rddata_vld),
					.user_ddr3_rddata(user_ddr3_rddata)
				);	


//UART需要发送数据缓存
wire ddr3uart_tx_en;
wire[7:0] ddr3uart_tx_db;
			
uart_tx_source		u3_uart_tx_source(
						.clk(ui_clk),	//波特率选择模块
						.rst_n(!ui_clk_sync_rst),
						.user_ddr3_rddata_vld(user_ddr3_rddata_vld),
						.user_ddr3_rddata(user_ddr3_rddata),
						.ddr3uart_tx_db(ddr3uart_tx_db),
						.ddr3uart_tx_en(ddr3uart_tx_en)
					);
		
				
//下面的四个模块中,speed_rx和speed_tx是两个完全独立的硬件模块,可称之为逻辑复制
//(不是资源共享,和软件中的同一个子程序调用不能混为一谈)

wire bps_start1,bps_start2;	//接收到数据后,波特率时钟启动信号置位
wire clk_bps1,clk_bps2;		// clk_bps_r高电平为接收数据位的中间采样点,同时也作为发送数据的数据改变点 
//wire[7:0] rx_data;	//接收数据寄存器,保存直至下一个数据来到
//wire rx_int;		//接收数据中断信号,接收到数据期间始终为高电平

	//UART接收信号波特率设置
speed_setting		u4_speed_rx(	
							.clk(ui_clk),	//波特率选择模块
							.rst_n(!ui_clk_sync_rst),
							.bps_start(bps_start1),
							.clk_bps(clk_bps1)
						);

	//UART接收数据处理
my_uart_rx			u5_my_uart_rx(		
							.clk(ui_clk),	//接收数据模块
							.rst_n(!ui_clk_sync_rst),
							.uart_rx(uart_rx),
							.rx_data(user_ddr3_addr),
							.rx_rdy(user_ddr3_rden),
							.clk_bps(clk_bps1),
							.bps_start(bps_start1)
						);
		
//-------------------------------------

	//UART发送信号波特率设置													
speed_setting		u6_speed_tx(	
							.clk(ui_clk),	//波特率选择模块
							.rst_n(!ui_clk_sync_rst),
							.bps_start(bps_start2),
							.clk_bps(clk_bps2)
						);
						
	//UART发送数据处理
my_uart_tx			u7_my_uart_tx(		
							.clk(ui_clk),	//发送数据模块
							.rst_n(!ui_clk_sync_rst),
							.rx_data(ddr3uart_tx_db),
							.rx_int(ddr3uart_tx_en),//uart_tx_source模块的ddr3uart_tx_en连接rx_int端口使能串口发送模块
							.uart_tx(uart_tx),
							.clk_bps(clk_bps2),
							.bps_start(bps_start2)
						);
						

//LED闪烁逻辑产生模块例化

led_controller		u8_led_controller(
						.clk(ui_clk),			
						.rst_n(!ui_clk_sync_rst),
						.led(led[0])
					);	
	
	
endmodule

2.3 my_uart_rx.V模块、my_uart_tx.V模块和speed_setting.V模块

这一部分是上一节记录过的串口通信。文件层次图如下,这里直接放上工程,可以下载学习,我就不贴代码了。

链接:https://pan.baidu.com/s/1rX317rWFyBW2n2yrr2nHkQ 
提取码:0809 

 2.4 顶层文件

/
//特权同学 精心打造 Xilinx FPGA开发板系列
//工程硬件平台: Xilinx Artex7 FPGA 
//开发套件型号: SF-AT7 特权打造
//版   权  申   明: 本例程由《深入浅出玩转FPGA》作者“特权同学”原创,
//				仅供SF-AT7开发套件学习使用,谢谢支持
//官方淘宝店铺: http://myfpga.taobao.com/
//最新资料下载: http://pan.baidu.com/s/1c2iTPra
//公                司: 上海或与电子科技有限公司
/
module at7(
			// DDR3接口
			inout [15:0]       ddr3_dq,
			inout [1:0]        ddr3_dqs_n,
			inout [1:0]        ddr3_dqs_p,
			output [13:0]     ddr3_addr,
			output [2:0]        ddr3_ba,
			output            ddr3_ras_n,
			output            ddr3_cas_n,
			output            ddr3_we_n,
			output            ddr3_reset_n,
			output [0:0]       ddr3_ck_p,
			output [0:0]       ddr3_ck_n,
			output [0:0]       ddr3_cke,
			output [1:0]     ddr3_dm,
			output [0:0]       ddr3_odt,
			//系统时钟、外部复位
			input       sys_clk_i,
			input		ext_rst_n,	
			//UART接口
			input uart_rx,		// UART接收数据信号
			output uart_tx,		// UART发送数据信号
			//LED指示灯接口
			output[0:0] led		//用于测试的LED指示灯	PIN_L5
    );


//PLL例化
wire clk_200m;
wire sys_rst_n;
	
  clk_wiz_0 	uut_clk_wiz_0
   (
    .clk_in1(sys_clk_i),   
	
    .clk_out1(clk_200m),  

    .reset(!ext_rst_n), 
    .locked(sys_rst_n));      
	

//DDR3 controller例化

wire ui_clk;	        //时钟信号,是DDR3时钟(400MHz)的1/4,即100MHz,ui_clk是DDR3IP输出的一个时钟,供后面所有模块使用
wire ui_clk_sync_rst;	//复位信号,也是DDR3IP输出的一个信号,供后面所由模块使用

/*地址、命令*/
wire[27:0] app_addr;		//DDR3地址总线
wire[2:0] app_cmd;			//DDR3命令总线,3‘b000--写;3'b001--读;
wire app_en;	        	//DDR3操作请求信号,高电平有效
wire app_rdy;	        	//DDR3操作响应信号,表示当前的app_en请求已经获得响应,可以继续操作
wire init_calib_complete;	//校准初始化完成标志信号,高电平有效

/*向DDR3写数据*/
wire[127:0] app_wdf_data;	//DDR3写入数据总线
wire app_wdf_end;	        //DDR3最后一个字节写入指示信号,与app_wdf_data同步指示当前操作为最后一个数据写入
wire app_wdf_wren;	        //DDR3写入数据使能信号,表示当前写入数据有效
wire app_wdf_rdy;	        //DDR3可以执行写入数据操作

/*从DDR3读数据*/
wire[127:0] app_rd_data;	//DDR3读取数据总线
wire app_rd_data_end;	    //DDR3最有一个字节读取指示信号,与app_rd_data同步指示当前操作为最后一个数据读出
wire app_rd_data_valid;	    //DDR3读出数据使能信号,表示当前读出数据有效,这个信号会使能uart_tx_source模块中的fifo,DDR3读出的数据会进入fifo缓存

/*DDR3控制器IP的用户接口信号:刷新请求与响应*/
wire app_ref_req = 1'b0;	//DDR3刷新请求信号,高电平有效,该信号拉高必须保持到app_ref_ack拉高表示刷新请求已经响应
wire app_ref_ack;	        //DDR3刷新响应信号,高电平有效,该信号拉高表示已经执行DDR3的刷新操作

/*DDR3控制器IP的用户接口信号:ZQ校准请求与响应*/
wire app_zq_req = 1'b0;	    //DDR3 ZQ校准命令请求信号,高电平有效,该信号拉高必须保持到app_zq_ack拉高表示刷新请求已经响应
wire app_zq_ack;	        //DDR3 ZQ校准响应信号,高电平有效,该信号拉高表示已经执行DDR3的ZQ校准操作

/*DDR3控制器IP的用户接口信号*/
wire app_sr_req = 1'b0;
wire app_sr_active;
		  
		  
mig_7series_0 		u1_mig_7series_0 (
    // Memory interface ports
    .ddr3_addr                      (ddr3_addr),  // output [13:0]		ddr3_addr
    .ddr3_ba                        (ddr3_ba),  // output [2:0]		ddr3_ba
    .ddr3_cas_n                     (ddr3_cas_n),  // output			ddr3_cas_n
    .ddr3_ck_n                      (ddr3_ck_n),  // output [0:0]		ddr3_ck_n
    .ddr3_ck_p                      (ddr3_ck_p),  // output [0:0]		ddr3_ck_p
    .ddr3_cke                       (ddr3_cke),  // output [0:0]		ddr3_cke
    .ddr3_ras_n                     (ddr3_ras_n),  // output			ddr3_ras_n
    .ddr3_reset_n                   (ddr3_reset_n),  // output			ddr3_reset_n
    .ddr3_we_n                      (ddr3_we_n),  // output			ddr3_we_n
    .ddr3_dq                        (ddr3_dq),  // inout [15:0]		ddr3_dq
    .ddr3_dqs_n                     (ddr3_dqs_n),  // inout [1:0]		ddr3_dqs_n
    .ddr3_dqs_p                     (ddr3_dqs_p),  // inout [1:0]		ddr3_dqs_p
    .init_calib_complete            (init_calib_complete),  // output			init_calib_complete
      
    .ddr3_dm                        (ddr3_dm),  // output [1:0]		ddr3_dm
    .ddr3_odt                       (ddr3_odt),  // output [0:0]		ddr3_odt
    // Application interface ports
    .app_addr                       (app_addr),  // input [27:0]		app_addr
    .app_cmd                        (app_cmd),  // input [2:0]		app_cmd
    .app_en                         (app_en),  // input				app_en
    .app_wdf_data                   (app_wdf_data),  // input [127:0]		app_wdf_data
    .app_wdf_end                    (app_wdf_end),  // input				app_wdf_end
    .app_wdf_wren                   (app_wdf_wren),  // input				app_wdf_wren
    .app_rd_data                    (app_rd_data),  // output [127:0]		app_rd_data
    .app_rd_data_end                (app_rd_data_end),  // output			app_rd_data_end
    .app_rd_data_valid              (app_rd_data_valid),  // output			app_rd_data_valid
    .app_rdy                        (app_rdy),  // output			app_rdy
    .app_wdf_rdy                    (app_wdf_rdy),  // output			app_wdf_rdy
    .app_sr_req                     (app_sr_req),  // input			app_sr_req
    .app_ref_req                    (app_ref_req),  // input			app_ref_req
    .app_zq_req                     (app_zq_req),  // input			app_zq_req
    .app_sr_active                  (app_sr_active),  // output			app_sr_active
    .app_ref_ack                    (app_ref_ack),  // output			app_ref_ack
    .app_zq_ack                     (app_zq_ack),  // output			app_zq_ack
    .ui_clk                         (ui_clk),  // output			ui_clk
    .ui_clk_sync_rst                (ui_clk_sync_rst),  // output			ui_clk_sync_rst
    .app_wdf_mask                   (16'h00/*app_wdf_mask*/),  // input [15:0]		app_wdf_mask不确认高低有效
    // System Clock Ports
    .sys_clk_i                       (clk_200m),  // input			sys_clk_i
    .sys_rst                        (sys_rst_n) // input sys_rst
    );	
	

//产生数据源,用于测试DDR2的读写
	//用户逻辑读写DDR3接口
wire user_ddr3_rden;
wire[7:0] user_ddr3_addr;
wire user_ddr3_rddata_vld;
wire[127:0] user_ddr3_rddata;
			
data_source		u2_data_source(
					.clk(ui_clk),
					.rst_n(!ui_clk_sync_rst & init_calib_complete),
					.app_addr(app_addr),
					.app_cmd(app_cmd),
					.app_en(app_en),
					.app_rdy(app_rdy),
					.app_wdf_data(app_wdf_data),
					.app_wdf_end(app_wdf_end),
					.app_wdf_wren(app_wdf_wren),
					.app_wdf_rdy(app_wdf_rdy),
					.app_rd_data(app_rd_data),
					.app_rd_data_end(app_rd_data_end),
					.app_rd_data_valid(app_rd_data_valid),
					.user_ddr3_rden(user_ddr3_rden),
					.user_ddr3_addr(user_ddr3_addr),//串口调试助手发送的8位地址数据通过u5_my_uart_rx的rx_data输出给user_ddr3_addr端口
													//这8位地址数据将成为一个地址起点,从此地址开始往后的所有数据再通过串口返回给PC端
					.user_ddr3_rddata_vld(user_ddr3_rddata_vld),
					.user_ddr3_rddata(user_ddr3_rddata)
				);	


//UART需要发送数据缓存
wire ddr3uart_tx_en;
wire[7:0] ddr3uart_tx_db;
			
uart_tx_source		u3_uart_tx_source(
						.clk(ui_clk),	//波特率选择模块
						.rst_n(!ui_clk_sync_rst),
						.user_ddr3_rddata_vld(user_ddr3_rddata_vld),
						.user_ddr3_rddata(user_ddr3_rddata),
						.ddr3uart_tx_db(ddr3uart_tx_db),
						.ddr3uart_tx_en(ddr3uart_tx_en)
					);
		
				
//下面的四个模块中,speed_rx和speed_tx是两个完全独立的硬件模块,可称之为逻辑复制
//(不是资源共享,和软件中的同一个子程序调用不能混为一谈)

wire bps_start1,bps_start2;	//接收到数据后,波特率时钟启动信号置位
wire clk_bps1,clk_bps2;		// clk_bps_r高电平为接收数据位的中间采样点,同时也作为发送数据的数据改变点 
//wire[7:0] rx_data;	//接收数据寄存器,保存直至下一个数据来到
//wire rx_int;		//接收数据中断信号,接收到数据期间始终为高电平

	//UART接收信号波特率设置
speed_setting		u4_speed_rx(	
							.clk(ui_clk),	//波特率选择模块
							.rst_n(!ui_clk_sync_rst),
							.bps_start(bps_start1),
							.clk_bps(clk_bps1)
						);

	//UART接收数据处理
my_uart_rx			u5_my_uart_rx(		
							.clk(ui_clk),	//接收数据模块
							.rst_n(!ui_clk_sync_rst),
							.uart_rx(uart_rx),
							.rx_data(user_ddr3_addr),
							.rx_rdy(user_ddr3_rden),
							.clk_bps(clk_bps1),
							.bps_start(bps_start1)
						);
		
//-------------------------------------

	//UART发送信号波特率设置													
speed_setting		u6_speed_tx(	
							.clk(ui_clk),	//波特率选择模块
							.rst_n(!ui_clk_sync_rst),
							.bps_start(bps_start2),
							.clk_bps(clk_bps2)
						);
						
	//UART发送数据处理
my_uart_tx			u7_my_uart_tx(		
							.clk(ui_clk),	//发送数据模块
							.rst_n(!ui_clk_sync_rst),
							.rx_data(ddr3uart_tx_db),
							.rx_int(ddr3uart_tx_en),
							.uart_tx(uart_tx),
							.clk_bps(clk_bps2),
							.bps_start(bps_start2)
						);
						

//LED闪烁逻辑产生模块例化

led_controller		u8_led_controller(
						.clk(ui_clk),			
						.rst_n(!ui_clk_sync_rst),
						.led(led[0])
					);	
	
	
endmodule

三、实验现象

打开串口调试助手,发0,代表首地址是0,从首地址开始,读出DDR3  512byte数据

如图,返回了512字节数据!! 

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值