fpga控制sdram存储器的读写4:sdram写数据

一.理论知识

1.写数据之前,芯片已经完成初始化操作。初始化操作对所有L-Bank进行预充电,此时芯片中没有激活的Bank和行。所以在写数据之前,第一步要激活某个Bank和Bank中的特定行,表示即将要对该行进行写数据操作,此时需要给芯片发送激活指令,Bank地址,13位行地址。

2.紧接着要给芯片发送写数据指令和列地址信号,因为addr是分时复用信号线,此时只需要给芯片发送9位列地址信号,A9~A12是空闲状态。A10 的电平变化控制突发写操作完成后是否立即执行自动预充电操作,若 A10 为高电平,突发写操作完成后,立即执行自动预充电操作,关闭当前行;若 A10 为低电平,突发写操作完成后,当前行依然处于激活状态,以便对当前行执行新的读/写操作,想要关闭当前激活行,需写入预充电指令。剩下的A9,A11和A12信号当前不起作用,只需要赋值0即可。

3.发送写数据指令的同时发送第一个数据,然后每个时钟上升沿依次发送下一个数据。因为这里写数据选择的是页突发模式,所以数据的个数不能超过列地址个数,也就是2的9次方等于512。当不需要写数据的时候,只需要发送突发停止指令即可。

4.由于上面采用的是非自动预充电模式,因此在突发停止指令发送完之后,要给芯片发送预充电指令,用来关闭激活的bank和特定行,这样就不能在当前bank和特定行中继续执行读写操作。下次读写数据的时候,需要重新激活bank和特定行。

二.芯片时序分析

在这里插入图片描述

三.设计verilog时序图

请添加图片描述

四.verilog代码
module sdram_write
(
	input	wire	sys_clk,
	input	wire	sys_rst_n,
	input	wire	init_end,
	input	wire	wr_en,
	input	wire	[23:0] wr_addr,
	input	wire	[15:0] wr_data,
	input	wire	[9:0] wr_burst_len,
	
	output	reg		wr_ack,
	output	reg		[3:0] wr_sdram_cmd,
	output	reg		[1:0] wr_sdram_ba,
	output	reg		[12:0] wr_sdram_addr,
	output	reg		wr_end,
	output	reg		wr_sdram_en,
	output	reg		[15:0] wr_sdram_data
);

// 状态
parameter	ST_IDLE		= 0,
			ST_ACTIVE 	= 1,
			ST_ACT_WAIT	= 2,
			ST_WRITE 	= 3,
			ST_WR_DATA 	= 4,
			ST_BURST 	= 5,
			ST_PRE	 	= 6,
			ST_PRE_WAIT	= 7,
			ST_WR_END	= 8;

// 延迟计数器的值
parameter	CNT_ACT_WAIT	= 2,
			CNT_PRE_WAIT	= 2;

// 命令
parameter	CMD_NOP		= 4'b0111,
			CMD_ACTIVE	= 4'b0011,
			CMD_PRE		= 4'b0010,
			CMD_WRITE	= 4'b0100,
			CMD_BURST	= 4'b0110;

reg		[3:0] state;
reg		[9:0] cnt_wait;
reg		cnt_wait_rst;
reg		write_flag;
reg		burst_flag;
reg		pre_flag;
reg		end_flag;

// state信号
always@(posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		state <= ST_IDLE;
	else 
		case(state)
			ST_IDLE		:
				if(init_end == 1 && wr_en == 1)
					state <= ST_ACTIVE;
				else 
					state <= ST_IDLE;
			ST_ACTIVE 	:
				state <= ST_ACT_WAIT;
			ST_ACT_WAIT	:
				if(write_flag == 1)
					state <= ST_WRITE;
				else 
					state <= ST_ACT_WAIT;
			ST_WRITE 	:
				state <= ST_WR_DATA;
			ST_WR_DATA 	:
				if(burst_flag == 1)
					state <= ST_BURST;
				else 
					state <= ST_WR_DATA;
			ST_BURST 	:
				state <= ST_PRE;
			ST_PRE	 	:
				state <= ST_PRE_WAIT;
			ST_PRE_WAIT	:
				if(end_flag == 1)
					state <= ST_WR_END;
				else 
					state <= ST_PRE_WAIT;
			ST_WR_END	:
				state <= ST_IDLE;
			default		:
				state <= ST_IDLE;
		endcase
end

// cnt_wait信号
always@(posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		cnt_wait <= 0;
	else if(cnt_wait_rst == 1)
		cnt_wait <= 0;
	else if(cnt_wait_rst == 0)
		cnt_wait <= cnt_wait + 1;
end

// cnt_wait_rst信号
always@(*) begin
	if(!sys_rst_n)
		cnt_wait_rst <= 1;
	else if(state == ST_IDLE)
		cnt_wait_rst <= 1;
	else if(write_flag == 1 || burst_flag == 1 || pre_flag == 1 || end_flag == 1 || state == ST_WR_END)
		cnt_wait_rst <= 1;
	else
		cnt_wait_rst <= 0;
end

// write_flag信号
always@(*) begin
	if(!sys_rst_n)
		write_flag <= 0;
	else if(state == ST_ACT_WAIT && cnt_wait == CNT_ACT_WAIT)
		write_flag <= 1;
	else 
		write_flag <= 0;
end

// burst_flag信号
always@(*) begin
	if(!sys_rst_n)
		burst_flag <= 0;
	else if(state == ST_WR_DATA && cnt_wait == wr_burst_len - 1)
		burst_flag <= 1;
	else
		burst_flag <= 0;
end

// pre_flag信号
always@(*) begin
	if(!sys_rst_n)
		pre_flag <= 0;
	else if(state == ST_BURST)
		pre_flag <= 1;
	else 
		pre_flag <= 0;
end

// end_flag信号
always@(*) begin
	if(!sys_rst_n)
		end_flag <= 0;
	else if(state == ST_PRE_WAIT && cnt_wait == CNT_PRE_WAIT)
		end_flag <= 1;
	else
		end_flag <= 0;
end

// wr_end信号
always@(*) begin
	if(!sys_rst_n)
		wr_end <= 0;
	else if(state == ST_WR_END)
		wr_end <= 1;
	else 
		wr_end <= 0;
end

// wr_ack信号
always@(*) begin
	if(!sys_rst_n)
		wr_ack <= 0;
	else if(state == ST_WRITE)
		wr_ack <= 1;
	else if(state == ST_BURST)
		wr_ack <= 0;
	else 
		wr_ack <= wr_ack;
end

// wr_sdram_en信号
always@(posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		wr_sdram_en <= 0;
	else 
		wr_sdram_en <= wr_ack;
end

// wr_sdram_data信号
always@(*) begin
	if(!sys_rst_n)
		wr_sdram_data <= 0;
	else if(wr_sdram_en == 1)
		wr_sdram_data <= wr_data;
	else if(wr_sdram_en == 0)
		wr_sdram_data <= 0;
end

// wr_sdram_cmd信号
always@(posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		wr_sdram_cmd <= CMD_NOP;
	else if(state == ST_ACTIVE)
		wr_sdram_cmd <= CMD_ACTIVE;
	else if(state == ST_WRITE)
		wr_sdram_cmd <= CMD_WRITE;
	else if(state == ST_BURST)
		wr_sdram_cmd <= CMD_BURST;
	else if(state == ST_PRE)
		wr_sdram_cmd <= CMD_PRE;
	else
		wr_sdram_cmd <= CMD_NOP;
end

// wr_sdram_ba信号
always@(posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		wr_sdram_ba <= 2'b11;
	else if(state == ST_ACTIVE || state == ST_WRITE || state == ST_PRE)
		wr_sdram_ba <= wr_addr[23:22];
	else 
		wr_sdram_ba <= 2'b11;
end

// wr_sdram_addr信号
always@(posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n)
		wr_sdram_addr <= 13'h1fff;
	else if(state == ST_ACTIVE)
		wr_sdram_addr <= wr_addr[21:9];
	else if(state == ST_WRITE)
		wr_sdram_addr <= {4'b0000,wr_addr[8:0]};
	else if(state == ST_PRE)
		wr_sdram_addr <= 13'h0400;
	else 
		wr_sdram_addr <= 13'h1fff;
end
	
endmodule
五.仿真代码
`timescale 1ns/1ns

module tb_sdram_write();

reg		sys_clk;
reg		sys_rst_n;
reg		wr_en;
reg		[23:0] wr_addr;
reg		[15:0] wr_data;
reg		[9:0] wr_burst_len;

wire	[3:0] init_cmd;
wire	[1:0] init_ba;
wire	[12:0] init_addr;
wire	init_end;

wire	wr_ack;
wire	[3:0] wr_sdram_cmd;
wire	[1:0] wr_sdram_ba;
wire	[12:0] wr_sdram_addr;
wire	wr_end;
wire	wr_sdram_en;
wire	[15:0] wr_sdram_data;

wire	clk_100m;
wire	clk_100m_shift;
wire	clk_locked;
wire	rst_n;

wire	[3:0] sdram_cmd;
wire	[1:0] sdram_ba;
wire	[12:0] sdram_addr;
wire	[15:0] sdram_dq;

assign	rst_n = sys_rst_n & clk_locked;

initial begin
	sys_clk		= 0;
	sys_rst_n	<= 0;
	#100
	sys_rst_n	<= 1;
end

always #10 sys_clk = ~sys_clk;

// wr_en信号
always@(posedge clk_100m or negedge rst_n) begin
	if(!rst_n)
		wr_en <= 0;
	else if(wr_end == 1)
		wr_en <= 0;
	else if(init_end == 1)
		wr_en <= 1;
end

// bank和地址信号
//assign wr_addr = 24'h000000;

// wr_data信号
always@(posedge clk_100m or negedge rst_n) begin
    if(!rst_n)
        wr_data <= 0;
    else if(wr_ack == 1)
        wr_data <= wr_data + 1;
    else if(wr_ack == 0)
		wr_data <= 0;
	else
        wr_data <= wr_data;
end

// wr_burst_len信号
//assign wr_burst_len = 10;

// dq信号
assign sdram_dq = (wr_sdram_en == 1) ? wr_sdram_data : 16'hz;

clk_100m clk_100m_inst
(
	.areset (~sys_rst_n	),
	.inclk0 (sys_clk	),
	.c0 	(clk_100m	),
	.c1 	(clk_100m_shift	),
	.locked (clk_locked)
);

sdram_init sdram_init_inst
(
	.sys_clk	(clk_100m	),
	.sys_rst_n	(rst_n		),

	.init_cmd	(init_cmd	),
	.init_ba	(init_ba	),
	.init_addr	(init_addr	),
	.init_end	(init_end	)
);

defparam	sdram_model_plus_inst.addr_bits = 13;	// 行地址13位
defparam	sdram_model_plus_inst.data_bits = 16;	// 一次读写数据16位
defparam	sdram_model_plus_inst.col_bits = 9;		// 列地址9位
defparam	sdram_model_plus_inst.mem_sizes = 2*1024*1024;	// L-Bank容量

sdram_write sdram_write_inst
(
	.sys_clk		(clk_100m		),
	.sys_rst_n		(rst_n			),
	.init_end		(init_end		),
	.wr_en			(wr_en			),
	.wr_addr		(24'h000000		),
	.wr_data		(wr_data		),
	.wr_burst_len	(10				),

	.wr_ack			(wr_ack			),
	.wr_sdram_cmd	(wr_sdram_cmd	),
	.wr_sdram_ba	(wr_sdram_ba	),
	.wr_sdram_addr	(wr_sdram_addr	),
	.wr_end			(wr_end			),
	.wr_sdram_en	(wr_sdram_en	),
	.wr_sdram_data	(wr_sdram_data	)
);

assign sdram_addr = (init_end == 1) ? wr_sdram_addr : init_addr;
assign sdram_ba = (init_end == 1) ? wr_sdram_ba : init_ba;
assign sdram_cmd = (init_end == 1) ? wr_sdram_cmd : init_cmd;

sdram_model_plus sdram_model_plus_inst
(
	.Dq		(sdram_dq	), 	// 数据输入输出端口
	.Addr	(sdram_addr	), 	// 地址端口
	.Ba		(sdram_ba	), 	// Bank地址
	.Clk	(clk_100m_shift	), 	// 带有偏移的时钟信号
	.Cke	(1			), 	// 时钟使能信号
	.Cs_n	(sdram_cmd[3]),	// 命令第4位
	.Ras_n	(sdram_cmd[2]),	// 命令第3位
	.Cas_n	(sdram_cmd[1]),	// 命令第2位
	.We_n	(sdram_cmd[0]),	// 命令第1位
	.Dqm	(2'b00		),	// 数据掩码
	.Debug	(1			)	// 开启Debug模式
);

endmodule
六.仿真结果

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值