0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于SANXIN -B01 FPGA開(kāi)發(fā)板的SDR SDRAM驅(qū)動(dòng)設(shè)計(jì)

電子工程師 ? 來(lái)源:FPGA技術(shù)江湖 ? 作者:郝旭帥 ? 2021-04-15 15:14 ? 次閱讀

本系列將帶來(lái)FPGA的系統(tǒng)性學(xué)習(xí),從最基本的數(shù)字電路基礎(chǔ)開(kāi)始,最詳細(xì)操作步驟,最直白的言語(yǔ)描述,手把手的“傻瓜式”講解,讓電子信息、通信類(lèi)專(zhuān)業(yè)學(xué)生、初入職場(chǎng)小白及打算進(jìn)階提升的職業(yè)開(kāi)發(fā)者都可以有系統(tǒng)性學(xué)習(xí)的機(jī)會(huì)。

系統(tǒng)性的掌握技術(shù)開(kāi)發(fā)以及相關(guān)要求,對(duì)個(gè)人就業(yè)以及職業(yè)發(fā)展都有著潛在的幫助,希望對(duì)大家有所幫助。后續(xù)會(huì)陸續(xù)更新 Xilinx 的 Vivado、ISE 及相關(guān)操作軟件的開(kāi)發(fā)的相關(guān)內(nèi)容,學(xué)習(xí)FPGA設(shè)計(jì)方法及設(shè)計(jì)思想的同時(shí),實(shí)操結(jié)合各類(lèi)操作軟件,會(huì)讓你在技術(shù)學(xué)習(xí)道路上無(wú)比的順暢,告別技術(shù)學(xué)習(xí)小BUG卡破腦殼,告別目前忽悠性的培訓(xùn)誘導(dǎo),真正的去學(xué)習(xí)去實(shí)戰(zhàn)應(yīng)用,這種快樂(lè)試試你就會(huì)懂的。話不多說(shuō),上貨。

本篇實(shí)現(xiàn)基于叁芯智能科技的SANXIN -B01 FPGA開(kāi)發(fā)板。

隨機(jī)訪問(wèn)存儲(chǔ)器(RAM)分為靜態(tài)RAM(SRAM)和動(dòng)態(tài)RAM(DRAM)。由于動(dòng)態(tài)存儲(chǔ)器存儲(chǔ)單元的結(jié)構(gòu)非常簡(jiǎn)單,所以它能達(dá)到的集成度遠(yuǎn)高于靜態(tài)存儲(chǔ)器。但是動(dòng)態(tài)存儲(chǔ)器的存取速度不如靜態(tài)存儲(chǔ)器快。

RAM的動(dòng)態(tài)存儲(chǔ)單元是利用電容可以存儲(chǔ)電荷的原理制成的。由于存儲(chǔ)單元的機(jī)構(gòu)能夠做得很簡(jiǎn)單,所以在大容量、高集成度的RAM中得到了普遍的應(yīng)用。但是由于電容的容量很小,而漏電流又不可能絕對(duì)等于零,所以電荷保存的時(shí)間有限。為了及時(shí)補(bǔ)充漏掉的電荷以避免存儲(chǔ)的信號(hào)丟失,必須定時(shí)地給電容補(bǔ)充電荷,通常將這種操作稱(chēng)為刷新。

51463cea-9dac-11eb-8b86-12bb97331649.png

行列地址線被選中后,數(shù)據(jù)線(data_bit)直接和電容相連接。當(dāng)寫(xiě)入時(shí),數(shù)據(jù)線給電容充放電;讀取時(shí),電容將數(shù)據(jù)線拉高或者置低。

SDRAM 的全稱(chēng)即同步動(dòng)態(tài)隨機(jī)存儲(chǔ)器(Synchronous Dynamic Random Access Memory);這里的同步是指其時(shí)鐘頻率與對(duì)應(yīng)控制器的系統(tǒng)時(shí)鐘頻率相同,并且內(nèi)部命令的發(fā)送與數(shù)據(jù)傳輸都是以該時(shí)鐘為基準(zhǔn);動(dòng)態(tài)是指存儲(chǔ)陣列需要不斷的刷新來(lái)保證數(shù)據(jù)不丟失。

SDR SDRAM中的SDR是指單數(shù)據(jù)速率,即每一根數(shù)據(jù)線上,每個(gè)時(shí)鐘只傳輸一個(gè)bit的數(shù)據(jù)。SDR SDRAM的時(shí)鐘頻率可以達(dá)到100MHz以上,按照100MHz的速率計(jì)算,一片16位數(shù)據(jù)寬度的SDR SDRAM的讀寫(xiě)數(shù)據(jù)帶寬可以達(dá)到1.6Gbit/s。

SANXIN – B01的開(kāi)發(fā)板上有一個(gè)容量為256Mbit(16M x 16bit)的SDR SDRAM(H57V2562GTR)。其內(nèi)部存儲(chǔ)時(shí),分為了4個(gè)獨(dú)立的區(qū)域(BANK),每個(gè)bank為4Mx16bit的存儲(chǔ)空間;每個(gè)bank在存儲(chǔ)時(shí),按照二維的方式進(jìn)行存儲(chǔ),利用行列來(lái)進(jìn)行確定,有8192行(13bit地址線),有512列(9bit地址線),8192 x 512為4M的存儲(chǔ)量。

在進(jìn)行指定某個(gè)地址時(shí),共需要2位bank地址,13位行地址,9位列地址,合計(jì)共24位地址。但是在SDR SDRAM的指定某個(gè)地址時(shí),行地址和列地址不是同時(shí)給出,SDR SDRAM采用行列地址線復(fù)用,所以地址線合計(jì)為2(bank 地址)+13(行、列地址復(fù)用)。

SDR SDRAM需要時(shí)鐘端和時(shí)鐘使能端。SDR SDRAM所有的操作都依靠于此時(shí)鐘;當(dāng)時(shí)鐘使能端無(wú)效時(shí),SDR SDRAM自動(dòng)忽略時(shí)鐘上升沿。

SDR SDRAM擁有四個(gè)命令控制線,分別為CS、RAS、CAS、WE。組成的命令表如下:

51827e4e-9dac-11eb-8b86-12bb97331649.png

在寫(xiě)入數(shù)據(jù)時(shí),有時(shí)會(huì)出現(xiàn)不想對(duì)某8bit進(jìn)行寫(xiě)入,就可以采用DQM進(jìn)行控制。

SDR SDRAM的內(nèi)部機(jī)構(gòu)為:

5192167e-9dac-11eb-8b86-12bb97331649.png

由于SDR SDRAM為DRAM,內(nèi)部的存儲(chǔ)都是靠電容進(jìn)行保存數(shù)據(jù),電容的保持?jǐn)?shù)據(jù)的時(shí)間為64ms,SDR SDRAM每次只能夠刷新一行,為了不丟失任何數(shù)據(jù),所以要保證64ms內(nèi),將所有的行都要刷新一遍。

SDR SDRAM支持讀寫(xiě)的長(zhǎng)度為1、2、4、8和一行(整頁(yè))。

具體的SDR SDRAM的介紹可以查看手冊(cè)。下面只介紹幾個(gè)相對(duì)重要的時(shí)序圖。

在SDR SDRAM正常使用之前,需要進(jìn)行初始化。初始化的時(shí)序圖如下:

51d11c0c-9dac-11eb-8b86-12bb97331649.png

在PRECHARGE時(shí),A10為高,表示選中所有的bank;A10為低,表示選中BA0、BA1所指定的bank。初始化中,A10置高。

在LOAD MOOE REGISTER中,采用地址線進(jìn)行配置模式寄存器。說(shuō)明如下:

51e6441a-9dac-11eb-8b86-12bb97331649.png

在模式配置中,利用CL(CAS Latency)表示列選通潛伏期,利用BL(Burst Length)表示突發(fā)長(zhǎng)度。

SDR SDRAM中有內(nèi)部的刷新控制器和刷新的行計(jì)數(shù)器,外部控制器只需要保證在64ms之內(nèi)進(jìn)行8192次刷新即可。

在進(jìn)行PRECHARGE時(shí),A10要為高電平。

5255e856-9dac-11eb-8b86-12bb97331649.png

SDR SDRAM中,我們可以在任意位置進(jìn)行寫(xiě)入。寫(xiě)入的時(shí)序圖如下:

52764b00-9dac-11eb-8b86-12bb97331649.png

SDR SDRAM中,我們可以在任意位置進(jìn)行讀出。讀出的時(shí)序圖如下:

529427d8-9dac-11eb-8b86-12bb97331649.png

在各個(gè)時(shí)序中的時(shí)序參數(shù)如下:

530165fa-9dac-11eb-8b86-12bb97331649.png

5326db00-9dac-11eb-8b86-12bb97331649.png

設(shè)計(jì)要求

設(shè)計(jì)一個(gè)突發(fā)長(zhǎng)度為2,列選通潛伏期為2的SDR SDRAM的控制器。

設(shè)計(jì)分析

該控制器共有四部分功能,初始化、刷新、寫(xiě)和讀。四部分的執(zhí)行控制采用一個(gè)模塊來(lái)控制。

SDR SDRAM必須要進(jìn)行初始化,初始化只用執(zhí)行一次。然后啟動(dòng)一個(gè)計(jì)時(shí)器,等計(jì)時(shí)器達(dá)到后,進(jìn)行刷新。在刷新的間隔中,根據(jù)讀寫(xiě)的要求進(jìn)行讀寫(xiě)。

四個(gè)模塊都會(huì)對(duì)SDR SDRAM的命令線和地址線進(jìn)行控制,所以輸出時(shí),采用多路選擇器對(duì)齊進(jìn)行選擇輸出。

四個(gè)模塊按照對(duì)應(yīng)的時(shí)序圖進(jìn)行編寫(xiě)代碼即可。

架構(gòu)設(shè)計(jì)和信號(hào)說(shuō)明

該控制器命名為sdr_drive。

53527f76-9dac-11eb-8b86-12bb97331649.png

pll_sdr(鎖相環(huán)模塊):產(chǎn)生驅(qū)動(dòng)所需要的100MHz的時(shí)鐘(0度相位)、SDR SDRAM所需要的100MHz的時(shí)鐘(270度相位)、以及PLL鎖定信號(hào)當(dāng)作系統(tǒng)復(fù)位使用。

timer(刷新計(jì)時(shí)器):當(dāng)啟動(dòng)計(jì)時(shí)器后,開(kāi)始計(jì)時(shí),當(dāng)計(jì)時(shí)到規(guī)定時(shí)間后,輸出刷新請(qǐng)求,計(jì)數(shù)器直接清零計(jì)數(shù)計(jì)數(shù)。當(dāng)控制器響應(yīng)后,輸出清除信號(hào)后,刷新請(qǐng)求拉低。

refresh(刷新模塊)、init(初始化模塊)、sdr_write(寫(xiě)模塊)、sdr_read(讀模塊):當(dāng)啟動(dòng)模塊后,按照規(guī)定的時(shí)序進(jìn)行輸出即可,然后輸出完成信號(hào)。

sdr_ctrl(控制模塊):控制各個(gè)模塊協(xié)調(diào)工作。

mux4_1(四選一多路選擇器模塊):選擇對(duì)應(yīng)的bus總線作為輸出。

*_bus的組成為:高四位為sdr_cs_n、sdr_ras_n、sdr_cas_n、sdr_we_n。然后是bank的兩位,后續(xù)為13位的sdr_addr。

535fa232-9dac-11eb-8b86-12bb97331649.png

536999e0-9dac-11eb-8b86-12bb97331649.png

537aea10-9dac-11eb-8b86-12bb97331649.png

sdr_drive_head聲明

將驅(qū)動(dòng)中用到各種參數(shù)定義在該文件中。

`define SDR_ADDR_WIDTH 13`define SDR_COL_ADDR_WIDTH 9`define SDR_REFRESH_TIME 64_000_000

`define ADDR_WIDTH 2 + `SDR_ADDR_WIDTH + `SDR_COL_ADDR_WIDTH`define BUS_WIDTH 4 + 2 + `SDR_ADDR_WIDTH

`define CMD_INH 4‘b1000`define NOP 4’b0111`define ACT 4‘b0011`define RD 4’b0101`define WR 4‘b0100`define BT 4’b0110`define PREC 4‘b0010`define REFR 4’b0001`define LMR 4‘b0000

`define PU_DELAY 20_000`define Trp 3`define Trfc 7`define Tmrd 3`define Trcd 3`define Twr 3`define Tcl 2

`define CODE 13’b000_0_00_010_0_001`define REFRESH_TIME (`SDR_REFRESH_TIME/(2**`SDR_ADDR_WIDTH))/10

pll_sdr設(shè)計(jì)實(shí)現(xiàn)

該模塊為IP core,輸出0相位的100MHz(系統(tǒng)時(shí)鐘)和270相位的100MHz(SDR的時(shí)鐘)。系統(tǒng)設(shè)計(jì)中,信號(hào)在上升沿輸出;對(duì)于外部器件(相位調(diào)整為270),能夠較好的滿足建立和保持時(shí)間。

init設(shè)計(jì)實(shí)現(xiàn)

該模塊負(fù)責(zé)將SDR SDRAM進(jìn)行初始化。上電延遲(PU_DELAY)設(shè)置為200us;預(yù)充電時(shí)間(Trp)設(shè)置為3個(gè)時(shí)鐘周期(30ns);自刷新時(shí)間(Trfc)設(shè)置為7個(gè)時(shí)鐘周期(70ns);模式寄存器應(yīng)用時(shí)間(Tmrd)設(shè)置為3個(gè)時(shí)鐘周期(30ns);突發(fā)長(zhǎng)度為2;列選通潛伏期為3。

按照對(duì)應(yīng)的初始化的時(shí)序圖,做出如下設(shè)計(jì)。

本模塊采用狀態(tài)機(jī)的方式設(shè)計(jì)實(shí)現(xiàn)。

538519d6-9dac-11eb-8b86-12bb97331649.png

設(shè)計(jì)代碼為:

`include “。./rtl/sdr_drive_head.v”

module init (

input wire clk, input wire rst_n,

input wire init_en, output reg init_done,

output wire [`BUS_WIDTH - 1 : 0] init_bus);

localparam IDLE = 7‘b000_0001; localparam PUD = 7’b000_0010; localparam PRECHARGE = 7‘b000_0100; localparam AUTOREFR1 = 7’b000_1000; localparam AUTOREFR2 = 7‘b001_0000; localparam LMR_STATE = 7’b010_0000; localparam INITDONE = 7‘b100_0000;

reg [6:0] c_state; reg [6:0] n_state; wire [1:0] sdr_bank; reg [3:0] sdr_cmd; reg [`SDR_ADDR_WIDTH - 1 : 0] sdr_addr; reg [14:0] cnt;

assign sdr_bank = 2’b00; assign init_bus = {sdr_cmd,sdr_bank,sdr_addr};

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) c_state 《= IDLE; else c_state 《= n_state; end

always @ * begin case (c_state) IDLE : begin if (init_en == 1’b1) n_state = PUD; else n_state = IDLE; end

PUD : begin if (cnt == `PU_DELAY - 1‘b1) n_state = PRECHARGE; else n_state = PUD; end

PRECHARGE : begin if (cnt == `Trp - 1’b1) n_state = AUTOREFR1; else n_state = PRECHARGE; end

AUTOREFR1 : begin if (cnt == `Trfc - 1‘b1) n_state = AUTOREFR2; else n_state = AUTOREFR1; end

AUTOREFR2 : begin if (cnt == `Trfc - 1’b1) n_state = LMR_STATE; else n_state = AUTOREFR2; end

LMR_STATE : begin if (cnt == `Tmrd - 1‘b1) n_state = INITDONE; else n_state = LMR_STATE; end

INITDONE : begin n_state = INITDONE; end

default : n_state = IDLE; endcase end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) sdr_cmd 《= `NOP; else case (c_state) IDLE : sdr_cmd 《= `NOP; PUD : begin if (cnt == `PU_DELAY - 1‘b1) sdr_cmd 《= `PREC; else sdr_cmd 《= `NOP; end PRECHARGE : begin if (cnt == `Trp - 1’b1) sdr_cmd 《= `REFR; else sdr_cmd 《= `NOP; end AUTOREFR1 : begin if (cnt == `Trfc - 1‘b1) sdr_cmd 《= `REFR; else sdr_cmd 《= `NOP; end AUTOREFR2 : begin if (cnt == `Trfc - 1’b1) sdr_cmd 《= `LMR; else sdr_cmd 《= `NOP; end LMR_STATE : sdr_cmd 《= `NOP; INITDONE : sdr_cmd 《= `NOP; default : sdr_cmd 《= `NOP; endcase end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) cnt 《= 15’d0; else case (c_state) IDLE : cnt 《= 16‘d0; PUD : begin if (cnt 《 `PU_DELAY - 1’b1) cnt 《= cnt + 1‘b1; else cnt 《= 16’d0; end

PRECHARGE : begin if (cnt 《 `Trp - 1‘b1) cnt 《= cnt + 1’b1; else cnt 《= 16‘d0; end AUTOREFR1 : begin if (cnt 《 `Trfc - 1’b1) cnt 《= cnt + 1‘b1; else cnt 《= 16’d0; end AUTOREFR2 : begin if (cnt 《 `Trfc - 1‘b1) cnt 《= cnt + 1’b1; else cnt 《= 16‘d0; end LMR_STATE : begin if (cnt 《 `Tmrd - 1’b1) cnt 《= cnt + 1‘b1; else cnt 《= 16’d0; end INITDONE : cnt 《= 16‘d0; default : cnt 《= 16’d0; endcase end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) init_done 《= 1’b0; else if (c_state == LMR_STATE && cnt == `Tmrd - 1‘b1) init_done 《= 1’b1; else init_done 《= 1‘b0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) sdr_addr 《= 0; else if (c_state == PUD && cnt == `PU_DELAY - 1‘b1) sdr_addr[10] 《= 1’b1; else if (c_state == AUTOREFR2 && cnt == `Trfc - 1‘b1) sdr_addr 《= `CODE; else sdr_addr 《= 0; end

endmodule

timer設(shè)計(jì)實(shí)現(xiàn)

SDR SDRAM內(nèi)部構(gòu)造為DRAM,需要不間斷的刷新,要求64ms刷新一遍。每次刷新為一行,開(kāi)發(fā)板上的SDR SDRAM共有8192行,平均需要7812.5ns刷新一次,我們選擇7810刷新一次。

到達(dá)規(guī)定的刷新時(shí)間時(shí),控制器有可能正在進(jìn)行其他的操作。在設(shè)計(jì)時(shí),達(dá)到時(shí)間后,發(fā)出刷新請(qǐng)求,當(dāng)外部執(zhí)行刷新后,將次請(qǐng)求清除。發(fā)出刷新請(qǐng)求的同時(shí),計(jì)數(shù)器重新歸零計(jì)數(shù)。

`include “。./rtl/sdr_drive_head.v”

module timer (

input wire clk, input wire rst_n,

input wire time_en, input wire req_clr,

output reg refresh_req);

reg [9:0] cnt;

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) cnt 《= 10‘d0; else if (time_en == 1’b1 && cnt 《 `REFRESH_TIME - 1‘b1) cnt 《= cnt + 1’b1; else cnt 《= 10‘d0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) refresh_req 《= 1‘b0; else if (cnt == `REFRESH_TIME - 1’b1) refresh_req 《= 1‘b1; else if (req_clr == 1’b1) refresh_req 《= 1‘b0; else refresh_req 《= refresh_req; end

endmodule

refresh設(shè)計(jì)實(shí)現(xiàn)

該模塊負(fù)責(zé)刷新,按照對(duì)應(yīng)的時(shí)序圖進(jìn)行控制即可。

該模塊利用狀態(tài)機(jī)的方式實(shí)現(xiàn)。狀態(tài)轉(zhuǎn)移圖如下:

5391101a-9dac-11eb-8b86-12bb97331649.png

設(shè)計(jì)代碼為:

`include “。./rtl/sdr_drive_head.v”

module refresh (

input wire clk, input wire rst_n,

input wire refresh_en, output reg refresh_done,

output wire [`BUS_WIDTH - 1 : 0] refresh_bus);

localparam IDLE = 5’b0_0001; localparam PRECHARGE = 5‘b0_0010; localparam AUTOREFR1 = 5’b0_0100; localparam AUTOREFR2 = 5‘b0_1000; localparam REFRDONE = 5’b1_0000;

reg [4:0] c_state; reg [4:0] n_state; wire [1:0] sdr_bank; reg [3:0] sdr_cmd; reg [`SDR_ADDR_WIDTH - 1 : 0] sdr_addr; reg [3:0] cnt;

assign sdr_bank = 2‘b00; assign refresh_bus = {sdr_cmd,sdr_bank,sdr_addr};

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) c_state 《= IDLE; else c_state 《= n_state; end

always @ * begin case (c_state) IDLE : begin if (refresh_en == 1‘b1) n_state = PRECHARGE; else n_state = IDLE; end

PRECHARGE : begin if (cnt == `Trp - 1’b1) n_state = AUTOREFR1; else n_state = PRECHARGE; end

AUTOREFR1 : begin if (cnt == `Trfc - 1‘b1) n_state = AUTOREFR2; else n_state = AUTOREFR1; end

AUTOREFR2 : begin if (cnt == `Trfc - 1’b1) n_state = REFRDONE; else n_state = AUTOREFR2; end

REFRDONE : begin n_state = IDLE; end

default : n_state = IDLE; endcase end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) sdr_cmd 《= `NOP; else case (c_state) IDLE : begin if (refresh_en == 1’b1) sdr_cmd 《= `PREC; else sdr_cmd 《= `NOP; end PRECHARGE : begin if (cnt == `Trp - 1‘b1) sdr_cmd 《= `REFR; else sdr_cmd 《= `NOP; end AUTOREFR1 : begin if (cnt == `Trfc - 1’b1) sdr_cmd 《= `REFR; else sdr_cmd 《= `NOP; end AUTOREFR2 : sdr_cmd 《= `NOP;

REFRDONE : sdr_cmd 《= `NOP; default : sdr_cmd 《= `NOP; endcase end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) cnt 《= 4’d0; else case (c_state) IDLE : cnt 《= 4‘d0;

PRECHARGE : begin if (cnt 《 `Trp - 1’b1) cnt 《= cnt + 1‘b1; else cnt 《= 4’d0; end AUTOREFR1 : begin if (cnt 《 `Trfc - 1‘b1) cnt 《= cnt + 1’b1; else cnt 《= 4‘d0; end AUTOREFR2 : begin if (cnt 《 `Trfc - 1’b1) cnt 《= cnt + 1‘b1; else cnt 《= 4’d0; end REFRDONE : cnt 《= 4‘d0; default : cnt 《= 4’d0; endcase end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) refresh_done 《= 1’b0; else if (c_state == AUTOREFR2 && cnt == `Trfc - 1‘b1) refresh_done 《= 1’b1; else refresh_done 《= 1‘b0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) sdr_addr 《= 0; else if (c_state == IDLE && refresh_en == 1‘b1) sdr_addr[10] 《= 1’b1; else sdr_addr 《= 0; end

endmodule

sdr_write設(shè)計(jì)實(shí)現(xiàn)

該模塊負(fù)責(zé)將外部的數(shù)據(jù)寫(xiě)入到規(guī)定的地址中去。在SDR SDRAM中,每操作(讀寫(xiě))一次,都會(huì)引起該存儲(chǔ)位的漏電,每次結(jié)束時(shí),可以進(jìn)行預(yù)充電。SDR SDRAM提供了自動(dòng)預(yù)充電的機(jī)制,在讀寫(xiě)命令時(shí),sdr_addr[10]=1,即可自動(dòng)預(yù)充電。在設(shè)計(jì)時(shí),應(yīng)該要為自動(dòng)預(yù)充電預(yù)留出足夠的時(shí)間。

根據(jù)對(duì)應(yīng)的寫(xiě)入時(shí)序圖,利用狀態(tài)機(jī)完成此設(shè)計(jì)。

539a5f30-9dac-11eb-8b86-12bb97331649.png

設(shè)計(jì)代碼如下:

`include “。./rtl/sdr_drive_head.v”

module sdr_write (

input wire clk, input wire rst_n,

input wire write_en, input wire [`ADDR_WIDTH - 1 : 0] wr_addr, input wire [31:0] wr_data,

output reg [15:0] odq, output wire [`BUS_WIDTH - 1 : 0] wr_bus, output reg wr_done);

localparam IDLE = 4‘b0001; localparam ACT_STATE = 4’b0010; localparam WR1 = 4‘b0100; localparam WR2 = 4’b1000;

reg [3:0] c_state; reg [3:0] n_state; wire [1:0] sdr_bank; reg [3:0] sdr_cmd; reg [`SDR_ADDR_WIDTH - 1 : 0] sdr_addr; reg [14:0] cnt;

assign sdr_bank = wr_addr[23:22]; assign wr_bus = {sdr_cmd,sdr_bank,sdr_addr};

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) c_state 《= IDLE; else c_state 《= n_state; end

always @ * begin case (c_state) IDLE : begin if (write_en == 1’b1) n_state = ACT_STATE; else n_state = IDLE; end

ACT_STATE : begin if (cnt == `Trcd - 1‘b1) n_state = WR1; else n_state = ACT_STATE; end

WR1 : n_state = WR2;

WR2 : begin if (cnt == `Twr + `Trp - 1’b1) n_state = IDLE; else n_state = WR2; end

default : n_state = IDLE; endcase end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) sdr_cmd 《= `NOP; else if (c_state == IDLE && write_en == 1’b1) sdr_cmd 《= `ACT; else if (c_state == ACT_STATE && cnt == `Trcd - 1‘b1) sdr_cmd 《= `WR; else sdr_cmd 《= `NOP; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) sdr_addr 《= 0; else if (c_state == IDLE && write_en == 1‘b1) sdr_addr 《= wr_addr[21:9]; else if (c_state == ACT_STATE && cnt == `Trcd - 1’b1) begin sdr_addr[10] 《= 1‘b1; sdr_addr[8:0] 《= wr_addr[8:0]; end else sdr_addr 《= 0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) cnt 《= 4‘d0; else if (c_state == ACT_STATE && cnt 《 `Trcd - 1’b1) cnt 《= cnt + 1‘b1; else if (c_state == WR2 && cnt 《 `Twr + `Trp - 1’b1) cnt 《= cnt + 1‘b1; else cnt 《= 4’d0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) odq 《= 16’d0; else if (c_state == ACT_STATE && cnt == `Trcd - 1‘b1) odq 《= wr_data[15:0]; else if (c_state == WR1) odq 《= wr_data[31:16]; else odq 《= 16’d0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) wr_done 《= 1’b0; else if (c_state == WR2 && cnt 《 `Twr + `Trp - 1‘b1) wr_done 《= 1’b1; else wr_done 《= 1‘b0; end

endmodule

sdr_read設(shè)計(jì)實(shí)現(xiàn)

該模塊負(fù)責(zé)從指定的地址中,將數(shù)據(jù)讀出。

按照對(duì)應(yīng)的讀時(shí)序圖即可實(shí)現(xiàn)功能,本模塊采用狀態(tài)機(jī)方式實(shí)現(xiàn),狀態(tài)轉(zhuǎn)移圖如下:

53a42e98-9dac-11eb-8b86-12bb97331649.png

設(shè)計(jì)代碼為:

module sdr_read (

input wire clk, input wire rst_n,

input wire read_en, input wire [`ADDR_WIDTH - 1 : 0] rd_addr,

input wire [15:0] sdr_dq,

output reg [31:0] rd_data, output reg rd_done,

output wire [`BUS_WIDTH - 1 : 0] rd_bus);

localparam IDLE = 5’b00001; localparam ACT_STATE = 5‘b00010; localparam READ_STATE = 5’b00100; localparam RD1 = 5‘b01000; localparam RD2 = 5’b10000;

reg [4:0] c_state; reg [4:0] n_state; wire [1:0] sdr_bank; reg [3:0] sdr_cmd; reg [`SDR_ADDR_WIDTH - 1 : 0] sdr_addr; reg [3:0] cnt;

assign sdr_bank = rd_addr[23:22]; assign rd_bus = {sdr_cmd,sdr_bank,sdr_addr};

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) c_state 《= IDLE; else c_state 《= n_state; end

always @ * begin case (c_state) IDLE : begin if (read_en == 1’b1) n_state = ACT_STATE; else n_state = IDLE; end

ACT_STATE : begin if (cnt == `Trcd - 1‘b1) n_state = READ_STATE; else n_state = ACT_STATE; end

READ_STATE : begin if (cnt == `Tcl) n_state = RD1; else n_state = READ_STATE; end

RD1 : n_state = RD2;

RD2 : begin if (cnt == `Trp - 1’b1) n_state = IDLE; else n_state = RD2; end

default : n_state = IDLE; endcase end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) sdr_cmd 《= `NOP; else if (c_state == IDLE && read_en == 1’b1) sdr_cmd 《= `ACT; else if (c_state == ACT_STATE && cnt == `Trcd - 1‘b1) sdr_cmd 《= `RD; else sdr_cmd 《= `NOP; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) sdr_addr 《= 0; else if (c_state == IDLE && read_en == 1‘b1) sdr_addr 《= rd_addr[21:9]; else if (c_state == ACT_STATE && cnt == `Trcd - 1’b1) begin sdr_addr[10] 《= 1‘b1; sdr_addr[8:0] 《= rd_addr[8:0]; end else sdr_addr 《= 0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) cnt 《= 4‘d0; else case (c_state) IDLE : cnt 《= 4’d0; ACT_STATE : begin if (cnt 《 `Trcd - 1‘b1) cnt 《= cnt + 1’b1; else cnt 《= 4‘d0; end READ_STATE: begin if (cnt 《 `Tcl) cnt 《= cnt + 1’b1; else cnt 《= 4‘d0; end

RD1 : cnt 《= 4’d0; RD2 : begin if (cnt 《 `Trp - 1‘b1) cnt 《= cnt + 1’b1; else cnt 《= 4‘d0; end default : cnt 《= 4’d0; endcase end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) rd_data 《= 32’d0; else if (c_state == READ_STATE && cnt == `Tcl) rd_data[15:0] 《= sdr_dq; else if (c_state == RD1) rd_data[31:16] 《= sdr_dq; else rd_data 《= rd_data; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) rd_done 《= 1’b0; else if (c_state == RD2 && cnt 《 `Trp - 1‘b1) rd_done 《= 1’b1; else rd_done 《= 1‘b0; end

endmodule

mux4_1設(shè)計(jì)實(shí)現(xiàn)

該模塊負(fù)責(zé)選擇出對(duì)應(yīng)的bus,然后將對(duì)應(yīng)位作為輸出即可。

設(shè)計(jì)代碼為:

module mux4_1 (

input wire [`BUS_WIDTH - 1 : 0] init_bus, input wire [`BUS_WIDTH - 1 : 0] refresh_bus, input wire [`BUS_WIDTH - 1 : 0] wr_bus, input wire [`BUS_WIDTH - 1 : 0] rd_bus, input wire [1:0] mux_sel,

output wire [1 : 0] sdr_bank, output wire [`ADDR_WIDTH - 1 : 0] sdr_addr, output wire sdr_cs_n, output wire sdr_ras_n, output wire sdr_cas_n, output wire sdr_we_n);

reg [`BUS_WIDTH - 1 : 0] sdr_bus;

assign sdr_cs_n = sdr_bus[18]; assign sdr_ras_n = sdr_bus[17]; assign sdr_cas_n = sdr_bus[16]; assign sdr_we_n = sdr_bus[15];

assign sdr_bank = sdr_bus[14:13];

assign sdr_addr = sdr_bus[12:0];

always @ * begin case (mux_sel) 2’b00 : sdr_bus = init_bus; 2‘b01 : sdr_bus = refresh_bus; 2’b10 : sdr_bus = wr_bus; 2‘b11 : sdr_bus = rd_bus; default : sdr_bus = init_bus; endcase end

endmodule

sdr_ctrl設(shè)計(jì)實(shí)現(xiàn)

該模塊負(fù)責(zé)調(diào)度整個(gè)控制器,利用狀態(tài)機(jī)實(shí)現(xiàn)。

53c683b2-9dac-11eb-8b86-12bb97331649.png

設(shè)計(jì)代碼為:

`include “。./rtl/sdr_drive_head.v”

module sdr_ctrl (

input wire clk, input wire rst_n,

input wire wr_en, input wire rd_en, input wire [`ADDR_WIDTH - 1 : 0] addr, input wire [31:0] wdata, output reg [31:0] rdata, output reg rd_valid,

output wire sdr_busy,

output reg [1:0] mux_sel,

output reg init_en, input wire init_done,

output reg time_en, input wire refresh_req, output reg req_clr,

output reg refresh_en, input wire refresh_done,

output reg out_en, output reg write_en, output reg [`ADDR_WIDTH - 1 : 0] wr_addr, output reg [31:0] wr_data, input wire wr_done,

output reg read_en, output reg [`ADDR_WIDTH - 1 : 0] rd_addr, input wire [31:0] rd_data, input wire rd_done);

localparam IDLE = 6’b000_001; localparam INIT_STATE = 6‘b000_010; localparam REFRESH_STATE = 6’b000_100; localparam NO_BUSY = 6‘b001_000; localparam WR_STATE = 6’b010_000; localparam RD_STATE = 6‘b100_000;

reg [5:0] c_state; reg [5:0] n_state; reg wren; reg wren_clr; reg rden; reg rden_clr; reg [`ADDR_WIDTH - 1 : 0] addrr; reg [31:0] wdatar; reg busy;

assign sdr_busy = busy | rd_en | wr_en;

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) wren 《= 1‘b0; else if (wr_en == 1’b1) wren 《= 1‘b1; else if (wren_clr == 1’b1) wren 《= 1‘b0; else wren 《= wren; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) rden 《= 1‘b0; else if (rd_en == 1’b1) rden 《= 1‘b1; else if (rden_clr == 1’b1) rden 《= 1‘b0; else rden 《= rden; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) wdatar 《= 32‘d0; else if (wr_en == 1’b1) wdatar 《= wdata; else wdatar 《= wdatar; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) addrr 《= 0; else if (wr_en == 1’b1 || rd_en == 1‘b1) addrr 《= addr; else addrr 《= addrr; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) c_state 《= IDLE; else c_state 《= n_state; end

always @ * begin case (c_state) IDLE : n_state = INIT_STATE;

INIT_STATE : begin if (init_done == 1‘b1) n_state = REFRESH_STATE; else n_state = INIT_STATE; end

REFRESH_STATE : begin if (refresh_done == 1’b1) n_state = NO_BUSY; else n_state = REFRESH_STATE; end

NO_BUSY : begin if (refresh_req == 1‘b1) n_state = REFRESH_STATE; else if (wren == 1’b1) n_state = WR_STATE; else if (rden == 1‘b1) n_state = RD_STATE; else n_state = NO_BUSY; end

WR_STATE : begin if (wr_done == 1’b1) n_state = NO_BUSY; else n_state = WR_STATE; end

RD_STATE : begin if (rd_done == 1‘b1) n_state = NO_BUSY; else n_state = RD_STATE; end

default : n_state = IDLE; endcase end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) busy 《= 1‘b1; else if (c_state == NO_BUSY && wren == 1’b0 && rden == 1‘b0 && refresh_req == 1’b0) busy 《= rd_en | wr_en; else busy 《= 1‘b1; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) init_en 《= 1‘b0; else if (c_state == IDLE) init_en 《= 1’b1; else init_en 《= 1‘b0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) time_en 《= 1‘b0; else if (c_state == INIT_STATE && init_done == 1’b1) time_en 《= 1‘b1; else time_en 《= time_en; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) refresh_en 《= 1‘b0; else if (c_state == INIT_STATE && init_done == 1’b1) refresh_en 《= 1‘b1; else if (c_state == NO_BUSY && refresh_req == 1’b1) refresh_en 《= 1‘b1; else refresh_en 《= 1’b0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) req_clr 《= 1’b0; else if (c_state == NO_BUSY && refresh_req == 1‘b1) req_clr 《= 1’b1; else req_clr 《= 1‘b0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) write_en 《= 1‘b0; else if (c_state == NO_BUSY && refresh_req == 1’b0 && wren == 1‘b1) write_en 《= 1’b1; else write_en 《= 1‘b0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) out_en 《= 1‘b0; else if (c_state == NO_BUSY && refresh_req == 1’b0 && wren == 1‘b1) out_en 《= 1’b1; else if (c_state == WR_STATE && wr_done == 1‘b1) out_en 《= 1’b0; else out_en 《= out_en; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) wr_addr 《= 0; else if (c_state == NO_BUSY && refresh_req == 1’b0 && wren == 1‘b1) wr_addr 《= addrr; else wr_addr 《= wr_addr; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) wr_data 《= 0; else if (c_state == NO_BUSY && refresh_req == 1‘b0 && wren == 1’b1) wr_data 《= wdatar; else wr_data 《= wr_data; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) wren_clr 《= 1’b0; else if (c_state == NO_BUSY && refresh_req == 1‘b0 && wren == 1’b1) wren_clr 《= 1‘b1; else wren_clr 《= 1’b0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) rden_clr 《= 1’b0; else if (c_state == NO_BUSY && refresh_req == 1‘b0 && wren == 1’b0 && rden == 1‘b1) rden_clr 《= 1’b1; else rden_clr 《= 1‘b0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) read_en 《= 1‘b0; else if (c_state == NO_BUSY && refresh_req == 1’b0 && wren == 1‘b0 && rden == 1’b1) read_en 《= 1‘b1; else read_en 《= 1’b0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) rd_addr 《= 0; else if (c_state == NO_BUSY && refresh_req == 1’b0 && wren == 1‘b0 && rden == 1’b1) rd_addr 《= addrr; else rd_addr 《= rd_addr; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) rdata 《= 32’d0; else if (c_state == RD_STATE && rd_done == 1‘b1) rdata 《= rd_data; else rdata 《= rdata; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) rd_valid 《= 1‘b0; else if (c_state == RD_STATE && rd_done == 1’b1) rd_valid 《= 1‘b1; else rd_valid 《= 1’b0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) mux_sel 《= 2’b00; else case (c_state) IDLE : mux_sel 《= 2‘b00; INIT_STATE : begin if (init_done == 1’b1) mux_sel 《= 2‘b01; else mux_sel 《= mux_sel; end REFRESH_STATE: mux_sel 《= mux_sel; NO_BUSY : begin if (refresh_req == 1’b1) mux_sel 《= 2‘b01; else if (wren == 1’b1) mux_sel 《= 2‘b10; else if (rden == 1’b1) mux_sel 《= 2‘b11; else mux_sel 《= mux_sel; end RD_STATE : mux_sel 《= mux_sel; WR_STATE : mux_sel 《= mux_sel;

default : mux_sel 《= 2’b00; endcase end

endmodule

為了防止在進(jìn)行刷新的起始部分丟失讀寫(xiě)命令,所以在設(shè)計(jì)時(shí),加入了緩存結(jié)構(gòu),只要有讀寫(xiě)命令時(shí),都會(huì)進(jìn)行保存。在讀寫(xiě)執(zhí)行時(shí),才會(huì)清除此命令。

RTL仿真

為了能夠仿真此設(shè)計(jì),需要用到SDR SDRAM的仿真模型。仿真模型在msim的sdr_sim_module中,將其修改為行線為13bit,列為9bit,每個(gè)bank有4194304個(gè)存儲(chǔ)空間。

53d2294c-9dac-11eb-8b86-12bb97331649.png

在仿真時(shí),在第二個(gè)bank,第五行,第10列,寫(xiě)入一個(gè)隨機(jī)值。然后讀取出來(lái)。

仿真代碼為:

`timescale 1ns/1ps

module sdr_drive_tb;

reg clk; reg rst_n;

wire sys_clk; wire sys_rst_n;

wire sdr_busy; reg wr_en; reg rd_en; reg [23:0] addr; reg [31:0] wdata; wire [31:0] rdata; wire rd_valid;

wire sdr_clk; wire sdr_cke; wire sdr_cs_n; wire sdr_ras_n; wire sdr_cas_n; wire sdr_we_n; wire [15:0] sdr_dq; wire [1:0] sdr_bank; wire [1:0] sdr_dqm; wire [12:0] sdr_addr;

sdr_drive sdr_drive_inst(

.clk (clk), .rst_n (rst_n),

.sys_clk (sys_clk), .sys_rst_n (sys_rst_n),

// local .sdr_busy (sdr_busy), .wr_en (wr_en), .rd_en (rd_en), .addr (addr), .wdata (wdata), .rdata (rdata), .rd_valid (rd_valid),

// sdr .sdr_clk (sdr_clk), .sdr_cke (sdr_cke), .sdr_cs_n (sdr_cs_n), .sdr_ras_n (sdr_ras_n), .sdr_cas_n (sdr_cas_n), .sdr_we_n (sdr_we_n), .sdr_bank (sdr_bank), .sdr_addr (sdr_addr), .sdr_dqm (sdr_dqm), .sdr_dq (sdr_dq) );

mt48lc32m16a2 mt48lc32m16a2_inst( .Dq (sdr_dq), .Addr (sdr_addr), .Ba (sdr_bank), .Clk (sdr_clk), .Cke (sdr_cke), .Cs_n (sdr_cs_n), .Ras_n (sdr_ras_n), .Cas_n (sdr_cas_n), .We_n (sdr_we_n), .Dqm (sdr_dqm) );

initial clk = 1‘b0; always # 10 clk = ~clk;

initial begin rst_n = 1’b0; wr_en = 1‘b0; rd_en = 1’b0; addr = {2‘b01, 13’d5,9‘d10}; wdata = 32’d0; # 201 rst_n = 1‘b1; @ (negedge sdr_busy); @ (posedge sys_clk); # 2; wr_en = 1’b1; wdata = $random; @ (posedge sys_clk); # 2; wr_en = 1‘b0; # 2000; @ (negedge sdr_busy); @ (posedge sys_clk); # 2; rd_en = 1’b1; @ (posedge sys_clk); # 2; rd_en = 1‘b0; # 2000; $stop; end

endmodule

這設(shè)置激勵(lì)時(shí),將tb文件和仿真模型文件同時(shí)加入添加文件中。

53fbe5b6-9dac-11eb-8b86-12bb97331649.png

在modelsim的報(bào)告界面會(huì)顯示出具體的配置信息以及讀寫(xiě)信息。

544c0e6a-9dac-11eb-8b86-12bb97331649.png

從打印的報(bào)告中可以看出,在初始化時(shí),列選通潛伏期為2,突發(fā)長(zhǎng)度為2。在后續(xù)的讀寫(xiě)時(shí),在指定的位置,寫(xiě)入了13604,后續(xù)的一個(gè)位置為4629;在讀出時(shí),也正確的讀出了數(shù)據(jù)。

報(bào)告打印出寫(xiě)入數(shù)據(jù),即認(rèn)為寫(xiě)入成功;報(bào)告打印出讀出數(shù)據(jù),只能證明控制器將數(shù)據(jù)讀出,并不表示控制器能把數(shù)據(jù)接收到。

54c1d442-9dac-11eb-8b86-12bb97331649.png

通過(guò)控制輸出的rdata以及對(duì)應(yīng)的rd_valid信號(hào),確定讀出成功。在rdata中顯示為16進(jìn)制,16進(jìn)制的1215為十進(jìn)制的4629;16進(jìn)制的3524的為十進(jìn)制的13604。證明讀數(shù)據(jù)接收正確。

板級(jí)測(cè)試

編寫(xiě)控制器的上游模塊(sdr_drive_test_crtl),控制寫(xiě)入和讀出。在固定的地址中addr = {2’b01, 13‘d128, 9’d20},寫(xiě)入一個(gè)固定的數(shù)字wdata = 32‘h5a5aa5a5,然后讀出,進(jìn)行驗(yàn)證。

讀者在進(jìn)行驗(yàn)證時(shí),可以采樣其他的地址或者數(shù)據(jù)進(jìn)行驗(yàn)證,且可以進(jìn)行多次嘗試,保證設(shè)計(jì)正確。

該模塊采用狀態(tài)機(jī)設(shè)計(jì)實(shí)現(xiàn)。

54d6a854-9dac-11eb-8b86-12bb97331649.png

設(shè)計(jì)代碼為:

`include “。./rtl/sdr_drive_head.v”

module sdr_drive_test_ctrl (

input wire clk, input wire rst_n,

input wire sdr_busy, output reg wr_en, output reg rd_en, output wire [31:0] wdata, input wire rd_valid, input wire [31:0] rdata, output wire [`ADDR_WIDTH - 1 : 0] addr);

localparam IDLE = 4’b0001; localparam WR_STATE = 4‘b0010; localparam RD_STATE = 4’b0100; localparam TEST_DONE = 4‘b1000;

reg [3:0] c_state; reg [3:0] n_state;

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) c_state 《= IDLE; else c_state 《= n_state; end

always @ * begin case (c_state) IDLE : begin if (sdr_busy == 1‘b0) n_state = WR_STATE; else n_state = IDLE; end

WR_STATE : begin if (sdr_busy == 1’b0) n_state = RD_STATE; else n_state = WR_STATE; end

RD_STATE : begin if (rd_valid == 1‘b1 && rdata == 32’h5a5aa5a5) n_state = TEST_DONE; else n_state = RD_STATE; end

TEST_DONE : n_state = TEST_DONE;

default : n_state = IDLE; endcase end

assign wdata = 32‘h5a5aa5a5; assign addr = {2’b01, 13‘d128, 9’d20};

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1‘b0) wr_en 《= 1’b0; else if (c_state == IDLE && sdr_busy == 1‘b0) wr_en 《= 1’b1; else wr_en 《= 1‘b0; end

always @ (posedge clk, negedge rst_n) begin if (rst_n == 1’b0) rd_en 《= 1‘b0; else if (c_state == WR_STATE && sdr_busy == 1’b0) rd_en 《= 1‘b1; else rd_en 《= 1’b0; end

endmodule

編寫(xiě)測(cè)試頂層,模塊命名為sdr_drive_test,并且設(shè)置為頂層。

此模塊負(fù)責(zé)例化sdr_drive和sdr_drive_test_ctrl,完成連接功能,以此測(cè)試。

代碼為:

`include “。./rtl/sdr_drive_head.v”

module sdr_drive_test (

input wire clk, input wire rst_n,

// sdr output wire sdr_clk, output wire sdr_cke, output wire sdr_cs_n, output wire sdr_ras_n, output wire sdr_cas_n, output wire sdr_we_n, output wire [1:0] sdr_bank, output wire [`SDR_ADDR_WIDTH - 1 : 0] sdr_addr, output wire [1:0] sdr_dqm, inout wire [15:0] sdr_dq);

wire sys_clk; wire sys_rst_n;

// local wire sdr_busy; wire wr_en; wire rd_en; wire [`ADDR_WIDTH - 1 : 0] addr; wire [31:0] wdata; wire [31:0] rdata; wire rd_valid;

sdr_drive_test_ctrl sdr_drive_test_ctrl_inst(

.clk (sys_clk), .rst_n (sys_rst_n),

.sdr_busy (sdr_busy), .wr_en (wr_en), .rd_en (rd_en), .wdata (wdata), .rd_valid (rd_valid), .rdata (rdata), .addr (addr) );

sdr_drive sdr_drive_inst(

.clk (clk), .rst_n (rst_n),

.sys_clk (sys_clk), .sys_rst_n (sys_rst_n),

// local .sdr_busy (sdr_busy), .wr_en (wr_en), .rd_en (rd_en), .addr (addr), .wdata (wdata), .rdata (rdata), .rd_valid (rd_valid),

// sdr .sdr_clk (sdr_clk), .sdr_cke (sdr_cke), .sdr_cs_n (sdr_cs_n), .sdr_ras_n (sdr_ras_n), .sdr_cas_n (sdr_cas_n), .sdr_we_n (sdr_we_n), .sdr_bank (sdr_bank), .sdr_addr (sdr_addr), .sdr_dqm (sdr_dqm), .sdr_dq (sdr_dq) );

endmodule

經(jīng)過(guò)綜合分析后,進(jìn)行分配管腳。在分配管腳后,需要將雙功能管腳中的NCEO設(shè)置為普通用戶IO。如果不設(shè)置,將會(huì)出現(xiàn)如下錯(cuò)誤:

54e11e1a-9dac-11eb-8b86-12bb97331649.png

右擊器件名稱(chēng),選擇DEVICE。

54f43dba-9dac-11eb-8b86-12bb97331649.png

選擇device and pin option。

54ff0da8-9dac-11eb-8b86-12bb97331649.png

選擇dual – purpose pins。

55432f9c-9dac-11eb-8b86-12bb97331649.png

將nceo設(shè)置為 use as regular IO。

5558828e-9dac-11eb-8b86-12bb97331649.png

點(diǎn)擊OK,進(jìn)行編譯即可。

連接上開(kāi)發(fā)板,啟動(dòng)邏輯分析儀。

將采樣時(shí)鐘選擇為,sys_clk(PLL的c0)。采樣深度選擇為1K。

55630542-9dac-11eb-8b86-12bb97331649.png

添加觀測(cè)信號(hào)如下,將wr_en的上升沿設(shè)置為觸發(fā)條件。

5577acea-9dac-11eb-8b86-12bb97331649.png

經(jīng)過(guò)保存,重新形成配置文件后,進(jìn)行下板測(cè)試。

下板后,按下復(fù)位。等待波形觸發(fā)。

55a8e562-9dac-11eb-8b86-12bb97331649.png

通過(guò)邏輯分析儀,就可以看出可以正確的寫(xiě)入和讀出數(shù)據(jù)。

讀者也可以進(jìn)行嘗試一次性寫(xiě)入多個(gè)數(shù)據(jù),然后進(jìn)行讀出,進(jìn)行驗(yàn)證設(shè)計(jì)的正確性。

原文標(biāo)題:FPGA零基礎(chǔ)學(xué)習(xí)精選 | SDR SDRAM 驅(qū)動(dòng)設(shè)計(jì)

文章出處:【微信公眾號(hào):FPGA技術(shù)江湖】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • FPGA
    +關(guān)注

    關(guān)注

    1630

    文章

    21778

    瀏覽量

    604822
  • 電路
    +關(guān)注

    關(guān)注

    172

    文章

    5954

    瀏覽量

    172634

原文標(biāo)題:FPGA零基礎(chǔ)學(xué)習(xí)精選 | SDR SDRAM 驅(qū)動(dòng)設(shè)計(jì)

文章出處:【微信號(hào):HXSLH1010101010,微信公眾號(hào):FPGA技術(shù)江湖】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    【RA8D1試用活動(dòng)】RA8D1B-CPKCOR開(kāi)發(fā)板移植linux

    【RA8D1試用活動(dòng)】RA8D1B-CPKCOR開(kāi)發(fā)板移植linux
    的頭像 發(fā)表于 11-16 01:02 ?283次閱讀
    【RA8D1試用活動(dòng)】RA8D1<b class='flag-5'>B</b>-CPKCOR<b class='flag-5'>開(kāi)發(fā)板</b>移植linux

    正點(diǎn)原子fpga開(kāi)發(fā)板不同型號(hào)

    正點(diǎn)原子作為國(guó)內(nèi)領(lǐng)先的FPGA開(kāi)發(fā)板供應(yīng)商,其產(chǎn)品線覆蓋了從入門(mén)級(jí)到高端應(yīng)用的各個(gè)領(lǐng)域。這些開(kāi)發(fā)板不僅適用于學(xué)術(shù)研究,還廣泛應(yīng)用于工業(yè)控制、通信、圖像處理等多個(gè)領(lǐng)域。 1. 入門(mén)級(jí)開(kāi)發(fā)板
    的頭像 發(fā)表于 11-13 09:30 ?1071次閱讀

    正點(diǎn)原子和野火開(kāi)發(fā)板哪個(gè)好

    在嵌入式開(kāi)發(fā)領(lǐng)域,FPGA開(kāi)發(fā)板因其靈活性和可定制性而受到工程師的青睞。正點(diǎn)原子(ZYNQ)和野火(Yihui)是兩個(gè)知名的FPGA開(kāi)發(fā)板
    的頭像 發(fā)表于 11-13 09:29 ?1434次閱讀

    ARM開(kāi)發(fā)板FPGA的結(jié)合應(yīng)用

    一、引言 ARM開(kāi)發(fā)板是一種基于ARM架構(gòu)的嵌入式開(kāi)發(fā)平臺(tái),具有高性能、低功耗的特點(diǎn)。FPGA是一種可編程的數(shù)字電路,可以根據(jù)需要配置不同的邏輯功能。將ARM開(kāi)發(fā)板
    的頭像 發(fā)表于 11-05 11:42 ?638次閱讀

    樹(shù)莓派和arm開(kāi)發(fā)板的區(qū)別

    ,已經(jīng)推出了多個(gè)版本,包括A、B、A+、B+、2、3、4等。 ARM開(kāi)發(fā)板 ARM開(kāi)發(fā)板是一種基于ARM架構(gòu)的嵌入式開(kāi)發(fā)板
    的頭像 發(fā)表于 08-30 15:36 ?1135次閱讀

    LoRa-Kit 開(kāi)發(fā)板使用介紹

    LoRa-Kit是安信可科技針對(duì)LoRa模組而設(shè)計(jì)的一款開(kāi)發(fā)板,上面搭載了STM32F103C8T6 芯片和TB-05模組,預(yù)留了LoRa轉(zhuǎn)接插針,適配Ra-01、Ra-03等轉(zhuǎn)接
    的頭像 發(fā)表于 05-21 10:23 ?556次閱讀
    LoRa-Kit <b class='flag-5'>開(kāi)發(fā)板</b>使用介紹

    鴻蒙OpenHarmony開(kāi)發(fā)板解析:【芯片解決方案】

    芯片解決方案是指基于某款開(kāi)發(fā)板的完整解決方案,包含驅(qū)動(dòng)、設(shè)備側(cè)接口適配、開(kāi)發(fā)板sdk等。
    的頭像 發(fā)表于 05-10 15:42 ?1287次閱讀
    鴻蒙OpenHarmony<b class='flag-5'>開(kāi)發(fā)板</b>解析:【芯片解決方案】

    如何評(píng)估選型FPGA開(kāi)發(fā)板的資源?

    如何評(píng)估選型FPGA開(kāi)發(fā)板的資源?
    發(fā)表于 03-30 11:29

    WT32-ETH02 plus 串口轉(zhuǎn)以太網(wǎng)開(kāi)發(fā),WT32-ETH01網(wǎng)關(guān)開(kāi)發(fā)板升級(jí)款!

    廣受歡迎的WT32-ETH01網(wǎng)關(guān)開(kāi)發(fā)板迎來(lái)了升級(jí)。就是這款啟明云端新推出的嵌入式串口轉(zhuǎn)以太網(wǎng)開(kāi)發(fā)板——WT32-ETH02plus。應(yīng)廣大客戶的需求,在WT32-ETH01的基礎(chǔ)上增
    的頭像 發(fā)表于 03-16 08:03 ?797次閱讀
    WT32-ETH02 plus 串口轉(zhuǎn)以太網(wǎng)<b class='flag-5'>開(kāi)發(fā)</b>,WT32-ETH<b class='flag-5'>01</b>網(wǎng)關(guān)<b class='flag-5'>開(kāi)發(fā)板</b>升級(jí)款!

    fpga開(kāi)發(fā)板是什么?fpga開(kāi)發(fā)板有哪些?

    FPGA開(kāi)發(fā)板是一種基于FPGA(現(xiàn)場(chǎng)可編程門(mén)陣列)技術(shù)的開(kāi)發(fā)平臺(tái),它允許工程師通過(guò)編程來(lái)定義和配置FPGA芯片上的邏輯電路,以實(shí)現(xiàn)各種數(shù)字
    的頭像 發(fā)表于 03-14 18:20 ?2100次閱讀

    fpga開(kāi)發(fā)板使用教程

    FPGA開(kāi)發(fā)板的使用教程主要包括以下幾個(gè)關(guān)鍵步驟。
    的頭像 發(fā)表于 03-14 15:50 ?1213次閱讀

    CYW920719B2Q40EVB-01開(kāi)發(fā)板錄音程序失敗怎么解決?

    我在用模組工具箱錄制程序到cyw920719b2q40evb-01開(kāi)發(fā)板時(shí),發(fā)現(xiàn)存正在尋找不到口所得的問(wèn)題,如下圖所示: 但是我的設(shè)備管理器中識(shí)別出來(lái)了 CYW920719B2Q40EVB-01 的口如圖所示: 請(qǐng)問(wèn)社區(qū),我
    發(fā)表于 03-01 07:54

    迅為RK3568開(kāi)發(fā)板驅(qū)動(dòng)開(kāi)發(fā)指南-輸入子系統(tǒng)

    迅為RK3568開(kāi)發(fā)板驅(qū)動(dòng)開(kāi)發(fā)指南-輸入子系統(tǒng)
    的頭像 發(fā)表于 02-23 15:11 ?939次閱讀
    迅為RK3568<b class='flag-5'>開(kāi)發(fā)板</b><b class='flag-5'>驅(qū)動(dòng)</b><b class='flag-5'>開(kāi)發(fā)</b>指南-輸入子系統(tǒng)

    fpga開(kāi)發(fā)板與linux開(kāi)發(fā)板區(qū)別

    FPGA開(kāi)發(fā)板與Linux開(kāi)發(fā)板是兩種不同的硬件開(kāi)發(fā)平臺(tái),各自具有不同的特點(diǎn)和應(yīng)用場(chǎng)景。在以下的文章中,我將詳細(xì)介紹FPGA
    的頭像 發(fā)表于 02-01 17:09 ?2364次閱讀