FPGA进阶(3):SDRAM读写控制器的设计与验证(一)+https://developer.aliyun.com/article/1556621
2. sdram_top
fifo_ctrl
`timescale 1ns/1ns module fifo_ctrl ( input wire sys_clk , //系统时钟 input wire sys_rst_n , //复位信号 //写fifo信号 input wire wr_fifo_wr_clk , //写FIFO写时钟 input wire wr_fifo_wr_req , //写FIFO写请求 input wire [15:0] wr_fifo_wr_data , //写FIFO写数据 input wire [23:0] sdram_wr_b_addr , //写SDRAM首地址 input wire [23:0] sdram_wr_e_addr , //写SDRAM末地址 input wire [9:0] wr_burst_len , //写SDRAM数据突发长度 input wire wr_rst , //写复位信号 //读fifo信号 input wire rd_fifo_rd_clk , //读FIFO读时钟 input wire rd_fifo_rd_req , //读FIFO读请求 input wire [23:0] sdram_rd_b_addr , //读SDRAM首地址 input wire [23:0] sdram_rd_e_addr , //读SDRAM末地址 input wire [9:0] rd_burst_len , //读SDRAM数据突发长度 input wire rd_rst , //读复位信号 output wire [15:0] rd_fifo_rd_data , //读FIFO读数据 output wire [9:0] rd_fifo_num , //读fifo中的数据量 input wire read_valid , //SDRAM读使能 input wire init_end , //SDRAM初始化完成标志 //SDRAM写信号 input wire sdram_wr_ack , //SDRAM写响应 output reg sdram_wr_req , //SDRAM写请求 output reg [23:0] sdram_wr_addr , //SDRAM写地址 output wire [15:0] sdram_data_in , //写入SDRAM的数据 //SDRAM读信号 input wire sdram_rd_ack , //SDRAM读相应 input wire [15:0] sdram_data_out , //读出SDRAM数据 output reg sdram_rd_req , //SDRAM读请求 output reg [23:0] sdram_rd_addr //SDRAM读地址 ); //wire define wire wr_ack_fall ; //写响应信号下降沿 wire rd_ack_fall ; //读相应信号下降沿 wire [9:0] wr_fifo_num ; //写fifo中的数据量 //reg define reg wr_ack_dly ; //写响应打拍 reg rd_ack_dly ; //读响应打拍 //wr_ack_dly:写响应信号打拍 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) wr_ack_dly <= 1'b0; else wr_ack_dly <= sdram_wr_ack; //rd_ack_dly:读响应信号打拍 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rd_ack_dly <= 1'b0; else rd_ack_dly <= sdram_rd_ack; //wr_ack_fall,rd_ack_fall:检测读写响应信号下降沿 assign wr_ack_fall = (wr_ack_dly & ~sdram_wr_ack); assign rd_ack_fall = (rd_ack_dly & ~sdram_rd_ack); //sdram_wr_addr:sdram写地址 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) sdram_wr_addr <= 24'd0; else if(wr_rst == 1'b1) sdram_wr_addr <= sdram_wr_b_addr; else if(wr_ack_fall == 1'b1) //一次突发写结束,更改写地址 begin if(sdram_wr_addr < (sdram_wr_e_addr - wr_burst_len)) //不使用乒乓操作,一次突发写结束,更改写地址,未达到末地址,写地址累加 sdram_wr_addr <= sdram_wr_addr + wr_burst_len; else //不使用乒乓操作,到达末地址,回到写起始地址 sdram_wr_addr <= sdram_wr_b_addr; end //sdram_rd_addr:sdram读地址 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) sdram_rd_addr <= 24'd0; else if(rd_rst == 1'b1) sdram_rd_addr <= sdram_rd_b_addr; else if(rd_ack_fall == 1'b1) //一次突发读结束,更改读地址 begin if(sdram_rd_addr < (sdram_rd_e_addr - rd_burst_len)) //读地址未达到末地址,读地址累加 sdram_rd_addr <= sdram_rd_addr + rd_burst_len; else //到达末地址,回到首地址 sdram_rd_addr <= sdram_rd_b_addr; end //sdram_wr_req,sdram_rd_req:读写请求信号 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) begin sdram_wr_req <= 1'b0; sdram_rd_req <= 1'b0; end else if(init_end == 1'b1) //初始化完成后响应读写请求 begin //优先执行写操作,防止写入SDRAM中的数据丢失 if(wr_fifo_num >= wr_burst_len) begin //写FIFO中的数据量达到写突发长度 sdram_wr_req <= 1'b1; //写请求有效 sdram_rd_req <= 1'b0; end else if((rd_fifo_num < rd_burst_len) && (read_valid == 1'b1)) begin //读FIFO中的数据量小于读突发长度,且读使能信号有效 sdram_wr_req <= 1'b0; sdram_rd_req <= 1'b1; //读请求有效 end else begin sdram_wr_req <= 1'b0; sdram_rd_req <= 1'b0; end end else begin sdram_wr_req <= 1'b0; sdram_rd_req <= 1'b0; end //------------- wr_fifo_data ------------- fifo_data wr_fifo_data( //用户接口 .wrclk (wr_fifo_wr_clk ), //写时钟 .wrreq (wr_fifo_wr_req ), //写请求 .data (wr_fifo_wr_data), //写数据 //SDRAM接口 .rdclk (sys_clk ), //读时钟 .rdreq (sdram_wr_ack ), //读请求 .q (sdram_data_in ), //读数据 .rdusedw (wr_fifo_num ), //FIFO中的数据量 .wrusedw ( ), .aclr (~sys_rst_n || wr_rst) //清零信号 ); //------------- rd_fifo_data ------------- fifo_data rd_fifo_data( //sdram接口 .wrclk (sys_clk ), //写时钟 .wrreq (sdram_rd_ack ), //写请求 .data (sdram_data_out ), //写数据 //用户接口 .rdclk (rd_fifo_rd_clk ), //读时钟 .rdreq (rd_fifo_rd_req ), //读请求 .q (rd_fifo_rd_data), //读数据 .rdusedw ( ), .wrusedw (rd_fifo_num ), //FIFO中的数据量 .aclr (~sys_rst_n || rd_rst) //清零信号 ); endmodule
sdram_top
`timescale 1ns/1ns module sdram_top ( input wire sys_clk , //系统时钟 input wire clk_out , //相位偏移时钟 input wire sys_rst_n , //复位信号,低有效 //写FIFO信号 input wire wr_fifo_wr_clk , //写FIFO写时钟 input wire wr_fifo_wr_req , //写FIFO写请求 input wire [15:0] wr_fifo_wr_data , //写FIFO写数据 input wire [23:0] sdram_wr_b_addr , //写SDRAM首地址 input wire [23:0] sdram_wr_e_addr , //写SDRAM末地址 input wire [9:0] wr_burst_len , //写SDRAM数据突发长度 input wire wr_rst , //写复位信号 //读FIFO信号 input wire rd_fifo_rd_clk , //读FIFO读时钟 input wire rd_fifo_rd_req , //读FIFO读请求 input wire [23:0] sdram_rd_b_addr , //读SDRAM首地址 input wire [23:0] sdram_rd_e_addr , //读SDRAM末地址 input wire [9:0] rd_burst_len , //读SDRAM数据突发长度 input wire rd_rst , //读复位信号 output wire [15:0] rd_fifo_rd_data , //读FIFO读数据 output wire [9:0] rd_fifo_num , //读fifo中的数据量 input wire read_valid , //SDRAM读使能 output wire init_end , //SDRAM初始化完成标志 //SDRAM接口信号 output wire sdram_clk , //SDRAM芯片时钟 output wire sdram_cke , //SDRAM时钟有效信号 output wire sdram_cs_n , //SDRAM片选信号 output wire sdram_ras_n , //SDRAM行地址选通脉冲 output wire sdram_cas_n , //SDRAM列地址选通脉冲 output wire sdram_we_n , //SDRAM写允许位 output wire [1:0] sdram_ba , //SDRAM的L-Bank地址线 output wire [12:0] sdram_addr , //SDRAM地址总线 output wire [1:0] sdram_dqm , //SDRAM数据掩码 inout wire [15:0] sdram_dq //SDRAM数据总线 ); //wire define wire sdram_wr_req ; //sdram 写请求 wire sdram_wr_ack ; //sdram 写响应 wire [23:0] sdram_wr_addr ; //sdram 写地址 wire [15:0] sdram_data_in ; //写入sdram中的数据 wire sdram_rd_req ; //sdram 读请求 wire sdram_rd_ack ; //sdram 读响应 wire [23:0] sdram_rd_addr ; //sdram 读地址 wire [15:0] sdram_data_out ; //从sdram中读出的数据 //sdram_clk:SDRAM芯片时钟 assign sdram_clk = clk_out; //sdram_dqm:SDRAM数据掩码 assign sdram_dqm = 2'b00; //------------- fifo_ctrl_inst ------------- fifo_ctrl fifo_ctrl_inst( //system signal .sys_clk (sys_clk ), //SDRAM控制时钟 .sys_rst_n (sys_rst_n ), //复位信号 //write fifo signal .wr_fifo_wr_clk (wr_fifo_wr_clk ), //写FIFO写时钟 .wr_fifo_wr_req (wr_fifo_wr_req ), //写FIFO写请求 .wr_fifo_wr_data(wr_fifo_wr_data), //写FIFO写数据 .sdram_wr_b_addr(sdram_wr_b_addr), //写SDRAM首地址 .sdram_wr_e_addr(sdram_wr_e_addr), //写SDRAM末地址 .wr_burst_len (wr_burst_len ), //写SDRAM数据突发长度 .wr_rst (wr_rst ), //写清零信号 //read fifo signal .rd_fifo_rd_clk (rd_fifo_rd_clk ), //读FIFO读时钟 .rd_fifo_rd_req (rd_fifo_rd_req ), //读FIFO读请求 .rd_fifo_rd_data(rd_fifo_rd_data), //读FIFO读数据 .rd_fifo_num (rd_fifo_num ), //读FIFO中的数据量 .sdram_rd_b_addr(sdram_rd_b_addr), //读SDRAM首地址 .sdram_rd_e_addr(sdram_rd_e_addr), //读SDRAM末地址 .rd_burst_len (rd_burst_len ), //读SDRAM数据突发长度 .rd_rst (rd_rst ), //读清零信号 //USER ctrl signal .read_valid (read_valid ), //SDRAM读使能 .init_end (init_end ), //SDRAM初始化完成标志 //SDRAM ctrl of write .sdram_wr_ack (sdram_wr_ack ), //SDRAM写响应 .sdram_wr_req (sdram_wr_req ), //SDRAM写请求 .sdram_wr_addr (sdram_wr_addr ), //SDRAM写地址 .sdram_data_in (sdram_data_in ), //写入SDRAM的数据 //SDRAM ctrl of read .sdram_rd_ack (sdram_rd_ack ), //SDRAM读请求 .sdram_data_out (sdram_data_out ), //SDRAM读响应 .sdram_rd_req (sdram_rd_req ), //SDRAM读地址 .sdram_rd_addr (sdram_rd_addr ) //读出SDRAM数据 ); //------------- sdram_ctrl_inst ------------- sdram_ctrl sdram_ctrl_inst( .sys_clk (sys_clk ), //系统时钟 .sys_rst_n (sys_rst_n ), //复位信号,低电平有效 //SDRAM 控制器写端口 .sdram_wr_req (sdram_wr_req ), //写SDRAM请求信号 .sdram_wr_addr (sdram_wr_addr ), //SDRAM写操作的地址 .wr_burst_len (wr_burst_len ), //写sdram时数据突发长度 .sdram_data_in (sdram_data_in ), //写入SDRAM的数据 .sdram_wr_ack (sdram_wr_ack ), //写SDRAM响应信号 //SDRAM 控制器读端口 .sdram_rd_req (sdram_rd_req ), //读SDRAM请求信号 .sdram_rd_addr (sdram_rd_addr ), //SDRAM写操作的地址 .rd_burst_len (rd_burst_len ), //读sdram时数据突发长度 .sdram_data_out (sdram_data_out ), //从SDRAM读出的数据 .init_end (init_end ), //SDRAM 初始化完成标志 .sdram_rd_ack (sdram_rd_ack ), //读SDRAM响应信号 //FPGA与SDRAM硬件接口 .sdram_cke (sdram_cke ), // SDRAM 时钟有效信号 .sdram_cs_n (sdram_cs_n ), // SDRAM 片选信号 .sdram_ras_n (sdram_ras_n ), // SDRAM 行地址选通脉冲 .sdram_cas_n (sdram_cas_n ), // SDRAM 列地址选通脉冲 .sdram_we_n (sdram_we_n ), // SDRAM 写允许位 .sdram_ba (sdram_ba ), // SDRAM L-Bank地址线 .sdram_addr (sdram_addr ), // SDRAM 地址总线 .sdram_dq (sdram_dq ) // SDRAM 数据总线 ); endmodule
3. uart_sdram
uart_rx
`timescale 1ns/1ns module uart_rx #( parameter UART_BPS = 'd9600, //串口波特率 parameter CLK_FREQ = 'd50_000_000 //时钟频率 ) ( input wire sys_clk , //系统时钟50MHz input wire sys_rst_n , //全局复位 input wire rx , //串口接收数据 output reg [7:0] po_data , //串转并后的8bit数据 output reg po_flag //串转并后的数据有效标志信号 ); //localparam define localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ; //reg define reg rx_reg1 ; reg rx_reg2 ; reg rx_reg3 ; reg start_nedge ; reg work_en ; reg [12:0] baud_cnt ; reg bit_flag ; reg [3:0] bit_cnt ; reg [7:0] rx_data ; reg rx_flag ; //插入两级寄存器进行数据同步,用来消除亚稳态 //rx_reg1:第一级寄存器,寄存器空闲状态复位为1 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rx_reg1 <= 1'b1; else rx_reg1 <= rx; //rx_reg2:第二级寄存器,寄存器空闲状态复位为1 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rx_reg2 <= 1'b1; else rx_reg2 <= rx_reg1; //rx_reg3:第三级寄存器和第二级寄存器共同构成下降沿检测 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rx_reg3 <= 1'b1; else rx_reg3 <= rx_reg2; //start_nedge:检测到下降沿时start_nedge产生一个时钟的高电平 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) start_nedge <= 1'b0; else if((~rx_reg2) && (rx_reg3)) start_nedge <= 1'b1; else start_nedge <= 1'b0; //work_en:接收数据工作使能信号 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) work_en <= 1'b0; else if(start_nedge == 1'b1) work_en <= 1'b1; else if((bit_cnt == 4'd8) && (bit_flag == 1'b1)) work_en <= 1'b0; //baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) baud_cnt <= 13'b0; else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0)) baud_cnt <= 13'b0; else if(work_en == 1'b1) baud_cnt <= baud_cnt + 1'b1; //bit_flag:当baud_cnt计数器计数到中间数时采样的数据最稳定, //此时拉高一个标志信号表示数据可以被取走 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) bit_flag <= 1'b0; else if(baud_cnt == BAUD_CNT_MAX/2 - 1) bit_flag <= 1'b1; else bit_flag <= 1'b0; //bit_cnt:有效数据个数计数器,当8个有效数据(不含起始位和停止位) //都接收完成后计数器清零 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) bit_cnt <= 4'b0; else if((bit_cnt == 4'd8) && (bit_flag == 1'b1)) bit_cnt <= 4'b0; else if(bit_flag ==1'b1) bit_cnt <= bit_cnt + 1'b1; //rx_data:输入数据进行移位 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rx_data <= 8'b0; else if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1)) rx_data <= {rx_reg3, rx_data[7:1]}; //rx_flag:输入数据移位完成时rx_flag拉高一个时钟的高电平 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rx_flag <= 1'b0; else if((bit_cnt == 4'd8) && (bit_flag == 1'b1)) rx_flag <= 1'b1; else rx_flag <= 1'b0; //po_data:输出完整的8位有效数据 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) po_data <= 8'b0; else if(rx_flag == 1'b1) po_data <= rx_data; //po_flag:输出数据有效标志(比rx_flag延后一个时钟周期,为了和po_data同步) always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) po_flag <= 1'b0; else po_flag <= rx_flag; endmodule
uart_tx
`timescale 1ns/1ns module uart_tx #( parameter UART_BPS = 'd9600, //串口波特率 parameter CLK_FREQ = 'd50_000_000 //时钟频率 ) ( input wire sys_clk , //系统时钟50MHz input wire sys_rst_n , //全局复位 input wire [7:0] pi_data , //模块输入的8bit数据 input wire pi_flag , //并行数据有效标志信号 output reg tx //串转并后的1bit数据 ); //localparam define localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ; //reg define reg [12:0] baud_cnt; reg bit_flag; reg [3:0] bit_cnt ; reg work_en ; //work_en:接收数据工作使能信号 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) work_en <= 1'b0; else if(pi_flag == 1'b1) work_en <= 1'b1; else if((bit_flag == 1'b1) && (bit_cnt == 4'd9)) work_en <= 1'b0; //baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) baud_cnt <= 13'b0; else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0)) baud_cnt <= 13'b0; else if(work_en == 1'b1) baud_cnt <= baud_cnt + 1'b1; //bit_flag:当baud_cnt计数器计数到1时让bit_flag拉高一个时钟的高电平 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) bit_flag <= 1'b0; else if(baud_cnt == 13'd1) bit_flag <= 1'b1; else bit_flag <= 1'b0; //bit_cnt:数据位数个数计数,10个有效数据(含起始位和停止位)到来后计数器清零 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) bit_cnt <= 4'b0; else if((bit_flag == 1'b1) && (bit_cnt == 4'd9)) bit_cnt <= 4'b0; else if((bit_flag == 1'b1) && (work_en == 1'b1)) bit_cnt <= bit_cnt + 1'b1; //tx:输出数据在满足rs232协议(起始位为0,停止位为1)的情况下一位一位输出 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) tx <= 1'b1; //空闲状态时为高电平 else if(bit_flag == 1'b1) case(bit_cnt) 0 : tx <= 1'b0; 1 : tx <= pi_data[0]; 2 : tx <= pi_data[1]; 3 : tx <= pi_data[2]; 4 : tx <= pi_data[3]; 5 : tx <= pi_data[4]; 6 : tx <= pi_data[5]; 7 : tx <= pi_data[6]; 8 : tx <= pi_data[7]; 9 : tx <= 1'b1; default : tx <= 1'b1; endcase endmodule
fifo_read
`timescale 1ns/1ns module fifo_read ( input wire sys_clk , //系统时钟,频率50MHz input wire sys_rst_n , //复位信号,低电平有效 input wire [9:0] rd_fifo_num , //SDRAM中读fifo中数据个数 input wire [7:0] pi_data , //读出数据 input wire [9:0] burst_num , //一次突发数据个数 output reg read_en , //SDRAM中读fifo的读使能 output wire [7:0] tx_data , //输出数据 output reg tx_flag //输出数据标志信号 ); //parameter define parameter BAUD_CNT_END = 13'd5207 , BAUD_CNT_END_HALF = 13'd2603 ; parameter CNT_WAIT_MAX = 24'd4_999_999 ; //wire define wire [9:0] data_num ; //fifo中数据个数 //reg define reg read_en_dly ; reg [12:0] baud_cnt ; reg rd_en ; reg rd_flag ; reg [9:0] cnt_read ; reg [3:0] bit_cnt ; reg bit_flag ; //read_en:SDRAM中读fifo的读使能 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) read_en <= 1'b0; else if(rd_fifo_num == burst_num) read_en <= 1'b1; else if(data_num == burst_num - 2) read_en <= 1'b0; //read_en_dly:SDRAM中读fifo的读使能打拍 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) read_en_dly <= 1'b0; else read_en_dly <= read_en; //rd_flag:向tx模块发送数据使能 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rd_flag <= 1'b0; else if(cnt_read == burst_num) rd_flag <= 1'b0; else if(data_num == burst_num) rd_flag <= 1'b1; //baud_cnt:波特率计数器计数从0计数到BAUD_CNT_END always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) baud_cnt <= 13'd0; else if(baud_cnt == BAUD_CNT_END) baud_cnt <= 13'd0; else if(rd_flag == 1'b1) baud_cnt <= baud_cnt + 1'b1; //bit_flag:bit计数器计数使能 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) bit_flag <= 1'b0; else if(baud_cnt == BAUD_CNT_END_HALF) bit_flag <= 1'b1; else bit_flag <= 1'b0; //bit_cnt:bit计数器 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) bit_cnt <= 4'b0; else if((bit_cnt == 4'd9) && (bit_flag == 1'b1)) bit_cnt <= 4'b0; else if(bit_flag == 1'b1) bit_cnt <= bit_cnt + 1'b1; //rd_en:读fifo的读使能 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) rd_en <= 1'b0; else if(bit_cnt == 4'd9 && bit_flag == 1'b1) rd_en <= 1'b1; else rd_en <= 1'b0; //cnt_read:读出数据计数 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) cnt_read <= 10'd0; else if(cnt_read == burst_num) cnt_read <= 10'b0; else if(rd_en == 1'b1) cnt_read <= cnt_read + 1'b1; else cnt_read <= cnt_read; //tx_flag:读出数据标志信号 always@(posedge sys_clk or negedge sys_rst_n) if(sys_rst_n == 1'b0) tx_flag <= 1'b0; else tx_flag <= rd_en; //-------------fifo_read_inst-------------- read_fifo read_fifo_inst( .clock (sys_clk ), //input clk .data (pi_data ), //input [7 : 0] din .wrreq (read_en_dly ), //input wr_en .rdreq (rd_en ), //input rd_en .q (tx_data ), //output [7 : 0] dout .usedw (data_num ) ); endmodule
uart_sdram
`timescale 1ns/1ns module uart_sdram ( input wire sys_clk , //时钟信号 input wire sys_rst_n , //复位信号 input wire rx , //串口接收数据 output wire tx , //串口发送数据 output wire sdram_clk , //SDRAM 芯片时钟 output wire sdram_cke , //SDRAM 时钟有效 output wire sdram_cs_n , //SDRAM 片选 output wire sdram_cas_n , //SDRAM 行有效 output wire sdram_ras_n , //SDRAM 列有效 output wire sdram_we_n , //SDRAM 写有效 output wire [1:0] sdram_ba , //SDRAM Bank地址 output wire [12:0] sdram_addr , //SDRAM 行/列地址 output wire [1:0] sdram_dqm , //SDRAM 数据掩码 inout wire [15:0] sdram_dq //SDRAM 数据 ); //parameter define parameter DATA_NUM = 24'd10 ; //写入SDRAM数据个数 parameter WAIT_MAX = 16'd750 ; //等待计数最大值 parameter UART_BPS = 14'd9600 , //比特率 CLK_FREQ = 26'd50_000_000 ; //时钟频率 // wire define //uart_rx wire [ 7:0] rx_data ; //串口接收模块拼接后的8位数据 wire rx_flag ; //数据标志信号 //fifo_read wire [ 7:0] rfifo_wr_data ; //读fifo发热写入数据 wire rfifo_wr_en ; //读fifo的写使能 wire [ 7:0] rfifo_rd_data ; //读fifo的读数据 wire rfifo_rd_en ; //读fifo的读使能 wire [9:0] rd_fifo_num ; //读fifo中的数据量 //clk_gen wire clk_50m ; wire clk_100m ; wire clk_100m_shift ; //pll产生时钟 wire locked ; //pll锁定信号 wire rst_n ; //复位信号 //sdram_top_inst reg [23:0] data_num ; //写入SDRAM数据个数计数 reg read_valid ; //数据读使能 reg [15:0] cnt_wait ; //等待计数器 //rst_n:复位信号 assign rst_n = sys_rst_n & locked; //data_num:写入SDRAM数据个数计数 always@(posedge clk_50m or negedge sys_rst_n) if(sys_rst_n == 1'b0) data_num <= 24'd0; else if(read_valid == 1'b1) data_num <= 24'd0; else if(rx_flag == 1'b1) data_num <= data_num + 1'b1; else data_num <= data_num; //cnt_wait:等待计数器 always@(posedge clk_50m or negedge sys_rst_n) if(sys_rst_n == 1'b0) cnt_wait <= 16'd0; else if(cnt_wait == WAIT_MAX) cnt_wait <= 16'd0; else if(data_num == DATA_NUM) cnt_wait <= cnt_wait + 1'b1; //read_valid:数据读使能 always@(posedge clk_50m or negedge sys_rst_n) if(sys_rst_n == 1'b0) read_valid <= 1'b0; else if(cnt_wait == WAIT_MAX) read_valid <= 1'b1; else if(rd_fifo_num == DATA_NUM) read_valid <= 1'b0; //------------- clk_gen_inst ------------- clk_gen clk_gen_inst ( .inclk0 (sys_clk ), .areset (~sys_rst_n ), .c0 (clk_50m ), .c1 (clk_100m ), .c2 (clk_100m_shift ), .locked (locked ) ); //-------------uart_rx_inst------------- uart_rx #( .UART_BPS (UART_BPS ), //串口波特率 .CLK_FREQ (CLK_FREQ ) //时钟频率 ) uart_rx_inst ( .sys_clk (clk_50m ), //input sys_clk .sys_rst_n (rst_n ), //input sys_rst_n .rx (rx ), //input rx .po_data (rx_data ), //output [7:0] rx_data .po_flag (rx_flag ) //output rx_flag ); //------------- sdram_top_inst ------------- sdram_top sdram_top_inst ( .sys_clk (clk_100m ), //sdram 控制器参考时钟 .clk_out (clk_100m_shift ), //用于输出的相位偏移时钟 .sys_rst_n (rst_n ), //系统复位 //用户写端口 .wr_fifo_wr_clk (clk_50m ), //写端口FIFO: 写时钟 .wr_fifo_wr_req (rx_flag ), //写端口FIFO: 写使能 .wr_fifo_wr_data ({8'b0,rx_data} ), //写端口FIFO: 写数据 .sdram_wr_b_addr (24'd0 ), //写SDRAM的起始地址 .sdram_wr_e_addr (DATA_NUM ), //写SDRAM的结束地址 .wr_burst_len (DATA_NUM ), //写SDRAM时的数据突发长度 .wr_rst ( ), //写复位 //用户读端口 .rd_fifo_rd_clk (clk_50m ), //读端口FIFO: 读时钟 .rd_fifo_rd_req (rfifo_wr_en ), //读端口FIFO: 读使能 .rd_fifo_rd_data (rfifo_wr_data ), //读端口FIFO: 读数据 .sdram_rd_b_addr (24'd0 ), //读SDRAM的起始地址 .sdram_rd_e_addr (DATA_NUM ), //读SDRAM的结束地址 .rd_burst_len (DATA_NUM ), //从SDRAM中读数据时的突发长度 .rd_rst ( ), //读复位 .rd_fifo_num (rd_fifo_num ), //读fifo中的数据量 //用户控制端口 .read_valid (read_valid ), //SDRAM 读使能 .init_end ( ), //SDRAM 初始化完成标志 //SDRAM 芯片接口 .sdram_clk (sdram_clk ), //SDRAM 芯片时钟 .sdram_cke (sdram_cke ), //SDRAM 时钟有效 .sdram_cs_n (sdram_cs_n ), //SDRAM 片选 .sdram_ras_n (sdram_ras_n ), //SDRAM 行有效 .sdram_cas_n (sdram_cas_n ), //SDRAM 列有效 .sdram_we_n (sdram_we_n ), //SDRAM 写有效 .sdram_ba (sdram_ba ), //SDRAM Bank地址 .sdram_addr (sdram_addr ), //SDRAM 行/列地址 .sdram_dq (sdram_dq ), //SDRAM 数据 .sdram_dqm (sdram_dqm ) //SDRAM 数据掩码 ); //------------- fifo_read_inst -------------- fifo_read fifo_read_inst ( .sys_clk (clk_50m ), //input sys_clk .sys_rst_n (sys_rst_n ), //input sys_rst_n .rd_fifo_num (rd_fifo_num ), .pi_data (rfifo_wr_data ), //input [7:0] pi_data .burst_num (DATA_NUM ), .read_en (rfifo_wr_en ), //input pi_flag .tx_data (rfifo_rd_data ), //output [7:0] tx_data .tx_flag (rfifo_rd_en ) //output tx_flag ); //-------------uart_tx_inst------------- uart_tx #( .UART_BPS (UART_BPS ), //串口波特率 .CLK_FREQ (CLK_FREQ ) //时钟频率 ) uart_tx_inst ( .sys_clk (sys_clk ), //input sys_clk .sys_rst_n (sys_rst_n ), //input sys_rst_n .pi_data (rfifo_rd_data ), //input [7:0] pi_data .pi_flag (rfifo_rd_en ), //input pi_flag .tx (tx ) //output tx ); endmodule