(原創) 如何在DE2用硬體存取SDRAM? (IC Design) (DE2)

Abstract
之前討論過在DE2用軟體的C語言存取SDRAM,本文討論用硬體的Verilog存取SDRAM。

Introduction
使用環境:Quartus II 7.2 SP1 + MegaCore IP 7.2 SP1 + DE2(Cyclone II EP2C35F627C6)

(原創) 如何在DE2用軟體存取SDRAM? (IC Design) (DE2) (Nios II) 討論過在Nios II下,用軟體C語言去存取SDRAM,由於DE2的Cyclone II是個FPGA,為了硬體加速,有時可能會想將演算法用硬體Verilog實現,這時就得用硬體Verilog去直接存取SDRAM。

如同上一篇的範例,用switch當成2進位的輸入,但這次改用七段顯示器做16進位輸出,使用到(原創) 如何顯示8位數的七段顯示器? (IC Design) (Verilog) (DE2)所開發的module。

Verilog / SDRAM_HR_HW.v

  1  /*  
  2  (C) OOMusou 2008  http://oomusou.cnblogs.com
  3 
  4  Filename    : SDRAM_HR_HW.v
  5  Compiler    : Quartus II 7.2 SP1
  6  Description : Demo how to use abstract base class simulate interface
  7  Release     : 04/25/2008 1.0
  8  */
  9  module SDRAM_HR_HW (
 10    input         CLOCK_50,
 11    input  [ 3 : 0 ]  KEY,
 12    input  [ 17 : 0 ] SW,
 13    output [ 17 : 0 ] LEDR,
 14    output [ 6 : 0 ]  HEX0,
 15                  HEX1,
 16                  HEX2,
 17                  HEX3,
 18                  HEX4,
 19                  HEX5,
 20                  HEX6,
 21                  HEX7,
 22     // SDRAM side
 23    output [ 11 : 0 ] DRAM_ADDR,
 24    inout  [ 15 : 0 ] DRAM_DQ,
 25    output        DRAM_BA_0,
 26                  DRAM_BA_1,
 27                  DRAM_RAS_N,
 28                  DRAM_CAS_N,
 29                  DRAM_CKE,
 30                  DRAM_CLK,
 31                  DRAM_WE_N,
 32                  DRAM_CS_N,
 33                  DRAM_LDQM,
 34                  DRAM_UDQM
 35  );
 36 
 37  wire        RESET_n  =  KEY[ 0 ];
 38  wire        DONE;      //  write / read done
 39  reg  [ 22 : 0 ] addr;      //  address regitster
 40  reg         read,      //  read enable register
 41              write;     //  write enable register
 42  reg  [ 1 : 0 ]  state;     //  FSM state register
 43  reg  [ 15 : 0 ] data_in;   //  data input register
 44  wire [ 15 : 0 ] DATA_OUT;  //  data output
 45  reg  [ 15 : 0 ] data_out;  //  data output register
 46 
 47  assign LEDR  =  SW;
 48 
 49  Sdram_Controller u0 (
 50     //  HOST
 51    .REF_CLK(CLOCK_50),  // system clock
 52    .RESET_N(RESET_n),   // system reset
 53    .ADDR(address),      // address for controller request
 54    .WR(write),          // write request
 55    .RD(read),           // read request
 56    .LENGTH( 8 ' h02),     //request data length
 57    .ACT(),              // SDRAM ACK(acknowledge)
 58    .DONE(DONE),         // write/read done
 59    .DATAIN(data_in),    // Data input
 60    .DATAOUT(DATA_OUT),  // Data output
 61    .IN_REQ(),           // input data request
 62    .OUT_VALID(),        // output data vilid
 63    .DM( 2 ' b00),         //Data mask input
 64     //  SDRAM
 65    .SA(DRAM_ADDR),
 66    .BA({DRAM_BA_1,DRAM_BA_0}),
 67    .CS_N(DRAM_CS_N),
 68    .CKE(DRAM_CKE),
 69    .RAS_N(DRAM_RAS_N),
 70    .CAS_N(DRAM_CAS_N),
 71    .WE_N(DRAM_WE_N),
 72    .DQ(DRAM_DQ),
 73    .DQM({DRAM_UDQM,DRAM_LDQM}),
 74    .SDR_CLK(DRAM_CLK)
 75  );
 76 
 77  SEG7_LUT_8 u1 (
 78    .oSEG0(HEX0),       //  output SEG0
 79    .oSEG1(HEX1),       //  output SEG1
 80    .oSEG2(HEX2),       //  output SEG2
 81    .oSEG3(HEX3),       //  output SEG3
 82    .oSEG4(HEX4),       //  output SEG4
 83    .oSEG5(HEX5),       //  output SEG5
 84    .oSEG6(HEX6),       //  output SEG6
 85    .oSEG7(HEX7),       //  output SEG7
 86    .iDIG(data_out),    //  input data
 87    .iWR( 1 ' b1),        // write enable
 88    .iCLK(CLOCK_50),    //  clock
 89    .iRESET_n(RESET_n)  //  RESET
 90  );
 91 
 92  //  state 0 : prepare write
 93  //  state 1 : read switch & write SDRAM
 94  //  state 2 : prepare read
 95  //  state 3 : read SDRAM & write to SEG7
 96  always @(posedge CLOCK_50 or negedge RESET_n)
 97  begin
 98     if  ( ! RESET_n) begin
 99      addr     <=   0 //  address register
100      read     <=   0 //  read enable register
101      write    <=   0 //  write enale register
102      state    <=   0 //  FSM state register
103      data_in  <=   0 //  data input register
104    end
105     else
106    begin
107       case  (state)
108         //  state 0 : prepare write
109         0 : begin
110          read   <=   0 //  read diable
111          write  <=   1 //  write enable
112          state  <=   1 //  next state
113        end
114        
115         // state 1 : read switch & write SDRAM
116         1 : begin
117           if  (DONE)   //  prepared done
118          begin
119            addr     <=  { 23 { 1 ' b0}}; // write SDRAM address
120            data_in  <=  {SW[ 15 : 0 ]};  //  write SDRAM data
121            
122             //  ensure done change to 0
123            read     <=   0 ;           //  read disable
124            write    <=   0 ;           //  write disable
125            state    <=   2 ;           //  next state
126          end
127        end
128        
129         //  state 2 : prepare read
130         2 : begin
131          read   <=   1 //  read enable
132          write  <=   0 //  write disable
133          state  <=   3 //  next state
134        end
135 
136         //  state 3 : read SDRAM & write to SEG7
137         3 : begin
138           if  (DONE) begin
139            addr      <=  { 23 { 1 ' b0}}; // read SDRAM address
140            data_out  <=  DATA_OUT;    //  read SDRAM data
141            
142            read      <=   0 ;           //  read disable
143            write     <=   0 ;           //  write disable
144            state     <=   0 ;           //  next state
145          end
146        end
147      endcase
148    end
149  end
150 
151  endmodule


49行

Sdram_Controller u0 (
  
//  HOST
  .REF_CLK(CLOCK_50),  // system clock
  .RESET_N(RESET_n),   // system reset
  .ADDR(address),      // address for controller request
  .WR(write),          // write request
  .RD(read),           // read request
  .LENGTH( 8 ' h02),     //request data length
  .ACT(),              // SDRAM ACK(acknowledge)
  .DONE(DONE),         // write/read done
  .DATAIN(data_in),    // Data input
  .DATAOUT(DATA_OUT),  // Data output
  .IN_REQ(),           // input data request
  .OUT_VALID(),        // output data vilid
  .DM( 2 ' b00),         //Data mask input
   //  SDRAM
  .SA(DRAM_ADDR),
  .BA({DRAM_BA_1,DRAM_BA_0}),
  .CS_N(DRAM_CS_N),
  .CKE(DRAM_CKE),
  .RAS_N(DRAM_RAS_N),
  .CAS_N(DRAM_CAS_N),
  .WE_N(DRAM_WE_N),
  .DQ(DRAM_DQ),
  .DQM({DRAM_UDQM,DRAM_LDQM}),
  .SDR_CLK(DRAM_CLK)
);


我們引進了Sdram_Controller,這是個2 port的controller,1 read 1 write,大部分狀況下,2 port已經夠用,4 port的我會另外討論。

77行

SEG7_LUT_8 u1 (
  .oSEG0(HEX0),      
//  output SEG0
  .oSEG1(HEX1),       //  output SEG1
  .oSEG2(HEX2),       //  output SEG2
  .oSEG3(HEX3),       //  output SEG3
  .oSEG4(HEX4),       //  output SEG4
  .oSEG5(HEX5),       //  output SEG5
  .oSEG6(HEX6),       //  output SEG6
  .oSEG7(HEX7),       //  output SEG7
  .iDIG(data_out),    //  input data
  .iWR( 1 ' b1),        // write enable
  .iCLK(CLOCK_50),    //  clock
  .iRESET_n(RESET_n)  //  RESET
);


引進了之前所寫的七段顯示器module,將output用七段顯示器表示。

91行

//  state 0 : prepare write
//  state 1 : read switch & write SDRAM
//  state 2 : prepare read
//  state 3 : read SDRAM & write to SEG7
always @(posedge CLOCK_50 or negedge RESET_n)
begin
  
if  ( ! RESET_n) begin
    addr    
<=   0 //  address register
    read     <=   0 //  read enable register
    write    <=   0 //  write enale register
    state    <=   0 //  FSM state register
    data_in  <=   0 //  data input register
  end
  
else
  begin
    
case  (state)
      
//  state 0 : prepare write
       0 : begin
        read  
<=   0 //  read diable
        write  <=   1 //  write enable
        state  <=   1 //  next state
      end
      
      
// state 1 : read switch & write SDRAM
       1 : begin
        
if  (DONE)   //  prepared done
        begin
          addr    
<=  { 23 { 1 ' b0}}; // write SDRAM address
          data_in  <=  {SW[ 15 : 0 ]};  //  write SDRAM data
          
          
//  ensure done change to 0
          read     <=   0 ;           //  read disable
          write    <=   0 ;           //  write disable
          state    <=   2 ;           //  next state
        end
      end
      
      
//  state 2 : prepare read
       2 : begin
        read  
<=   1 //  read enable
        write  <=   0 //  write disable
        state  <=   3 //  next state
      end

      
//  state 3 : read SDRAM & write to SEG7
       3 : begin
        
if  (DONE) begin
          addr     
<=  { 23 { 1 ' b0}}; // read SDRAM address
          data_out  <=  DATA_OUT;    //  read SDRAM data
          state     <=   0 ;           //  next state
        end
      end
    endcase
  end
end


我們採用了FSM,對SDRAM做存取。
1.當state為0時,送出寫入準備信號。
2.當state為1時,讀取switch值並寫入SDRAM。
3.當state為2時,送出讀取準備信號。
4.當state為3時,讀取SDRAM並回到state 0。

108行

0 : begin
  read  
<=   0 //  read diable
  write  <=   1 //  write enable
  state  <=   1 //  next state
end


當state為0時,read <= 0;,write <= 1;表示準備寫入SDRAM,state <= 1;進入下一個state。

115行

// state 1 : read switch & write SDRAM
1 : begin
  
if  (DONE)   //  prepared done
  begin
    addr    
<=  { 23 { 1 ' b0}}; // write SDRAM address
    data_in  <=  {SW[ 15 : 0 ]};  //  write SDRAM data
          
    
//  ensure done change to 0
    read     <=   0 ;           //  read disable
    write    <=   0 ;           //  write disable
    state    <=   2 ;           //  next state
  end
end


這是本程式最重要的一段程式碼。

當state為1時,對SDRAM正式寫入。

當DONE為0時,表示SDRAM還無法讀寫,必須先回到state 0做寫入準備,或state 2做讀取準備,等到DONE為1時才可對SDRAM作正常讀寫。

addr為指定寫入SDRAM的記憶體位址,data_in為欲寫入SDRAM的資料。DE2上的SDRAM容量為8 MB,由4個bank所組成,addr[22:20]為bank數,addr[19:0]為每個bank內的記憶體位址。

最後須將 read <= 0;與wrie <= 0;讓DONE還原成0,因為在Sdram_Controller.v的245行

if ( ! WR  &&   ! RD)
  mDONE
<= 0 ;


DONE變成0,SDRAM可重新做讀取與寫入準備。最後 state <= 2;進入下一個state。

130行

//  state 2 : prepare read
2 : begin
  read  
<=   1 //  read enable
  write  <=   0 //  write disable
  state  <=   3 //  next state
end


道理同state 0,但此時是做讀取準備。

137行

//  state 3 : read SDRAM & write to SEG7
3 : begin
  
if  (DONE) begin
    addr     
<=  { 23 { 1 ' b0}}; // read SDRAM address
    data_out  <=  DATA_OUT;    //  read SDRAM data
          
    read     
<=   0 ;           //  read disable
    write     <=   0 ;           //  write disable
    state     <=   0 ;           //  next state
  end
end


道理同state 1,但此時是從SDRAM讀取資料,從DATA_OUT讀取資料進register後,回到state 0。

完整程式碼下載
sdram_hr_hw.7z

Conclusion
SDRAM_Controller都放在完整程式碼中,有需要的人可自行下載。

相對於其他記憶體,SDRAM是最麻煩的,但其最便宜且容量最大,當你的資料很大時(如影像處理),使用SDRAM的機會就很大。在此範例也學到循序電路配合FSM後,可重複做不同的事情,這是硬體描述語言慣用的手法。

See Also
(原創) 如何在DE2用軟體存取SDRAM? (IC Design) (DE2) (Nios II)
(原創) 如何顯示8位數的七段顯示器? (IC Design) (Verilog) (DE2)
(原創) 如何在DE2用硬體存取SDRAM(4 port)? (IC Design) (DE2)
(筆記) DE2與SDRAM相關資料總整理 (SOC) (DE2)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值