[FPGA] Einige grundlegende Modulcodes

Inhaltsverzeichnis

VGA-Treibermodul:

OV5640-Kamera

Datei der obersten Ebene:

COMS-Modul:

Kamera-CFG-Konfiguration:

IIc-Modul:

SDRAM-Modul:

TOP-Modul

FIFO-Steuermodul:

Erstellen Sie zwei FIFOs

SDRAM-Steuermodul TOP

SDRAM-Befehlssteuermodul

SDRAM-Statuskontrollmodul

SDRAM-Datenlese- und -schreibmodul

SDRAM-Parameterdatei


camera_top:

module cam_vga(    
    input                 sys_clk     ,  //系统时钟
    input                 sys_rst_n   ,  //系统复位,低电平有效
    //摄像头接口
    input                 cam_pclk    ,  //cmos 数据像素时钟
    input                 cam_vsync   ,  //cmos 场同步信号
    input                 cam_href    ,  //cmos 行同步信号
    input        [7:0]    cam_data    ,  //cmos 数据  
	output                cam_rst_n   ,  //cmos 复位信号,低电平有效
    output                cam_pwdn    ,  //cmos 电源休眠模式选择信号
    output                cam_scl     ,  //cmos SCCB_SCL线
    inout                 cam_sda     ,  //cmos SCCB_SDA线
    //SDRAM接口
    output                sdram_clk   ,  //SDRAM 时钟
    output                sdram_cke   ,  //SDRAM 时钟有效
    output                sdram_cs_n  ,  //SDRAM 片选
    output                sdram_ras_n ,  //SDRAM 行有效
    output                sdram_cas_n ,  //SDRAM 列有效
    output                sdram_we_n  ,  //SDRAM 写有效
    output       [1:0]    sdram_ba    ,  //SDRAM Bank地址
    output       [1:0]    sdram_dqm   ,  //SDRAM 数据掩码
    output       [12:0]   sdram_addr  ,  //SDRAM 地址
    inout        [15:0]   sdram_data  ,  //SDRAM 数据    
    //VGA接口                          
    output                vga_hs      ,  //行同步信号
    output                vga_vs      ,  //场同步信号
    output        [15:0]  vga_rgb        //红绿蓝三原色输出 
	);

//parameter define
parameter  SLAVE_ADDR = 7'h3c         ;  //OV5640的器件地址7'h3c
parameter  BIT_CTRL   = 1'b1          ;  //OV5640的字节地址为16位  0:8位 1:16位
parameter  CLK_FREQ   = 26'd65_000_000;  //i2c_dri模块的驱动时钟频率 65MHz
parameter  I2C_FREQ   = 18'd250_000   ;  //I2C的SCL时钟频率,不超过400KHz
parameter  CMOS_H_PIXEL = 24'd1024    ;  //CMOS水平方向像素个数,用于设置SDRAM缓存大小
parameter  CMOS_V_PIXEL = 24'd768     ;  //CMOS垂直方向像素个数,用于设置SDRAM缓存大小
                                      
									  
wire   [15:0]         wr_data         ;  //sdram_ctrl模块写数据
wire   [15:0]         rd_data         ;  //sdram_ctrl模块读数据

//*****************************************************
//**                    main code
//*****************************************************

assign  rst_n = sys_rst_n & locked;
//系统初始化完成:SDRAM和摄像头都初始化完成
//避免了在SDRAM初始化过程中向里面写入数据
//assign  sys_init_done = sdram_init_done & cam_init_done;
//不对摄像头硬件复位,固定高电平
assign  cam_rst_n = 1'b1;
//电源休眠模式选择 0:正常模式 1:电源休眠模式
assign  cam_pwdn = 1'b0;

//锁相环
pll_clk u_pll_clk(
    .areset             (~sys_rst_n),
    .inclk0             (sys_clk),			
    .c0                 (clk_100m),			//100mhz时钟,SDRAM操作时钟
    .c1                 (clk_100m_shift),	//100mhz时钟,SDRAM相位偏移时钟
    .c2                 (clk_65m),			//65mhz时钟,提供给IIC驱动时钟和vga驱动时钟
    .locked             (locked)
    );

//摄像头模块
camera
	#(
	.SLAVE_ADDR			(SLAVE_ADDR),
	.BIT_CTRL  			(BIT_CTRL),
	
	.CLK_FREQ 			(CLK_FREQ) ,
    .I2C_FREQ			(I2C_FREQ),
	
	.CMOS_H_PIXEL      (CMOS_H_PIXEL),
	.CMOS_V_PIXEL      (CMOS_V_PIXEL)
    )
	cam(
	.clk_65m      	  	(clk_65m),
	.rst_n    		  	(rst_n),
		
	.cam_pclk        	(cam_pclk),  //cmos 数据像素时钟
	.cam_vsync       	(cam_vsync),  //cmos 场同步信号
	.cam_href        	(cam_href),  //cmos 行同步信号
	.cam_data        	(cam_data),  //cmos 数据   
	
	//与SDRAM的接口
	.sdram_init_done 	(sdram_init_done),
	.cmos_frame_valid	(wr_en),  //数据有效使能信号
	.cmos_frame_data 	(wr_data),   //有效数据        
	
	.cam_scl        	  	(cam_scl),      // I2C的SCL时钟信号
	.cam_sda              	(cam_sda)// I2C的SDA信号
);



//SDRAM 控制器顶层模块,封装成FIFO接口
//SDRAM 控制器地址组成: {bank_addr[1:0],row_addr[12:0],col_addr[8:0]}
sdram_top u_sdram_top(
    .ref_clk            (clk_100m),                   //sdram 控制器参考时钟
    .out_clk            (clk_100m_shift),             //用于输出的相位偏移时钟
    .rst_n              (rst_n),                      //系统复位
                                                        
    //用户写端口                                        
    .wr_clk             (cam_pclk),                   //写端口FIFO: 写时钟
    .wr_en              (wr_en),                      //写端口FIFO: 写使能
    .wr_data            (wr_data),                    //写端口FIFO: 写数据
    .wr_min_addr        (24'd0),                      //写SDRAM的起始地址
    .wr_max_addr        (CMOS_H_PIXEL*CMOS_V_PIXEL),  //写SDRAM的结束地址
    .wr_len             (10'd512),                    //写SDRAM时的数据突发长度
    .wr_load            (~rst_n),                     //写端口复位: 复位写地址,清空写FIFO
                                                        
    //用户读端口                                        
    .rd_clk             (clk_65m),                    //读端口FIFO: 读时钟
    .rd_en              (rd_en),                      //读端口FIFO: 读使能
    .rd_data            (rd_data),                    //读端口FIFO: 读数据
    .rd_min_addr        (24'd0),                      //读SDRAM的起始地址
    .rd_max_addr        (CMOS_H_PIXEL*CMOS_V_PIXEL),  //读SDRAM的结束地址
    .rd_len             (10'd512),                    //从SDRAM中读数据时的突发长度
    .rd_load            (~rst_n),                     //读端口复位: 复位读地址,清空读FIFO
                                                
    //用户控制端口                                
    .sdram_read_valid   (1'b1),                       //SDRAM 读使能
    .sdram_pingpang_en  (1'b1),                       //SDRAM 乒乓操作使能
    .sdram_init_done    (sdram_init_done),            //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_data         (sdram_data),                 //SDRAM 数据
    .sdram_dqm          (sdram_dqm)                   //SDRAM 数据掩码
    );


//VGA驱动模块
vga_driver u_vga_driver(
    .vga_clk            (clk_65m),    
    .sys_rst_n          (rst_n),    
    
    .vga_hs             (vga_hs),       
    .vga_vs             (vga_vs),       
    .vga_rgb            (vga_rgb),      
        
    .pixel_data         (rd_data), 
    .data_req           (rd_en),                      //请求像素点颜色数据输入
    .pixel_xpos         (), 
    .pixel_ypos         ()
    ); 
   
endmodule

VGA-Treibermodul:

erklären:

3 rein——— 5 raus

eingeben:

1,50 Mio. Uhr

2. Zurücksetzen

3. Ein Pixel des eingehenden 16-Bit-Pixelbildes

Ausgang:

1. Leitungssynchronisation direkt an der VGA-Schnittstelle angeschlossen

2. Feldsynchronisation direkt angeschlossen an die VGA-Schnittstelle

3.RGB16-Bit-Pixelausgang direkt mit der VGA-Schnittstelle verbunden

4. Pixel-Abszisse. Dies ist im Allgemeinen der Ort, an dem das Pixel verarbeitet werden soll, die Bildverarbeitung

5. Vertikale Pixelkoordinate Dies ist im Allgemeinen der Ort, an dem das Pixel verarbeitet werden soll, die Bildverarbeitung

module vga_driver(
    input           vga_clk,      //VGA驱动时钟
    input           sys_rst_n,    //复位信号
    //VGA接口                          
    output          vga_hs,       //行同步信号
    output          vga_vs,       //场同步信号
    output  [15:0]  vga_rgb,      //红绿蓝三原色输出
    
    input   [15:0]  pixel_data,   //像素点数据
    output          data_req  ,   //请求像素点颜色数据输入 
    output  [ 9:0]  pixel_xpos,   //像素点横坐标
    output  [ 9:0]  pixel_ypos    //像素点纵坐标    
    );                             
                                                        
//parameter define  
parameter  H_SYNC   =  10'd96;    //行同步
parameter  H_BACK   =  10'd48;    //行显示后沿
parameter  H_DISP   =  10'd640;   //行有效数据
parameter  H_FRONT  =  10'd16;    //行显示前沿
parameter  H_TOTAL  =  10'd800;   //行扫描周期

parameter  V_SYNC   =  10'd2;     //场同步
parameter  V_BACK   =  10'd33;    //场显示后沿
parameter  V_DISP   =  10'd480;   //场有效数据
parameter  V_FRONT  =  10'd10;    //场显示前沿
parameter  V_TOTAL  =  10'd525;   //场扫描周期
          
//reg define                                     
reg  [9:0] cnt_h;
reg  [9:0] cnt_v;

//wire define
wire       vga_en;
wire       data_req; 

//*****************************************************
//**                    main code
//*****************************************************
//VGA行场同步信号
assign vga_hs  = (cnt_h <= H_SYNC - 1'b1) ? 1'b0 : 1'b1;
assign vga_vs  = (cnt_v <= V_SYNC - 1'b1) ? 1'b0 : 1'b1;

//使能RGB565数据输出
assign vga_en  = (((cnt_h >= H_SYNC+H_BACK) && (cnt_h < H_SYNC+H_BACK+H_DISP))
                 &&((cnt_v >= V_SYNC+V_BACK) && (cnt_v < V_SYNC+V_BACK+V_DISP)))
                 ?  1'b1 : 1'b0;
                 
//RGB565数据输出                 
assign vga_rgb = vga_en ? pixel_data : 16'd0;

//请求像素点颜色数据输入                
assign data_req = (((cnt_h >= H_SYNC+H_BACK-1'b1) && (cnt_h < H_SYNC+H_BACK+H_DISP-1'b1))
                  && ((cnt_v >= V_SYNC+V_BACK) && (cnt_v < V_SYNC+V_BACK+V_DISP)))
                  ?  1'b1 : 1'b0;

//像素点坐标                
assign pixel_xpos = data_req ? (cnt_h - (H_SYNC + H_BACK - 1'b1)) : 10'd0;
assign pixel_ypos = data_req ? (cnt_v - (V_SYNC + V_BACK - 1'b1)) : 10'd0;

//行计数器对像素时钟计数
always @(posedge vga_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)
        cnt_h <= 10'd0;                                  
    else begin
        if(cnt_h < H_TOTAL - 1'b1)                                               
            cnt_h <= cnt_h + 1'b1;                               
        else 
            cnt_h <= 10'd0;  
    end
end

//场计数器对行计数
always @(posedge vga_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)
        cnt_v <= 10'd0;                                  
    else if(cnt_h == H_TOTAL - 1'b1) begin
        if(cnt_v < V_TOTAL - 1'b1)                                               
            cnt_v <= cnt_v + 1'b1;                               
        else 
            cnt_v <= 10'd0;  
    end
end
endmodule 

OV5640-Kamera

Datei der obersten Ebene:

module camera_top(
	input                 clk_65m      	  ,
	input                 rst_n    		  ,  
	
	//与SDRAM的接口
	input                 sdram_init_done ,
	output                cmos_frame_valid,  //数据有效使能信号
	output       [15:0]   cmos_frame_data ,   //有效数据        
	
	// 硬件输入
	input                 cam_pclk        ,  //cmos 数据像素时钟
	input                 cam_vsync       ,  //cmos 场同步信号
	input                 cam_href        ,  //cmos 行同步信号
	input        [7:0]    cam_data        ,  //cmos 数据 
	// 硬件输出
	output            	  cam_scl        	  ,      // I2C的SCL时钟信号
	inout                 cam_sda              // I2C的SDA信号
);

//parameter define
parameter  SLAVE_ADDR = 7'h3c         ;  //OV5640的器件地址7'h3c
parameter  BIT_CTRL   = 1'b1          ;  //OV5640的字节地址为16位  0:8位 1:16位
parameter  CLK_FREQ   = 26'd65_000_000;  //i2c_dri模块的驱动时钟频率 65MHz
parameter  I2C_FREQ   = 18'd250_000   ;  //I2C的SCL时钟频率,不超过400KHz
parameter  CMOS_H_PIXEL = 24'd1024    ;  //CMOS水平方向像素个数,用于设置SDRAM缓存大小
parameter  CMOS_V_PIXEL = 24'd768     ;  //CMOS垂直方向像素个数,用于设置SDRAM缓存大小

wire    [23:0]  i2c_data ;

assign  sys_init_done = sdram_init_done & cam_init_done;

//I2C配置模块
i2c_ov5640_rgb565_cfg 
   #(
     .CMOS_H_PIXEL      (CMOS_H_PIXEL),
     .CMOS_V_PIXEL      (CMOS_V_PIXEL)
    )   
   u_i2c_cfg(   
    .clk                (i2c_dri_clk),
    .rst_n              (rst_n),
    .i2c_done           (i2c_done),
    .i2c_exec           (i2c_exec),
    .i2c_data           (i2c_data),
    .init_done          (cam_init_done)
    );
	 
//I2C驱动模块
i2c_dri 
   #(
    .SLAVE_ADDR         (SLAVE_ADDR),       //参数传递
    .CLK_FREQ           (CLK_FREQ  ),              
    .I2C_FREQ           (I2C_FREQ  )                
    )   
   u_i2c_dri(   
    .clk                (clk_65m   ),
    .rst_n              (rst_n     ),   
        
    .i2c_exec           (i2c_exec  ),   
    .bit_ctrl           (BIT_CTRL  ),   
    .i2c_rh_wl          (1'b0),             //固定为0,只用到了IIC驱动的写操作   
    .i2c_addr           (i2c_data[23:8]),   
    .i2c_data_w         (i2c_data[7:0]),   
    .i2c_data_r         (),   
    .i2c_done           (i2c_done  ),   
    .scl                (cam_scl   ),   
    .sda                (cam_sda   ),   
        
    .dri_clk            (i2c_dri_clk)       //I2C操作时钟
);


//CMOS图像数据采集模块
cmos_capture_data u_cmos_capture_data(  //系统初始化完成之后再开始采集数据 
    .rst_n              (rst_n & sys_init_done), 		//只有当iic配置+SDRAM配置完成,才行
        
    .cam_pclk           (cam_pclk),
    .cam_vsync          (cam_vsync),
    .cam_href           (cam_href),
    .cam_data           (cam_data),
        
        
    .cmos_frame_vsync   (),
    .cmos_frame_href    (),
    .cmos_frame_valid   (cmos_frame_valid),       //数据有效使能信号
    .cmos_frame_data    (cmos_frame_data)      //有效数据 
    );

	 
endmodule

COMS-Modul:

module cmos_capture_data(
    input                 rst_n           ,  //复位信号
    //摄像头接口
    input                 cam_pclk        ,  //cmos 数据像素时钟
    input                 cam_vsync       ,  //cmos 场同步信号
    input                 cam_href        ,  //cmos 行同步信号
    input        [7:0]    cam_data        ,  //cmos 数据                             
    //用户接口
    output                cmos_frame_vsync,  //帧有效信号    
    output                cmos_frame_href ,  //行有效信号
    output                cmos_frame_valid,  //数据有效使能信号
    output       [15:0]   cmos_frame_data    //有效数据        
    );

//寄存器全部配置完成后,先等待10帧数据
//待寄存器配置生效后再开始采集图像
parameter  WAIT_FRAME = 4'd10  ;             //寄存器数据稳定等待的帧个数            

//reg define
reg             cam_vsync_d0   ;
reg             cam_vsync_d1   ;
reg             cam_href_d0    ;
reg             cam_href_d1    ;
reg    [3:0]    cmos_ps_cnt    ;             //等待帧数稳定计数器
reg             frame_val_flag ;             //帧有效的标志

reg    [7:0]    cam_data_d0    ;             
reg    [15:0]   cmos_data_t    ;             //用于8位转16位的临时寄存器
reg             byte_flag      ;             
reg             byte_flag_d0   ;

//wire define
wire            pos_vsync      ;

//*****************************************************
//**                    main code
//*****************************************************

//采输入场同步信号的上升沿
assign pos_vsync = (~cam_vsync_d1) & cam_vsync_d0;  

//输出帧有效信号
assign  cmos_frame_vsync = frame_val_flag  ?  cam_vsync_d1  :  1'b0; 
//输出行有效信号
assign  cmos_frame_href  = frame_val_flag  ?  cam_href_d1   :  1'b0; 
//输出数据使能有效信号
assign  cmos_frame_valid = frame_val_flag  ?  byte_flag_d0  :  1'b0; 
//输出数据
assign  cmos_frame_data  = frame_val_flag  ?  cmos_data_t   :  1'b0; 

//采输入场同步信号的上升沿
always @(posedge cam_pclk or negedge rst_n) begin
    if(!rst_n) begin
        cam_vsync_d0 <= 1'b0;
        cam_vsync_d1 <= 1'b0;
        cam_href_d0 <= 1'b0;
        cam_href_d1 <= 1'b0;
    end
    else begin
        cam_vsync_d0 <= cam_vsync;
        cam_vsync_d1 <= cam_vsync_d0;
        cam_href_d0 <= cam_href;
        cam_href_d1 <= cam_href_d0;
    end
end

//对帧数进行计数
always @(posedge cam_pclk or negedge rst_n) begin
    if(!rst_n)
        cmos_ps_cnt <= 4'd0;
    else if(pos_vsync && (cmos_ps_cnt < WAIT_FRAME))
        cmos_ps_cnt <= cmos_ps_cnt + 4'd1;
end

//帧有效标志
always @(posedge cam_pclk or negedge rst_n) begin
    if(!rst_n)
        frame_val_flag <= 1'b0;
    else if((cmos_ps_cnt == WAIT_FRAME) && pos_vsync)
        frame_val_flag <= 1'b1;
    else;    
end            

//8位数据转16位RGB565数据        
always @(posedge cam_pclk or negedge rst_n) begin
    if(!rst_n) begin
        cmos_data_t <= 16'd0;
        cam_data_d0 <= 8'd0;
        byte_flag <= 1'b0;
    end
    else if(cam_href) begin
        byte_flag <= ~byte_flag;
        cam_data_d0 <= cam_data;
        if(byte_flag)
            cmos_data_t <= {cam_data_d0,cam_data};
        else;   
    end
    else begin
        byte_flag <= 1'b0;
        cam_data_d0 <= 8'b0;
    end    
end        

//产生输出数据有效信号(cmos_frame_valid)
always @(posedge cam_pclk or negedge rst_n) begin
    if(!rst_n)
        byte_flag_d0 <= 1'b0;
    else
        byte_flag_d0 <= byte_flag;    
end          

endmodule 

Kamera-CFG-Konfiguration:

module i2c_ov5640_rgb565_cfg
  #(
    parameter CMOS_H_PIXEL = 24'd1024,//CMOS水平方向像素个数
    parameter CMOS_V_PIXEL = 24'd768  //CMOS垂直方向像素个数
    )
   (  
    input                clk      ,   //时钟信号
    input                rst_n    ,   //复位信号,低电平有效
    
    input                i2c_done ,   //I2C寄存器配置完成信号
    output  reg          i2c_exec ,   //I2C触发执行信号
    output  reg  [23:0]  i2c_data ,   //I2C要配置的地址与数据(高16位地址,低8位数据)
    output  reg          init_done    //初始化完成信号
    );

//parameter define
localparam  REG_NUM = 8'd248  ;       //总共需要配置的寄存器个数
localparam  TOTAL_H_PIXEL = CMOS_H_PIXEL + 13'd1216;  //水平总像素大小
localparam  TOTAL_V_PIXEL = CMOS_V_PIXEL + 13'd504;   //垂直总像素大小

//reg define
reg   [14:0]   start_init_cnt;        //等待延时计数器
reg    [7:0]   init_reg_cnt  ;        //寄存器配置个数计数器

//*****************************************************
//**                    main code
//*****************************************************

//cam_scl配置成250khz,输入的clk为1Mhz,周期为1us,20000*1us = 20ms
//OV5640上电到开始配置IIC至少等待20ms
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        start_init_cnt <= 15'd0;
    else if(start_init_cnt < 15'd20000)
        start_init_cnt <= start_init_cnt + 1'b1;                    
end

//寄存器配置个数计数    
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        init_reg_cnt <= 8'd0;
    else if(i2c_exec)   
        init_reg_cnt <= init_reg_cnt + 8'b1;
end

//i2c触发执行信号   
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        i2c_exec <= 1'b0;
    else if(start_init_cnt == 15'd19999)
        i2c_exec <= 1'b1;
    else if(i2c_done && (init_reg_cnt < REG_NUM))
        i2c_exec <= 1'b1;
    else
        i2c_exec <= 1'b0;
end 

//初始化完成信号
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        init_done <= 1'b0;
    else if((init_reg_cnt == REG_NUM) && i2c_done)  
        init_done <= 1'b1;  
end

//配置寄存器地址与数据
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        i2c_data <= 24'd0;
    else begin
        case(init_reg_cnt)
            //先对寄存器进行软件复位,使寄存器恢复初始值
            8'd0  : i2c_data <= {16'h3008,8'h82}; //Bit[7]:复位 Bit[6]:电源休眠
            8'd1  : i2c_data <= {16'h3008,8'h02}; //正常工作模式
            8'd2  : i2c_data <= {16'h3103,8'h02}; //Bit[1]:1 PLL Clock
            //引脚输入/输出控制 FREX/VSYNC/HREF/PCLK/D[9:6]
            8'd3  : i2c_data <= {8'h30,8'h17,8'hff};
            //引脚输入/输出控制 D[5:0]/GPIO1/GPIO0 
            8'd4  : i2c_data <= {16'h3018,8'hff};
            8'd5  : i2c_data <= {16'h3037,8'h13}; //PLL分频控制
            8'd6  : i2c_data <= {16'h3108,8'h01}; //系统根分频器
            8'd7  : i2c_data <= {16'h3630,8'h36};
            8'd8  : i2c_data <= {16'h3631,8'h0e};
            8'd9  : i2c_data <= {16'h3632,8'he2};
            8'd10 : i2c_data <= {16'h3633,8'h12};
            8'd11 : i2c_data <= {16'h3621,8'he0};
            8'd12 : i2c_data <= {16'h3704,8'ha0};
            8'd13 : i2c_data <= {16'h3703,8'h5a};
            8'd14 : i2c_data <= {16'h3715,8'h78};
            8'd15 : i2c_data <= {16'h3717,8'h01};
            8'd16 : i2c_data <= {16'h370b,8'h60};
            8'd17 : i2c_data <= {16'h3705,8'h1a};
            8'd18 : i2c_data <= {16'h3905,8'h02};
            8'd19 : i2c_data <= {16'h3906,8'h10};
            8'd20 : i2c_data <= {16'h3901,8'h0a};
            8'd21 : i2c_data <= {16'h3731,8'h12};
            8'd22 : i2c_data <= {16'h3600,8'h08}; //VCM控制,用于自动聚焦
            8'd23 : i2c_data <= {16'h3601,8'h33}; //VCM控制,用于自动聚焦
            8'd24 : i2c_data <= {16'h302d,8'h60}; //系统控制
            8'd25 : i2c_data <= {16'h3620,8'h52};
            8'd26 : i2c_data <= {16'h371b,8'h20};
            8'd27 : i2c_data <= {16'h471c,8'h50};
            8'd28 : i2c_data <= {16'h3a13,8'h43}; //AEC(自动曝光控制)
            8'd29 : i2c_data <= {16'h3a18,8'h00}; //AEC 增益上限
            8'd30 : i2c_data <= {16'h3a19,8'hf8}; //AEC 增益上限
            8'd31 : i2c_data <= {16'h3635,8'h13};
            8'd32 : i2c_data <= {16'h3636,8'h03};
            8'd33 : i2c_data <= {16'h3634,8'h40};
            8'd34 : i2c_data <= {16'h3622,8'h01};
            8'd35 : i2c_data <= {16'h3c01,8'h34};
            8'd36 : i2c_data <= {16'h3c04,8'h28};
            8'd37 : i2c_data <= {16'h3c05,8'h98};
            8'd38 : i2c_data <= {16'h3c06,8'h00}; //light meter 1 阈值[15:8]
            8'd39 : i2c_data <= {16'h3c07,8'h08}; //light meter 1 阈值[7:0]
            8'd40 : i2c_data <= {16'h3c08,8'h00}; //light meter 2 阈值[15:8]
            8'd41 : i2c_data <= {16'h3c09,8'h1c}; //light meter 2 阈值[7:0]
            8'd42 : i2c_data <= {16'h3c0a,8'h9c}; //sample number[15:8]
            8'd43 : i2c_data <= {16'h3c0b,8'h40}; //sample number[7:0]
            8'd44 : i2c_data <= {16'h3810,8'h00}; //Timing Hoffset[11:8]
            8'd45 : i2c_data <= {16'h3811,8'h10}; //Timing Hoffset[7:0]
            8'd46 : i2c_data <= {16'h3812,8'h00}; //Timing Voffset[10:8]
            8'd47 : i2c_data <= {16'h3708,8'h64};
            8'd48 : i2c_data <= {16'h4001,8'h02}; //BLC(黑电平校准)补偿起始行号
            8'd49 : i2c_data <= {16'h4005,8'h1a}; //BLC(黑电平校准)补偿始终更新
            8'd50 : i2c_data <= {16'h3000,8'h00}; //系统块复位控制
            8'd51 : i2c_data <= {16'h3004,8'hff}; //时钟使能控制
            8'd52 : i2c_data <= {16'h4300,8'h61}; //格式控制 RGB565
            8'd53 : i2c_data <= {16'h501f,8'h01}; //ISP RGB
            8'd54 : i2c_data <= {16'h440e,8'h00};
            8'd55 : i2c_data <= {16'h5000,8'ha7}; //ISP控制
            8'd56 : i2c_data <= {16'h3a0f,8'h30}; //AEC控制;stable range in high
            8'd57 : i2c_data <= {16'h3a10,8'h28}; //AEC控制;stable range in low
            8'd58 : i2c_data <= {16'h3a1b,8'h30}; //AEC控制;stable range out high
            8'd59 : i2c_data <= {16'h3a1e,8'h26}; //AEC控制;stable range out low
            8'd60 : i2c_data <= {16'h3a11,8'h60}; //AEC控制; fast zone high
            8'd61 : i2c_data <= {16'h3a1f,8'h14}; //AEC控制; fast zone low
            //LENC(镜头校正)控制 16'h5800~16'h583d
            8'd62 : i2c_data <= {16'h5800,8'h23}; 
            8'd63 : i2c_data <= {16'h5801,8'h14};
            8'd64 : i2c_data <= {16'h5802,8'h0f};
            8'd65 : i2c_data <= {16'h5803,8'h0f};
            8'd66 : i2c_data <= {16'h5804,8'h12};
            8'd67 : i2c_data <= {16'h5805,8'h26};
            8'd68 : i2c_data <= {16'h5806,8'h0c};
            8'd69 : i2c_data <= {16'h5807,8'h08};
            8'd70 : i2c_data <= {16'h5808,8'h05};
            8'd71 : i2c_data <= {16'h5809,8'h05};
            8'd72 : i2c_data <= {16'h580a,8'h08};
            8'd73 : i2c_data <= {16'h580b,8'h0d};
            8'd74 : i2c_data <= {16'h580c,8'h08};
            8'd75 : i2c_data <= {16'h580d,8'h03};
            8'd76 : i2c_data <= {16'h580e,8'h00};
            8'd77 : i2c_data <= {16'h580f,8'h00};
            8'd78 : i2c_data <= {16'h5810,8'h03};
            8'd79 : i2c_data <= {16'h5811,8'h09};
            8'd80 : i2c_data <= {16'h5812,8'h07};
            8'd81 : i2c_data <= {16'h5813,8'h03};
            8'd82 : i2c_data <= {16'h5814,8'h00};
            8'd83 : i2c_data <= {16'h5815,8'h01};
            8'd84 : i2c_data <= {16'h5816,8'h03};
            8'd85 : i2c_data <= {16'h5817,8'h08};
            8'd86 : i2c_data <= {16'h5818,8'h0d};
            8'd87 : i2c_data <= {16'h5819,8'h08};
            8'd88 : i2c_data <= {16'h581a,8'h05};
            8'd89 : i2c_data <= {16'h581b,8'h06};
            8'd90 : i2c_data <= {16'h581c,8'h08};
            8'd91 : i2c_data <= {16'h581d,8'h0e};
            8'd92 : i2c_data <= {16'h581e,8'h29};
            8'd93 : i2c_data <= {16'h581f,8'h17};
            8'd94 : i2c_data <= {16'h5820,8'h11};
            8'd95 : i2c_data <= {16'h5821,8'h11};
            8'd96 : i2c_data <= {16'h5822,8'h15};
            8'd97 : i2c_data <= {16'h5823,8'h28};
            8'd98 : i2c_data <= {16'h5824,8'h46};
            8'd99 : i2c_data <= {16'h5825,8'h26};
            8'd100: i2c_data <= {16'h5826,8'h08};
            8'd101: i2c_data <= {16'h5827,8'h26};
            8'd102: i2c_data <= {16'h5828,8'h64};
            8'd103: i2c_data <= {16'h5829,8'h26};
            8'd104: i2c_data <= {16'h582a,8'h24};
            8'd105: i2c_data <= {16'h582b,8'h22};
            8'd106: i2c_data <= {16'h582c,8'h24};
            8'd107: i2c_data <= {16'h582d,8'h24};
            8'd108: i2c_data <= {16'h582e,8'h06};
            8'd109: i2c_data <= {16'h582f,8'h22};
            8'd110: i2c_data <= {16'h5830,8'h40};
            8'd111: i2c_data <= {16'h5831,8'h42};
            8'd112: i2c_data <= {16'h5832,8'h24};
            8'd113: i2c_data <= {16'h5833,8'h26};
            8'd114: i2c_data <= {16'h5834,8'h24};
            8'd115: i2c_data <= {16'h5835,8'h22};
            8'd116: i2c_data <= {16'h5836,8'h22};
            8'd117: i2c_data <= {16'h5837,8'h26};
            8'd118: i2c_data <= {16'h5838,8'h44};
            8'd119: i2c_data <= {16'h5839,8'h24};
            8'd120: i2c_data <= {16'h583a,8'h26};
            8'd121: i2c_data <= {16'h583b,8'h28};
            8'd122: i2c_data <= {16'h583c,8'h42};
            8'd123: i2c_data <= {16'h583d,8'hce};
            //AWB(自动白平衡控制) 16'h5180~16'h519e
            8'd124: i2c_data <= {16'h5180,8'hff};
            8'd125: i2c_data <= {16'h5181,8'hf2};
            8'd126: i2c_data <= {16'h5182,8'h00};
            8'd127: i2c_data <= {16'h5183,8'h14};
            8'd128: i2c_data <= {16'h5184,8'h25};
            8'd129: i2c_data <= {16'h5185,8'h24};
            8'd130: i2c_data <= {16'h5186,8'h09};
            8'd131: i2c_data <= {16'h5187,8'h09};
            8'd132: i2c_data <= {16'h5188,8'h09};
            8'd133: i2c_data <= {16'h5189,8'h75};
            8'd134: i2c_data <= {16'h518a,8'h54};
            8'd135: i2c_data <= {16'h518b,8'he0};
            8'd136: i2c_data <= {16'h518c,8'hb2};
            8'd137: i2c_data <= {16'h518d,8'h42};
            8'd138: i2c_data <= {16'h518e,8'h3d};
            8'd139: i2c_data <= {16'h518f,8'h56};
            8'd140: i2c_data <= {16'h5190,8'h46};
            8'd141: i2c_data <= {16'h5191,8'hf8};
            8'd142: i2c_data <= {16'h5192,8'h04};
            8'd143: i2c_data <= {16'h5193,8'h70};
            8'd144: i2c_data <= {16'h5194,8'hf0};
            8'd145: i2c_data <= {16'h5195,8'hf0};
            8'd146: i2c_data <= {16'h5196,8'h03};
            8'd147: i2c_data <= {16'h5197,8'h01};
            8'd148: i2c_data <= {16'h5198,8'h04};
            8'd149: i2c_data <= {16'h5199,8'h12};
            8'd150: i2c_data <= {16'h519a,8'h04};
            8'd151: i2c_data <= {16'h519b,8'h00};
            8'd152: i2c_data <= {16'h519c,8'h06};
            8'd153: i2c_data <= {16'h519d,8'h82};
            8'd154: i2c_data <= {16'h519e,8'h38};
            //Gamma(伽马)控制 16'h5480~16'h5490
            8'd155: i2c_data <= {16'h5480,8'h01}; 
            8'd156: i2c_data <= {16'h5481,8'h08};
            8'd157: i2c_data <= {16'h5482,8'h14};
            8'd158: i2c_data <= {16'h5483,8'h28};
            8'd159: i2c_data <= {16'h5484,8'h51};
            8'd160: i2c_data <= {16'h5485,8'h65};
            8'd161: i2c_data <= {16'h5486,8'h71};
            8'd162: i2c_data <= {16'h5487,8'h7d};
            8'd163: i2c_data <= {16'h5488,8'h87};
            8'd164: i2c_data <= {16'h5489,8'h91};
            8'd165: i2c_data <= {16'h548a,8'h9a};
            8'd166: i2c_data <= {16'h548b,8'haa};
            8'd167: i2c_data <= {16'h548c,8'hb8};
            8'd168: i2c_data <= {16'h548d,8'hcd};
            8'd169: i2c_data <= {16'h548e,8'hdd};
            8'd170: i2c_data <= {16'h548f,8'hea};
            8'd171: i2c_data <= {16'h5490,8'h1d};
            //CMX(彩色矩阵控制) 16'h5381~16'h538b
            8'd172: i2c_data <= {16'h5381,8'h1e};
            8'd173: i2c_data <= {16'h5382,8'h5b};
            8'd174: i2c_data <= {16'h5383,8'h08};
            8'd175: i2c_data <= {16'h5384,8'h0a};
            8'd176: i2c_data <= {16'h5385,8'h7e};
            8'd177: i2c_data <= {16'h5386,8'h88};
            8'd178: i2c_data <= {16'h5387,8'h7c};
            8'd179: i2c_data <= {16'h5388,8'h6c};
            8'd180: i2c_data <= {16'h5389,8'h10};
            8'd181: i2c_data <= {16'h538a,8'h01};
            8'd182: i2c_data <= {16'h538b,8'h98};
            //SDE(特殊数码效果)控制 16'h5580~16'h558b
            8'd183: i2c_data <= {16'h5580,8'h06};
            8'd184: i2c_data <= {16'h5583,8'h40};
            8'd185: i2c_data <= {16'h5584,8'h10};
            8'd186: i2c_data <= {16'h5589,8'h10};
            8'd187: i2c_data <= {16'h558a,8'h00};
            8'd188: i2c_data <= {16'h558b,8'hf8};
            8'd189: i2c_data <= {16'h501d,8'h40}; //ISP MISC
            //CIP(颜色插值)控制 (16'h5300~16'h530c)
            8'd190: i2c_data <= {16'h5300,8'h08};
            8'd191: i2c_data <= {16'h5301,8'h30};
            8'd192: i2c_data <= {16'h5302,8'h10};
            8'd193: i2c_data <= {16'h5303,8'h00};
            8'd194: i2c_data <= {16'h5304,8'h08};
            8'd195: i2c_data <= {16'h5305,8'h30};
            8'd196: i2c_data <= {16'h5306,8'h08};
            8'd197: i2c_data <= {16'h5307,8'h16};
            8'd198: i2c_data <= {16'h5309,8'h08};
            8'd199: i2c_data <= {16'h530a,8'h30};
            8'd200: i2c_data <= {16'h530b,8'h04};
            8'd201: i2c_data <= {16'h530c,8'h06};
            8'd202: i2c_data <= {16'h5025,8'h00};
            //系统时钟分频 Bit[7:4]:系统时钟分频 input clock =24Mhz, PCLK = 48Mhz
            8'd203: i2c_data <= {16'h3035,8'h11}; 
            8'd204: i2c_data <= {16'h3036,8'h3c}; //PLL倍频
            8'd205: i2c_data <= {16'h3c07,8'h08};
            //时序控制 16'h3800~16'h3821
            8'd206: i2c_data <= {16'h3820,8'h46};
            8'd207: i2c_data <= {16'h3821,8'h01};
            8'd208: i2c_data <= {16'h3814,8'h31};
            8'd209: i2c_data <= {16'h3815,8'h31};
            8'd210: i2c_data <= {16'h3800,8'h00};
            8'd211: i2c_data <= {16'h3801,8'h00};
            8'd212: i2c_data <= {16'h3802,8'h00};
            8'd213: i2c_data <= {16'h3803,8'h04};
            8'd214: i2c_data <= {16'h3804,8'h0a};
            8'd215: i2c_data <= {16'h3805,8'h3f};
            8'd216: i2c_data <= {16'h3806,8'h07};
            8'd217: i2c_data <= {16'h3807,8'h9b};

            //设置输出像素个数
            //DVP 输出水平像素点数高4位
            8'd218: i2c_data <= {16'h3808,{4'd0,CMOS_H_PIXEL[11:8]}};
            //DVP 输出水平像素点数低8位
            8'd219: i2c_data <= {16'h3809,CMOS_H_PIXEL[7:0]};
            //DVP 输出垂直像素点数高3位
            8'd220: i2c_data <= {16'h380a,{5'd0,CMOS_V_PIXEL[10:8]}};
            //DVP 输出垂直像素点数低8位
            8'd221: i2c_data <= {16'h380b,CMOS_V_PIXEL[7:0]};
            //水平总像素大小高5位
            8'd222: i2c_data <= {16'h380c,{3'd0,TOTAL_H_PIXEL[12:8]}};
            //水平总像素大小低8位 
            8'd223: i2c_data <= {16'h380d,TOTAL_H_PIXEL[7:0]};
            //垂直总像素大小高5位 
            8'd224: i2c_data <= {16'h380e,{3'd0,TOTAL_V_PIXEL[12:8]}};
            //垂直总像素大小低8位     
            8'd225: i2c_data <= {16'h380f,TOTAL_V_PIXEL[7:0]};

            8'd226: i2c_data <= {16'h3813,8'h06};
            8'd227: i2c_data <= {16'h3618,8'h00};
            8'd228: i2c_data <= {16'h3612,8'h29};
            8'd229: i2c_data <= {16'h3709,8'h52};
            8'd230: i2c_data <= {16'h370c,8'h03};
            8'd231: i2c_data <= {16'h3a02,8'h17}; //60Hz max exposure
            8'd232: i2c_data <= {16'h3a03,8'h10}; //60Hz max exposure
            8'd233: i2c_data <= {16'h3a14,8'h17}; //50Hz max exposure
            8'd234: i2c_data <= {16'h3a15,8'h10}; //50Hz max exposure
            8'd235: i2c_data <= {16'h4004,8'h02}; //BLC(背光) 2 lines
            8'd236: i2c_data <= {16'h4713,8'h03}; //JPEG mode 3
            8'd237: i2c_data <= {16'h4407,8'h04}; //量化标度
            8'd238: i2c_data <= {16'h460c,8'h22};     
            8'd239: i2c_data <= {16'h4837,8'h22}; //DVP CLK divider
            8'd240: i2c_data <= {16'h3824,8'h02}; //DVP CLK divider
            8'd241: i2c_data <= {16'h5001,8'ha3}; //ISP 控制
            8'd242: i2c_data <= {16'h3b07,8'h0a}; //帧曝光模式  
            //彩条测试使能 
            8'd243: i2c_data <= {16'h503d,8'h00}; //8'h00:正常模式 8'h80:彩条显示
            //测试闪光灯功能
            8'd244: i2c_data <= {16'h3016,8'h02};
            8'd245: i2c_data <= {16'h301c,8'h02};
            8'd246: i2c_data <= {16'h3019,8'h02}; //打开闪光灯
            8'd247: i2c_data <= {16'h3019,8'h00}; //关闭闪光灯
            //只读存储器,防止在case中没有列举的情况,之前的寄存器被重复改写
            default : i2c_data <= {16'h300a,8'h00}; //器件ID高8位
        endcase
    end
end

endmodule

IIc-Modul:

module i2c_dri
    #(// slave address(器件地址),放此处方便参数传递
      parameter   SLAVE_ADDR =  7'b1010000   ,
      parameter   CLK_FREQ   = 26'd50_000_000,   // i2c_dri模块的驱动时钟频率(CLK_FREQ)
      parameter   I2C_FREQ   = 18'd250_000       // I2C的SCL时钟频率
     )(
          //global clock
          input                clk        ,      // i2c_dri模块的驱动时钟(CLK_FREQ)
          input                rst_n      ,      // 复位信号

          //i2c interface
          input                i2c_exec   ,      // I2C触发执行信号
          input                bit_ctrl   ,      // 字地址位控制(16b/8b)
          input                i2c_rh_wl  ,      // I2C读写控制信号
          input        [15:0]  i2c_addr   ,      // I2C器件内地址
          input        [ 7:0]  i2c_data_w ,      // I2C要写的数据
          output  reg  [ 7:0]  i2c_data_r ,      // I2C读出的数据
          output  reg          i2c_done   ,      // I2C一次操作完成
          output  reg          scl        ,      // I2C的SCL时钟信号
          inout                sda        ,      // I2C的SDA信号

          //user interface
          output  reg          dri_clk           // 驱动I2C操作的驱动时钟
     );

//localparam define
localparam  st_idle     = 8'b0000_0001;          // 空闲状态
localparam  st_sladdr   = 8'b0000_0010;          // 发送器件地址(slave address)
localparam  st_addr16   = 8'b0000_0100;          // 发送16位字地址
localparam  st_addr8    = 8'b0000_1000;          // 发送8位字地址
localparam  st_data_wr  = 8'b0001_0000;          // 写数据(8 bit)
localparam  st_addr_rd  = 8'b0010_0000;          // 发送器件地址读
localparam  st_data_rd  = 8'b0100_0000;          // 读数据(8 bit)
localparam  st_stop     = 8'b1000_0000;          // 结束I2C操作

//reg define
reg            sda_dir     ;                     // I2C数据(SDA)方向控制
reg            sda_out     ;                     // SDA输出信号
reg            st_done     ;                     // 状态结束
reg            wr_flag     ;                     // 写标志
reg    [ 6:0]  cnt         ;                     // 计数
reg    [ 7:0]  cur_state   ;                     // 状态机当前状态
reg    [ 7:0]  next_state  ;                     // 状态机下一状态
reg    [15:0]  addr_t      ;                     // 地址
reg    [ 7:0]  data_r      ;                     // 读取的数据
reg    [ 7:0]  data_wr_t   ;                     // I2C需写的数据的临时寄存
reg    [ 9:0]  clk_cnt     ;                     // 分频时钟计数

//wire define
wire          sda_in      ;                      // SDA输入信号
wire   [8:0]  clk_divide  ;                      // 模块驱动时钟的分频系数

//*****************************************************
//**                    main code
//*****************************************************

//SDA控制
assign  sda     = sda_dir ?  sda_out : 1'bz;     // SDA数据输出或高阻
assign  sda_in  = sda ;                          // SDA数据输入
assign  clk_divide = (CLK_FREQ/I2C_FREQ) >> 3;   // 模块驱动时钟的分频系数

//生成I2C的SCL的四倍频率的驱动时钟用于驱动i2c的操作
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        dri_clk <=  1'b1;
        clk_cnt <= 10'd0;
    end
    else if(clk_cnt == clk_divide - 1'd1) begin
        clk_cnt <= 10'd0;
        dri_clk <= ~dri_clk;
    end
    else
        clk_cnt <= clk_cnt + 1'b1;
end

//(三段式状态机)同步时序描述状态转移
always @(posedge dri_clk or negedge rst_n) begin
    if(!rst_n)
        cur_state <= st_idle;
    else
        cur_state <= next_state;
end

//组合逻辑判断状态转移条件
always @( * ) begin
//    next_state = st_idle;
    case(cur_state)
        st_idle: begin                           // 空闲状态
           if(i2c_exec) begin
               next_state = st_sladdr;
           end
           else
               next_state = st_idle;
        end
        st_sladdr: begin
            if(st_done) begin
                if(bit_ctrl)                     // 判断是16位还是8位字地址
                   next_state = st_addr16;
                else
                   next_state = st_addr8 ;
            end
            else
                next_state = st_sladdr;
        end
        st_addr16: begin                         // 写16位字地址
            if(st_done) begin
                next_state = st_addr8;
            end
            else begin
                next_state = st_addr16;
            end
        end
        st_addr8: begin                          // 8位字地址
            if(st_done) begin
                if(wr_flag==1'b0)                // 读写判断
                    next_state = st_data_wr;
                else
                    next_state = st_addr_rd;
            end
            else begin
                next_state = st_addr8;
            end
        end
        st_data_wr: begin                        // 写数据(8 bit)
            if(st_done)
                next_state = st_stop;
            else
                next_state = st_data_wr;
        end
        st_addr_rd: begin                        // 写地址以进行读数据
            if(st_done) begin
                next_state = st_data_rd;
            end
            else begin
                next_state = st_addr_rd;
            end
        end
        st_data_rd: begin                        // 读取数据(8 bit)
            if(st_done)
                next_state = st_stop;
            else
                next_state = st_data_rd;
        end
        st_stop: begin                           // 结束I2C操作
            if(st_done)
                next_state = st_idle;
            else
                next_state = st_stop ;
        end
        default: next_state= st_idle;
    endcase
end

//时序电路描述状态输出
always @(posedge dri_clk or negedge rst_n) begin
    //复位初始化
    if(!rst_n) begin
        scl        <= 1'b1;
        sda_out    <= 1'b1;
        sda_dir    <= 1'b1;
        i2c_done   <= 1'b0;
        cnt        <= 1'b0;
        st_done    <= 1'b0;
        data_r     <= 1'b0;
        i2c_data_r <= 1'b0;
        wr_flag    <= 1'b0;
        addr_t     <= 1'b0;
        data_wr_t  <= 1'b0;
    end
    else begin
        st_done <= 1'b0 ;
        cnt     <= cnt +1'b1 ;
        case(cur_state)
             st_idle: begin                            // 空闲状态
                scl     <= 1'b1;
                sda_out <= 1'b1;
                sda_dir <= 1'b1;
                i2c_done<= 1'b0;
                cnt     <= 7'b0;
                if(i2c_exec) begin
                    wr_flag   <= i2c_rh_wl ;
                    addr_t    <= i2c_addr  ;
                    data_wr_t <= i2c_data_w;
                end
            end
            st_sladdr: begin                           // 写地址(器件地址和字地址)
                case(cnt)
                    7'd1 : sda_out <= 1'b0;            // 开始I2C
                    7'd3 : scl <= 1'b0;
                    7'd4 : sda_out <= SLAVE_ADDR[6];   // 传送器件地址
                    7'd5 : scl <= 1'b1;
                    7'd7 : scl <= 1'b0;
                    7'd8 : sda_out <= SLAVE_ADDR[5];
                    7'd9 : scl <= 1'b1;
                    7'd11: scl <= 1'b0;
                    7'd12: sda_out <= SLAVE_ADDR[4];
                    7'd13: scl <= 1'b1;
                    7'd15: scl <= 1'b0;
                    7'd16: sda_out <= SLAVE_ADDR[3];
                    7'd17: scl <= 1'b1;
                    7'd19: scl <= 1'b0;
                    7'd20: sda_out <= SLAVE_ADDR[2];
                    7'd21: scl <= 1'b1;
                    7'd23: scl <= 1'b0;
                    7'd24: sda_out <= SLAVE_ADDR[1];
                    7'd25: scl <= 1'b1;
                    7'd27: scl <= 1'b0;
                    7'd28: sda_out <= SLAVE_ADDR[0];
                    7'd29: scl <= 1'b1;
                    7'd31: scl <= 1'b0;
                    7'd32: sda_out <= 1'b0;            // 0:写
                    7'd33: scl <= 1'b1;
                    7'd35: scl <= 1'b0;
                    7'd36: begin
                        sda_dir <= 1'b0;               // 从机应答
                        sda_out <= 1'b1;
                    end
                    7'd37: scl     <= 1'b1;
                    7'd38: st_done <= 1'b1;
                    7'd39: begin
                        scl <= 1'b0;
                        cnt <= 1'b0;
                    end
                    default :  ;
                endcase
            end
            st_addr16: begin
                case(cnt)
                    7'd0 : begin
                        sda_dir <= 1'b1 ;
                        sda_out <= addr_t[15];         // 传送字地址
                    end
                    7'd1 : scl <= 1'b1;
                    7'd3 : scl <= 1'b0;
                    7'd4 : sda_out <= addr_t[14];
                    7'd5 : scl <= 1'b1;
                    7'd7 : scl <= 1'b0;
                    7'd8 : sda_out <= addr_t[13];
                    7'd9 : scl <= 1'b1;
                    7'd11: scl <= 1'b0;
                    7'd12: sda_out <= addr_t[12];
                    7'd13: scl <= 1'b1;
                    7'd15: scl <= 1'b0;
                    7'd16: sda_out <= addr_t[11];
                    7'd17: scl <= 1'b1;
                    7'd19: scl <= 1'b0;
                    7'd20: sda_out <= addr_t[10];
                    7'd21: scl <= 1'b1;
                    7'd23: scl <= 1'b0;
                    7'd24: sda_out <= addr_t[9];
                    7'd25: scl <= 1'b1;
                    7'd27: scl <= 1'b0;
                    7'd28: sda_out <= addr_t[8];
                    7'd29: scl <= 1'b1;
                    7'd31: scl <= 1'b0;
                    7'd32: begin
                        sda_dir <= 1'b0;               // 从机应答
                        sda_out <= 1'b1;
                    end
                    7'd33: scl     <= 1'b1;
                    7'd34: st_done <= 1'b1;
                    7'd35: begin
                        scl <= 1'b0;
                        cnt <= 1'b0;
                    end
                    default :  ;
                endcase
            end
            st_addr8: begin
                case(cnt)
                    7'd0: begin
                       sda_dir <= 1'b1 ;
                       sda_out <= addr_t[7];           // 字地址
                    end
                    7'd1 : scl <= 1'b1;
                    7'd3 : scl <= 1'b0;
                    7'd4 : sda_out <= addr_t[6];
                    7'd5 : scl <= 1'b1;
                    7'd7 : scl <= 1'b0;
                    7'd8 : sda_out <= addr_t[5];
                    7'd9 : scl <= 1'b1;
                    7'd11: scl <= 1'b0;
                    7'd12: sda_out <= addr_t[4];
                    7'd13: scl <= 1'b1;
                    7'd15: scl <= 1'b0;
                    7'd16: sda_out <= addr_t[3];
                    7'd17: scl <= 1'b1;
                    7'd19: scl <= 1'b0;
                    7'd20: sda_out <= addr_t[2];
                    7'd21: scl <= 1'b1;
                    7'd23: scl <= 1'b0;
                    7'd24: sda_out <= addr_t[1];
                    7'd25: scl <= 1'b1;
                    7'd27: scl <= 1'b0;
                    7'd28: sda_out <= addr_t[0];
                    7'd29: scl <= 1'b1;
                    7'd31: scl <= 1'b0;
                    7'd32: begin
                        sda_dir <= 1'b0;               // 从机应答
                        sda_out <= 1'b1;
                    end
                    7'd33: scl     <= 1'b1;
                    7'd34: st_done <= 1'b1;
                    7'd35: begin
                        scl <= 1'b0;
                        cnt <= 1'b0;
                    end
                    default :  ;
                endcase
            end
            st_data_wr: begin                          // 写数据(8 bit)
                case(cnt)
                    7'd0: begin
                        sda_out <= data_wr_t[7];       // I2C写8位数据
                        sda_dir <= 1'b1;
                    end
                    7'd1 : scl <= 1'b1;
                    7'd3 : scl <= 1'b0;
                    7'd4 : sda_out <= data_wr_t[6];
                    7'd5 : scl <= 1'b1;
                    7'd7 : scl <= 1'b0;
                    7'd8 : sda_out <= data_wr_t[5];
                    7'd9 : scl <= 1'b1;
                    7'd11: scl <= 1'b0;
                    7'd12: sda_out <= data_wr_t[4];
                    7'd13: scl <= 1'b1;
                    7'd15: scl <= 1'b0;
                    7'd16: sda_out <= data_wr_t[3];
                    7'd17: scl <= 1'b1;
                    7'd19: scl <= 1'b0;
                    7'd20: sda_out <= data_wr_t[2];
                    7'd21: scl <= 1'b1;
                    7'd23: scl <= 1'b0;
                    7'd24: sda_out <= data_wr_t[1];
                    7'd25: scl <= 1'b1;
                    7'd27: scl <= 1'b0;
                    7'd28: sda_out <= data_wr_t[0];
                    7'd29: scl <= 1'b1;
                    7'd31: scl <= 1'b0;
                    7'd32: begin
                        sda_dir <= 1'b0;               // 从机应答
                        sda_out <= 1'b1;
                    end
                    7'd33: scl <= 1'b1;
                    7'd34: st_done <= 1'b1;
                    7'd35: begin
                        scl  <= 1'b0;
                        cnt  <= 1'b0;
                    end
                    default  :  ;
                endcase
            end
            st_addr_rd: begin                          // 写地址以进行读数据
                case(cnt)
                    7'd0 : begin
                        sda_dir <= 1'b1;
                        sda_out <= 1'b1;
                    end
                    7'd1 : scl <= 1'b1;
                    7'd2 : sda_out <= 1'b0;            // 重新开始
                    7'd3 : scl <= 1'b0;
                    7'd4 : sda_out <= SLAVE_ADDR[6];   // 传送器件地址
                    7'd5 : scl <= 1'b1;
                    7'd7 : scl <= 1'b0;
                    7'd8 : sda_out <= SLAVE_ADDR[5];
                    7'd9 : scl <= 1'b1;
                    7'd11: scl <= 1'b0;
                    7'd12: sda_out <= SLAVE_ADDR[4];
                    7'd13: scl <= 1'b1;
                    7'd15: scl <= 1'b0;
                    7'd16: sda_out <= SLAVE_ADDR[3];
                    7'd17: scl <= 1'b1;
                    7'd19: scl <= 1'b0;
                    7'd20: sda_out <= SLAVE_ADDR[2];
                    7'd21: scl <= 1'b1;
                    7'd23: scl <= 1'b0;
                    7'd24: sda_out <= SLAVE_ADDR[1];
                    7'd25: scl <= 1'b1;
                    7'd27: scl <= 1'b0;
                    7'd28: sda_out <= SLAVE_ADDR[0];
                    7'd29: scl <= 1'b1;
                    7'd31: scl <= 1'b0;
                    7'd32: sda_out <= 1'b1;            // 1:读
                    7'd33: scl <= 1'b1;
                    7'd35: scl <= 1'b0;
                    7'd36: begin
                        sda_dir <= 1'b0;               // 从机应答
                        sda_out <= 1'b1;
                    end
                    7'd37: scl     <= 1'b1;
                    7'd38: st_done <= 1'b1;
                    7'd39: begin
                        scl <= 1'b0;
                        cnt <= 1'b0;
                    end
                    default : ;
                endcase
            end
            st_data_rd: begin                          // 读取数据(8 bit)
                case(cnt)
                    7'd0: sda_dir <= 1'b0;
                    7'd1: begin
                        data_r[7] <= sda_in;
                        scl       <= 1'b1;
                    end
                    7'd3: scl  <= 1'b0;
                    7'd5: begin
                        data_r[6] <= sda_in ;
                        scl       <= 1'b1   ;
                    end
                    7'd7: scl  <= 1'b0;
                    7'd9: begin
                        data_r[5] <= sda_in;
                        scl       <= 1'b1  ;
                    end
                    7'd11: scl  <= 1'b0;
                    7'd13: begin
                        data_r[4] <= sda_in;
                        scl       <= 1'b1  ;
                    end
                    7'd15: scl  <= 1'b0;
                    7'd17: begin
                        data_r[3] <= sda_in;
                        scl       <= 1'b1  ;
                    end
                    7'd19: scl  <= 1'b0;
                    7'd21: begin
                        data_r[2] <= sda_in;
                        scl       <= 1'b1  ;
                    end
                    7'd23: scl  <= 1'b0;
                    7'd25: begin
                        data_r[1] <= sda_in;
                        scl       <= 1'b1  ;
                    end
                    7'd27: scl  <= 1'b0;
                    7'd29: begin
                        data_r[0] <= sda_in;
                        scl       <= 1'b1  ;
                    end
                    7'd31: scl  <= 1'b0;
                    7'd32: begin
                        sda_dir <= 1'b1;              // 非应答
                        sda_out <= 1'b1;
                    end
                    7'd33: scl     <= 1'b1;
                    7'd34: st_done <= 1'b1;
                    7'd35: begin
                        scl <= 1'b0;
                        cnt <= 1'b0;
                        i2c_data_r <= data_r;
                    end
                    default  :  ;
                endcase
            end
            st_stop: begin                            // 结束I2C操作
                case(cnt)
                    7'd0: begin
                        sda_dir <= 1'b1;              // 结束I2C
                        sda_out <= 1'b0;
                    end
                    7'd1 : scl     <= 1'b1;
                    7'd3 : sda_out <= 1'b1;
                    7'd15: st_done <= 1'b1;
                    7'd16: begin
                        cnt      <= 1'b0;
                        i2c_done <= 1'b1;             // 向上层模块传递I2C结束信号
                    end
                    default  : ;
                endcase
            end
        endcase
    end
end

endmodule

SDRAM-Modul:

Insgesamt 9 Dateien: drei oberste Schichten, zwei FIFOs, drei Statussteuerbefehle und ein Parameter

TOP-Modul

module  sdram_top(
    input         ref_clk,                  //sdram 控制器参考时钟
    input         out_clk,                  //用于输出的相位偏移时钟
    input         rst_n,                    //系统复位
    
    //用户写端口         
    input         wr_clk,                   //写端口FIFO: 写时钟
    input         wr_en,                    //写端口FIFO: 写使能
    input  [15:0] wr_data,                  //写端口FIFO: 写数据
    input  [23:0] wr_min_addr,              //写SDRAM的起始地址
    input  [23:0] wr_max_addr,              //写SDRAM的结束地址
    input  [ 9:0] wr_len,                   //写SDRAM时的数据突发长度
    input         wr_load,                  //写端口复位: 复位写地址,清空写FIFO
    
    //用户读端口
    input         rd_clk,                   //读端口FIFO: 读时钟
    input         rd_en,                    //读端口FIFO: 读使能
    output [15:0] rd_data,                  //读端口FIFO: 读数据
    input  [23:0] rd_min_addr,              //读SDRAM的起始地址
    input  [23:0] rd_max_addr,              //读SDRAM的结束地址
    input  [ 9:0] rd_len,                   //从SDRAM中读数据时的突发长度
    input         rd_load,                  //读端口复位: 复位读地址,清空读FIFO
    
    //用户控制端口  
    input         sdram_read_valid,         //SDRAM 读使能
    input         sdram_pingpang_en,        //SDRAM 乒乓操作使能
    output        sdram_init_done,          //SDRAM 初始化完成标志
    
    //SDRAM 芯片接口
    output        sdram_clk,                //SDRAM 芯片时钟
    output        sdram_cke,                //SDRAM 时钟有效
    output        sdram_cs_n,               //SDRAM 片选
    output        sdram_ras_n,              //SDRAM 行有效
    output        sdram_cas_n,              //SDRAM 列有效
    output        sdram_we_n,               //SDRAM 写有效
    output [ 1:0] sdram_ba,                 //SDRAM Bank地址
    output [12:0] sdram_addr,               //SDRAM 行/列地址
    inout  [15:0] sdram_data,               //SDRAM 数据
    output [ 1:0] sdram_dqm                 //SDRAM 数据掩码
    );

//wire define
wire        sdram_wr_req;                   //sdram 写请求
wire        sdram_wr_ack;                   //sdram 写响应
wire [23:0] sdram_wr_addr;                  //sdram 写地址
wire [15:0] sdram_din;                      //写入sdram中的数据

wire        sdram_rd_req;                   //sdram 读请求
wire        sdram_rd_ack;                   //sdram 读响应
wire [23:0] sdram_rd_addr;                   //sdram 读地址
wire [15:0] sdram_dout;                     //从sdram中读出的数据

//*****************************************************
//**                    main code
//***************************************************** 
assign  sdram_clk = out_clk;                //将相位偏移时钟输出给sdram芯片
assign  sdram_dqm = 2'b00;                  //读写过程中均不屏蔽数据线
            
//SDRAM 读写端口FIFO控制模块
sdram_fifo_ctrl u_sdram_fifo_ctrl(
    .clk_ref            (ref_clk),          //SDRAM控制器时钟
    .rst_n              (rst_n),            //系统复位

    //用户写端口
    .clk_write          (wr_clk),           //写端口FIFO: 写时钟
    .wrf_wrreq          (wr_en),            //写端口FIFO: 写请求
    .wrf_din            (wr_data),          //写端口FIFO: 写数据  
    .wr_min_addr        (wr_min_addr),      //写SDRAM的起始地址
    .wr_max_addr        (wr_max_addr),      //写SDRAM的结束地址
    .wr_length          (wr_len),           //写SDRAM时的数据突发长度
    .wr_load            (wr_load),          //写端口复位: 复位写地址,清空写FIFO    
    
    //用户读端口                                                 
    .clk_read           (rd_clk),           //读端口FIFO: 读时钟
    .rdf_rdreq          (rd_en),            //读端口FIFO: 读请求
    .rdf_dout           (rd_data),          //读端口FIFO: 读数据
    .rd_min_addr        (rd_min_addr),      //读SDRAM的起始地址
    .rd_max_addr        (rd_max_addr),      //读SDRAM的结束地址
    .rd_length          (rd_len),           //从SDRAM中读数据时的突发长度
    .rd_load            (rd_load),          //读端口复位: 复位读地址,清空读FIFO
   
    //用户控制端口    
    .sdram_read_valid   (sdram_read_valid), //sdram 读使能
    .sdram_init_done    (sdram_init_done),  //sdram 初始化完成标志
    .sdram_pingpang_en  (sdram_pingpang_en),//sdram 乒乓操作使能
    
    //SDRAM 控制器写端口
    .sdram_wr_req       (sdram_wr_req),     //sdram 写请求
    .sdram_wr_ack       (sdram_wr_ack),     //sdram 写响应
    .sdram_wr_addr      (sdram_wr_addr),    //sdram 写地址
    .sdram_din          (sdram_din),        //写入sdram中的数据
    
    //SDRAM 控制器读端口
    .sdram_rd_req       (sdram_rd_req),     //sdram 读请求
    .sdram_rd_ack       (sdram_rd_ack),     //sdram 读响应
    .sdram_rd_addr      (sdram_rd_addr),    //sdram 读地址
    .sdram_dout         (sdram_dout)        //从sdram中读出的数据
    );

//SDRAM控制器
sdram_controller u_sdram_controller(
    .clk                (ref_clk),          //sdram 控制器时钟
    .rst_n              (rst_n),            //系统复位
    
    //SDRAM 控制器写端口  
    .sdram_wr_req       (sdram_wr_req),     //sdram 写请求
    .sdram_wr_ack       (sdram_wr_ack),     //sdram 写响应
    .sdram_wr_addr      (sdram_wr_addr),    //sdram 写地址
    .sdram_wr_burst     (wr_len),           //写sdram时数据突发长度
    .sdram_din          (sdram_din),        //写入sdram中的数据
    
    //SDRAM 控制器读端口
    .sdram_rd_req       (sdram_rd_req),     //sdram 读请求
    .sdram_rd_ack       (sdram_rd_ack),     //sdram 读响应
    .sdram_rd_addr      (sdram_rd_addr),    //sdram 读地址
    .sdram_rd_burst     (rd_len),           //读sdram时数据突发长度
    .sdram_dout         (sdram_dout),       //从sdram中读出的数据
    
    .sdram_init_done    (sdram_init_done),  //sdram 初始化完成标志

    //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_data         (sdram_data)        //SDRAM 数据  
    );
    
endmodule 

FIFO-Steuermodul:

module sdram_fifo_ctrl(
    input             clk_ref,           //SDRAM控制器时钟
    input             rst_n,             //系统复位 
                                         
    //用户写端口                         
    input             clk_write,         //写端口FIFO: 写时钟 
    input             wrf_wrreq,         //写端口FIFO: 写请求 
    input      [15:0] wrf_din,           //写端口FIFO: 写数据 
    input      [23:0] wr_min_addr,       //写SDRAM的起始地址
    input      [23:0] wr_max_addr,       //写SDRAM的结束地址
    input      [ 9:0] wr_length,         //写SDRAM时的数据突发长度 
    input             wr_load,           //写端口复位: 复位写地址,清空写FIFO 
                                         
    //用户读端口                         
    input             clk_read,          //读端口FIFO: 读时钟
    input             rdf_rdreq,         //读端口FIFO: 读请求 
    output     [15:0] rdf_dout,          //读端口FIFO: 读数据
    input      [23:0] rd_min_addr,       //读SDRAM的起始地址
    input      [23:0] rd_max_addr,       //读SDRAM的结束地址
    input      [ 9:0] rd_length,         //从SDRAM中读数据时的突发长度 
    input             rd_load,           //读端口复位: 复位读地址,清空读FIFO
                                         
    //用户控制端口                         
    input             sdram_read_valid,  //SDRAM 读使能
    input             sdram_init_done,   //SDRAM 初始化完成标志
    input             sdram_pingpang_en, //SDRAM 乒乓操作使能
                                         
    //SDRAM 控制器写端口                 
    output reg        sdram_wr_req,      //sdram 写请求
    input             sdram_wr_ack,      //sdram 写响应
    output reg [23:0] sdram_wr_addr,     //sdram 写地址
    output     [15:0] sdram_din,         //写入SDRAM中的数据 
                                         
    //SDRAM 控制器读端口                 
    output reg        sdram_rd_req,      //sdram 读请求
    input             sdram_rd_ack,      //sdram 读响应
    output reg [23:0] sdram_rd_addr,     //sdram 读地址 
    input      [15:0] sdram_dout         //从SDRAM中读出的数据 
    );

//reg define
reg        wr_ack_r1;                    //sdram写响应寄存器      
reg        wr_ack_r2;                    
reg        rd_ack_r1;                    //sdram读响应寄存器      
reg        rd_ack_r2;                    
reg        wr_load_r1;                   //写端口复位寄存器      
reg        wr_load_r2;                   
reg        rd_load_r1;                   //读端口复位寄存器      
reg        rd_load_r2;                   
reg        read_valid_r1;                //sdram读使能寄存器      
reg        read_valid_r2;                
reg        sw_bank_en;                   //切换BANK使能信号
reg        rw_bank_flag;                 //读写bank的标志
                                         
//wire define                            
wire       write_done_flag;              //sdram_wr_ack 下降沿标志位      
wire       read_done_flag;               //sdram_rd_ack 下降沿标志位      
wire       wr_load_flag;                 //wr_load      上升沿标志位      
wire       rd_load_flag;                 //rd_load      上升沿标志位      
wire [9:0] wrf_use;                      //写端口FIFO中的数据量
wire [9:0] rdf_use;                      //读端口FIFO中的数据量

//*****************************************************
//**                    main code
//***************************************************** 

//检测下降沿
assign write_done_flag = wr_ack_r2   & ~wr_ack_r1;  
assign read_done_flag  = rd_ack_r2   & ~rd_ack_r1;

//检测上升沿
assign wr_load_flag    = ~wr_load_r2 & wr_load_r1;
assign rd_load_flag    = ~rd_load_r2 & rd_load_r1;

//寄存sdram写响应信号,用于捕获sdram_wr_ack下降沿
always @(posedge clk_ref or negedge rst_n) begin
    if(!rst_n) begin
        wr_ack_r1 <= 1'b0;
        wr_ack_r2 <= 1'b0;
    end
    else begin
        wr_ack_r1 <= sdram_wr_ack;
        wr_ack_r2 <= wr_ack_r1;     
    end
end 

//寄存sdram读响应信号,用于捕获sdram_rd_ack下降沿
always @(posedge clk_ref or negedge rst_n) begin
    if(!rst_n) begin
        rd_ack_r1 <= 1'b0;
        rd_ack_r2 <= 1'b0;
    end
    else begin
        rd_ack_r1 <= sdram_rd_ack;
        rd_ack_r2 <= rd_ack_r1;
    end
end 

//同步写端口复位信号,用于捕获wr_load上升沿
always @(posedge clk_ref or negedge rst_n) begin
    if(!rst_n) begin
        wr_load_r1 <= 1'b0;
        wr_load_r2 <= 1'b0;
    end
    else begin
        wr_load_r1 <= wr_load;
        wr_load_r2 <= wr_load_r1;
    end
end

//同步读端口复位信号,同时用于捕获rd_load上升沿
always @(posedge clk_ref or negedge rst_n) begin
    if(!rst_n) begin
        rd_load_r1 <= 1'b0;
        rd_load_r2 <= 1'b0;
    end
    else begin
        rd_load_r1 <= rd_load;
        rd_load_r2 <= rd_load_r1;
    end
end

//同步sdram读使能信号
always @(posedge clk_ref or negedge rst_n) begin
    if(!rst_n) begin
        read_valid_r1 <= 1'b0;
        read_valid_r2 <= 1'b0;
    end
    else begin
        read_valid_r1 <= sdram_read_valid;
        read_valid_r2 <= read_valid_r1;
    end
end

//sdram写地址产生模块
always @(posedge clk_ref or negedge rst_n) begin
    if (!rst_n) begin
        sdram_wr_addr <= 24'd0;
        sw_bank_en <= 1'b0;
        rw_bank_flag <= 1'b0;
    end
    else if(wr_load_flag) begin              //检测到写端口复位信号时,写地址复位
        sdram_wr_addr <= wr_min_addr;   
        sw_bank_en <= 1'b0;
        rw_bank_flag <= 1'b0;
    end
    else if(write_done_flag) begin           //若突发写SDRAM结束,更改写地址
                                             //若未到达写SDRAM的结束地址,则写地址累加
        if(sdram_pingpang_en) begin          //SDRAM 读写乒乓使能
            if(sdram_wr_addr[22:0] < wr_max_addr - wr_length)
                sdram_wr_addr <= sdram_wr_addr + wr_length;
            else begin                       //切换BANK
                rw_bank_flag <= ~rw_bank_flag;   
                sw_bank_en <= 1'b1;          //拉高切换BANK使能信号
            end            
        end       
                                             //若突发写SDRAM结束,更改写地址
        else if(sdram_wr_addr < wr_max_addr - wr_length)
            sdram_wr_addr <= sdram_wr_addr + wr_length;
        else                                 //到达写SDRAM的结束地址,回到写起始地址
            sdram_wr_addr <= wr_min_addr;
    end
    else if(sw_bank_en) begin                //到达写SDRAM的结束地址,回到写起始地址
        sw_bank_en <= 1'b0;
        if(rw_bank_flag == 1'b0)             //切换BANK
            sdram_wr_addr <= {1'b0,wr_min_addr[22:0]};
        else
            sdram_wr_addr <= {1'b1,wr_min_addr[22:0]};     
    end
end

//sdram读地址产生模块
always @(posedge clk_ref or negedge rst_n) begin
    if(!rst_n) begin
        sdram_rd_addr <= 24'd0;
    end 
    else if(rd_load_flag)                    //检测到读端口复位信号时,读地址复位
        sdram_rd_addr <= rd_min_addr;
    else if(read_done_flag) begin            //突发读SDRAM结束,更改读地址
                                             //若未到达读SDRAM的结束地址,则读地址累加                 
        if(sdram_pingpang_en) begin          //SDRAM 读写乒乓使能  
            if(sdram_rd_addr[22:0] < rd_max_addr - rd_length)
                sdram_rd_addr <= sdram_rd_addr + rd_length;
            else begin                       //到达读SDRAM的结束地址,回到读起始地址
                                             //读取没有在写数据的bank地址
                if(rw_bank_flag == 1'b0)     //根据rw_bank_flag的值切换读BANK地址
                    sdram_rd_addr <= {1'b1,rd_min_addr[22:0]};
                else
                    sdram_rd_addr <= {1'b0,rd_min_addr[22:0]};    
            end    
        end
                                             //若突发写SDRAM结束,更改写地址
        else if(sdram_rd_addr < rd_max_addr - rd_length)  
            sdram_rd_addr <= sdram_rd_addr + rd_length;
        else                                 //到达写SDRAM的结束地址,回到写起始地址
            sdram_rd_addr <= rd_min_addr;
    end
end

//sdram 读写请求信号产生模块
always@(posedge clk_ref or negedge rst_n) begin
    if(!rst_n) begin
        sdram_wr_req <= 0;
        sdram_rd_req <= 0;
    end
    else if(sdram_init_done) begin       //SDRAM初始化完成后才能响应读写请求
                                         //优先执行写操作,防止写入SDRAM中的数据丢失
        if(wrf_use >= wr_length) begin   //若写端口FIFO中的数据量达到了写突发长度
            sdram_wr_req <= 1;           //发出写sdarm请求
            sdram_rd_req <= 0;           
        end
        else if((rdf_use < rd_length)    //若读端口FIFO中的数据量小于读突发长度,
                 && read_valid_r2) begin //同时sdram读使能信号为高
            sdram_wr_req <= 0;           
            sdram_rd_req <= 1;           //发出读sdarm请求
        end
        else begin
            sdram_wr_req <= 0;
            sdram_rd_req <= 0;
        end
    end
    else begin
        sdram_wr_req <= 0;
        sdram_rd_req <= 0;
    end
end

//例化写端口FIFO
wrfifo  u_wrfifo(
    //用户接口
    .wrclk      (clk_write),             //写时钟
    .wrreq      (wrf_wrreq),             //写请求
    .data       (wrf_din),               //写数据
    
    //sdram接口
    .rdclk      (clk_ref),               //读时钟
    .rdreq      (sdram_wr_ack),          //读请求
    .q          (sdram_din),             //读数据

    .rdusedw    (wrf_use),               //FIFO中的数据量
    .aclr       (~rst_n | wr_load_flag)  //异步清零信号
    );  

//例化读端口FIFO
rdfifo  u_rdfifo(
    //sdram接口
    .wrclk      (clk_ref),               //写时钟
    .wrreq      (sdram_rd_ack),          //写请求
    .data       (sdram_dout),            //写数据
    
    //用户接口
    .rdclk      (clk_read),              //读时钟
    .rdreq      (rdf_rdreq),             //读请求
    .q          (rdf_dout),              //读数据

    .wrusedw    (rdf_use),               //FIFO中的数据量
    .aclr       (~rst_n | rd_load_flag)  //异步清零信号   
    );
    
endmodule 

Erstellen Sie zwei FIFOs

16 Bit, 1024 Byte

SDRAM-Steuermodul TOP

module sdram_controller(
    input         clk,              //SDRAM控制器时钟,100MHz
    input         rst_n,            //系统复位信号,低电平有效
    
    //SDRAM 控制器写端口  
    input         sdram_wr_req,     //写SDRAM请求信号
    output        sdram_wr_ack,     //写SDRAM响应信号
    input  [23:0] sdram_wr_addr,    //SDRAM写操作的地址
    input  [ 9:0] sdram_wr_burst,   //写sdram时数据突发长度
    input  [15:0] sdram_din,        //写入SDRAM的数据
    
    //SDRAM 控制器读端口  
    input         sdram_rd_req,     //读SDRAM请求信号
    output        sdram_rd_ack,     //读SDRAM响应信号
    input  [23:0] sdram_rd_addr,    //SDRAM写操作的地址
    input  [ 9:0] sdram_rd_burst,   //读sdram时数据突发长度
    output [15:0] sdram_dout,       //从SDRAM读出的数据
    
    output        sdram_init_done,  //SDRAM 初始化完成标志
                                     
    // FPGA与SDRAM硬件接口
    output        sdram_cke,        // SDRAM 时钟有效信号
    output        sdram_cs_n,       // SDRAM 片选信号
    output        sdram_ras_n,      // SDRAM 行地址选通脉冲
    output        sdram_cas_n,      // SDRAM 列地址选通脉冲
    output        sdram_we_n,       // SDRAM 写允许位
    output [ 1:0] sdram_ba,         // SDRAM L-Bank地址线
    output [12:0] sdram_addr,       // SDRAM 地址总线
    inout  [15:0] sdram_data        // SDRAM 数据总线
    );

//wire define
wire [4:0] init_state;              // SDRAM初始化状态
wire [3:0] work_state;              // SDRAM工作状态
wire [9:0] cnt_clk;                 // 延时计数器
wire       sdram_rd_wr;             // SDRAM读/写控制信号,低电平为写,高电平为读

//*****************************************************
//**                    main code
//*****************************************************     

// SDRAM 状态控制模块                
sdram_ctrl u_sdram_ctrl(            
    .clk                (clk),                      
    .rst_n              (rst_n),

    .sdram_wr_req       (sdram_wr_req), 
    .sdram_rd_req       (sdram_rd_req),
    .sdram_wr_ack       (sdram_wr_ack),
    .sdram_rd_ack       (sdram_rd_ack),                     
    .sdram_wr_burst     (sdram_wr_burst),
    .sdram_rd_burst     (sdram_rd_burst),
    .sdram_init_done    (sdram_init_done),
    
    .init_state         (init_state),
    .work_state         (work_state),
    .cnt_clk            (cnt_clk),
    .sdram_rd_wr        (sdram_rd_wr)
    );

// SDRAM 命令控制模块
sdram_cmd u_sdram_cmd(              
    .clk                (clk),
    .rst_n              (rst_n),

    .sys_wraddr         (sdram_wr_addr),            
    .sys_rdaddr         (sdram_rd_addr),
    .sdram_wr_burst     (sdram_wr_burst),
    .sdram_rd_burst     (sdram_rd_burst),
    
    .init_state         (init_state),   
    .work_state         (work_state),
    .cnt_clk            (cnt_clk),
    .sdram_rd_wr        (sdram_rd_wr),
    
    .sdram_cke          (sdram_cke),        
    .sdram_cs_n         (sdram_cs_n),   
    .sdram_ras_n        (sdram_ras_n),  
    .sdram_cas_n        (sdram_cas_n),  
    .sdram_we_n         (sdram_we_n),   
    .sdram_ba           (sdram_ba),         
    .sdram_addr         (sdram_addr)
    );

// SDRAM 数据读写模块
sdram_data u_sdram_data(        
    .clk                (clk),
    .rst_n              (rst_n),
    
    .sdram_data_in      (sdram_din),
    .sdram_data_out     (sdram_dout),
    .work_state         (work_state),
    .cnt_clk            (cnt_clk),
    
    .sdram_data         (sdram_data)
    );

endmodule 

SDRAM-Befehlssteuermodul

module sdram_cmd(
    input             clk,              //系统时钟
    input             rst_n,            //低电平复位信号

    input      [23:0] sys_wraddr,       //写SDRAM时地址
    input      [23:0] sys_rdaddr,       //读SDRAM时地址
    input      [ 9:0] sdram_wr_burst,   //突发写SDRAM字节数
    input      [ 9:0] sdram_rd_burst,   //突发读SDRAM字节数
    
    input      [ 4:0] init_state,       //SDRAM初始化状态
    input      [ 3:0] work_state,       //SDRAM工作状态
    input      [ 9:0] cnt_clk,          //延时计数器 
    input             sdram_rd_wr,      //SDRAM读/写控制信号,低电平为写
    
    output            sdram_cke,        //SDRAM时钟有效信号
    output            sdram_cs_n,       //SDRAM片选信号
    output            sdram_ras_n,      //SDRAM行地址选通脉冲
    output            sdram_cas_n,      //SDRAM列地址选通脉冲
    output            sdram_we_n,       //SDRAM写允许位
    output reg [ 1:0] sdram_ba,         //SDRAM的L-Bank地址线
    output reg [12:0] sdram_addr        //SDRAM地址总线
    );

`include "sdram_para.v"                 //包含SDRAM参数定义模块

//reg define
reg  [ 4:0] sdram_cmd_r;                //SDRAM操作指令

//wire define
wire [23:0] sys_addr;                   //SDRAM读写地址 

//*****************************************************
//**                    main code
//***************************************************** 

//SDRAM 控制信号线赋值
assign {sdram_cke,sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} = sdram_cmd_r;

//SDRAM 读/写地址总线控制
assign sys_addr = sdram_rd_wr ? sys_rdaddr : sys_wraddr;
    
//SDRAM 操作指令控制
always @ (posedge clk or negedge rst_n) begin
    if(!rst_n) begin
            sdram_cmd_r <= `CMD_INIT;
            sdram_ba    <= 2'b11;
            sdram_addr  <= 13'h1fff;
    end
    else
        case(init_state)
                                        //初始化过程中,以下状态不执行任何指令
            `I_NOP,`I_TRP,`I_TRF,`I_TRSC: begin
                    sdram_cmd_r <= `CMD_NOP;
                    sdram_ba    <= 2'b11;
                    sdram_addr  <= 13'h1fff;    
                end
            `I_PRE: begin               //预充电指令
                    sdram_cmd_r <= `CMD_PRGE;
                    sdram_ba    <= 2'b11;
                    sdram_addr  <= 13'h1fff;
                end 
            `I_AR: begin
                                        //自动刷新指令
                    sdram_cmd_r <= `CMD_A_REF;
                    sdram_ba    <= 2'b11;
                    sdram_addr  <= 13'h1fff;                        
                end                 
            `I_MRS: begin               //模式寄存器设置指令
                    sdram_cmd_r <= `CMD_LMR;
                    sdram_ba    <= 2'b00;
                    sdram_addr  <= {    //利用地址线设置模式寄存器,可根据实际需要进行修改
                        3'b000,         //预留
                        1'b0,           //读写方式 A9=0,突发读&突发写
                        2'b00,          //默认,{A8,A7}=00
                        3'b011,         //CAS潜伏期设置,这里设置为3,{A6,A5,A4}=011
                        1'b0,           //突发传输方式,这里设置为顺序,A3=0
                        3'b111          //突发长度,这里设置为页突发,{A2,A1,A0}=011
                    };
                end 
            `I_DONE:                    //SDRAM初始化完成
                    case(work_state)    //以下工作状态不执行任何指令
                        `W_IDLE,`W_TRCD,`W_CL,`W_TWR,`W_TRP,`W_TRFC: begin
                                sdram_cmd_r <= `CMD_NOP;
                                sdram_ba    <= 2'b11;
                                sdram_addr  <= 13'h1fff;
                            end
                        `W_ACTIVE: begin//行有效指令
                                sdram_cmd_r <= `CMD_ACTIVE;
                                sdram_ba    <= sys_addr[23:22];
                                sdram_addr  <= sys_addr[21:9];
                            end
                        `W_READ: begin  //读操作指令
                                sdram_cmd_r <= `CMD_READ;
                                sdram_ba    <= sys_addr[23:22];
                                sdram_addr  <= {4'b0000,sys_addr[8:0]};
                            end
                        `W_RD: begin    //突发传输终止指令
                                if(`end_rdburst) 
                                    sdram_cmd_r <= `CMD_B_STOP;
                                else begin
                                    sdram_cmd_r <= `CMD_NOP;
                                    sdram_ba    <= 2'b11;
                                    sdram_addr  <= 13'h1fff;
                                end
                            end                             
                        `W_WRITE: begin //写操作指令
                                sdram_cmd_r <= `CMD_WRITE;
                                sdram_ba    <= sys_addr[23:22];
                                sdram_addr  <= {4'b0000,sys_addr[8:0]};
                            end     
                        `W_WD: begin    //突发传输终止指令
                                if(`end_wrburst) 
                                    sdram_cmd_r <= `CMD_B_STOP;
                                else begin
                                    sdram_cmd_r <= `CMD_NOP;
                                    sdram_ba    <= 2'b11;
                                    sdram_addr  <= 13'h1fff;
                                end
                            end
                        `W_PRE:begin    //预充电指令
                                sdram_cmd_r <= `CMD_PRGE;
                                sdram_ba    <= sys_addr[23:22];
                                sdram_addr  <= 13'h0400;
                            end             
                        `W_AR: begin    //自动刷新指令
                                sdram_cmd_r <= `CMD_A_REF;
                                sdram_ba    <= 2'b11;
                                sdram_addr  <= 13'h1fff;
                            end
                        default: begin
                                sdram_cmd_r <= `CMD_NOP;
                                sdram_ba    <= 2'b11;
                                sdram_addr  <= 13'h1fff;
                            end
                    endcase
            default: begin
                    sdram_cmd_r <= `CMD_NOP;
                    sdram_ba    <= 2'b11;
                    sdram_addr  <= 13'h1fff;
                end
        endcase
end

endmodule 

SDRAM-Statuskontrollmodul

module sdram_ctrl(
    input            clk,			    //系统时钟
    input            rst_n,			    //复位信号,低电平有效
    
    input            sdram_wr_req,	    //写SDRAM请求信号
    input            sdram_rd_req,	    //读SDRAM请求信号
    output           sdram_wr_ack,	    //写SDRAM响应信号
    output           sdram_rd_ack,	    //读SDRAM响应信号
    input      [9:0] sdram_wr_burst,	//突发写SDRAM字节数(1-512个)
    input      [9:0] sdram_rd_burst,	//突发读SDRAM字节数(1-256个)	
    output           sdram_init_done,   //SDRAM系统初始化完毕信号

    output reg [4:0] init_state,	    //SDRAM初始化状态
    output reg [3:0] work_state,	    //SDRAM工作状态
    output reg [9:0] cnt_clk,	        //时钟计数器
    output reg       sdram_rd_wr 		//SDRAM读/写控制信号,低电平为写,高电平为读
    );

`include "sdram_para.v"		            //包含SDRAM参数定义模块
                                        
//parameter define                      
parameter  TRP_CLK	  = 10'd4;	        //预充电有效周期
parameter  TRC_CLK	  = 10'd6;	        //自动刷新周期
parameter  TRSC_CLK	  = 10'd6;	        //模式寄存器设置时钟周期
parameter  TRCD_CLK	  = 10'd2;	        //行选通周期
parameter  TCL_CLK	  = 10'd3;	        //列潜伏期
parameter  TWR_CLK	  = 10'd2;	        //写入校正
                                        
//reg define                            
reg [14:0] cnt_200us;                   //SDRAM 上电稳定期200us计数器
reg [10:0] cnt_refresh;	                //刷新计数寄存器
reg        sdram_ref_req;		        //SDRAM 自动刷新请求信号
reg        cnt_rst_n;		            //延时计数器复位信号,低有效	
reg [ 3:0] init_ar_cnt;                 //初始化过程自动刷新计数器
                                        
//wire define                           
wire       done_200us;		            //上电后200us输入稳定期结束标志位
wire       sdram_ref_ack;		        //SDRAM自动刷新请求应答信号	

//*****************************************************
//**                    main code
//***************************************************** 

//SDRAM上电后200us稳定期结束后,将标志信号拉高
assign done_200us = (cnt_200us == 15'd20_000);

//SDRAM初始化完成标志 
assign sdram_init_done = (init_state == `I_DONE);

//SDRAM 自动刷新应答信号
assign sdram_ref_ack = (work_state == `W_AR);

//写SDRAM响应信号
assign sdram_wr_ack = ((work_state == `W_TRCD) & ~sdram_rd_wr) | 
					  ( work_state == `W_WRITE)|
					  ((work_state == `W_WD) & (cnt_clk < sdram_wr_burst - 2'd2));
                      
//读SDRAM响应信号
assign sdram_rd_ack = (work_state == `W_RD) & 
					  (cnt_clk >= 10'd1) & (cnt_clk < sdram_rd_burst + 2'd1);
                      
//上电后计时200us,等待SDRAM状态稳定
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) 
        cnt_200us <= 15'd0;
	else if(cnt_200us < 15'd20_000) 
        cnt_200us <= cnt_200us + 1'b1;
    else
        cnt_200us <= cnt_200us;
end
 
//刷新计数器循环计数7812ns (60ms内完成全部8192行刷新操作)
always @ (posedge clk or negedge rst_n)
	if(!rst_n) 
        cnt_refresh <= 11'd0;
	else if(cnt_refresh < 11'd781)      // 64ms/8192 =7812ns
        cnt_refresh <= cnt_refresh + 1'b1;	
	else 
        cnt_refresh <= 11'd0;	

//SDRAM 刷新请求
always @ (posedge clk or negedge rst_n)
	if(!rst_n) 
        sdram_ref_req <= 1'b0;
	else if(cnt_refresh == 11'd780) 
        sdram_ref_req <= 1'b1;	        //刷新计数器计时达7812ns时产生刷新请求
	else if(sdram_ref_ack) 
        sdram_ref_req <= 1'b0;		    //收到刷新请求响应信号后取消刷新请求 

//延时计数器对时钟计数
always @ (posedge clk or negedge rst_n) 
	if(!rst_n) 
        cnt_clk <= 10'd0;
	else if(!cnt_rst_n)                 //在cnt_rst_n为低电平时延时计数器清零
        cnt_clk <= 10'd0;
	else 
        cnt_clk <= cnt_clk + 1'b1;
        
//初始化过程中对自动刷新操作计数
always @ (posedge clk or negedge rst_n) 
	if(!rst_n) 
        init_ar_cnt <= 4'd0;
	else if(init_state == `I_NOP) 
        init_ar_cnt <= 4'd0;
	else if(init_state == `I_AR)
        init_ar_cnt <= init_ar_cnt + 1'b1;
    else
        init_ar_cnt <= init_ar_cnt;
	
//SDRAM的初始化状态机
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) 
        init_state <= `I_NOP;
	else 
		case (init_state)
                                        //上电复位后200us结束则进入下一状态
            `I_NOP:  init_state <= done_200us  ? `I_PRE : `I_NOP;
                                        //预充电状态
			`I_PRE:  init_state <= `I_TRP;
                                        //预充电等待,TRP_CLK个时钟周期
			`I_TRP:  init_state <= (`end_trp)  ? `I_AR  : `I_TRP;
                                        //自动刷新
			`I_AR :  init_state <= `I_TRF;	
                                        //等待自动刷新结束,TRC_CLK个时钟周期
			`I_TRF:  init_state <= (`end_trfc) ? 
                                        //连续8次自动刷新操作
                                   ((init_ar_cnt == 4'd8) ? `I_MRS : `I_AR) : `I_TRF;
                                        //模式寄存器设置
			`I_MRS:	 init_state <= `I_TRSC;	
                                        //等待模式寄存器设置完成,TRSC_CLK个时钟周期
			`I_TRSC: init_state <= (`end_trsc) ? `I_DONE : `I_TRSC;
                                        //SDRAM的初始化设置完成标志
			`I_DONE: init_state <= `I_DONE;
			default: init_state <= `I_NOP;
		endcase
end

//SDRAM的工作状态机,工作包括读、写以及自动刷新操作
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) 
		work_state <= `W_IDLE;          //空闲状态
	else
		case(work_state)
                                        //定时自动刷新请求,跳转到自动刷新状态
            `W_IDLE: if(sdram_ref_req & sdram_init_done) begin
						 work_state <= `W_AR; 		
					     sdram_rd_wr <= 1'b1;
				     end 		        
                                        //写SDRAM请求,跳转到行有效状态
					 else if(sdram_wr_req & sdram_init_done) begin
						 work_state <= `W_ACTIVE;
						 sdram_rd_wr <= 1'b0;	
					 end                
                                        //读SDRAM请求,跳转到行有效状态
					 else if(sdram_rd_req && sdram_init_done) begin
						 work_state <= `W_ACTIVE;
						 sdram_rd_wr <= 1'b1;	
					 end                
                                        //无操作请求,保持空闲状态
					 else begin 
						 work_state <= `W_IDLE;
						 sdram_rd_wr <= 1'b1;
					 end
                     
            `W_ACTIVE:                  //行有效,跳转到行有效等待状态
                         work_state <= `W_TRCD;
            `W_TRCD: if(`end_trcd)      //行有效等待结束,判断当前是读还是写
						 if(sdram_rd_wr)//读:进入读操作状态
                             work_state <= `W_READ;
						 else           //写:进入写操作状态
                             work_state <= `W_WRITE;
					 else 
                         work_state <= `W_TRCD;
                         
            `W_READ:	                //读操作,跳转到潜伏期
                         work_state <= `W_CL;	
            `W_CL:		                //潜伏期:等待潜伏期结束,跳转到读数据状态
                         work_state <= (`end_tcl) ? `W_RD:`W_CL;	                                        
            `W_RD:		                //读数据:等待读数据结束,跳转到预充电状态
                         work_state <= (`end_tread) ? `W_PRE:`W_RD;
                         
            `W_WRITE:	                //写操作:跳转到写数据状态
                         work_state <= `W_WD;
            `W_WD:		                //写数据:等待写数据结束,跳转到写回周期状态
                         work_state <= (`end_twrite) ? `W_TWR:`W_WD;                         
            `W_TWR:	                    //写回周期:写回周期结束,跳转到预充电状态
                         work_state <= (`end_twr) ? `W_PRE:`W_TWR;
                         
            `W_PRE:		                //预充电:跳转到预充电等待状态
                         work_state <= `W_TRP;
            `W_TRP:	                //预充电等待:预充电等待结束,进入空闲状态
                         work_state <= (`end_trp) ? `W_IDLE:`W_TRP;
                         
            `W_AR:		                //自动刷新操作,跳转到自动刷新等待
                         work_state <= `W_TRFC;             
            `W_TRFC:	                //自动刷新等待:自动刷新等待结束,进入空闲状态
                         work_state <= (`end_trfc) ? `W_IDLE:`W_TRFC;
            default: 	 work_state <= `W_IDLE;
		endcase
end

//计数器控制逻辑
always @ (*) begin
	case (init_state)
        `I_NOP:	 cnt_rst_n <= 1'b0;     //延时计数器清零(cnt_rst_n低电平复位)
                                        
        `I_PRE:	 cnt_rst_n <= 1'b1;     //预充电:延时计数器启动(cnt_rst_n高电平启动)
                                        //等待预充电延时计数结束后,清零计数器
        `I_TRP:	 cnt_rst_n <= (`end_trp) ? 1'b0 : 1'b1;
                                        //自动刷新:延时计数器启动
        `I_AR:
                 cnt_rst_n <= 1'b1;
                                        //等待自动刷新延时计数结束后,清零计数器
        `I_TRF:
                 cnt_rst_n <= (`end_trfc) ? 1'b0 : 1'b1;	
                                        
        `I_MRS:  cnt_rst_n <= 1'b1;	    //模式寄存器设置:延时计数器启动
                                        //等待模式寄存器设置延时计数结束后,清零计数器
        `I_TRSC: cnt_rst_n <= (`end_trsc) ? 1'b0:1'b1;
                                        
        `I_DONE: begin                  //初始化完成后,判断工作状态
		    case (work_state)
				`W_IDLE:	cnt_rst_n <= 1'b0;
                                        //行有效:延时计数器启动
				`W_ACTIVE: 	cnt_rst_n <= 1'b1;
                                        //行有效延时计数结束后,清零计数器
				`W_TRCD:	cnt_rst_n <= (`end_trcd)   ? 1'b0 : 1'b1;
                                        //潜伏期延时计数结束后,清零计数器
				`W_CL:		cnt_rst_n <= (`end_tcl)    ? 1'b0 : 1'b1;
                                        //读数据延时计数结束后,清零计数器
				`W_RD:		cnt_rst_n <= (`end_tread)  ? 1'b0 : 1'b1;
                                        //写数据延时计数结束后,清零计数器
				`W_WD:		cnt_rst_n <= (`end_twrite) ? 1'b0 : 1'b1;
                                        //写回周期延时计数结束后,清零计数器
				`W_TWR:	    cnt_rst_n <= (`end_twr)    ? 1'b0 : 1'b1;
                                        //预充电等待延时计数结束后,清零计数器
				`W_TRP:	cnt_rst_n <= (`end_trp) ? 1'b0 : 1'b1;
                                        //自动刷新等待延时计数结束后,清零计数器
				`W_TRFC:	cnt_rst_n <= (`end_trfc)   ? 1'b0 : 1'b1;
				default:    cnt_rst_n <= 1'b0;
		    endcase
        end
		default: cnt_rst_n <= 1'b0;
	endcase
end
 
endmodule 

SDRAM-Datenlese- und -schreibmodul

module sdram_data(
    input             clk,              //系统时钟
    input             rst_n,            //低电平复位信号

    input   [15:0]    sdram_data_in,    //写入SDRAM中的数据
    output  [15:0]    sdram_data_out,   //从SDRAM中读取的数据
    input   [ 3:0]    work_state,       //SDRAM工作状态寄存器
    input   [ 9:0]    cnt_clk,          //时钟计数
    
    inout   [15:0]    sdram_data        //SDRAM数据总线
    );

`include "sdram_para.v"                 //包含SDRAM参数定义模块

//reg define
reg        sdram_out_en;                //SDRAM数据总线输出使能
reg [15:0] sdram_din_r;                 //寄存写入SDRAM中的数据
reg [15:0] sdram_dout_r;                //寄存从SDRAM中读取的数据

//*****************************************************
//**                    main code
//***************************************************** 

//SDRAM 双向数据线作为输入时保持高阻态
assign sdram_data = sdram_out_en ? sdram_din_r : 16'hzzzz;

//输出SDRAM中读取的数据
assign sdram_data_out = sdram_dout_r;

//SDRAM 数据总线输出使能
always @ (posedge clk or negedge rst_n) begin 
    if(!rst_n) 
       sdram_out_en <= 1'b0;
   else if((work_state == `W_WRITE) | (work_state == `W_WD)) 
       sdram_out_en <= 1'b1;            //向SDRAM中写数据时,输出使能拉高
   else 
       sdram_out_en <= 1'b0;
end

//将待写入数据送到SDRAM数据总线上
always @ (posedge clk or negedge rst_n) begin
    if(!rst_n) 
        sdram_din_r <= 16'd0;
    else if((work_state == `W_WRITE) | (work_state == `W_WD))
        sdram_din_r <= sdram_data_in;   //寄存写入SDRAM中的数据
end

//读数据时,寄存SDRAM数据线上的数据
always @ (posedge clk or negedge rst_n) begin
    if(!rst_n) 
        sdram_dout_r <= 16'd0;
    else if(work_state == `W_RD) 
        sdram_dout_r <= sdram_data;     //寄存从SDRAM中读取的数据
end

endmodule 

SDRAM-Parameterdatei


// SDRAM 初始化过程各个状态
`define     I_NOP           5'd0                            //等待上电200us稳定期结束
`define     I_PRE           5'd1                            //预充电状态
`define     I_TRP           5'd2                            //等待预充电完成       tRP
`define     I_AR            5'd3                            //自动刷新            
`define     I_TRF           5'd4                            //等待自动刷新结束    tRC
`define     I_MRS           5'd5                            //模式寄存器设置
`define     I_TRSC          5'd6                            //等待模式寄存器设置完成 tRSC
`define     I_DONE          5'd7                            //初始化完成

// SDRAM 工作过程各个状态
`define     W_IDLE          4'd0                            //空闲
`define     W_ACTIVE        4'd1                            //行有效
`define     W_TRCD          4'd2                            //行有效等待
`define     W_READ          4'd3                            //读操作
`define     W_CL            4'd4                            //潜伏期
`define     W_RD            4'd5                            //读数据
`define     W_WRITE         4'd6                            //写操作
`define     W_WD            4'd7                            //写数据
`define     W_TWR           4'd8                            //写回
`define     W_PRE           4'd9                            //预充电
`define     W_TRP           4'd10                           //预充电等待
`define     W_AR            4'd11                           //自动刷新
`define     W_TRFC          4'd12                           //自动刷新等待
  
//延时参数
`define     end_trp         cnt_clk == TRP_CLK              //预充电有效周期结束
`define     end_trfc        cnt_clk == TRC_CLK              //自动刷新周期结束
`define     end_trsc        cnt_clk == TRSC_CLK             //模式寄存器设置时钟周期结束
`define     end_trcd        cnt_clk == TRCD_CLK-1           //行选通周期结束
`define     end_tcl         cnt_clk == TCL_CLK-1            //潜伏期结束
`define     end_rdburst     cnt_clk == sdram_rd_burst-4     //读突发终止
`define     end_tread       cnt_clk == sdram_rd_burst+2     //突发读结束     
`define     end_wrburst     cnt_clk == sdram_wr_burst-1     //写突发终止
`define     end_twrite      cnt_clk == sdram_wr_burst-1     //突发写结束
`define     end_twr         cnt_clk == TWR_CLK              //写回周期结束

//SDRAM控制信号命令
`define     CMD_INIT        5'b01111                        // INITIATE
`define     CMD_NOP         5'b10111                        // NOP COMMAND
`define     CMD_ACTIVE      5'b10011                        // ACTIVE COMMAND
`define     CMD_READ        5'b10101                        // READ COMMADN
`define     CMD_WRITE       5'b10100                        // WRITE COMMAND
`define     CMD_B_STOP      5'b10110                        // BURST STOP
`define     CMD_PRGE        5'b10010                        // PRECHARGE
`define     CMD_A_REF       5'b10001                        // AOTO REFRESH
`define     CMD_LMR         5'b10000                        // LODE MODE REGISTER

Supongo que te gusta

Origin blog.csdn.net/qq_42792802/article/details/127114781
Recomendado
Clasificación