1)实验平台:正点原子开拓者FPGA 开发板
2)摘自《开拓者FPGA开发指南》关注官方微信号公众号,获取更多资料:正点原子
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-13912-1-1.html
第四十五章 以太网传输图片(LCD显示)
我们在“基于SDRAM的VGA图片显示实验”中利用网口接收上位机发送的图片,并将图片存
储到SDRAM中,最终通过VGA接口显示到显示器屏幕上。本章我们学习如何将SDRAM中的图片显
示在RGB TFT-LCD液晶屏上。
本章包括以下几个部分:
45.1 SDRAM-LCD图片显示简介
45.2 实验任务
45.3 硬件设计
45.4 程序设计
45.5 下载验证
SDRAM-LCD图片显示简介
我们在“基于SDRAM的VGA图片显示实验”中对SDRAM-VGA图片显示的方法作了详细的介绍,
本次实验与之类似,只是显示设备不同,因此这部分内容大家可以参考“基于SDRAM的VGA图片
显示实验”。
实验任务
本章的实验任务是使用开拓者开发板上的网口接收上位机传输的图片(分辨率为800*480),
然后将图片存储在SDRAM中并通过RGB TFTLCD接口在ATK-7’RGBLCD液晶屏上显示。
硬件设计
SDRAM部分的硬件设计原理与“SDRAM读写测试实验”完全相同,请参考“SDRAM读写测试
实验”中的硬件设计部分。以太网接口部分的硬件设计请参考“以太网通信实验”中的硬件设
计部分。RGB TFT-LCD接口部分的硬件设计请参考“RGB TFT-LCD彩条显示实验”中的硬件设计
部分。
由于SDRAM、以太网接口和LCD接口的引脚数目较多且在前面相应的章节中已经给出它们的
管脚列表,这里不再列出管脚分配。
程序设计
根据本章的实验任务我们可以得到整个系统的框图如下所示:
图 45.4.1 以太网传输图片(LCD显示)实验系统框图
上位机通过网线将图片以bin文件格式传输到开发板上,UDP模块负责接收图片数据;然后将UDP模块输出的位宽为32bit的数据转成16bit,并通过SDRAM控制器存入SDRAM;最后LCD驱动
模块通过SDRAM控制器读取SDRAM中存储的图片数据,最终通过RGB TFT-LCD接口显示在液晶屏
上。
程序中各模块端口及信号连接如图 45.4.2所示:
图 45.4.2 顶层模块原理图
FPGA顶层(eth_sdram_lcd)例化了以下五个模块:PLL时钟模块(pll_clk)、UDP模块(udp)、
32bit转16bit模块(udp_32_to_16bit)、SDRAM控制器模块(sdram_top)以及LCD驱动模块
(lcd_driver)。
PLL时钟模块(pll_clk):本实验中LCD驱动模块所需要的像素时钟为33.3MHz,SDRAM控
制器工作在100MHz时钟频率下,另外还需要一个输出给SDRAM芯片的100MHz相位偏移时钟。因
此需要一个PLL模块用于产生系统各个模块所需的时钟频率。
UDP模块(udp):UDP模块实现以太网通信的收发功能,该模块内部例化了以太网接收模
块(ip_receive)、以太网发送模块(ip_send)和CRC32校验模块(crc32_d4)。由于本章实
验中网口只负责接收数据,所以其中以太网的发送功能并没有用到。有关该模块的详细介绍请
大家参考“以太网通信实验”。
32bit转16bit模块(udp_32_to_16bit):该模块将UDP模块输出的位宽为32bit的数据转
换成16bit,这是因为数据需要写入SDRAM,而SDRAM控制器的数据接口位宽为16bit。有关该模
块的详细介绍请大家参考“基于SDRAM的VGA图片显示实验”。
SDRAM控制器模块(sdram_top):SDRAM控制器模块负责驱动SDRAM片外存储器。该模块将
SDRAM复杂的读写操作封装成类似FIFO的用户接口,非常方便用户的使用。有关该模块的详细
介绍请大家参考“SDRAM读写测试实验”。
LCD驱动模块(lcd_driver):LCD驱动模输出数据请求信号用于读取SDRAM中的图片数据,
并将图片通过RGB TFT-LCD接口显示在液晶屏上。有关该模块的详细介绍请大家参考“RGB TFT
LCD彩条显示实验”。
顶层模块的代码如下:
1 module eth_sdram_lcd(
2 input clk, //FPGA外部时钟,50MHz
3 input rst_n, //按键复位,低电平有效
4 //以太网接口
5 input eth_rx_clk, //MII接收数据时钟
6 input eth_rxdv, //MII输入数据有效信号
7 input [ 3:0] eth_rx_data, //MII输入数据
8 output eth_tx_en, //MII输出数据有效信号
9 output eth_rst_n, //以太网芯片复位信号,低电平有效
10 //SDRAM接口
11 output sdram_clk, //SDRAM 芯片时钟
12 output sdram_cke, //SDRAM 时钟有效
13 output sdram_cs_n, //SDRAM 片选
14 output sdram_ras_n, //SDRAM 行有效
15 output sdram_cas_n, //SDRAM 列有效
16 output sdram_we_n, //SDRAM 写有效
17 output [ 1:0] sdram_ba, //SDRAM Bank地址
18 output [12:0] sdram_addr, //SDRAM 行/列地址
19 inout [15:0] sdram_data, //SDRAM 数据
20 output [ 1:0] sdram_dqm, //SDRAM 数据掩码
21 //RGB LCD接口
22 output lcd_hs, //LCD 行同步信号
23 output lcd_vs, //LCD 场同步信号
24 output lcd_de, //LCD 数据输入使能
25 output [15:0] lcd_rgb, //LCD RGB565颜色数据
26 output lcd_bl, //LCD 背光控制信号
27 output lcd_rst, //LCD 复位信号
28 output lcd_pclk //LCD 采样时钟
29 );
30
31 //parameter define
32 //开发板MAC地址 00-11-22-33-44-55
33 parameter BOARD_MAC = 48'h00_11_22_33_44_55;
34 //开发板IP地址 192.168.1.123
35 parameter BOARD_IP = {8'd192,8'd168,8'd1,8'd123};
36 //目的MAC地址 ff_ff_ff_ff_ff_ff
37 parameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;
38 //目的IP地址 192.168.1.102
39 parameter DES_IP = {8'd192,8'd168,8'd1,8'd102};
40
41 //wire define
42 wire lcd_clk; //RGB LCD驱动时钟,33.33MHz
43 wire clk_100m; //SDRAM 控制器时钟
44 wire clk_100m_shift; //相位偏移时钟
45
46 wire locked; //PLL输出有效标志
47 wire sys_rst_n; //系统复位信号
48 wire sdram_init_done; //SDRAM 初始化完成标志
49
50 wire udp_rec_en; //以太网接收的数据有效信号
51 wire [31:0] udp_rec_data; //以太网接收的数据
52
53 wire wr_en; //SDRAM 写端口:写使能
54 wire [15:0] wr_data; //SDRAM 写端口:写入的数据
55 wire rd_en; //SDRAM 读端口:读使能
56 wire [15:0] rd_data; //SDRAM 读端口:读出的数据
57
58 //*****************************************************
59 //** main code
60 //*****************************************************
61
62 //待PLL输出稳定之后,停止系统复位
63 assign sys_rst_n = rst_n & locked;
64
65 //例化PLL, 产生各模块所需要的时钟
66 pll_clk u_pll_clk(
67 .inclk0 (clk),
68 .areset (~rst_n),
69
70 .c0 (lcd_clk),
71 .c1 (clk_100m),
72 .c2 (clk_100m_shift),
73 .locked (locked)
74 );
75
76 //UDP模块接收网口数据
77 udp #(
78 .BOARD_MAC (BOARD_MAC), //开发板MAC地址
79 .BOARD_IP (BOARD_IP), //开发板IP地址
80 .DES_MAC (DES_MAC), //目的MAC地址
81 .DES_IP (DES_IP) //目的IP地址
82 )
83 u_udp(
84 .rst_n (sys_rst_n),
85
86 .eth_rx_clk (eth_rx_clk), //MII接收数据时钟
87 .eth_rxdv (eth_rxdv), //MII输入数据有效信号
88 .eth_rx_data (eth_rx_data), //MII输入数据
89 .eth_rst_n (eth_rst_n), //以太网芯片复位信号,低电平有效
90 .rec_en (udp_rec_en), //以太网接收的数据有效信号
91 .rec_data (udp_rec_data), //以太网接收的数据
92 .rec_pkt_done (), //以太网单包数据接收完成信号
93 .rec_byte_num (), //以太网接收的有效字节数 单位:byte
94
95 .eth_tx_clk (),
96 .eth_tx_en (eth_tx_en), //MII输出数据有效信号
97 .tx_start_en (),
98 .tx_data (),
99 .tx_byte_num (),
100 .tx_done (),
101 .tx_req (),
102 .eth_tx_data ()
103 );
104
105 //将UDP模块接收到的32bit数据转换成16bit数据
106 udp_32_to_16bit(
107 .eth_rx_clk (eth_rx_clk),
108 .rst_n (sys_rst_n),
109
110 .udp_rec_en (udp_rec_en),
111 .udp_rec_data (udp_rec_data),
112 .udp_rec_en_16 (wr_en),
113 .udp_rec_data_16 (wr_data)
114 );
115
116 //SDRAM 控制器顶层模块,封装成FIFO接口
117 //SDRAM 控制器地址组成: {bank_addr[1:0],row_addr[12:0],col_addr[8:0]}
118 sdram_top u_sdram_top(
119 .ref_clk (clk_100m), //sdram 控制器参考时钟
120 .out_clk (clk_100m_shift), //用于输出的相位偏移时钟
121 .rst_n (sys_rst_n), //系统复位
122
123 //用户写端口
124 .wr_clk (eth_rx_clk), //写端口FIFO: 写时钟
125 .wr_en (wr_en), //写端口FIFO: 写使能
126 .wr_data (wr_data), //写端口FIFO: 写数据
127 .wr_min_addr (24'd0), //写SDRAM的起始地址
128 .wr_max_addr (24'd800*24'd480), //写SDRAM的结束地址
129 .wr_len (10'd512), //写SDRAM时的数据突发长度
130 .wr_load (~sys_rst_n), //写端口复位: 复位写地址,清空写FIFO
131
132 //用户读端口
133 .rd_clk (lcd_clk), //读端口FIFO: 读时钟
134 .rd_en (rd_en), //读端口FIFO: 读使能
135 .rd_data (rd_data), //读端口FIFO: 读数据
136 .rd_min_addr (24'd0), //读SDRAM的起始地址
137 .rd_max_addr (24'd800*24'd480), //读SDRAM的结束地址
138 .rd_len (10'd512), //从SDRAM中读数据时的突发长度
139 .rd_load (~sys_rst_n), //读端口复位: 复位读地址,清空读FIFO
140
141 //用户控制端口
142 .sdram_read_valid (1'b1), //SDRAM 读使能
143 .sdram_init_done (sdram_init_done), //SDRAM 初始化完成标志
144
145 //SDRAM 芯片接口
146 .sdram_clk (sdram_clk), //SDRAM 芯片时钟
147 .sdram_cke (sdram_cke), //SDRAM 时钟有效
148 .sdram_cs_n (sdram_cs_n), //SDRAM 片选
149 .sdram_ras_n (sdram_ras_n), //SDRAM 行有效
150 .sdram_cas_n (sdram_cas_n), //SDRAM 列有效
151 .sdram_we_n (sdram_we_n), //SDRAM 写有效
152 .sdram_ba (sdram_ba), //SDRAM Bank地址
153 .sdram_addr (sdram_addr), //SDRAM 行/列地址
154 .sdram_data (sdram_data), //SDRAM 数据
155 .sdram_dqm (sdram_dqm) //SDRAM 数据掩码
156 );
157
158 //RGB LCD驱动模块
159 lcd_driver u_lcd_driver(
160 .lcd_clk (lcd_clk),
161 .sys_rst_n (sdram_init_done),
162
163 .lcd_hs (lcd_hs),
164 .lcd_vs (lcd_vs),
165 .lcd_de (lcd_de),
166 .lcd_rgb (lcd_rgb),
167 .lcd_bl (lcd_bl),
168 .lcd_rst (lcd_rst),
169 .lcd_pclk (lcd_pclk),
170
171 .data_req (rd_en),
172 .pixel_data (rd_data),
173 .pixel_xpos (),
174 .pixel_ypos ()
175 );
176
177 endmodule
相比于SDRAM-VGA图片显示程序,SDRAM-LCD图片显示程序仅仅是在顶层模块中将VGA驱动
模块替换成LCD驱动模块。另外由于ATK-7’RGBLCD液晶屏显示分辨率为800*480,所以SDRAM的
读写结束地址均设置为“800*480”,如代码中第128行和第137行所示。
下载验证
首先在eth_sdram_lcd/par文件夹中双击“eth_sdram_lcd.qpf”打开基于SDRAM的LCD图片
显示实验工程,工程打开后如图 45.5.1所示:
图 45.5.1 基于SDRAM的VGA图片显示工程
用FPC排线将ATK-7 RGBLCD模块与开发板连接,然后将网线一端连接电脑网口,另一端与
开发板上的网口连接;将下载器一端连电脑,另一端与开发板上对应端口连接,最后连接电源
线并打开电源开关。
接下来请大家参考SDRAM-VGA图片显示实验中的下载验证部分。首先将eth_sdram_lcd
/par/output_files目录下的“eth_sdram_lcd.sof”文件下载至开发板。然后在软件Img2Lcd
中打开一幅分辨率为800*480的jpg格式图片并导出bin文件,如下图所示:
图 45.5.2 Img2Lcd工具界面
本章同样需要在设备管理器中配置网卡属性,设置“巨型帧”为“9KB MTU”。然后在网
口调试助手中将生成的bin文件通过网线发送到开发板,如下图所示:
图 45.5.3 网络调试助手发送bin文件
图片发送完成后液晶屏上显示的图片如下所示,说明基于SDRAM的LCD显示实验下载验证成
功:
图 45.5.4 LCD液晶屏显示的图片