原创 SRAM操作一点通

2010-8-10 21:17 2232 3 3 分类: FPGA/CPLD
诸如UT62256,GM76C256,IS61LV5128等SRAM芯片,基本上他们的时序操作大同小异,在这里总结一些它们共性的东西,也提一些简单的快速操作SRAM的技巧。

    这里就拿刚用着的IS61LV5128说吧,它的管脚分配如下:




具体什么功能我就不废话,上面都有。具体在硬件连接的时候,其实很多人喜欢直接把输出使能信号OE和片选信号CE接地,这样一来不仅节省了处理器和SRAM连接的管教数,而且在读写SRAM的时候其实只要对写使能信号WE操作就可以了,简化了软件部分。


SRAM的读写时序操作如下:





 


    因为在硬件上已经把CE和OE拉低了,所以如果不希望读写SRAM的时候,实际上SRAM的数据总线上的值是这时候的地址总线上的地址对应的数据。所以为了避免误操作,我们可以把地址总线置高阻态,其实我们不去操作数据总线(最好不是复用的数据总线)也无大碍。因为这样简化了软硬件的设计。上面的时序图,我们也只要关心ADDR,DATA总线和WE信号。


    具体操作是这样的,我们要写数据,(我这里是相对与用HDL操作SRAM而言的,软件读写可能有时间顺序的问题需要注意),那么比较高效率的操作是同时把WE拉低,送数据送地址,然后延时>TWC,把WE拉高,这时就把数据写入了相应地址了,就这么简单。因为数据的锁存不是在WE的上升沿,所以WE拉高后也没有必要保持数据总线的数据(即THD=0)。读数据就更简单了,只要把送需要读出的地址,然后延时>TAA后就可以读出你要的数据了。确实很简单的。


    如果要高效的读写SRAM,那么对于FPGA/CPLD来说,我假设目前这个芯片是10ns(TWC)的读取速度,系统时钟50MHz(20ns),我第一个时钟周期送地址,拉高(读)或者拉低(写)WE信号,送数据(写操作,读就把数据总线置高阻态),然后第二个时钟周期可以改变地址做下一步操作(如果是读数据这个时候同时把数据读出),如此下去,可以做到沿着时钟周期流水线般的读写数据。


 


   这是我们实验的源代码,要实现的功能我就不多说了,大家消化了代码(有很详细的注释)就明白了:


 


`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date:   
// Design Name:   
// Module Name:   
// Project Name:  
// Target Device: 
// Tool versions: 
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////
module sram_test(
    clk,rst_n,led,
    sram_addr,sram_wr_n,sram_data
   );


input clk;  // 50MHz
input rst_n; //低电平复位
output led;  // LED1


 // CPLD与SRAM外部接口
output[14:0] sram_addr; // SRAM地址总线
output sram_wr_n;  // SRAM写选通
inout[7:0] sram_data; // SRAM数据总线


//-------------------------------------------------------
reg[25:0] delay; //延时计数器


always @ (posedge clk or negedge rst_n)
 if(!rst_n) delay <= 26'd0;
 else delay <= delay+1; //不断计数,周期约为1.28s
 
//-------------------------------------------------------
reg[7:0] wr_data; // SRAM写入数据总线 
reg[7:0] rd_data; // SRAM读出数据
reg[14:0] addr_r; // SRAM地址总线
wire sram_wr_req; // SRAM写请求信号
wire sram_rd_req; // SRAM读请求信号
reg led_r;   // LED寄存器


assign sram_wr_req = (delay == 26'd9999); //产生写请求信号
assign sram_rd_req = (delay == 26'd19999); //产生读请求信号
 
always @ (posedge clk or negedge rst_n)
 if(!rst_n) wr_data <= 8'd0;
 else if(delay == 26'd29999) wr_data <= wr_data+1'b1; //写入数据每1.28s自增1
always @ (posedge clk or negedge rst_n)
 if(!rst_n) addr_r <= 15'd0;
 else if(delay == 26'd29999) addr_r <= addr_r+1'b1; //写入地址每1.28s自增1
 
always @ (posedge clk or negedge rst_n)
 if(!rst_n) led_r <= 1'b0;
 else if(delay == 26'd20099) begin //每1.28s比较一次同一地址写入和读出的数据
   if(wr_data == rd_data) led_r <= 1'b1; //写入和读出数据一致,LED点亮
   else led_r <= 1'b0;      //写入和读出数据不同,LED熄灭
  end
assign led = led_r;


//-------------------------------------------------------
`define DELAY_80NS  (cnt==3'd7)


reg[2:0] cnt; //延时计数器


always @ (posedge clk or negedge rst_n)
 if(!rst_n) cnt <= 3'd0;
 else if(cstate == IDLE) cnt <= 3'd0;
 else cnt <= cnt+1'b1;
   
//------------------------------------
parameter IDLE = 4'd0,
   WRT0 = 4'd1,
   WRT1 = 4'd2,
   REA0 = 4'd3,
   REA1 = 4'd4;


reg[3:0] cstate,nstate;


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


always @ (cstate or sram_wr_req or sram_rd_req or cnt)
 case (cstate)
   IDLE: if(sram_wr_req) nstate <= WRT0;  //进入写状态
      else if(sram_rd_req) nstate <= REA0; //进入读状态
      else nstate <= IDLE;
   WRT0: if(`DELAY_80NS) nstate <= WRT1;
      else nstate <= WRT0;    //延时等待160ns 
   WRT1: nstate <= IDLE;   //写结束,返回
   REA0: if(`DELAY_80NS) nstate <= REA1;
      else nstate <= REA0;    //延时等待160ns
   REA1: nstate <= IDLE;   //读结束,返回
  default: nstate <= IDLE;
  endcase
   
//-------------------------------------


assign sram_addr = addr_r; // SRAM地址总线连接


//-------------------------------------   
reg sdlink;    // SRAM数据总线控制信号


always @ (posedge clk or negedge rst_n)
 if(!rst_n) rd_data <= 8'd0;
 else if(cstate == REA1) rd_data <= sram_data;  //读出数据


always @ (posedge clk or negedge rst_n)
 if(!rst_n) sdlink <=1'b0;
 else
  case (cstate)
   IDLE: if(sram_wr_req) sdlink <= 1'b1;  //进入连续写状态
      else if(sram_rd_req) sdlink <= 1'b0; //进入单字节读状态
      else sdlink <= 1'b0;
   WRT0: sdlink <= 1'b1;
   default: sdlink <= 1'b0;
   endcase


assign sram_data = sdlink ? wr_data : 8'hzz; // SRAM地址总线连接   
assign sram_wr_n = ~sdlink;
   
endmodule

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
3
关闭 站长推荐上一条 /3 下一条