实验目标:在 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传输)