FPGA-SRAM读写测试

之前一直没太搞懂这个SRAM 是用来做什么的,现在做完了vga的觉得这个SRAM的作用很大,说白了这就是个储存器,而在我vga的字符的读取显示中,难度最大的也是在存储器上,之前有人建议我在做的时候改用ram可以实现字符的动态显示而不是局限于自己独自开辟的显示区域,下面我就先从SRAM入手,好好的介绍下这几个存储器(最近更ROM  RAM  SRAM )

在有数据传输的地方就会有存储器

SRAM(static RAM):异步传输易失存储器

优点:读写传输迅速,控制时序不复杂(这里我用的特权的板子就直接把他们写的东西拿来用了)

找来任何一颗SRAM芯片的datasheet,会发现它们的时序操作大同小异,在这里总结一些它们共性的东西,也提一些用Verilog简单的快速操作SRAM的技巧。SRAM内部的结构如图所示,

1、要访问实际的Momory区域,FPGA必须送地址(A0-A14)和控制信号(CE  \OE  \WE  ),

2、SRAM内部有与此对应的地址译码(decoder)

3、控制处理电路(control circuit)。

这样,数据总线(I/O0-I/O7)上的数据就可以相应的读或写了。

         这里就以本实验使用的IS62LV256-45U为例进行说明。其管脚定义如表所示。

序号

管脚

方向

描述

1

A0-A14

Input

地址总线。

2

CEn

Input

芯片使能输入,低有效。

3

OEn

Input

输出使能输入,低有效。

4

WEn

Input

写使能输入,低有效。

5

I/O0-I/O7

Inout

数据输入/输出总线。

6

VCC

Input

电源。

7

GND

Input

数字地。

本设计的硬件原理图如图所示。

图6.59 SRAM接口

对于SRAM的读操作时序,其波形如图所示。

对于SRAM的写操作时序,其波形如图所示。

代码如下:

top.v:

module top(ext_clk_25m,ext_rst_n,led,
sram_cs_n,sram_we_n,sram_oe_n,
sram_data,sram_addr
    );
	input ext_clk_25m;
	input ext_rst_n;
	output led;
	output sram_cs_n;
	output sram_we_n;
	output sram_oe_n;
	output [14:0] sram_addr;
	inout [7:0] sram_data;

	wire clk_12m5;
	wire clk_25m;
	wire clk_50m;
	wire clk_65m;
	wire clk_108m;
	wire clk_130m;
	wire sys_rst_n;
	
	pll_controller uut_pll_controller
   (// Clock in ports
    .CLK_IN1(ext_clk_25m),      // IN
    // Clock out ports
    .CLK_OUT1(clk_12m5),     // OUT
    .CLK_OUT2(clk_25m),     // OUT
    .CLK_OUT3(clk_50m),     // OUT
    .CLK_OUT4(clk_65m),     // OUT
    .CLK_OUT5(clk_108m),     // OUT
    .CLK_OUT6(clk_130m),     // OUT
    // Status and control signals
    .RESET(~ext_rst_n),// IN
    .LOCKED(sys_rst_n)
	);    
	
	//定时写sram测试模块
	wire sramwr_req;
	wire sramrd_req;
	wire [7:0] sramwr_data;
	wire [7:0] sramrd_data;
	wire [14:0] sramwr_addr;
	wire [14:0] sramrd_addr;
	test_timing uut_test_timing(
	.clk(clk_50m),
	.rst_n(sys_rst_n),
	.led(led),
	.sramwr_req(sramwr_req),
	.sramrd_req(sramrd_req),
	.sramwr_data(sramwr_data),
	.sramrd_data(sramrd_data),
	.sramwr_addr(sramwr_addr),
	.sramrd_addr(sramrd_addr)
    );
	//sram基本读写模块
	sram_controller uut_sram_controller(
	.clk(clk_50m),
	.rst_n(sys_rst_n),
	.sramwr_req(sramwr_req),
	.sramrd_req(sramrd_req),
	.sramwr_data(sramwr_data),
	.sramrd_data(sramrd_data),
	.sramwr_addr(sramwr_addr),
	.sramrd_addr(sramrd_addr),
	.sram_cs_n(sram_cs_n),
	.sram_we_n(sram_we_n),
	.sram_oe_n(sram_oe_n),
	.sram_addr(sram_addr),
	.sram_data(sram_data)
    );
endmodule

timing.v:

module test_timing(clk,rst_n,led,sramwr_req,sramrd_req,sramwr_data,sramrd_data,sramwr_addr,sramrd_addr
    );
	input clk;//输入时钟
	input rst_n;//复位信号
	output reg led;//LED指示灯
	output           sramwr_req ;//SRAM写请求信号,高电位有效,用于状态机控制
	output           sramrd_req ;//SRAM读请求信号,高电位有效,用于状态机控制
	output reg [7:0] sramwr_data;//SRAM写入数据寄存器
	input      [7:0] sramrd_data;//SRAM读出数据寄存器
	output reg [14:0]sramwr_addr;//SRAM写入地址寄存器
	output reg [14:0]sramrd_addr;//SRAM读取地址寄存器
	
	//一秒定时
	
	reg[25:0] delay;
	always@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			delay<=1'b0;
		end
		else if(delay<26'd49_999_999)begin
			delay<=delay+1'b1;
		end
		else begin
			delay<=1'b0;
		end
	end
	assign sramwr_req =(delay==26'd1000);
	assign sramrd_req =(delay==26'd1100);
	//定时写入数据寄存器
	always@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			sramwr_data<=8'd0;
		end
		else if(delay==26'd4000)begin
			sramwr_data<=sramrd_data+1'b1;
		end
	end
	//定时SRAM读和写地址寄存器
	always@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			sramwr_addr<=1'b0;
		end
		else if(delay==26'd4000)begin
			sramwr_addr<=sramwr_addr+1'b1;
		end
	end
	always@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			sramrd_addr<=1'b0;
		end
		else if(delay==26'd4000)begin
			sramrd_addr<=sramrd_addr+1'b1;
		end
	end
	//比较数据
	always@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			led<=1'b1;
		end
		else if(delay==26'd3000)begin
			if(sramrd_data==sramwr_data)begin
				led<=1'b0;
			end
			else begin
				led<=1'b1;
			end
		end
	end
	
	
endmodule

sram_controller.v:

module sram_controller(clk,rst_n,
sramwr_req,sramrd_req,sramwr_data,sramrd_data,sramwr_addr,sramrd_addr,
sram_cs_n,sram_we_n,sram_oe_n,sram_addr,sram_data
    );
	input clk;
	input rst_n;
	//读写控制信号
	input            sramwr_req;//SRAM写请求信号,高电位有效,用于状态机控制     
	input            sramrd_req;//SRAM读请求信号,高电位有效,用于状态机控制
	input [7:0]     sramwr_data;//SRAM写入数据寄存器
	output reg [7:0]sramrd_data;//SRAM读出数据寄存器
	input [14:0]    sramwr_addr;//SRAM写入地址寄存器
	input [14:0]    sramrd_addr;//SRAM读取地址寄存器
	//FPGA与芯片的接口信号
	output reg        sram_cs_n;//SRAM片选信号
	output reg        sram_we_n;//SRAM写入信号
	output reg        sram_oe_n;//SRAM输出选通信号
	output reg [14:0] sram_addr;//地址总线
	inout [7:0] sram_data;//数据总线
	`define DELAY_00NS  (cnt==3'd0) 
	`define DELAY_20NS  (cnt==3'd1)
	`define DELAY_40NS  (cnt==3'd2) 
	`define DELAY_60NS  (cnt==3'd3)
	parameter	IDLE = 4'd0,
				WRT0 = 4'd1,
				WRT1 = 4'd2,
				REA0 = 4'd3,
				REA1 = 4'd4;
	reg [3:0]state_c;
	reg [3:0]state_n;
	reg [2:0] cnt;
	//延时计数器
	always@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			cnt<=1'b0;
		end
		else if(state_c==IDLE)begin
			cnt<=1'b0;
		end
		else begin
			cnt<=cnt+1'b1;
		end
	end
	
	//SRAM读写状态机
	always@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			state_c<=IDLE;
		end
		else begin
			state_c<=state_n;
		end
	end
	always@(state_c or sramwr_req or sramrd_req or cnt)begin
		case(state_c)
			IDLE:if(sramwr_req==1'b1)begin
					state_n<=WRT0;
				end
				else if(sramrd_req==1'b1)begin
					state_n<=REA0;
				end
				else begin
					state_n<=IDLE;
				end
			WRT0:if(`DELAY_60NS)begin
					state_n<=WRT1;
				end
				else begin
					state_n<=WRT0;
				end
			WRT1:state_n<=IDLE;
			REA0:if(`DELAY_60NS)begin
					state_n<=REA1;
				end
				else begin
					state_n<=REA0;
				end
			REA1:state_n<=IDLE;
			default:state_n<=IDLE;
		endcase
	end
	//地址赋值
	always@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			sram_addr<=15'd0;
		end
		else if(state_c==WRT0)begin
			sram_addr<=sramwr_addr;
		end
		else if(state_c==WRT1)begin
			sram_addr<=15'd0;
		end
		else if(state_c==REA0)begin
			sram_addr<=sramrd_addr;
		end
		else if(state_c==REA1)begin
			sram_addr<=15'd0;
		end
	end
	reg sdlink;
	//SRAM读写控制
	always@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			sramrd_data<=8'd0;
		end
		else if((state_c==REA0)&&`DELAY_60NS)begin
			sramrd_data<=sram_data;
		end
	end
	always@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			sdlink<=1'b0;
		end
		else if(state_c==WRT0)begin
			sdlink<=1'b1;
		end
		else if(state_c==WRT1)begin
			sdlink<=1'b0;
		end
	end
	assign sram_data = sdlink?sramwr_data:8'hzz;
	//SRAM片选控制
	always@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			sram_cs_n<=1'b1;
		end
		else if(state_c==WRT0)begin
			if(`DELAY_00NS)begin
				sram_cs_n<=1'b1;
			end
			else begin
				sram_cs_n<=1'b0;
			end
		end
		else if(state_c==REA0)begin
			sram_cs_n<=1'b0;
		end
		else begin
			sram_cs_n<=1'b1;
		end
	end
	//读选通控制
	always@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			sram_oe_n<=1'b1;
		end
		else if(state_c==REA0)begin
			sram_oe_n<=1'b0;
		end
		else begin
			sram_oe_n<=1'b1;
		end
	end
	
	//写选通控制
	always@(posedge clk or negedge rst_n)begin
		if(rst_n==1'b0)begin
			sram_we_n<=1'b1;
		end
		else if(state_c==WRT0)begin
			if(`DELAY_20NS)begin
				sram_we_n<=1'b0;
			end
				else if(`DELAY_60NS)begin
				sram_we_n<=1'b1;
			end
		end
	end
endmodule

 

你可能感兴趣的:(FPGA专栏)