66.基于DDR3 SDRAM的HDMI图像显示

实验目标:在 PC 机上使用串口调试助手发送一幅像素为800 * 600 的图片数据给 FPGA,FPGA以外接 DDR3 SDRAM做缓存,将接收到的图片数据以800 * 600@60的显示模式通过 HDMI显示器显示出来。

(1)RS232模块设计:使用115200波特率进行传输和接受,发送顺序是先发送低位,后发送高位,以下为一帧数据的结构:

(2)参考代码如下:

//该模块波特率为115200
//     1_000_000_000/115200 = 8,680.555...
//50MHz时钟对应一个时钟周期为20ns 则 8680.555/20 = 434

//RS232 传输顺序为从最低位传到最高位

module rs232_rx
(
    input   wire            clk         ,
    input   wire            reset_n     ,
    input   wire            rx          ,
    input   wire            rx_start    ,
    
    output  reg     [7:0]   rx_data     ,
    output  wire            rx_done 
    
);

parameter BAUD_MCNT =   16'd433;

wire        nedge           ;

reg         rx_reg0         ;
reg         rx_reg1         ;
reg         rx_reg2         ;
reg         en_baud_cnt     ;
reg [15:0]  baud_cnt        ;
reg [3:0]   bit_cnt         ;
reg [7:0]   reg_rx_data     ;

//下降沿设计
//前两拍的目的是消除亚稳态
always@(posedge clk or negedge reset_n)
    if(!reset_n)begin
        rx_reg0 <= 1'd0;
        rx_reg1 <= 1'd0;
        rx_reg2 <= 1'd0;
    end
    else begin
        rx_reg0 <= rx;
        rx_reg1 <= rx_reg0;
        rx_reg2 <= rx_reg1;
    end

assign nedge = rx_reg2 && (!rx_reg1) ;

//结束信号设计
assign rx_done = (bit_cnt == 4'd9) && (baud_cnt == BAUD_MCNT/2);

//波特率计数使能信号设计
always@(posedge clk or negedge reset_n)
    if(!reset_n)
        en_baud_cnt <= 1'd0;
    else if(!rx_start)
        en_baud_cnt <= 1'd0;
    else if(rx_done)
        en_baud_cnt <= 1'd0;
    else if((bit_cnt == 4'd0) && (baud_cnt == BAUD_MCNT/2) && rx_reg2)   //防止停止位只是一个抖动
        en_baud_cnt <= 1'd0;
    else if(nedge)
        en_baud_cnt <= 1'd1;
    else 
        en_baud_cnt <= en_baud_cnt;
        
//波特计数器设计
always@(posedge clk or negedge reset_n)
    if(!reset_n)
        baud_cnt <= 16'd0;
    else if(!en_baud_cnt)
        baud_cnt <= 16'd0;
    else if(rx_done)
        baud_cnt <= 16'd0;
    else if(baud_cnt == BAUD_MCNT)
        baud_cnt <= 16'd0;
    else 
        baud_cnt <= baud_cnt + 16'd1;
        
//位计数器设计
always@(posedge clk or negedge reset_n)
    if(!reset_n)
        bit_cnt <= 4'd0;
    else if(rx_done)
        bit_cnt <= 4'd0;
    else if(baud_cnt == BAUD_MCNT)
        bit_cnt <= bit_cnt + 4'd1;
    else 
        bit_cnt <= bit_cnt;

//接收数据rx_data设计
always@(posedge clk or negedge reset_n)
    if(!reset_n)
        reg_rx_data <= 8'd0;
    else if(baud_cnt == BAUD_MCNT/2)begin
        case(bit_cnt)
            4'd1:reg_rx_data[0] <= rx_reg2;
            4'd2:reg_rx_data[1] <= rx_reg2;
            4'd3:reg_rx_data[2] <= rx_reg2;
            4'd4:reg_rx_data[3] <= rx_reg2;
            4'd5:reg_rx_data[4] <= rx_reg2;
            4'd6:reg_rx_data[5] <= rx_reg2;
            4'd7:reg_rx_data[6] <= rx_reg2;
            4'd8:reg_rx_data[7] <= rx_reg2;
            default:reg_rx_data <= reg_rx_data;
        endcase
    end
    else 
        reg_rx_data <= reg_rx_data;
    
always@(posedge clk or negedge reset_n)
    if(!reset_n)
        rx_data <= 8'd0;
    else if(rx_done)
        rx_data <= reg_rx_data;
    else 
        rx_data <= rx_data;

endmodule

(3)DDR3驱动模块设计:

  • mig IP核的配置:

(4)AXI写主机设计:

module axi_master_write
(
    //全局变量
    input   wire                ACLK                ,           //全局时钟
    input   wire                ARESETN             ,           //全局复位
    //写地址通道变量   
    output  wire    [3:0]       M_AXI_AWID          ,           //写地址ID         用来标记一组写信号
    output  wire    [31:0]      M_AXI_AWADDR        ,           //写地址           给出一次写突发传输的写地址
    output  wire    [7:0]       M_AXI_AWLEN         ,           //突出长度         
    output  wire    [2:0]       M_AXI_AWSIZE        ,           //突出大小          给出每次突发传输的字节数
    output  wire    [1:0]       M_AXI_AWBURST       ,           //突发类型
    output  wire                M_AXI_AWLOCK        ,           //总线锁信号
    output  wire    [3:0]       M_AXI_AWCACHE       ,           //内存类型,表明一次传输是怎么通过系统的
    output  wire    [2:0]       M_AXI_AWPROT        ,           //保护类型,表明一次传输的特权级及安全等级
    output  wire    [3:0]       M_AXI_AWQOS         ,           //质量服务QOS
    output  wire                M_AXI_AWVALID       ,           //有效信号,表明此通道的地址控制信号有效
    input   wire                M_AXI_AWREADY       ,           //表明从机可以接收地址和对应的控制信号
    //写数据通道变量   
    output  wire    [63:0]      M_AXI_WDATA         ,           //写数据
    output  wire    [7:0]       M_AXI_WSTRB         ,           //写数据有效字节数
    output  wire                M_AXI_WLAST         ,           //表明此次传输的最后一个突发传输
    output  wire                M_AXI_WVALID        ,           //写有效信号
    input   wire                M_AXI_WREADY        ,           //表明从机可以接收写数据
    //写响应通道变量       
    input   wire    [3:0]       M_AXI_BID           ,           //写响应ID TAG
    input   wire    [1:0]       M_AXI_BRESP         ,           //写响应,表明写传输的状态
    input   wire                M_AXI_BVALID        ,           //写响应有效
    output  wire                M_AXI_BREADY        ,           //表明主机可以接收写响应信号
    //用户端接口变量      
    input   wire                WR_START            ,           //写突发触发信号
    input   wire    [31:0]      WR_ADDR             ,           //地址
    input   wire    [7:0]       WR_LEN              ,           //长度
    output  wire                WR_READY            ,           //写空闲
    output  wire                WR_FIFO_RE          ,           //连接到fifo的读使能
    input   wire    [63:0]      WR_FIFO_DATA        ,           //连接到fifo的读数据
    output  wire                WR_BURAST_FINISH                //完成最后一次突发
                
);

reg     [6:0]       WR_STATE        ;
reg     [31:0]      awaddr_reg      ;
reg     [7:0]       awlen_reg       ;
reg                 awvalid_reg     ;
reg                 wvalid_reg      ;

localparam      S0_WR_IDLE          =       7'b000_0001;    //写空闲,等待用户端给出开始写入信号
localparam      S1_WR_WAIT          =       7'b000_0010;    //写地址等待,将用户端的写地址赋值给写地址通道的M_AXI_AWADDR信号
localparam      S2_WR_ADDR          =       7'b000_0100;    //写地址,将写地址有效信号和写有效信号都拉高
localparam      S3_WD_WAIT          =       7'b000_1000;    //写数据等待,将写地址有效信号拉低,将用户端要求的写入数据长度赋值给寄存器,方便计数
localparam      S4_WD_PROC          =       7'b001_0000;    //写数据循环,正式写入数据,直到M_AXI_AWLEN 等于 awlen_reg
localparam      S5_WR_RES           =       7'b010_0000;    //接收写应答,接收到从机传来的写响应有效信号,才进入写结束状态
localparam      S6_WR_DONE          =       7'b100_0000;    //写结束

//输出信号赋值
assign  M_AXI_AWID          = 4'b1111                       ;       //只有一个主机,因此可以随意设置
assign  M_AXI_AWADDR        = awaddr_reg                    ;       
assign  M_AXI_AWLEN         = WR_LEN - 8'd1                 ;       
assign  M_AXI_AWSIZE        = 3'b011                        ;       //表示AXI总线每个数据宽度是8字节,64位
assign  M_AXI_AWBURST       = 2'b01                         ;       //01表示地址递增,10表示地址递减
assign  M_AXI_AWLOCK        = 1'd0                          ;       
assign  M_AXI_AWCACHE       = 4'b0010                       ;
assign  M_AXI_AWPROT        = 3'b000                        ;
assign  M_AXI_AWQOS         = 4'b0000                       ;
assign  M_AXI_AWVALID       = awvalid_reg                   ;
            
assign  M_AXI_WDATA         = WR_FIFO_DATA                  ;
assign  M_AXI_WSTRB         = 8'b1111_1111                  ;
assign  M_AXI_WLAST         = (awlen_reg == 8'd0)           ;
assign  M_AXI_WVALID        = wvalid_reg                    ;
    
assign  M_AXI_BREADY        = M_AXI_BVALID                  ;
    
assign  WR_READY            = (WR_STATE == S0_WR_IDLE)      ;
assign  WR_FIFO_RE          = (M_AXI_WVALID && M_AXI_WREADY);
assign  WR_BURAST_FINISH    = (WR_STATE == S6_WR_DONE)      ;

//状态机设计
always@(posedge ACLK or negedge ARESETN)
    if(!ARESETN)begin
        WR_STATE        <= S0_WR_IDLE   ;
        awaddr_reg      <= 32'd0        ;
        awlen_reg       <= 8'd0         ;
        awvalid_reg     <= 1'd0         ;
        wvalid_reg      <= 1'd0         ;
    end
    else begin
        case(WR_STATE)
            S0_WR_IDLE  :begin
                awlen_reg <= 8'd0;
                awvalid_reg <= 1'd0;
                wvalid_reg <= 1'd0;
                if(WR_START)begin
                    WR_STATE <= S1_WR_WAIT;
                    awaddr_reg <= WR_ADDR;
                end
            end
            S1_WR_WAIT  :begin
                WR_STATE <= S2_WR_ADDR;
            end
            S2_WR_ADDR  :begin
                WR_STATE <= S3_WD_WAIT;
                awvalid_reg <= 1'd1;
                wvalid_reg <= 1'd1;
            end
            S3_WD_WAIT  :begin
                if(M_AXI_AWREADY)begin
                    WR_STATE <= S4_WD_PROC;
                    awvalid_reg <= 1'd0;
                    awlen_reg <= WR_LEN - 8'd1;
                end
            end
            S4_WD_PROC  :begin
                if(M_AXI_WREADY)begin
                    if(M_AXI_WLAST)begin
                        WR_STATE <= S5_WR_RES;
                        wvalid_reg <= 1'd0;
                    end
                    else begin
                        awlen_reg <= awlen_reg - 8'd1;
                        WR_STATE <= WR_STATE;
                    end
                end
            end
            S5_WR_RES   :begin
                if(M_AXI_BVALID)begin
                    WR_STATE <= S6_WR_DONE;
                end
            end
            S6_WR_DONE  :begin
                WR_STATE <= S0_WR_IDLE;
            end
            default     : WR_STATE <= S0_WR_IDLE;
        endcase
    end


endmodule

(5)AXI读主机设计:

module axi_master_read
(
    //全局变量
    input   wire            ACLK                ,   //全局时钟
    input   wire            ARESETN             ,   //全局复位
    //读地址通道变量
    output  wire    [3:0]   M_AXI_ARID          ,   //读地址ID     用来标志一组读信号
    output  wire    [31:0]  M_AXI_ARADDR        ,   //读地址       给出一次读突发传输的读地址
    output  wire    [7:0]   M_AXI_ARLEN         ,   //突发长度      给出每次突出传输的次数
    output  wire    [2:0]   M_AXI_ARSIZE        ,   //突发大小      给出每次突发传输的字节数
    output  wire    [1:0]   M_AXI_ARBURST       ,   //突发类型
    output  wire            M_AXI_ARLOCK        ,   //总线锁信号
    output  wire    [3:0]   M_AXI_ARCACHE       ,   //内存类型,表明一次传输是怎么通过系统的
    output  wire    [2:0]   M_AXI_ARPROT        ,   //保护类型,表明一次传输的特权级及安全等级
    output  wire    [3:0]   M_AXI_ARQOS         ,   //质量服务QOS
    output  wire            M_AXI_ARVALID       ,   //有效信号,表明此通道的地址控制信号有效
    input   wire            M_AXI_ARREADY       ,   //表明从机可以接收地址和对应的控制信号
    //读数据通道变量                                
    input   wire    [3:0]   M_AXI_RID           ,   //读ID   TAG
    input   wire    [63:0]  M_AXI_RDATA         ,   //读数据
    input   wire    [7:0]   M_AXI_RRESP         ,   //读响应,表明读传输的状态
    input   wire            M_AXI_RLAST         ,   //表明读突发的最后一次传输
    input   wire            M_AXI_RVALID        ,   //表明此通道信号有效
    output  wire            M_AXI_RREADY        ,   //表明主机能够接收读数据和响应信号
    //用户端接口变量       
    input   wire            RD_START            ,   //读突发触发信号
    input   wire    [31:0]  RD_ADDR             ,   //地址
    input   wire    [7:0]   RD_LEN              ,   //读长度
    output  wire            RD_READY            ,   //读空闲
    output  wire            RD_FIFO_RE          ,   //连接到FIFO的读使能
    output  wire    [63:0]  RD_FIFO_DATA        ,   //连接到FIFO的读数据
    output  wire            RD_BURAST_FINISH        //完成一次突发
       
);

reg     [5:0]   RD_STATE    ;
reg     [31:0]  araddr_reg  ;
reg             arvalid_reg ;

localparam S0_RA_IDLE   =   6'b00_0001;
localparam S1_RA_WAIT   =   6'b00_0010;
localparam S2_RA_ADDR   =   6'b00_0100;
localparam S3_RD_WAIT   =   6'b00_1000;
localparam S4_RD_PROC   =   6'b01_0000;
localparam S5_RD_DONE   =   6'b10_0000;

assign M_AXI_ARID       =   4'b1111                     ; 
assign M_AXI_ARADDR     =   araddr_reg                  ;
assign M_AXI_ARLEN      =   RD_LEN - 8'd1               ;   
assign M_AXI_ARSIZE     =   3'b011                      ;   //表明AXI总线每个数据宽度是8字节,64位   
assign M_AXI_ARBURST    =   2'b01                       ;   
assign M_AXI_ARLOCK     =   1'd0                        ;   
assign M_AXI_ARCACHE    =   4'b0011                     ;   
assign M_AXI_ARPROT     =   3'b000                      ;   
assign M_AXI_ARQOS      =   4'b0000                     ;   
assign M_AXI_ARVALID    =   arvalid_reg                 ;
   
assign M_AXI_RREADY     =   M_AXI_RVALID                ;
assign RD_READY         =   (RD_STATE == S0_RA_IDLE)    ;
assign RD_FIFO_RE       =   M_AXI_RVALID                ;
assign RD_FIFO_DATA     =   M_AXI_RDATA                 ;
assign RD_BURAST_FINISH =   (RD_STATE == S5_RD_DONE)    ;

always@(posedge ACLK or negedge ARESETN)
    if(!ARESETN)begin
        RD_STATE    <= S0_RA_IDLE;
        araddr_reg  <= 32'd0;
        arvalid_reg <= 1'd0;
    end
    else begin
        case(RD_STATE)
            S0_RA_IDLE :begin
                arvalid_reg <= 1'd0;
                if(RD_START)begin
                    RD_STATE <= S1_RA_WAIT;
                    araddr_reg <= RD_ADDR;
                end        
            end
            S1_RA_WAIT:begin           
                RD_STATE <= S2_RA_ADDR;
            end
            S2_RA_ADDR:begin
                RD_STATE <= S3_RD_WAIT;
                arvalid_reg <= 1'd1;
            end
            S3_RD_WAIT:begin
                if(M_AXI_ARREADY)begin
                    RD_STATE <= S4_RD_PROC;
                    arvalid_reg <= 1'd0;
                end
            end
            S4_RD_PROC:begin
                if(M_AXI_RREADY)begin
                    if(M_AXI_RLAST)
                        RD_STATE <= S5_RD_DONE;
                end                    
            end
            S5_RD_DONE:begin
                RD_STATE <= S0_RA_IDLE;
            end
            default: RD_STATE <= S0_RA_IDLE;
        endcase
    end

endmodule

(6)AXI控制模块代码及FIFO配置:

module axi_ctrl
(
    input   wire                ui_clk          ,       //时钟
    input   wire                ui_rst          ,       //复位,高电平有效
    input   wire                pingpang        ,       //是否进行乒乓操作,1表示进行,0表示不进行
    //写FIFO
    input   wire    [31:0]      wr_b_addr       ,       //写操作起始地址
    input   wire    [31:0]      wr_e_addr       ,       //写操作结束地址
    input   wire                wr_clk          ,       //写时钟
    input   wire                data_wren       ,       //数据开始写入使能
    input   wire    [63:0]      data_wr         ,       //写入数据
    input   wire                wr_rst          ,       //写复位
    //读FIFO
    input   wire    [31:0]      rd_b_addr       ,       //读操作起始地址
    input   wire    [31:0]      rd_e_addr       ,       //读操作结束地址
    input   wire                rd_clk          ,       //读时钟
    input   wire                data_rden       ,       //数据开始读出使能
    output  wire    [63:0]      data_rd         ,       //读数据
    input   wire                rd_rst          ,       //读复位
    input   wire                read_enable     ,       //确保可以开始读的信号
    output  wire                rd_data_valid   ,       //读数据有效信号
    //DDR3写
    output  wire                wr_burst_req    ,       //写突发触发信号
    output  wire    [31:0]      wr_burst_addr   ,       //写突发地址
    output  wire    [7:0]       wr_burst_len    ,       //写突发长度
    input   wire                wr_ready        ,       //写空闲
    input   wire                wr_fifo_re      ,       //连接到写fifo的读使能
    output  wire    [63:0]      wr_fifo_data    ,       //连接到写fifo的读数据
    input   wire                wr_burst_finish ,       //完成一次突发
    //DDR3读
    output  wire                rd_burst_req    ,       //读突发触发信号
    output  wire    [31:0]      rd_burst_addr   ,       //读突发地址
    output  wire    [7:0]       rd_burst_len    ,       //读突发长度
    input   wire                rd_ready        ,       //读空闲
    input   wire                rd_fifo_re      ,       //连接到读fifo的写使能
    input   wire    [63:0]      rd_fifo_data    ,       //连接到读fifo的写数据
    input   wire                rd_burst_finish         //完成一次突发
);

parameter MAX_DDR_WR_LEN    =   10'd128 ;   //写突发长度     128个64bit
parameter MAX_DDR_RD_LEN    =   10'd128 ;   //读突发长度     128个64bit

reg             wr_burst_req_reg        ;
reg     [31:0]  wr_burst_addr_reg       ;
reg             rd_burst_req_reg        ;
reg     [31:0]  rd_burst_addr_reg       ;
reg             pingpang_reg            ;

//写fifo
wire            wr_fifo_wr_clk          ; 
wire            wr_fifo_wr_rst          ; 
wire            wr_fifo_rd_clk          ; 
wire            wr_fifo_rd_rst          ; 
wire    [15:0]  wr_fifo_din             ; 
wire            wr_fifo_wr_en           ; 
wire            wr_fifo_rd_en           ; 
wire    [63:0]  wr_fifo_dout            ; 
wire            wr_ffifo_full           ; 
wire            wr_fifo_almost_full     ; 
wire            wr_fifo_empty           ; 
wire            wr_fifo_almost_empty    ; 
wire    [9:0]   wr_fifo_rd_data_count   ; 
wire    [11:0]  wr_fifo_wr_data_count   ; 
//读fifo
wire            rd_fifo_wr_clk          ;
wire            rd_fifo_wr_rst          ;
wire            rd_fifo_rd_clk          ;
wire            rd_fifo_rd_rst          ;
wire    [63:0]  rd_fifo_din             ;
wire            rd_fifo_wr_en           ;
wire            rd_fifo_rd_en           ;
wire    [15:0]  rd_fifo_dout            ;
wire            rd_fifo_full            ;
wire            rd_fifo_almost_full     ;
wire            rd_fifo_empty           ;
wire            rd_fifo_almost_empty    ;
wire    [11:0]  rd_fifo_rd_data_count   ;
wire    [9:0]   rd_fifo_wr_data_count   ;

//端口列表中各项输出信号的赋值
assign  data_rd         = rd_fifo_dout          ;
assign  rd_data_valid   = !rd_fifo_empty        ;

assign  wr_burst_req    = wr_burst_req_reg      ;
assign  wr_burst_addr   = wr_burst_addr_reg     ;
assign  wr_burst_len    = MAX_DDR_WR_LEN        ;
assign  wr_fifo_data    = wr_fifo_dout          ;

assign  rd_burst_req    = rd_burst_req_reg      ;  
assign  rd_burst_addr   = rd_burst_addr_reg     ;  
assign  rd_burst_len    = MAX_DDR_RD_LEN        ;  

//fifo变量的赋值
assign wr_fifo_wr_clk   = wr_clk        ;
assign wr_fifo_wr_rst   = ui_rst        ;
assign wr_fifo_rd_clk   = ui_clk        ;
assign wr_fifo_rd_rst   = ui_rst        ;
assign wr_fifo_din      = data_wr[15:0] ;
assign wr_fifo_wr_en    = data_wren     ;
assign wr_fifo_rd_en    = wr_fifo_re    ;

assign rd_fifo_wr_clk   = ui_clk        ;    
assign rd_fifo_wr_rst   = ui_rst        ;    
assign rd_fifo_rd_clk   = rd_clk        ;    
assign rd_fifo_rd_rst   = ui_rst        ;    
assign rd_fifo_din      = rd_fifo_data  ;    
assign rd_fifo_wr_en    = rd_fifo_re    ;      
assign rd_fifo_rd_en    = data_rden     ;    

always@(posedge ui_clk  or posedge ui_rst)
    if(ui_rst)
        wr_burst_req_reg <= 1'd0;
    else if(((wr_fifo_rd_data_count + 10'd2)>= MAX_DDR_WR_LEN) && (wr_ready))
        wr_burst_req_reg <= 1'd1;
    else 
        wr_burst_req_reg <= 1'd0;
        
always@(posedge ui_clk or posedge ui_rst)
    if(ui_rst)begin
        wr_burst_addr_reg <= wr_b_addr  ;
        pingpang_reg <= 1'd0;
    end
    else if(wr_burst_finish)begin
        wr_burst_addr_reg <= wr_burst_addr_reg + (MAX_DDR_WR_LEN << 3);     //64bit = 8 字节  而DDR一个地址存储1字节数据
        if(pingpang)begin
            if(wr_burst_addr_reg >= (((wr_e_addr - wr_b_addr) << 1) + wr_b_addr - (MAX_DDR_WR_LEN << 3)))
                wr_burst_addr_reg <= wr_b_addr;
            if(wr_burst_addr_reg < wr_e_addr)
                pingpang_reg <= 1'd0;
            else 
                pingpang_reg <= 1'd1;
        end
        else begin
            if(wr_burst_addr_reg >= wr_e_addr - (MAX_DDR_WR_LEN << 3))
                wr_burst_addr_reg <= wr_b_addr;
        end
    end
    else    
        wr_burst_addr_reg <= wr_burst_addr_reg;
        
always@(posedge ui_clk or posedge ui_rst)
    if(ui_rst)
        rd_burst_req_reg <= 1'd0;
    else if((rd_fifo_wr_data_count <= (10'd1000 - MAX_DDR_RD_LEN)) && rd_ready && read_enable)
        rd_burst_req_reg <= 1'd1;
    else 
        rd_burst_req_reg <= 1'd0;
       
always@(posedge ui_clk or posedge ui_rst)
    if(ui_rst)begin
        if(pingpang)
            rd_burst_addr_reg <= rd_e_addr;
        else 
            rd_burst_addr_reg <= rd_b_addr;
    end
    else if(rd_burst_finish)begin
        rd_burst_addr_reg <= rd_burst_addr_reg + (MAX_DDR_RD_LEN << 3);
        if(pingpang)begin
            if((rd_burst_addr_reg == (rd_e_addr - (MAX_DDR_RD_LEN << 3)))
            ||(rd_burst_addr_reg == (((rd_e_addr - rd_b_addr) << 1) + rd_b_addr - (MAX_DDR_RD_LEN << 3))))begin
                if(pingpang_reg)
                    rd_burst_addr_reg <= rd_b_addr;
                else 
                    rd_burst_addr_reg <= rd_e_addr;
            end
        end
        else begin
            if(rd_burst_addr_reg >= rd_e_addr - (MAX_DDR_RD_LEN << 3))
                rd_burst_addr_reg <= rd_b_addr;
        end
    end
    else 
        rd_burst_addr_reg <= rd_burst_addr_reg;
    
wr_fifo     wr_fifo_inst 
(
    .wr_clk         (wr_fifo_wr_clk         ),        
    .wr_rst         (wr_fifo_wr_rst         ),        
    .rd_clk         (wr_fifo_rd_clk         ),        
    .rd_rst         (wr_fifo_rd_rst         ),        
    .din            (wr_fifo_din            ),           
    .wr_en          (wr_fifo_wr_en          ),         
    .rd_en          (wr_fifo_rd_en          ),         
    .dout           (wr_fifo_dout           ),          
    .full           (wr_ffifo_full          ),          
    .almost_full    (wr_fifo_almost_full    ),   
    .empty          (wr_fifo_empty          ),         
    .almost_empty   (wr_fifo_almost_empty   ),  
    .rd_data_count  (wr_fifo_rd_data_count  ), 
    .wr_data_count  (wr_fifo_wr_data_count  )  
);

rd_fifo     rd_fifo_inst 
(
    .wr_clk         (rd_fifo_wr_clk         ),          
    .wr_rst         (rd_fifo_wr_rst         ),          
    .rd_clk         (rd_fifo_rd_clk         ),          
    .rd_rst         (rd_fifo_rd_rst         ),          
    .din            (rd_fifo_din            ),             
    .wr_en          (rd_fifo_wr_en          ),           
    .rd_en          (rd_fifo_rd_en          ),           
    .dout           (rd_fifo_dout           ),            
    .full           (rd_fifo_full           ),            
    .almost_full    (rd_fifo_almost_full    ),     
    .empty          (rd_fifo_empty          ),           
    .almost_empty   (rd_fifo_almost_empty   ),    
    .rd_data_count  (rd_fifo_rd_data_count  ),  
    .wr_data_count  (rd_fifo_wr_data_count  )  
);

endmodule

(7)ddr3顶层文件代码:

module axi_ddr3_top
(
    input   wire                ddr3_clk            ,
    input   wire                reset_n             ,
    input   wire                pingpang            ,
    output  wire                ui_clk              ,
    output  wire                ui_rst              ,
    //写FIFO
    input   wire    [31:0]      wr_b_addr           ,
    input   wire    [31:0]      wr_e_addr           ,
    input   wire                wr_clk              ,
    input   wire                data_wren           ,
    input   wire    [63:0]      data_wr             ,
    input   wire                wr_rst              ,
    //读FIFO
    input   wire    [31:0]      rd_b_addr           ,
    input   wire    [31:0]      rd_e_addr           ,
    input   wire                rd_clk              ,
    input   wire                data_rden           ,
    output  wire    [63:0]      data_rd             ,
    input   wire                rd_rst              ,
    input   wire                read_enable         ,
    output  wire                rd_data_valid       ,
    //DDR3物理接口
    output  wire    [14:0]		ddr3_addr           ,
    output  wire    [2:0]		ddr3_ba             ,
    output  wire    			ddr3_cas_n          ,
    output  wire    		    ddr3_ck_n           ,
    output  wire    		    ddr3_ck_p           ,
    output  wire    		    ddr3_cke            ,
    output  wire    			ddr3_ras_n          ,
    output  wire    			ddr3_reset_n        ,
    output  wire    			ddr3_we_n           ,
    inout   wire    [31:0]		ddr3_dq             ,
    inout   wire    [3:0]		ddr3_dqs_n          ,
    inout   wire    [3:0]		ddr3_dqs_p          ,
    output  wire    			init_calib_complete ,
    output  wire        		ddr3_cs_n           ,
    output  wire    [3:0]		ddr3_dm             ,
    output  wire        		ddr3_odt            
    
);

//写地址通道
wire    [3:0]               M_AXI_AWID              ;  
wire    [31:0]              M_AXI_AWADDR            ;  
wire    [7:0]               M_AXI_AWLEN             ;  
wire    [2:0]               M_AXI_AWSIZE            ;  
wire    [1:0]               M_AXI_AWBURST           ;  
wire                        M_AXI_AWLOCK            ;  
wire    [3:0]               M_AXI_AWCACHE           ;  
wire    [2:0]               M_AXI_AWPROT            ;  
wire    [3:0]               M_AXI_AWQOS             ;  
wire                        M_AXI_AWVALID           ;  
wire                        M_AXI_AWREADY           ;  
//写数据通道
wire     [63:0]             M_AXI_WDATA             ;
wire     [7:0]              M_AXI_WSTRB             ;
wire                        M_AXI_WLAST             ;
wire                        M_AXI_WVALID            ;
wire                        M_AXI_WREADY            ;
//写响应通道
wire     [3:0]              M_AXI_BID               ; 
wire     [1:0]              M_AXI_BRESP             ; 
wire                        M_AXI_BVALID            ; 
wire                        M_AXI_BREADY            ; 
//读地址通道
wire     [3:0]              M_AXI_ARID              ;   
wire     [31:0]             M_AXI_ARADDR            ;   
wire     [7:0]              M_AXI_ARLEN             ;   
wire     [2:0]              M_AXI_ARSIZE            ;   
wire     [1:0]              M_AXI_ARBURST           ;   
wire                        M_AXI_ARLOCK            ;   
wire     [3:0]              M_AXI_ARCACHE           ;   
wire     [2:0]              M_AXI_ARPROT            ;   
wire     [3:0]              M_AXI_ARQOS             ;   
wire                        M_AXI_ARVALID           ;   
wire                        M_AXI_ARREADY           ;   
//读数据通道
wire     [3:0]              M_AXI_RID               ;  
wire     [63:0]             M_AXI_RDATA             ;  
wire     [7:0]              M_AXI_RRESP             ;  
wire                        M_AXI_RLAST             ;  
wire                        M_AXI_RVALID            ;  
wire                        M_AXI_RREADY            ;  
//AXI写主机
wire                        wr_burst_req            ; 
wire     [31:0]             wr_burst_addr           ; 
wire     [7:0]              wr_burst_len            ; 
wire                        wr_ready                ; 
wire                        wr_fifo_re              ; 
wire     [63:0]             wr_fifo_data            ; 
wire                        wr_burst_finish         ; 
//AXI读主机
wire                        rd_burst_req            ;
wire     [31:0]             rd_burst_addr           ;
wire     [7:0]              rd_burst_len            ;
wire                        rd_ready                ;
wire                        rd_fifo_re              ;
wire     [63:0]             rd_fifo_data            ;
wire                        rd_burst_finish         ;

axi_mig     axi_mig_inst
(
    .ddr3_addr                      (ddr3_addr          ),                      
    .ddr3_ba                        (ddr3_ba            ),                        
    .ddr3_cas_n                     (ddr3_cas_n         ),                     
    .ddr3_ck_n                      (ddr3_ck_n          ),                      
    .ddr3_ck_p                      (ddr3_ck_p          ),                      
    .ddr3_cke                       (ddr3_cke           ),                       
    .ddr3_ras_n                     (ddr3_ras_n         ),                     
    .ddr3_reset_n                   (ddr3_reset_n       ),                   
    .ddr3_we_n                      (ddr3_we_n          ),                      
    .ddr3_dq                        (ddr3_dq            ),                        
    .ddr3_dqs_n                     (ddr3_dqs_n         ),                     
    .ddr3_dqs_p                     (ddr3_dqs_p         ),                     
    .init_calib_complete            (init_calib_complete),            
	.ddr3_cs_n                      (ddr3_cs_n          ),                      
    .ddr3_dm                        (ddr3_dm            ),                        
    .ddr3_odt                       (ddr3_odt           ),                       
    // Application interface ports
    .ui_clk                         (ui_clk             ),                         
    .ui_clk_sync_rst                (ui_rst             ),                         
    .mmcm_locked                    (),                               
    .aresetn                        (reset_n            ),                        
    .app_sr_req                     (1'd0               ),                           
    .app_ref_req                    (1'd0               ),                           
    .app_zq_req                     (1'd0               ),                           
    .app_sr_active                  (),                               
    .app_ref_ack                    (),                               
    .app_zq_ack                     (),                               
    // Slave Interface Write Address Ports      写地址通道
    .s_axi_awid                     (M_AXI_AWID         ),  
    .s_axi_awaddr                   (M_AXI_AWADDR       ),  
    .s_axi_awlen                    (M_AXI_AWLEN        ),  
    .s_axi_awsize                   (M_AXI_AWSIZE       ),  
    .s_axi_awburst                  (M_AXI_AWBURST      ),  
    .s_axi_awlock                   (M_AXI_AWLOCK       ),  
    .s_axi_awcache                  (M_AXI_AWCACHE      ),  
    .s_axi_awprot                   (M_AXI_AWPROT       ),  
    .s_axi_awqos                    (M_AXI_AWQOS        ),  
    .s_axi_awvalid                  (M_AXI_AWVALID      ),  
    .s_axi_awready                  (M_AXI_AWREADY      ),  
    // Slave Interface Write Data Ports         写数据通道
    .s_axi_wdata                    (M_AXI_WDATA        ), 
    .s_axi_wstrb                    (M_AXI_WSTRB        ), 
    .s_axi_wlast                    (M_AXI_WLAST        ), 
    .s_axi_wvalid                   (M_AXI_WVALID       ), 
    .s_axi_wready                   (M_AXI_WREADY       ), 
    // Slave Interface Write Response Ports     写响应通道
    .s_axi_bid                      (M_AXI_BID          ),  
    .s_axi_bresp                    (M_AXI_BRESP        ),  
    .s_axi_bvalid                   (M_AXI_BVALID       ),  
    .s_axi_bready                   (M_AXI_BREADY       ),  
    // Slave Interface Read Address Ports       读地址通道
    .s_axi_arid                     (M_AXI_ARID         ), 
    .s_axi_araddr                   (M_AXI_ARADDR       ), 
    .s_axi_arlen                    (M_AXI_ARLEN        ), 
    .s_axi_arsize                   (M_AXI_ARSIZE       ), 
    .s_axi_arburst                  (M_AXI_ARBURST      ), 
    .s_axi_arlock                   (M_AXI_ARLOCK       ), 
    .s_axi_arcache                  (M_AXI_ARCACHE      ), 
    .s_axi_arprot                   (M_AXI_ARPROT       ), 
    .s_axi_arqos                    (M_AXI_ARQOS        ), 
    .s_axi_arvalid                  (M_AXI_ARVALID      ), 
    .s_axi_arready                  (M_AXI_ARREADY      ), 
    // Slave Interface Read Data Ports          读数据通道
    .s_axi_rid                      (M_AXI_RID          ), 
    .s_axi_rdata                    (M_AXI_RDATA        ), 
    .s_axi_rresp                    (M_AXI_RRESP        ), 
    .s_axi_rlast                    (M_AXI_RLAST        ), 
    .s_axi_rvalid                   (M_AXI_RVALID       ), 
    .s_axi_rready                   (M_AXI_RREADY       ), 
    // System Clock Ports
    .sys_clk_i                      (ddr3_clk           ),
    // Reference Clock Ports
    .clk_ref_i                      (ddr3_clk           ),
    .sys_rst                        (reset_n            ) 
);

axi_ctrl    axi_ctrl_inst
(
    .ui_clk          (ui_clk            ),       //时钟
    .ui_rst          (ui_rst            ),       //复位,高电平有效
    .pingpang        (pingpang          ),       //是否进行乒乓操作,1表示进行,0表示不进行
    
    .wr_b_addr       (wr_b_addr         ),       //写操作起始地址
    .wr_e_addr       (wr_e_addr         ),       //写操作结束地址
    .wr_clk          (wr_clk            ),       //写时钟
    .data_wren       (data_wren         ),       //数据开始写入使能
    .data_wr         (data_wr           ),       //写入数据
    .wr_rst          (wr_rst            ),       //写复位

    .rd_b_addr       (rd_b_addr         ),       //读操作起始地址
    .rd_e_addr       (rd_e_addr         ),       //读操作结束地址
    .rd_clk          (rd_clk            ),       //读时钟
    .data_rden       (data_rden         ),       //数据开始读出使能
    .data_rd         (data_rd           ),       //读数据
    .rd_rst          (rd_rst            ),       //读复位
    .read_enable     (read_enable       ),       //确保可以开始读的信号
    .rd_data_valid   (rd_data_valid     ),       //读数据有效信号

    .wr_burst_req    (wr_burst_req      ),       //写突发触发信号
    .wr_burst_addr   (wr_burst_addr     ),       //写突发地址
    .wr_burst_len    (wr_burst_len      ),       //写突发长度
    .wr_ready        (wr_ready          ),       //写空闲
    .wr_fifo_re      (wr_fifo_re        ),       //连接到写fifo的读使能
    .wr_fifo_data    (wr_fifo_data      ),       //连接到写fifo的读数据
    .wr_burst_finish (wr_burst_finish   ),       //完成一次突发

    .rd_burst_req    (rd_burst_req      ),       //读突发触发信号
    .rd_burst_addr   (rd_burst_addr     ),       //读突发地址
    .rd_burst_len    (rd_burst_len      ),       //读突发长度
    .rd_ready        (rd_ready          ),       //读空闲
    .rd_fifo_re      (rd_fifo_re        ),       //连接到读fifo的写使能
    .rd_fifo_data    (rd_fifo_data      ),       //连接到读fifo的写数据
    .rd_burst_finish (rd_burst_finish   )        //完成一次突发
);

axi_master_write    axi_master_write_inst
(

    .ACLK                (ui_clk            ),           //全局时钟
    .ARESETN             (~ui_rst           ),           //全局复位
                     
    .M_AXI_AWID          (M_AXI_AWID        ),           //写地址ID         用来标记一组写信号
    .M_AXI_AWADDR        (M_AXI_AWADDR      ),           //写地址           给出一次写突发传输的写地址
    .M_AXI_AWLEN         (M_AXI_AWLEN       ),           //突出长度         
    .M_AXI_AWSIZE        (M_AXI_AWSIZE      ),           //突出大小          给出每次突发传输的字节数
    .M_AXI_AWBURST       (M_AXI_AWBURST     ),           //突发类型
    .M_AXI_AWLOCK        (M_AXI_AWLOCK      ),           //总线锁信号
    .M_AXI_AWCACHE       (M_AXI_AWCACHE     ),           //内存类型,表明一次传输是怎么通过系统的
    .M_AXI_AWPROT        (M_AXI_AWPROT      ),           //保护类型,表明一次传输的特权级及安全等级
    .M_AXI_AWQOS         (M_AXI_AWQOS       ),           //质量服务QOS
    .M_AXI_AWVALID       (M_AXI_AWVALID     ),           //有效信号,表明此通道的地址控制信号有效
    .M_AXI_AWREADY       (M_AXI_AWREADY     ),           //表明从机可以接收地址和对应的控制信号
                      
    .M_AXI_WDATA         (M_AXI_WDATA       ),           //写数据
    .M_AXI_WSTRB         (M_AXI_WSTRB       ),           //写数据有效字节数
    .M_AXI_WLAST         (M_AXI_WLAST       ),           //表明此次传输的最后一个突发传输
    .M_AXI_WVALID        (M_AXI_WVALID      ),           //写有效信号
    .M_AXI_WREADY        (M_AXI_WREADY      ),           //表明从机可以接收写数据
                     
    .M_AXI_BID           (M_AXI_BID         ),           //写响应ID TAG
    .M_AXI_BRESP         (M_AXI_BRESP       ),           //写响应,表明写传输的状态
    .M_AXI_BVALID        (M_AXI_BVALID      ),           //写响应有效
    .M_AXI_BREADY        (M_AXI_BREADY      ),           //表明主机可以接收写响应信号
                     
    .WR_START            (wr_burst_req      ),           //写突发触发信号
    .WR_ADDR             (wr_burst_addr     ),           //地址
    .WR_LEN              (wr_burst_len      ),           //长度
    .WR_READY            (wr_ready          ),           //写空闲
    .WR_FIFO_RE          (wr_fifo_re        ),           //连接到fifo的读使能
    .WR_FIFO_DATA        (wr_fifo_data      ),           //连接到fifo的读数据
    .WR_BURAST_FINISH    (wr_burst_finish   )            //完成最后一次突发
                
);

axi_master_read     axi_master_read_inst
(
    //全局变量
    .ACLK                (ui_clk            ),   //全局时钟
    .ARESETN             (~ui_rst           ),   //全局复位
                         
    .M_AXI_ARID          (M_AXI_ARID        ),   //读地址ID     用来标志一组读信号
    .M_AXI_ARADDR        (M_AXI_ARADDR      ),   //读地址       给出一次读突发传输的读地址
    .M_AXI_ARLEN         (M_AXI_ARLEN       ),   //突发长度      给出每次突出传输的次数
    .M_AXI_ARSIZE        (M_AXI_ARSIZE      ),   //突发大小      给出每次突发传输的字节数
    .M_AXI_ARBURST       (M_AXI_ARBURST     ),   //突发类型
    .M_AXI_ARLOCK        (M_AXI_ARLOCK      ),   //总线锁信号
    .M_AXI_ARCACHE       (M_AXI_ARCACHE     ),   //内存类型,表明一次传输是怎么通过系统的
    .M_AXI_ARPROT        (M_AXI_ARPROT      ),   //保护类型,表明一次传输的特权级及安全等级
    .M_AXI_ARQOS         (M_AXI_ARQOS       ),   //质量服务QOS
    .M_AXI_ARVALID       (M_AXI_ARVALID     ),   //有效信号,表明此通道的地址控制信号有效
    .M_AXI_ARREADY       (M_AXI_ARREADY     ),   //表明从机可以接收地址和对应的控制信号
                          
    .M_AXI_RID           (M_AXI_RID         ),   //读ID   TAG
    .M_AXI_RDATA         (M_AXI_RDATA       ),   //读数据
    .M_AXI_RRESP         (M_AXI_RRESP       ),   //读响应,表明读传输的状态
    .M_AXI_RLAST         (M_AXI_RLAST       ),   //表明读突发的最后一次传输
    .M_AXI_RVALID        (M_AXI_RVALID      ),   //表明此通道信号有效
    .M_AXI_RREADY        (M_AXI_RREADY      ),   //表明主机能够接收读数据和响应信号
                         
    .RD_START            (rd_burst_req      ),   //读突发触发信号
    .RD_ADDR             (rd_burst_addr     ),   //地址
    .RD_LEN              (rd_burst_len      ),   //读长度
    .RD_READY            (rd_ready          ),   //读空闲
    .RD_FIFO_RE          (rd_fifo_re        ),   //连接到FIFO的读使能
    .RD_FIFO_DATA        (rd_fifo_data      ),   //连接到FIFO的读数据
    .RD_BURAST_FINISH    (rd_burst_finish   )    //完成一次突发
       
);

endmodule

(8)vga控制模块代码:

module vga_ctrl
(
    input   wire                vga_clk     ,
    input   wire                reset_n     ,
    input   wire    [23:0]      data_in     ,
    
    output  wire    [9:0]       hang        ,
    output  wire    [9:0]       lie         ,
    output  wire                hsync       ,
    output  wire                vsync       ,
    output  wire    [23:0]      rgb_vga     ,
    output  wire                vga_DE      
    
);

reg [10:0] hang_cnt     ;
reg [9:0]  v_cnt        ;

wire        data_valid  ; 

parameter H_SYNC    =   128     ;
parameter H_BACK    =   88      ;
parameter H_LEEF    =   0       ;
parameter H_VALID   =   800     ;
parameter H_RIGHT   =   0       ;
parameter H_FRONT   =   40      ;
parameter H_TOTAL   =   1056    ;

parameter V_SYNC    =   4       ;
parameter V_BACK    =   23      ;
parameter V_TOP     =   0       ;
parameter V_VALID   =   600     ;
parameter V_BOTTOM  =   0       ;
parameter V_FRONT   =   1       ;
parameter V_TOTAL   =   628     ;

//行计数器设计
always@(posedge vga_clk or negedge reset_n)  
    if(!reset_n)
        hang_cnt <= 11'd0;
    else if(hang_cnt == H_TOTAL - 11'd1)
        hang_cnt <= 11'd0;
    else 
        hang_cnt <= hang_cnt + 11'd1;
        
//场计数器设计
always@(posedge vga_clk or negedge reset_n)
    if(!reset_n)
        v_cnt <= 10'd0;
    else if((v_cnt == V_TOTAL - 10'd1) && (hang_cnt == H_TOTAL - 11'd1))
        v_cnt <= 10'd0;
    else if(hang_cnt == H_TOTAL - 11'd1)
        v_cnt <= v_cnt + 10'd1;
    else 
        v_cnt <= v_cnt;
        
//数据有效信号设计
assign data_valid = ((hang_cnt >= H_SYNC + H_BACK + H_LEEF) &&
                        (hang_cnt < H_SYNC + H_BACK + H_LEEF + H_VALID)&&
                        (v_cnt >= V_SYNC + V_BACK + V_TOP)&&
                        (v_cnt < V_SYNC + V_BACK + V_TOP + V_VALID));
                       
//行列信号设计
assign hang = (data_valid) ? (hang_cnt - H_SYNC - H_BACK - H_LEEF + 10'd1) : 10'd0;
assign lie  = (data_valid) ? (v_cnt - V_SYNC - V_BACK - V_TOP + 10'd1) : 10'd0;

//行同步、场同步信号设计
assign hsync = (hang_cnt >= H_SYNC);
assign vsync = (v_cnt >= V_SYNC);

//rgb_vga、vga_DE信号设计
assign rgb_vga = (data_valid) ? data_in : 24'd0;
assign vga_DE  = data_valid;

endmodule

(9)IIC控制模块代码:

module IIC_ctrl
(
    input   wire            clk         ,
    input   wire            reset_n     ,
    input   wire            IIC_start   ,
    input   wire            wr_en       ,
    input   wire            rd_en       ,
    input   wire    [7:0]   device_addr ,
    input   wire    [15:0]  byte_addr   ,
    input   wire    [7:0]   wr_data     ,
    input   wire            addr_num    ,
    
    output  reg             IIC_SCL     ,
    inout   wire            IIC_SDA     ,
    output  reg             IIC_clk     ,
    output  reg             IIC_end     ,
    output  reg     [7:0]   rd_data
    
);

reg     [4:0]       cnt_1M          ;      //系统时钟为50MHz    20ns      1M时钟对应1000ns   半个周期需要25个系统时钟
reg     [15:0]      state           ;
reg     [1:0]       IIC_clk_cnt     ;
reg                 EN_IIC_clk_cnt  ;
reg     [2:0]       bit_cnt         ;
reg                 ack             ;
reg                 sda_out         ;
reg     [7:0]       rd_data_reg     ;

wire                sda_in          ;
wire                EN_IIC_SDA      ;
wire    [6:0]       device_addr_i   ;

assign device_addr_i = device_addr[7:1];

parameter IDLE        =  16'b0000_0000_0000_0001    ;       //空闲状态
parameter START       =  16'b0000_0000_0000_0010    ;       //发送开始信号
parameter SEND_D_A    =  16'b0000_0000_0000_0100    ;       //发送控制命令(器件地址+写操作)   {7'b1010_011,1'b0}
parameter ACK_1       =  16'b0000_0000_0000_1000    ;       //等待响应 
parameter SEND_B_H    =  16'b0000_0000_0001_0000    ;       //发送存储地址高8位  
parameter ACK_2       =  16'b0000_0000_0010_0000    ;       //等待响应
parameter SEND_B_L    =  16'b0000_0000_0100_0000    ;       //发送存储地址低8位
parameter ACK_3       =  16'b0000_0000_1000_0000    ;       //等待响应
parameter WR_DATA     =  16'b0000_0001_0000_0000    ;       //写入单比特数据   
parameter ACK_4       =  16'b0000_0010_0000_0000    ;       //等待响应
parameter START_2     =  16'b0000_0100_0000_0000    ;       //发送开始信号
parameter SEND_RD_A   =  16'b0000_1000_0000_0000    ;       //发送控制命令(器件地址+读操作)   {7'b0101_011,1'b1} 
parameter ACK_5       =  16'b0001_0000_0000_0000    ;       //等待响应
parameter RD_DATA     =  16'b0010_0000_0000_0000    ;       //读出单比特数据
parameter NO_ACK      =  16'b0100_0000_0000_0000    ;       //等待无响应信号
parameter END         =  16'b1000_0000_0000_0000    ;       //结束单比特传输

/*--------IIC_clk生成模块---------*/
always@(posedge clk or negedge reset_n)
    if(!reset_n)
        cnt_1M <= 5'd0;
    else if(cnt_1M == 5'd24)
        cnt_1M <= 5'd0;
    else 
        cnt_1M <= cnt_1M + 5'd1;
        
always@(posedge clk or negedge reset_n)
    if(!reset_n)
        IIC_clk <= 1'd0;
    else if(cnt_1M == 5'd24)
        IIC_clk <= ~IIC_clk;
    else 
        IIC_clk <= IIC_clk;
        
/*---------状态机设计---------*/
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        state <= IDLE   ;
    else begin
        case(state)
            IDLE:begin
                if(IIC_start)
                    state <= START;
                else 
                    state <= state;
            end
            START:begin
                if(IIC_clk_cnt == 2'd3)
                    state <= SEND_D_A;
                else 
                    state <= state;
            end
            SEND_D_A:begin
                if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
                    state <= ACK_1;
                else 
                    state <= state;
            end
            ACK_1:begin
                if((IIC_clk == 2'd3) && (ack == 1'd0) && (addr_num == 1'd1))
                    state <= SEND_B_H;
                else if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) && (addr_num == 1'd0))
                    state <= SEND_B_L;
                else 
                    state <= state;
            end
            SEND_B_H:begin
                if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
                    state <= ACK_2;
                else 
                    state <= state;
            end
            ACK_2:begin
                if((IIC_clk_cnt == 2'd3) && (ack == 1'd0))
                    state <= SEND_B_L;
                else 
                    state <= state;
            end
            SEND_B_L:begin
                if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
                    state <= ACK_3;
                else
                    state <= state;            
            end
            ACK_3:begin
                if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) && (wr_en == 1'd1))
                    state <= WR_DATA;
                else if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) && (rd_en == 1'd1))
                    state <= START_2;
                else 
                    state <= state;            
            end
            WR_DATA:begin
                if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
                    state <= ACK_4;
                else 
                    state <= state;
            end
            ACK_4:begin
                if((IIC_clk_cnt == 2'd3) && (ack == 1'd0))
                    state <= END;
                else 
                    state <= state;
            end
            START_2:begin
                if(IIC_clk_cnt == 2'd3)
                    state <= SEND_RD_A;
                else 
                    state <= state;
            end
            SEND_RD_A:begin
                if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
                    state <= ACK_5;
                else 
                    state <= state;
            end
            ACK_5:begin
                if((IIC_clk_cnt == 2'd3) && (ack == 1'd0))
                    state <= RD_DATA;
                else 
                    state <= state;            
            end
            RD_DATA:begin
                if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
                    state <= NO_ACK;
                else 
                    state <= state;
            end
            NO_ACK:begin
                if(IIC_clk_cnt == 2'd3)
                    state <= END;
                else 
                    state <= state;
            end
            END:begin
                if((bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))
                    state <= IDLE;
                else 
                    state <= state;
            end
            default: state <= IDLE;
        endcase
    end

/*---------EN_IIC_clk_cnt 、 IIC_clk_cnt--------*/
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        EN_IIC_clk_cnt <= 1'd0;
    else if((state == END) && (bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))
        EN_IIC_clk_cnt <= 1'd0;
    else if(IIC_start)
        EN_IIC_clk_cnt <= 1'd1;
    else 
        EN_IIC_clk_cnt <= EN_IIC_clk_cnt;
        
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        IIC_clk_cnt <= 2'd0;
    else if(!EN_IIC_clk_cnt)
        IIC_clk_cnt <= 2'd0;
    else 
        IIC_clk_cnt <= IIC_clk_cnt + 2'd1;
        
/*-------------bit_cnt--------*/
always@(posedge IIC_clk or negedge reset_n)  
    if(!reset_n)
        bit_cnt <= 3'd0;
    else if((state == IDLE) || (state == START) || (state == ACK_1)
            ||(state == ACK_2) || (state == ACK_3) || (state == ACK_4)
            ||(state == START_2) || (state == ACK_5) || (state == NO_ACK))
        bit_cnt <= 3'd0;
    else if((state == END) && (bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))
        bit_cnt <= 3'd0;
    else if(IIC_clk_cnt == 2'd3)
        bit_cnt <= bit_cnt + 3'd1;
    else 
        bit_cnt <= bit_cnt;
    
/*--------ack 、 sda_in -----------*/
always@(*)
    begin
        case(state)
            ACK_1,ACK_2,ACK_3,ACK_4,ACK_5 : if(IIC_clk_cnt == 2'd0)
                                                ack <= sda_in;
                                            else 
                                                ack <= ack;
            default                       : ack <= 1'd1;
        endcase
    end
    
assign sda_in = IIC_SDA ; 

/*------------IIC_SCL---------*/
always@(*)
    begin
        case(state)
            IDLE:
                    IIC_SCL <= 1'd1;
            START:
                    if(IIC_clk_cnt == 2'd3)
                        IIC_SCL <= 1'd0;
                    else 
                        IIC_SCL <= 1'd1;
            SEND_D_A,ACK_1,SEND_B_H,ACK_2,SEND_B_L,ACK_3,WR_DATA,
                ACK_4,START_2,SEND_RD_A,ACK_5,RD_DATA,NO_ACK:
                    if((IIC_clk_cnt == 2'd1) || (IIC_clk_cnt == 2'd2))
                        IIC_SCL <= 1'd1;
                    else 
                        IIC_SCL <= 1'd0;
            END:
                    if((bit_cnt == 3'd0) && (IIC_clk_cnt == 2'd0))
                        IIC_SCL <= 1'd0;
                    else 
                        IIC_SCL <= 1'd1;
            default: IIC_SCL <= 1'd1;
        endcase    
    end
    
/*----------sda_out 、 rd_data_reg----------*/
always@(*)
    begin
        case(state)
            IDLE:begin
                sda_out <= 1'd1;
                rd_data_reg <= 8'd0;
            end
            START:begin
                if(IIC_clk_cnt >= 2'd1)
                    sda_out <= 1'd0;
                else 
                    sda_out <= 1'd1;
           
            end
            SEND_D_A:begin
                if(bit_cnt <= 3'd6)
                    sda_out <= device_addr_i[6 - bit_cnt];
                else 
                    sda_out <= 1'd0;
            end
            ACK_1,ACK_2,ACK_3,ACK_4,ACK_5:begin
                sda_out <= 1'd1;
            end
            SEND_B_H:
                sda_out <= byte_addr[15 - bit_cnt];
            SEND_B_L:
                sda_out <= byte_addr[7 - bit_cnt];
            WR_DATA:
                sda_out <= wr_data[7 - bit_cnt];
            START_2:
                if(IIC_clk_cnt >= 2'd2)
                    sda_out <= 1'd0;
                else 
                    sda_out <= 1'd1;
            SEND_RD_A:
                if(bit_cnt <= 3'd6)
                    sda_out <= device_addr_i[6 - bit_cnt];
                else 
                    sda_out <= 1'd1;
            RD_DATA:begin
                sda_out <= 1'd1;
                if(IIC_clk_cnt == 2'd2)
                    rd_data_reg[7 - bit_cnt] <= sda_in;
                else 
                    rd_data_reg <= rd_data_reg;           
            end
            NO_ACK:
                sda_out <= 1'd1;
            END:begin
                if((bit_cnt == 3'd0) && (IIC_clk_cnt <= 2'd2))
                    sda_out <= 1'd0;
                else 
                    sda_out <= 1'd1;
            end
            default:begin
                sda_out <= 1'd1;
                rd_data_reg <= rd_data_reg;
            end
        endcase
    end
    
/*-----------rd_data-------*/
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        rd_data <= 8'd0;
    else if((state == RD_DATA)  && (bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))
        rd_data <= rd_data_reg;
    else 
        rd_data <= rd_data;
        
/*--------------------EN_IIC_SDA-----------------------*/ 
//EN_IIC_SDA信号为1,表示IIC_SDA输出;反之,EN_IIC_SDA信号为0,表示IIC_SDA作为输入.

assign EN_IIC_SDA = ((state == IDLE) || (state == START) || (state == SEND_D_A) 
                        || (state == SEND_B_H) || (state == SEND_B_L) || (state == WR_DATA)
                        || (state == START_2) || (state == SEND_RD_A) || (state == NO_ACK)
                        || (state == END));
    
/*--------------------IIC_SDA-----------------------*/ 
assign IIC_SDA = EN_IIC_SDA ? sda_out : 1'dz;

/*--------------------IIC_end设计-----------------------*/ 
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        IIC_end <= 1'd0;
    else if((state == END) && (bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))
        IIC_end <= 1'd1;
    else 
        IIC_end <= 1'd0;    
    
endmodule

(10)hdmi芯片寄存器配置模块及hdmi_iic顶层代码:

module hdmi_cfg
(
    input   wire                cfg_clk     ,
    input   wire                reset_n     ,
    input   wire                cfg_end     ,
    
    output  reg                 cfg_start   ,
    output  wire    [31:0]      cfg_data    ,
    output  reg                 cfg_done    
    
);

parameter NUM_REG           =   10'd4;
parameter CNT_WAIT_MAX      =   10'd1023;

reg     [9:0]   cnt_wait    ;
reg     [9:0]   cnt_num     ;

wire    [31:0]  cfg_data_reg[NUM_REG - 1 : 0];

assign cfg_data_reg[0] = {8'h72,16'h08,8'h35};
assign cfg_data_reg[1] = {8'h72,16'h49,8'h00};
assign cfg_data_reg[2] = {8'h72,16'h4a,8'h00};
assign cfg_data_reg[3] = {8'h72,16'h2f,8'h00};

always@(posedge cfg_clk or negedge reset_n)
    if(!reset_n)
        cnt_wait <= 10'd0;
    else if(cnt_wait == CNT_WAIT_MAX)
        cnt_wait <= cnt_wait;
    else 
        cnt_wait <= cnt_wait + 10'd1;
        
always@(posedge cfg_clk or negedge reset_n)
    if(!reset_n)
        cnt_num <= 10'd0;
    else if(cfg_end)
        cnt_num <= cnt_num + 10'd1;
    else 
        cnt_num <= cnt_num;
        
always@(posedge cfg_clk or negedge reset_n)
    if(!reset_n)
        cfg_start <= 1'd0;
    else if(cnt_wait == CNT_WAIT_MAX - 1)
        cfg_start <= 1'd1;
    else if(cfg_end == 1'd1 && cnt_num < NUM_REG)
        cfg_start <= 1'd1;
    else 
        cfg_start <= 1'd0;

always@(posedge cfg_clk or negedge reset_n)
    if(!reset_n)
        cfg_done <= 1'd0;
    else if(cfg_end == 1'd1 && cnt_num == NUM_REG)
        cfg_done <= 1'd1;
    else 
        cfg_done <= cfg_done;
        
assign cfg_data = cfg_done ? 32'd0: cfg_data_reg[cnt_num];

endmodule

module hdmi_iic
(
    input       wire        hdmi_clk    ,
    input       wire        reset_n     ,
    
    output      wire        hdmi_scl    ,
    inout       wire        hdmi_sda

);

wire            IIC_start   ;
wire            cfg_clk     ;
wire            IIC_end     ;
wire    [31:0]  cfg_data    ;

IIC_ctrl    IIC_ctrl_inst
(
    .clk         (hdmi_clk          ),
    .reset_n     (reset_n           ),
    .IIC_start   (IIC_start         ),
    .wr_en       (1'd1              ),
    .rd_en       (),
    .device_addr (cfg_data[31:24]   ),
    .byte_addr   (cfg_data[23:8]    ),
    .wr_data     (cfg_data[7:0]     ),
    .addr_num    (1'd1              ),

    .IIC_SCL     (hdmi_scl          ),
    .IIC_SDA     (hdmi_sda          ),
    .IIC_clk     (cfg_clk           ),
    .IIC_end     (IIC_end           ),
    .rd_data     ()
    
);

hdmi_cfg    hdmi_cfg_inst
(
    .cfg_clk     (cfg_clk       ),
    .reset_n     (reset_n       ),
    .cfg_end     (IIC_end       ),

    .cfg_start   (IIC_start     ),
    .cfg_data    (cfg_data      ),
    .cfg_done    ()
    
);

endmodule

(11)顶层设计:

module rs232_ddr3_hdmi
(
    input   wire                clk                 ,
    input   wire                reset_n             ,
    input   wire                rx                  ,
    //vga-hdmi接口
    output  wire                vga_hsync           ,
    output  wire                vga_vsync           ,
    output  wire                vga_clk             ,
    output  wire                vga_rst_n           ,
    output  wire    [23:0]      vga_rgb             ,
    output  wire                vga_DE              ,
    //hdmi配置端接口
    output  wire                ddc_scl             ,
    inout   wire                ddc_sda             ,
    //DDR3物理接口
    output  wire    [14:0]		ddr3_addr           ,
    output  wire    [2:0]		ddr3_ba             ,
    output  wire    			ddr3_cas_n          ,
    output  wire    		    ddr3_ck_n           ,
    output  wire    		    ddr3_ck_p           ,
    output  wire    		    ddr3_cke            ,
    output  wire    			ddr3_ras_n          ,
    output  wire    			ddr3_reset_n        ,
    output  wire    			ddr3_we_n           ,
    inout   wire    [31:0]		ddr3_dq             ,
    inout   wire    [3:0]		ddr3_dqs_n          ,
    inout   wire    [3:0]		ddr3_dqs_p          ,
    output  wire        		ddr3_cs_n           ,
    output  wire    [3:0]		ddr3_dm             ,
    output  wire        		ddr3_odt             
);

wire            clk_40M             ;
wire            clk_320M            ;
wire            locked              ;
wire            key_p_flag          ;
reg             rx_start            ;
wire    [7:0]   rx_data             ;
wire            rx_done             ;
wire            rst_n               ;
wire            init_rst_n          ;
wire            ui_clk              ;
wire            ui_rst              ;
wire            data_rden           ;
wire    [15:0]  data_rd             ;
wire            init_calib_complete ;    
wire    [23:0]  data_in             ;  
reg             data_wren           ;
reg     [20:0]  done_cnt            ; 
reg     [15:0]  temp_wrdata         ;

parameter  IMG_LENGTH   =   800;
parameter  IMG_WIDE     =   600;

assign rst_n = reset_n & locked ;
assign init_rst_n = reset_n & init_calib_complete;
assign vga_rst_n = rst_n;

pll     pll_inst
(
    .clk_40M    (clk_40M    ),    
    .clk_320M   (clk_320M   ),   
    
    .reset      (~reset_n   ),
    .locked     (locked     ),   
    
    .clk_in1    (clk        )
);     

assign vga_clk = clk_40M    ; 

always@(posedge clk or negedge init_rst_n)
    if(!init_rst_n)
        done_cnt <= 20'd0;
    else if(rx_done)
        done_cnt <= done_cnt + 20'd1;
    else 
        done_cnt <= done_cnt;
        
always@(posedge clk or negedge init_rst_n)
    if(!init_rst_n)
        temp_wrdata <= 16'd0;
    else if(rx_done)
        temp_wrdata <= {temp_wrdata[7:0],rx_data};
    else 
        temp_wrdata <= temp_wrdata;
        
always@(posedge clk or negedge init_rst_n)
    if(!init_rst_n)
        data_wren <= 1'd0;
    else if(rx_done && done_cnt[0])
        data_wren <= 1'd1;
    else 
        data_wren <= 1'd0;      

axi_ddr3_top    axi_ddr3_top_inst
(
    .ddr3_clk            (clk_320M              ),
    .reset_n             (rst_n                 ),
    .pingpang            (1'd0                  ),
    .ui_clk              (ui_clk                ),
    .ui_rst              (ui_rst                ),
    
    .wr_b_addr           (32'd0                 ),
    .wr_e_addr           (IMG_LENGTH*IMG_WIDE*2 ),
    .wr_clk              (clk                   ),
    .data_wren           (data_wren             ),
    .data_wr             (temp_wrdata           ),
    .wr_rst              (1'd0                  ),

    .rd_b_addr           (32'd0                 ),
    .rd_e_addr           (IMG_LENGTH*IMG_WIDE*2 ),
    .rd_clk              (clk_40M               ),
    .data_rden           (data_rden             ),
    .data_rd             (data_rd               ),
    .rd_rst              (1'd0                  ),
    .read_enable         (1'd1                  ),
    .rd_data_valid       (),

    .ddr3_addr           (ddr3_addr             ),
    .ddr3_ba             (ddr3_ba               ),
    .ddr3_cas_n          (ddr3_cas_n            ),
    .ddr3_ck_n           (ddr3_ck_n             ),
    .ddr3_ck_p           (ddr3_ck_p             ),
    .ddr3_cke            (ddr3_cke              ),
    .ddr3_ras_n          (ddr3_ras_n            ),
    .ddr3_reset_n        (ddr3_reset_n          ),
    .ddr3_we_n           (ddr3_we_n             ),
    .ddr3_dq             (ddr3_dq               ),
    .ddr3_dqs_n          (ddr3_dqs_n            ),
    .ddr3_dqs_p          (ddr3_dqs_p            ),
    .init_calib_complete (init_calib_complete   ),
    .ddr3_cs_n           (ddr3_cs_n             ),
    .ddr3_dm             (ddr3_dm               ),
    .ddr3_odt            (ddr3_odt              )  
);

rs232_rx    rs232_rx_inst
(
    .clk         (clk       ),
    .reset_n     (init_rst_n),
    .rx          (rx        ),
    .rx_start    (1'd1      ),

    .rx_data     (rx_data   ),
    .rx_done     (rx_done   )
);

hdmi_iic    hdmi_iic_inst
(
    .hdmi_clk    (clk_40M   ),
    .reset_n     (rst_n     ),

    .hdmi_scl    (ddc_scl   ),
    .hdmi_sda    (ddc_sda   )
);

vga_ctrl    vga_ctrl_inst
(
    .vga_clk     (clk_40M       ),
    .reset_n     (init_rst_n    ),
    .data_in     (data_in       ),

    .hang        (),
    .lie         (),
    .hsync       (vga_hsync     ),
    .vsync       (vga_vsync     ),
    .rgb_vga     (vga_rgb       ),
    .vga_DE      (vga_DE        )   
);

assign data_rden    = vga_DE;
assign data_in      = data_rden ? ({data_rd[15:11],3'b000,data_rd[10:5],2'b00,data_rd[4:0],3'b000}) : 24'hffffff;   

endmodule

(12)实验现象:(ps:传图工具将像素点的色彩信息以16bit传输)

相关推荐
ikun的男人16 小时前
FPGA图像处理仿真:生成数据源的方法
fpga开发
北京太速科技股份有限公司18 小时前
太速科技-430-基于RFSOC的8路5G ADC和8路10G的DAC PCIe卡
fpga开发
RIGOL小普20 小时前
如何用李萨如图形测正弦信号的频率?若不使用李萨如图形,如何用示波器测交流信号频率?
单片机·嵌入式硬件·fpga开发·硬件工程·射频工程
小眼睛FPGA1 天前
紫光同创——盘古 50KN 网口板
fpga开发·开发板·国产fpga
皮皮宽1 天前
数字IC开发:布局布线
fpga开发·bug·verilog·数字电路设计
北京太速科技股份有限公司2 天前
太速科技-217-A(B)-Base Camera link 转光纤传输双向模块
fpga开发
Q8343158192 天前
JL5109C 9口交换机芯片集成MAC RMII/MII百兆以太网交换机芯片
arm开发·网络协议·web安全·网络安全·fpga开发·信息与通信·信号处理
hi942 天前
基于KV260的基础视频链路通路(MIPI+Demosaic+VDMA)
fpga开发·视频·1024程序员节·mipi·vdma
FlechazoCLF2 天前
小柴冲刺软考中级嵌入式系统设计师系列二、嵌入式系统硬件基础知识(6)嵌入式系统总线及通信接口
c语言·单片机·fpga开发
望森FPGA2 天前
FPGA接口专题 | I2C总线 / 集成电路总线 / Inter-Integrated Circuit
学习·fpga开发·fpga