(以下内容是在学习完正点原子视频后的总结,代码均是来自正点原子)
1.实验内容
本节的实验任务是网口接收上位机传输的图片(分辨率为640*480),然后将图片存储在SDRAM中并通过VGA接口在显示器屏幕上显示。
2.实验系统框图
3.代码部分
顶层模块;
module eth_sdram_vga(
input clk, //FPGA外部时钟,50MHz
input rst_n, //按键复位,低电平有效
//以太网接口
input eth_rx_clk, //MII接收数据时钟
input eth_rxdv, //MII输入数据有效信号
input [ 3:0] eth_rx_data, //MII输入数据
output eth_tx_en, //MII输出数据有效信号
output eth_rst_n, //以太网芯片复位信号,低电平有效
//SDRAM接口
output sdram_clk, //SDRAM 芯片时钟
output sdram_cke, //SDRAM 时钟有效
output sdram_cs_n, //SDRAM 片选
output sdram_ras_n, //SDRAM 行有效
output sdram_cas_n, //SDRAM 列有效
output sdram_we_n, //SDRAM 写有效
output [ 1:0] sdram_ba, //SDRAM Bank地址
output [12:0] sdram_addr, //SDRAM 行/列地址
inout [15:0] sdram_data, //SDRAM 数据
output [ 1:0] sdram_dqm, //SDRAM 数据掩码
//VGA接口
output vga_hs, //行同步信号
output vga_vs, //场同步信号
output [15:0] vga_rgb //红绿蓝三原色输出
);
//parameter define
//开发板MAC地址 00-11-22-33-44-55
parameter BOARD_MAC = 48’h00_11_22_33_44_55;
//开发板IP地址 192.168.1.123
parameter BOARD_IP = {8’d192,8’d168,8’d1,8’d123};
//目的MAC地址 ff_ff_ff_ff_ff_ff
parameter DES_MAC = 48’hff_ff_ff_ff_ff_ff;
//目的IP地址 192.168.1.102
parameter DES_IP = {8’d192,8’d168,8’d1,8’d102};
//wire define
wire vga_clk; //VGA驱动时钟,25MHz
wire clk_100m; //SDRAM 控制器时钟
wire clk_100m_shift; //相位偏移时钟
wire locked; //PLL输出有效标志
wire sys_rst_n; //系统复位信号
wire sdram_init_done; //SDRAM 初始化完成标志
wire udp_rec_en; //以太网接收的数据有效信号
wire [31:0] udp_rec_data; //以太网接收的数据
wire wr_en; //SDRAM 写端口:写使能
wire [15:0] wr_data; //SDRAM 写端口:写入的数据
wire rd_en; //SDRAM 读端口:读使能
wire [15:0] rd_data; //SDRAM 读端口:读出的数据
//*****************************************************
//** main code
//*****************************************************
//待PLL输出稳定之后,停止系统复位
assign sys_rst_n = rst_n & locked;
//例化PLL, 产生各模块所需要的时钟
pll_clk u_pll_clk(
.inclk0 (clk),
.areset (~rst_n),
.c0 (vga_clk),
.c1 (clk_100m),
.c2 (clk_100m_shift),
.locked (locked)
);
//UDP模块接收网口数据
udp #(
.BOARD_MAC (BOARD_MAC), //开发板MAC地址
.BOARD_IP (BOARD_IP), //开发板IP地址
.DES_MAC (DES_MAC), //目的MAC地址
.DES_IP (DES_IP) //目的IP地址
)
u_udp(
.rst_n (sys_rst_n),
.eth_rx_clk (eth_rx_clk), //MII接收数据时钟
.eth_rxdv (eth_rxdv), //MII输入数据有效信号
.eth_rx_data (eth_rx_data), //MII输入数据
.eth_rst_n (eth_rst_n), //以太网芯片复位信号,低电平有效
.rec_en (udp_rec_en), //以太网接收的数据有效信号
.rec_data (udp_rec_data), //以太网接收的数据
.rec_pkt_done (), //以太网单包数据接收完成信号
.rec_byte_num (), //以太网接收的有效字节数 单位:byte
.eth_tx_clk (),
.eth_tx_en (eth_tx_en), //MII输出数据有效信号
.tx_start_en (),
.tx_data (),
.tx_byte_num (),
.tx_done (),
.tx_req (),
.eth_tx_data ()
);
//将UDP模块接收到的32bit数据转换成16bit数据
udp_32_to_16bit(
.eth_rx_clk (eth_rx_clk),
.rst_n (sys_rst_n),
.udp_rec_en (udp_rec_en),
.udp_rec_data (udp_rec_data),
.udp_rec_en_16 (wr_en),
.udp_rec_data_16 (wr_data)
);
//SDRAM 控制器顶层模块,封装成FIFO接口
//SDRAM 控制器地址组成: {bank_addr[1:0],row_addr[12:0],col_addr[8:0]}
sdram_top u_sdram_top(
.ref_clk (clk_100m), //sdram 控制器参考时钟
.out_clk (clk_100m_shift), //用于输出的相位偏移时钟
.rst_n (sys_rst_n), //系统复位
//用户写端口
.wr_clk (eth_rx_clk), //写端口FIFO: 写时钟
.wr_en (wr_en), //写端口FIFO: 写使能
.wr_data (wr_data), //写端口FIFO: 写数据
.wr_min_addr (24'd0), //写SDRAM的起始地址
.wr_max_addr (24'd640*24'd480), //写SDRAM的结束地址
.wr_len (10'd512), //写SDRAM时的数据突发长度
.wr_load (~sys_rst_n), //写端口复位: 复位写地址,清空写FIFO
//用户读端口
.rd_clk (vga_clk), //读端口FIFO: 读时钟
.rd_en (rd_en), //读端口FIFO: 读使能
.rd_data (rd_data), //读端口FIFO: 读数据
.rd_min_addr (24'd0), //读SDRAM的起始地址
.rd_max_addr (24'd640*24'd480), //读SDRAM的结束地址
.rd_len (10'd512), //从SDRAM中读数据时的突发长度
.rd_load (~sys_rst_n), //读端口复位: 复位读地址,清空读FIFO
//用户控制端口
.sdram_read_valid (1'b1), //SDRAM 读使能
.sdram_init_done (sdram_init_done), //SDRAM 初始化完成标志
//SDRAM 芯片接口
.sdram_clk (sdram_clk), //SDRAM 芯片时钟
.sdram_cke (sdram_cke), //SDRAM 时钟有效
.sdram_cs_n (sdram_cs_n), //SDRAM 片选
.sdram_ras_n (sdram_ras_n), //SDRAM 行有效
.sdram_cas_n (sdram_cas_n), //SDRAM 列有效
.sdram_we_n (sdram_we_n), //SDRAM 写有效
.sdram_ba (sdram_ba), //SDRAM Bank地址
.sdram_addr (sdram_addr), //SDRAM 行/列地址
.sdram_data (sdram_data), //SDRAM 数据
.sdram_dqm (sdram_dqm) //SDRAM 数据掩码
);
//VGA驱动模块
vga_driver u_vga_driver(
.vga_clk (vga_clk),
.sys_rst_n (sdram_init_done),
.vga_hs (vga_hs),
.vga_vs (vga_vs),
.vga_rgb (vga_rgb),
.data_req (rd_en),
.pixel_data (rd_data),
.pixel_xpos (),
.pixel_ypos ()
);
endmodule
UDP模块
module udp
#(
//开发板MAC地址 00-11-22-33-44-55
parameter BOARD_MAC = 48’h00_11_22_33_44_55,
//开发板IP地址 192.168.1.123
parameter BOARD_IP = {8’d192,8’d168,8’d1,8’d123},
//目的MAC地址 ff_ff_ff_ff_ff_ff
parameter DES_MAC = 48’hff_ff_ff_ff_ff_ff,
//目的IP地址 192.168.1.102
parameter DES_IP = {8’d192,8’d168,8’d1,8’d102}
)
(
input eth_rx_clk , //MII接收数据时钟
input rst_n , //复位信号,低电平有效
input eth_rxdv , //MII输入数据有效信号
input [3:0] eth_rx_data , //MII输入数据
input eth_tx_clk , //MII发送数据时钟
input tx_start_en , //以太网开始发送信号
input [31:0] tx_data , //以太网待发送数据
input [15:0] tx_byte_num , //以太网发送的有效字节数 单位:byte
output tx_done , //以太网发送完成信号
output tx_req , //读数据请求信号
output rec_pkt_done, //以太网单包数据接收完成信号
output rec_en , //以太网接收的数据使能信号
output [31:0] rec_data , //以太网接收的数据
output [15:0] rec_byte_num, //以太网接收的有效字节数 单位:byte
output eth_tx_en , //MII输出数据有效信号
output [3:0] eth_tx_data , //MII输出数据
output eth_rst_n //以太网芯片复位信号,低电平有效
);
32bit转换为16bit模块
module udp_32_to_16bit(
input eth_rx_clk,
input rst_n,
input udp_rec_en,
input [31:0] udp_rec_data,
output reg udp_rec_en_16,
output reg [15:0] udp_rec_data_16
);
//reg define
reg rec_en_flag;
//*****************************************************
//** main code
//*****************************************************
//将UDP模块的接收数据有效信号延时一个时钟周期
always @(posedge eth_rx_clk or negedge rst_n)begin
if(!rst_n)
rec_en_flag <=0;
else
rec_en_flag <= udp_rec_en;
end
//分两个时钟周期输出UPP模块接收数据的高十六位和低十六位
always @(posedge eth_rx_clk or negedge rst_n)begin
if(!rst_n) begin
udp_rec_en_16 <= 1’b0;
udp_rec_data_16 <= 1’b0;
end
else if(udp_rec_en)begin
udp_rec_en_16 <= 1’b1;
udp_rec_data_16 <= udp_rec_data[31:16];
end
else if(rec_en_flag)begin
udp_rec_en_16 <= 1’b1;
udp_rec_data_16 <= udp_rec_data[15:0];
end
else begin
udp_rec_en_16 <= 0;
udp_rec_data_16 <= udp_rec_data_16;
end
end
endmodule
SDRAM模块:
module sdram_top(
input ref_clk, //sdram 控制器参考时钟
input out_clk, //用于输出的相位偏移时钟
input rst_n, //系统复位
//用户写端口
input wr_clk, //写端口FIFO: 写时钟
input wr_en, //写端口FIFO: 写使能
input [15:0] wr_data, //写端口FIFO: 写数据
input [23:0] wr_min_addr, //写SDRAM的起始地址
input [23:0] wr_max_addr, //写SDRAM的结束地址
input [ 9:0] wr_len, //写SDRAM时的数据突发长度
input wr_load, //写端口复位: 复位写地址,清空写FIFO
//用户读端口
input rd_clk, //读端口FIFO: 读时钟
input rd_en, //读端口FIFO: 读使能
output [15:0] rd_data, //读端口FIFO: 读数据
input [23:0] rd_min_addr, //读SDRAM的起始地址
input [23:0] rd_max_addr, //读SDRAM的结束地址
input [ 9:0] rd_len, //从SDRAM中读数据时的突发长度
input rd_load, //读端口复位: 复位读地址,清空读FIFO
//用户控制端口
input sdram_read_valid, //SDRAM 读使能
output sdram_init_done, //SDRAM 初始化完成标志
//SDRAM 芯片接口
output sdram_clk, //SDRAM 芯片时钟
output sdram_cke, //SDRAM 时钟有效
output sdram_cs_n, //SDRAM 片选
output sdram_ras_n, //SDRAM 行有效
output sdram_cas_n, //SDRAM 列有效
output sdram_we_n, //SDRAM 写有效
output [ 1:0] sdram_ba, //SDRAM Bank地址
output [12:0] sdram_addr, //SDRAM 行/列地址
inout [15:0] sdram_data, //SDRAM 数据
output [ 1:0] sdram_dqm //SDRAM 数据掩码
);
VGA模块:
module vga_driver(
input vga_clk, //VGA驱动时钟
input sys_rst_n, //复位信号
//VGA接口
output vga_hs, //行同步信号
output vga_vs, //场同步信号
output [15:0] vga_rgb, //红绿蓝三原色输出
output data_req, //像素点数据请求
input [15:0] pixel_data, //像素点数据
output [ 9:0] pixel_xpos, //像素点横坐标
output [ 9:0] pixel_ypos //像素点纵坐标
);