Avalon 总线实现SDRAM读写功能系统设计
目录
2. Avalon存储器映射的接口——Avalon Memory-Mapped ( Avalon -MM)
④ 使用 waitrequestAllowance 属性进行传输
一. 需求分析
Avalon 总线实现SDRAM读写功能系统设计,可将读功能和写功能分别单独控制。
读功能启动可以使用按键控制,读出数据通过UART串口显示到PC上;
写操作可由串口发送需要写入的数据,再由wrfifo(写数据缓存fifo)控制何时写入。
二. SDRAM手册阅读
1. SDRAM概念
SDRAM(Synchronous Dynamic Random Access Memory),同步动态随机存储器。
同步(Synchronous ):内存工作需要同步时钟,内部的命令的发送与数据的传输都以它为基准;
动态(Dynamic ):存储阵列需要不断的刷新来保证数据不丢失;
随机(Random ):数据不是线性依次存储,而是自由指定地址进行数据读写。
SDRAM具有空间存储量大、读写速度快、价格相对便宜等优点。然而由于SDRAM内部利用电容来存储数据,为保证数据不丢失,需要持续对各存储电容进行刷新操作;同时在读写过程中 需要考虑行列管理、各种操作延时等,由此导致了其控制逻辑复杂的特点。
2. SDRAM手册关键处标注及说明
① 基本特征
a. 总存储32MByte 256Mbit;
b. 数据位宽16bit;
c. 4个bank 4194304个数据/bank;
a. 8192行/bank刷新周期64ms,64ms/8192 = 7.8us/行;
b. 4194304/8192=512列/bank;
c. 命令发出后延迟执行周期(CAS)=2或3周期;
d. 可编程突发有顺序和插入突发两种类型,顺序突发长度1,2,4,8或全页,插入突发长度1,2,4或8.
② 信号列表
信号标志 | 信号类型 | 位宽 | 描述 |
clk | input | 1 | 系统时钟,所有输入在时钟上升沿被锁存 |
cke | input | 1 | 时钟使能信号 |
cs_n | input | 1 | 片选 |
band_addr | input | 2 | band地址(地址总位宽:2+13+9=24) |
row_addr | input | 13 | 行地址13位,列地址9位,自动预充电标志位A10 |
ras_n | input | 1 | 行命令 |
cas_n | input | 1 | 列命令 |
we_n | input | 1 | 写使能命令 |
dqm | inout | 2 | 掩码标志 |
dq | inout | 16 | 数据输入输出 |
③ 关键时间参数
a. 周期参数
如表所示选择时钟周期时间10ns(100MHz),可兼容所有情况。
CL = 3 tAC = 5.4最大
b. 延时或工作时长参数
关键参数列表(时钟周期100MHz 10ns)
名称 | 时间 | 描述 |
tRRC | >63ns(6个周期) 取7个周期 | 自动刷新需要等待的时间 |
tRCD | >20ns(2个周期) 取3个周期 | 预充电需要等待的时间 |
tRP | >20ns(2个周期) 取3个周期 | 行激活需要等待的时间 |
TMRD | >2个周期 取3个周期 | 模式寄存器设置需要等待的时间 |
tDPL | >2个周期 取2个周期 | 数据写入到预充电等待延时的时间 |
④ 模式寄存器设置
模式寄存器格式:2bit bank地址 + 13bit 行地址。
⑤ 命令真值表
关键命令列表
各个指令 | {cs_n,ras_n,cas_n,we_n} | ADDR[12:0] + A10 +BA[1:0] |
Mode Register Set | 4’b0000 | BA(2’b00) + 3’b000,OP Code,2’b00,CAS Latency,BT,Burst Length |
Bank Active | 4’b0011 | BA(2’b00) + Row Address(addr[21:9]) |
Read | 4’b0101 | BA(2’b00) + A10(1’b0) + Column Address(addr[8:0])(其余补齐0) |
Write | 4’b0100 | BA(2’b00) + A10(1’b0) + Column Address(addr[8:0])(其余补齐0) |
Precharge All Banks | 4’b0010 | A10(11’b100_0000_0000) |
Auto Refresh | 4’b0001 |
⑥ 手册状态图
POWER_ON
PRECHARGE_ALL_BANK
MODE_REGISTER_SET
IDLE
AUTO_REFRESH
PRECHARGE_ALL
ROW_ACTIVE
WRITE
READ
⑦ 读时序
⑧ 写时序
⑨ 写到预充电
tDPL = 2 clk
⑩ 初始化刷新
刷新8次间隔8tREF。
⑪ 上电
上电等待200us
三. AVALON总线协议手册阅读
1.Avalon接口规范
规范定义了以下七个接口:
• Avalon Streaming Interface ( Avalon -ST) — 支持单向数据流的接口,包括多路复用流,数据包和 DSP 数据。
• Avalon Memory Mapped Interface ( Avalon -MM) — 一种基于地址的读/写接口,是主–从连接的典型接口。
• Avalon Conduit Interface — 一种接口类型,适用于那些不适合任何其他 Avalon 类型的单个信号或信号组。您可以在一个 Platform Designer 系统内部连接管道接口(conduit
interface)。或者,您可以将它们导出以连接到设计中的其他模块或者连接到 FPGA 管脚。
• Avalon Tri-State Conduit Interface ( Avalon -TC) — 支持与片外(off-chip)连接的接口。
多个外设可以通过信号多路复用(signal multiplexing)来共享管脚,从而减少 FPGA 的管脚数和 PCB 上的走线数量。
• Avalon Interrupt Interface—允许组件向其他组件发送事件信号的接口。
• Avalon Clock Interface—驱动或接收时钟的接口。
• Avalon Reset Interface—提供复位连接的接口。
一个组件可以包括任意数量的这些接口,并且还可以包括相同接口类型的多个实例。
2. Avalon存储器映射的接口——Avalon Memory-Mapped ( Avalon -MM)
① 接口简介
您可以使用 Avalon Memory-Mapped ( Avalon -MM)接口实现主从组件的读写接口。以下是通常
包含存储器映射接口的组件示例:
• 微处理器
• 储存器
• UART
• DMA
• 计时器(Timer)
Avalon -MM 接口有简单的也有有复杂的。例如,SRAM 接口有固定周期的读写传输,具有简单的
Avalon -MM 接口。能够进行突发传输的流水线接口(pipelined interface)很复杂。
② 接口信号
③ 典型的读传输和写传输
此时序图中的数字标记以下转换:
1. address,byteenable 和 read 在 clk 的上升沿后置位。slave 置位 waitrequest,
暂停传输。
2. waitrequest 被采样。由于 waitrequest 置位,因此周期变成一个等待状态(wait
state)。address,read,write 和 byteenable 保持不变。
3. slave 在 clk 的上升沿之后置低 waitrequest。slave 置位 readdata 和 response。
4. master 对 readdata,response 和置低的 waitrequest(完成传输)的进行采样。
5. address,writedata,byteenable 和 write 信号在 clk 的上升沿之后置位。slave
置位 waitrequest,暂停传输。
6. slave 在 clk 的上升沿之后置低 waitrequest。
7. slave 采集结束传输的写数据。
④ 使用 waitrequestAllowance 属性进行传输
此图中的编号标识了以下事件:
1. Avalon -MM master 驱动 write 和 data。
2. Avalon -MM slave 置位 waitrequest。由于 waitrequestAllowance 为 1,因此
master 能够写操作。
3. master 置低 write,因为 slave 置位 waitrequest 第二个周期。
4. Avalon -MM master 驱动 write 和 data。slave 没有置位 waitrequest。写操作完
成。
5. slave 置位 waitrequest。由于 waitrequestAllowance 为 1 个周期,因此写操作完
成。
6. Avalon -MM master 驱动 write 和 data。slave 没有置位 waitrequest。写操作完
成。
7. Avalon -MM slave 置位 waitrequest。由于 waitrequestAllowance 为 1,因此
master 能够完成 1 个额外的数据传输。
8. Avalon master 驱动 write 和 data。slave 没有置位 waitrequest。写操作完成。
注意:当waitrequestAllowance=0时,一旦waitrequest拉高,数据传输立即停止。
四. SDRAM接口IP核手册阅读
三百多页的手册就看了这张图,有时间可以慢慢研究。
IP核突发长度为1。
五. 系统模块划分(框图)
六. 各模块实现
其中按键消抖模块(key_filter)和UART串口模块直接调用以往编写好的模块,不再赘述。
1. pll(锁相环)模块
时钟1:产生100MHz的时钟驱动sdram_control和sdram_interface模块;
时钟2:产生一个100MHz,相位相比于上一个时钟偏移75deg的时钟驱动SDRAM;
调用步骤如下:
2. fifo模块
① wrfifo
目的实现8bit写入数据输入时钟50MHz到输出16bit数据输出时钟100MHz的跨时钟域数据的缓存传输。
② rdfifo
目的实现16bit写入数据输入时钟100MHz到输出8bit数据输出时钟50MHz的跨时钟域数据的缓存传输。
3. sdram_interface模块
SDRAM IP核实现
与FIFO和PLL等IP调用方法不同,tool-->Platform Designer
调用步骤:
搜索sdram,双击蓝色部分。
4. sdram_control模块
①信号列表
名称 | 类型 | 描述 |
clk_100m | input | pll生成时钟100MHz |
clk_50m_in | input | 系统时钟50MHz |
clk_50m_out | input | 系统时钟50MHz |
input | 系统复位 | |
din | input | 用户输入数据 |
din_vld | input | 用户输入数据有效信号 |
dout | output | 输出给用户数据 |
dout_vld | output | 输出给用户数据有效信号 |
busy | input | uart_tx忙信号 |
rd_en | ||
avm_addr | ||
avm_wr_n | ||
avm_wr_data | ||
② 状态机
③ 代码实现
/**************************************功能介绍***********************************
Description: avalon sdram 读写控制模块 对应SDRAM IP核接口
Change history: 2023年7月21日
*********************************************************************************/
//---------<模块及端口声名>------------------------------------------------------
module sdram_control(
input clk_50m_in ,//wrfifo写入端时钟
input clk_50m_out ,//rdfifo读出段时钟
input clk_100m ,//pll生成的100MHz时钟
input rst_n ,
//uart
input din_vld ,//用户输入数据有效信号
input [7:0] din ,//用户输入数据
input busy ,//uart_tx忙信号
output dout_vld ,//输出给用户数据有效信号
output [7:0] dout ,//输出给用户数据
//key
input rd_en ,//读请求信号
//sdram
output [23:0] avm_addr ,//访问sdram的地址
output avm_wr_n ,//访问sdram的写使能信号
output [15:0] avm_wr_data ,//访问sdram的写数据
output avm_rd_n ,//访问sdram的读使能信号
input [15:0] avm_rd_data ,//访问sdram的读出数据
input avm_rd_data_vld,//访问sdram的读出数据有效信号
input avm_waitrequest //sdram等待请求信号
);
//---------<参数定义>---------------------------------------------------------
//突发长度
parameter ROW_LENGTH = 24'h1fffff,//写(读)满一行
BURST_LENGTH = 1'd1 ;//SDRAM IP突发长度1
//状态机参数定义
localparam IDLE = 4'b0001,//
READ = 4'b0010,//
WRITE = 4'b0100,//
DONE = 4'b1000;//
//---------<内部信号定义>-----------------------------------------------------
reg [3:0] state_c ;//现态
reg [3:0] state_n ;//次态
//状态转移条件
wire idle2read ;
wire idle2write ;
wire read2done ;
wire write2done ;
wire done2idle ;
reg rd_en_reg ;//跨时钟域同步寄存
reg avm_waitrequest_reg;//从机输入信号 同步寄存
reg [15:0] avm_rd_data_reg ;//从机输入信号 同步寄存
reg avm_rd_data_vld_reg;//从机输入信号 同步寄存
// 读地址计数器
reg [23:0] cnt_rd_addr ;
wire add_cnt_rd_addr ;
wire end_cnt_rd_addr ;
// 写地址计数器
reg [23:0] cnt_wr_addr ;
wire add_cnt_wr_addr ;
wire end_cnt_wr_addr ;
// wrfifo
wire wrfifo_rdreq ;
wire wrfifo_wrreq ;
wire [15:0] wrfifo_q ;
wire wrfifo_rdempty ;
wire wrfifo_rdfull ;
wire [7:0] wrfifo_rdusedw ;
wire wrfifo_wrempty ;
wire wrfifo_wrfull ;
wire [8:0] wrfifo_wrusedw ;
// rdfifo
wire rdfifo_rdreq ;
wire rdfifo_wrreq ;
wire [7:0] rdfifo_q ;
wire rdfifo_rdempty ;
wire rdfifo_rdfull ;
wire [8:0] rdfifo_rdusedw ;
wire rdfifo_wrempty ;
wire rdfifo_wrfull ;
wire [7:0] rdfifo_wrusedw ;
//****************************************************************
//--rd_en_reg 由于按键模块与sdram_control时钟频率不同,所以按键模块发送来的信号需要同步寄存
//****************************************************************
always @(posedge clk_100m or negedge rst_n)begin
if(!rst_n)begin
rd_en_reg <= 1'b0;
end
else begin
rd_en_reg <= rd_en;
end
end
//****************************************************************
//--avm_waitrequest_reg avm_rd_data_reg avm_rd_data_vld_reg 由于主从机时钟相位不同,所以从机发送来的信号需要同步寄存
//****************************************************************
always @(posedge clk_100m or negedge rst_n)begin
if(!rst_n)begin
avm_waitrequest_reg <= 1'b0 ;
avm_rd_data_vld_reg <= 1'b0 ;
avm_rd_data_reg <= 16'b0;
end
else begin
avm_waitrequest_reg <= avm_waitrequest;
avm_rd_data_vld_reg <= avm_rd_data_vld;
avm_rd_data_reg <= avm_rd_data ;
end
end
//****************************************************************
//--状态机
//****************************************************************
//第一段:时序逻辑描述状态转移
always @(posedge clk_100m or negedge rst_n)begin
if(!rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
//第二段:组合逻辑描述状态转移规律和状态转移条件
always @(*) begin
case(state_c)
IDLE : begin
if(idle2read)begin
state_n = READ;
end
else if(idle2write)begin
state_n = WRITE;
end
else begin
state_n = state_c;
end
end
READ : begin
if(read2done)begin
state_n = DONE;
end
else begin
state_n = state_c;
end
end
WRITE : begin
if(write2done)begin
state_n = DONE;
end
else begin
state_n = state_c;
end
end
DONE : begin
if(done2idle)begin
state_n = IDLE;
end
else begin
state_n = state_c;
end
end
default : begin
state_n = state_c;
end
endcase
end
//状态转移条件
assign idle2read = state_c == IDLE && rd_en_reg ;
assign read2done = state_c == READ && !avm_waitrequest_reg;
assign idle2write = state_c == IDLE && wrfifo_rdusedw ;
assign write2done = state_c == WRITE && !avm_waitrequest_reg;
assign done2idle = state_c == DONE ;
//第三段:描述输出,时序逻辑或组合逻辑皆可
//****************************************************************
//--读地址计数器
//****************************************************************
always @(posedge clk_100m or negedge rst_n)begin
if(!rst_n)begin
cnt_rd_addr <= 24'b0;//访问的首地址24'b0
end
else if(add_cnt_rd_addr)begin
if(end_cnt_rd_addr)begin
cnt_rd_addr <= 24'b0;
end
else begin
cnt_rd_addr <= cnt_rd_addr + BURST_LENGTH;
end
end
else begin
cnt_rd_addr <= cnt_rd_addr;
end
end
assign add_cnt_rd_addr = read2done;//访问完一次地址+1
assign end_cnt_rd_addr = add_cnt_rd_addr && cnt_rd_addr == ROW_LENGTH - BURST_LENGTH;
//****************************************************************
//--写地址计数器
//****************************************************************
always @(posedge clk_100m or negedge rst_n)begin
if(!rst_n)begin
cnt_wr_addr <= 24'b0;
end
else if(add_cnt_wr_addr)begin
if(end_cnt_wr_addr)begin
cnt_wr_addr <= 24'b0;
end
else begin
cnt_wr_addr <= cnt_wr_addr + BURST_LENGTH;
end
end
else begin
cnt_wr_addr <= cnt_wr_addr;
end
end
assign add_cnt_wr_addr = write2done;
assign end_cnt_wr_addr = add_cnt_wr_addr && cnt_wr_addr == ROW_LENGTH - BURST_LENGTH;
//****************************************************************
//--FIFO IP 核例化调用
//****************************************************************
wrfifo wrfifo_inst (
.data ( din ),
.rdclk ( clk_100m ),
.rdreq ( wrfifo_rdreq ),
.wrclk ( clk_50m_in ),
.wrreq ( wrfifo_wrreq ),
.q ( wrfifo_q ),
.rdempty ( wrfifo_rdempty),
.rdfull ( wrfifo_rdfull ),
.rdusedw ( wrfifo_rdusedw),
.wrempty ( wrfifo_wrempty),
.wrfull ( wrfifo_wrfull ),
.wrusedw ( wrfifo_wrusedw)
);
assign wrfifo_wrreq = !wrfifo_wrfull && din_vld;
assign wrfifo_rdreq = !wrfifo_rdempty && state_c == WRITE && !avm_waitrequest_reg;
rdfifo rdfifo_inst (
.data ( avm_rd_data_reg),
.rdclk ( clk_50m_out ),
.rdreq ( rdfifo_rdreq ),
.wrclk ( clk_100m ),
.wrreq ( rdfifo_wrreq ),
.q ( rdfifo_q ),
.rdempty ( rdfifo_rdempty ),
.rdfull ( rdfifo_rdfull ),
.rdusedw ( rdfifo_rdusedw ),
.wrempty ( rdfifo_wrempty ),
.wrfull ( rdfifo_wrfull ),
.wrusedw ( rdfifo_wrusedw )
);
assign rdfifo_wrreq= !rdfifo_wrfull && avm_rd_data_vld_reg && !avm_waitrequest_reg;
assign rdfifo_rdreq= !rdfifo_rdempty && !busy;
//****************************************************************
//--output
//****************************************************************
//to sdram_interface
assign avm_addr = (state_c == WRITE) ? {cnt_wr_addr[23],cnt_wr_addr[21:9],cnt_wr_addr[22],cnt_wr_addr[8:0]} :
{cnt_rd_addr[23],cnt_rd_addr[21:9],cnt_rd_addr[22],cnt_rd_addr[8:0]} ;
// bankA1 行地址 bankA0 列地址
assign avm_wr_data = wrfifo_q ;
assign avm_rd_n = !(state_c == READ );
assign avm_wr_n = !(state_c == WRITE);
//to uart_tx
assign dout_vld = rdfifo_rdreq ;
assign dout = rdfifo_q ;
endmodule
④ 仿真
a. 代码
`timescale 1ns/1ns
module tb_sdram_control();
//激励信号定义
reg clk_50m_in ;
reg clk_50m_out ;
wire clk_100m ;
wire clk_100m_deg ;
reg rst_n ;
//uart
reg din_vld ;
reg [7:0] din ;
reg busy ;
wire dout_vld ;
wire [7:0] dout ;
//key
reg rd_en ;
//sdram
wire [23:0] avm_addr ;
wire avm_wr_n ;
wire [15:0] avm_wr_data ;
wire avm_rd_n ;
wire [15:0] avm_rd_data ;
wire avm_rd_data_vld;
wire avm_waitrequest;
wire [15:0] dq ;
wire [12:0] addr ;
wire [1:0] ba ;
wire cke ;
wire cs_n ;
wire ras_n ;
wire cas_n ;
wire we_n ;
wire [1:0] dqm ;
//模块例化
sdram_control u1(
/*input */.clk_50m_in (clk_50m_in ),//wrfifo写入端时钟
/*input */.clk_50m_out (clk_50m_out ),//rdfifo读出段时钟
/*input */.clk_100m (clk_100m ),//pll生成的100MHz时钟
/*input */.rst_n (rst_n ),
/*//uart */
/*input */.din_vld (din_vld ),//用户输入数据有效信号
/*input [7:0] */.din (din ),//用户输入数据
/*input */.busy (busy ),//uart_tx忙信号
/*output */.dout_vld (dout_vld ),//输出给用户数据有效信号
/*output [7:0] */.dout (dout ),//输出给用户数据
/*//key */
/*input */.rd_en (rd_en ),//读请求信号
/*//sdram */
/*output [23:0] */.avm_addr (avm_addr ),//访问sdram的地址
/*output */.avm_wr_n (avm_wr_n ),//访问sdram的写使能信号
/*output [15:0] */.avm_wr_data (avm_wr_data ),//访问sdram的写数据
/*output */.avm_rd_n (avm_rd_n ),//访问sdram的读使能信号
/*input [15:0] */.avm_rd_data (avm_rd_data ),//访问sdram的读出数据
/*input */.avm_rd_data_vld(avm_rd_data_vld),//访问sdram的读出数据有效信号
/*input */.avm_waitrequest(avm_waitrequest) //sdram等待请求信号
);
sdram_interface u0 (
.avalon_bus_address (avm_addr ), // avalon_bus.address
.avalon_bus_byteenable_n (2'b11 ), // .byteenable_n
.avalon_bus_chipselect (1'b1 ), // .chipselect
.avalon_bus_writedata (avm_wr_data ), // .writedata
.avalon_bus_read_n (avm_rd_n ), // .read_n
.avalon_bus_write_n (avm_wr_n ), // .write_n
.avalon_bus_readdata (avm_rd_data ), // .readdata
.avalon_bus_readdatavalid (avm_rd_data_vld ), // .readdatavalid
.avalon_bus_waitrequest (avm_waitrequest ), // .waitrequest
.clk_clk (clk_100m ), // clk.clk
.mem_port_addr (addr ), // mem_port.addr
.mem_port_ba (ba ), // .ba
.mem_port_cas_n (cas_n ), // .cas_n
.mem_port_cke (cke ), // .cke
.mem_port_cs_n (cs_n ), // .cs_n
.mem_port_dq (dq ), // .dq
.mem_port_dqm (dqm ), // .dqm
.mem_port_ras_n (ras_n ), // .ras_n
.mem_port_we_n (we_n ), // .we_n
.reset_reset_n (rst_n ) // reset.reset_n
);
sdr slave_module(
.Dq (dq ),
.Addr (addr ),
.Ba (ba ),
.Clk (clk_100m_deg),
.Cke (cke ),
.Cs_n (cs_n ),
.Ras_n (ras_n ),
.Cas_n (cas_n ),
.We_n (we_n ),
.Dqm (Dqm )
);
pll_ip_100m_75deg pll_ip_100m_75deg_inst (
.areset ( !rst_n ),
.inclk0 ( clk_50m_in ),
.c0 ( clk_100m ),
.c1 ( clk_100m_deg),
.locked ( )
);
//产生时钟
initial clk_50m_in = 1'b0;
always #10 clk_50m_in = ~clk_50m_in;
initial clk_50m_out = 1'b0;
always #10 clk_50m_out = ~clk_50m_out;
//产生激励
initial begin
rst_n = 1'b1;
din = 0;
din_vld = 0;
busy = 0;
rd_en = 0;
#200;
rst_n = 1'b0;
#400;
rst_n = 1'b1;
#3;
#220000 ;
//模拟写操作
din = 8'h12;
din_vld = 1'b1;
#20;
din_vld = 1'b0;
#20;
din = 8'h13;
din_vld = 1'b1;
#20;
din_vld = 1'b0;
#20;
din = 8'h14;
din_vld = 1'b1;
#20;
din_vld = 1'b0;
#20;
din = 8'h15;
din_vld = 1'b1;
#20;
din_vld = 1'b0;
din = 8'h0;
#20;
//模拟读操作
rd_en = 1'b1;
#20;
rd_en = 1'b0;
#1000;
rd_en = 1'b1;
#20;
rd_en = 1'b0;
#2000;
$stop;
end
endmodule
b. 仿真波形
5. 顶层模块
代码
/**************************************功能介绍***********************************
Description: avalon sdram 顶层模块 对应SDRAM IP核接口
Change history:
*********************************************************************************/
//---------<模块及端口声名>------------------------------------------------------
module top(
input clk ,
input rst_n ,
//key
input key_in ,
//uart
input rx ,
output tx ,
//sdram
output clk_100m_deg ,
inout [15:0] dq ,
output [12:0] addr ,
output [1:0] ba ,
output cke ,
output cs_n ,
output ras_n ,
output cas_n ,
output we_n ,
output [1:0] dqm
);
//---------<参数定义>---------------------------------------------------------
//---------<内部信号定义>-----------------------------------------------------
wire key_en ;
wire [7:0] rx_dout ;
wire rx_dout_vld ;
wire [7:0] tx_din ;
wire tx_req ;
wire busy ;
wire clk_100m ;
wire [23:0] avm_addr ;//访问sdram的地址
wire avm_wr_n ;//访问sdram的写使能信号
wire [15:0] avm_wr_data ;//访问sdram的写数据
wire avm_rd_n ;//访问sdram的读使能信号
wire [15:0] avm_rd_data ;//访问sdram的读出数据
wire avm_rd_data_vld;//访问sdram的读出数据有效信号
wire avm_waitrequest;//sdram等待请求信号
key_filter u_key_filter(
/*input */.clk (clk ) ,
/*input */.rst_n (rst_n ) ,
/*input */.key_in (key_in ) ,
/*output reg */.key_down (key_en )
);
uart_rx u_uart_rx(
/*input */.clk (clk ) ,
/*input */.rst_n (rst_n ) ,
/*input */.rx_din (rx ) ,//串口数据接收端
/*input [2:0] */.baud_sel (3'd0 ) ,//波特率选择信号
/*output reg [7:0] */.rx_dout (rx_dout ) ,//接收模块输出的数据
/*output reg */.rx_dout_vld(rx_dout_vld) //接收模块输出的数据有效的标志信号,高有效
);
uart_tx u_uart_tx(
/*input */.clk (clk ) ,
/*input */.rst_n (rst_n ) ,
/*input [7:0] */.tx_din (tx_din ) ,//输入要发的数据
/*input */.tx_req (tx_req ) ,//发送请求信号
/*input [2:0] */.baud_sel (3'd0 ) ,
/*output reg */.tx_dout (tx ) ,//发送模块输出数据,1bit
/*output reg */.busy (busy ) //忙闲指示信号,busy为0时,表示空闲;busy为1时,表示正在发送数据(忙)
);
sdram_control u_sdram_control(
/*input */.clk_50m_in (clk ),//wrfifo写入端时钟
/*input */.clk_50m_out (clk ),//rdfifo读出段时钟
/*input */.clk_100m (clk_100m ),//pll生成的100MHz时钟
/*input */.rst_n (rst_n ),
/*//uart */
/*input */.din_vld (rx_dout_vld ),//用户输入数据有效信号
/*input [7:0] */.din (rx_dout ),//用户输入数据
/*input */.busy (busy ),//uart_tx忙信号
/*output */.dout_vld (tx_req ),//输出给用户数据有效信号
/*output [7:0] */.dout (tx_din ),//输出给用户数据
/*//key */
/*input */.rd_en (key_en ),//读请求信号
/*//sdram */
/*output [23:0] */.avm_addr (avm_addr ),//访问sdram的地址
/*output */.avm_wr_n (avm_wr_n ),//访问sdram的写使能信号
/*output [15:0] */.avm_wr_data (avm_wr_data ),//访问sdram的写数据
/*output */.avm_rd_n (avm_rd_n ),//访问sdram的读使能信号
/*input [15:0] */.avm_rd_data (avm_rd_data ),//访问sdram的读出数据
/*input */.avm_rd_data_vld(avm_rd_data_vld),//访问sdram的读出数据有效信号
/*input */.avm_waitrequest(avm_waitrequest) //sdram等待请求信号
);
sdram_interface u0 (
.avalon_bus_address (avm_addr ), // avalon_bus.address
.avalon_bus_byteenable_n (2'b0 ), // .byteenable_n
.avalon_bus_chipselect (1'b1 ), // .chipselect
.avalon_bus_writedata (avm_wr_data ), // .writedata
.avalon_bus_read_n (avm_rd_n ), // .read_n
.avalon_bus_write_n (avm_wr_n ), // .write_n
.avalon_bus_readdata (avm_rd_data ), // .readdata
.avalon_bus_readdatavalid (avm_rd_data_vld ), // .readdatavalid
.avalon_bus_waitrequest (avm_waitrequest ), // .waitrequest
.clk_clk (clk_100m ), // clk.clk
.mem_port_addr (addr ), // mem_port.addr
.mem_port_ba (ba ), // .ba
.mem_port_cas_n (cas_n ), // .cas_n
.mem_port_cke (cke ), // .cke
.mem_port_cs_n (cs_n ), // .cs_n
.mem_port_dq (dq ), // .dq
.mem_port_dqm (dqm ), // .dqm
.mem_port_ras_n (ras_n ), // .ras_n
.mem_port_we_n (we_n ), // .we_n
.reset_reset_n (rst_n ) // reset.reset_n
);
pll_ip_100m_75deg pll_ip_100m_75deg_inst (
.areset ( !rst_n ),
.inclk0 ( clk ),
.c0 ( clk_100m ),
.c1 ( clk_100m_deg),
.locked ( )
);
endmodule
6. 上板验证
由于SDRAM IP核突发长度只有1,所以只能一个数据一个数据的读写
串口可发送多个写入数据,读功能只能按一下按键读一个数据(16bit)