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

本文探讨了在DE2平台上使用Verilog硬件语言直接访问SDRAM的方法,通过状态机实现读写操作,展示了如何利用Sdram_Controller模块进行数据交换,并将数据输出至七段显示器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值