搜索
bottom↓
回复: 0

《ATK-DFPGL22G之FPGA开发指南_V1.0》第五十三章

[复制链接]

出0入234汤圆

发表于 2023-3-14 09:49:27 | 显示全部楼层 |阅读模式
1)实验平台:正点原子紫光PGL22G开发板
2)购买链接:https://item.taobao.com/item.htm?&id=692368045899
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-340253-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子FPGA交流群:435699340 lQLPJxaFi2zaB4UWWrDAMgIsFEW2pwLb3abnwDMA_90_22.png
lQDPJxaFi2nfFizMjM0CbLCPlxn_FVheIQLb3aGrwFQA_620_140.jpg

lQLPJxaFi2nfFhLMkM0BXrDNvOUyeU_FPgLb3aGvQNIA_350_144.png

第五十三章以太网传图片(LCD显示)
由于FPGA片上存储资源有限,只能存储分辨率较小的图片,所以在本章,我们将学习如何利用以太网传输图片数据,使用DDR3来存储图片,并通过LCD接口显示。
本章包括以下几个部分:
53.1简介
53.2实验任务
53.3硬件设计
53.4程序设计
53.5下载验证


53.1简介

利用LCD接口显示图片时,需要一个存储器用于存储图片数据。这个存储器可以采用FPGA片上存储资源,也可以使用片外存储设备,如DDR3、SD卡、FLASH等。
由于FPGA的片上存储资源有限,所以能够存储的图片大小也受到限制。开发板上的FPGA芯片型号为PGL22G-6MBG324,它的片上存储资源为864 Kbit,也就是说存储的图片大小不能超过864 Kbit。对于分辨率为800*480的图片,当采用RGB565数据格式时,所需要的存储空间为800*480*16bit=6144000bit=6000Kbit=5.9 Mbit(1Kbit=1024bit,1 Mbit =1024 Kbit)。也就是说,如果是采用LCD显示分辨率800*480,FPGA的片上存储资源也远远不能够满足图片存储的需求。
开发板上的DDR3存储容量为2048Mbit,大约可以存储340张上述格式的图片。另外,相比于开发板上的SD卡、FLASH等片外存储设备,DDR3还具有读写速度快的优点。因此在利用LCD显示图片时,DDR3是一种非常理想的存储设备。然而DDR3不像SD卡一样可以事先将图片导入,作为易失性存储器中的一种,DDR3中的数据在掉电后会丢失,因此用于LCD图片显示时需要向DDR3中写入图片数据。这里我们采用开发板上的网口接收上位机发送的图片数据,并将其写入DDR3,然后读出数据,最终通过LCD接口驱动LCD屏显示。
我们在“OV7725摄像头RGB-LCD显示”中对DDR3控制器作了详细的介绍,包括DDR3读写控制、寻址方法、用户接口等等。如果大家对这部分内容不是很熟悉的话,请参考“OV7725摄像头RGB-LCD显示”中的DDR3控制器部分的程序讲解。
53.2实验任务
本节实验任务是使用开发板上的网口接收上位机传输的图片(分辨率为800*480),然后将图片存储在DDR3中并通过LCD接口在LCD屏幕上显示,支持4.3寸480*272、4.3寸800*480、7寸800*480、7寸1024*600、10.1寸1280*800这些尺寸/分辨率的屏幕。
53.3硬件设计
RGB TFT-LCD接口部分的硬件设计请参考“RGB TFT-LCD彩条显示实验”中的硬件设计部分。以太网原理图请参考“MDIO 接口读写测试实验”中的硬件设计部分,DDR3原理则参考“DDR3读写测试”中的硬件设计部分。由于以太网、LCD接口和DDR3引脚数目较多且在前面相应的章节中已经给出它们的管脚列表,这里不再列出管脚分配。
53.4程序设计
下图是根据本章实验任务画出的系统框图。上位机通过网线将大小固定为800*480的图片以bin文件格式传输到开发板上,以太网顶层模块负责接收图片数据并且实现ARP功能,位宽转换模块负责将太网UDP模块接收到的32bit的数据转成16bit,并通过DDR3控制器存入DDR3中。当使用到4.3寸480*272的屏幕时,由于屏幕大小小于图片,我们将对图片进行裁剪后存入DDR3。LCD顶层模块从DDR3控制器读取DDR3中存储的图片数据并通过LCD接口显示在LCD屏上,另外当遇到屏幕大小大于图片大小时,需要在屏幕四周实现黑边填充。
以太网传图片1457.png
图 53.4.1 系统框图

FPGA顶层(eth_ddr3_lcd)例化了以下六个模块:时钟模块(clk_wiz_0)、以太网顶层模块(eth_top)、图片裁剪模块(picture_tailor)、32bit转16bit模块(udp_32_to_16bit)、DDR3控制器模块(ddr3_top)以及LCD顶层驱动模块(lcd_rgb_top)。
时钟模块(clk_wiz_0):该时钟模块产生一个50M时钟,50M时钟分别供LCD顶层驱动模块使用与太网顶层模块和DDR3控制器模块使用。
以太网顶层模块(eth_top):太网顶层内部例化ARP顶层和UDP顶层,ARP主要是用来实现ARP协议的,避免用户每次使用以太网通信都去手动绑定IP,具体可以看以“以太网ARP测试”章节,UDP顶层则用来实现以太网通信的数据收发功能,该模块下面包含了以太网UDP接收模块(udp_rx)、以太网UDP发送模块(udp_tx)和CRC32校验模块(crc32_d8)。由于本章实验中网口只负责接收数据,所以以太网的UDP发送模块功能并没有用到。有关该UDP模块的详细介绍请大家参考“以太网UDP测试实验”章节。
裁剪模块(picture_tailor):裁剪模块用于把固定分辨率(800*480)的图片裁剪成大小为480*272的图片然后送到DDR3储存,从而适配正点原子480*272的LCD屏幕。
32bit转16bit模块(udp_32_to_16bit):该模块将UDP模块接收到的位宽为32bit的数据转换成16bit图像数据,这是因为图像数据需要写入DDR3,而DDR3控制器的图像数据接口位宽为16bit。
DDR3控制器模块(ddr3_top):DDR3控制器模块负责驱动DDR3片外存储器。该模块将DDR3复杂的读写操作封装成类似FIFO的用户接口,非常方便用户的使用。有关该模块的详细介绍请大家参考“OV7725摄像头RGB-LCD显示”章节。
LCD顶层模块(lcd_rgb_top):LCD顶层驱动模块根据LCD时序参数输出行、场同步信号;同时它还要输出数据请求信号用于读取DDR3中的图片数据,并将图片通过LCD接口显示出来。另外当遇到大于800*480的屏幕时,需要实现屏幕四周的黑边填充。
顶层模块的代码如下:
1   module eth_ddr3_lcd(
2       input             sys_clk        ,  //FPGA外部时钟,50MHz
3       input             rst_n          ,  //按键复位,低电平有效
4       //以太网接口                        
5       input             eth_rxc        ,  //RGMII接收数据时钟
6       input             eth_rx_ctl     ,  //RGMII输入数据有效信号
7       input  [3:0]      eth_rxd        ,  //RGMII输入数据
8       output            eth_txc        ,  //RGMII发送数据时钟   
9       output            eth_tx_ctl     ,  //RGMII输出数据有效信号
10      output [3:0]      eth_txd        ,  //RGMII输出数据         
11      output            eth_rst_n      ,  //以太网芯片复位信号,低电平有效   
12      //DDR3接口
13      input             pad_loop_in    ,
14      input             pad_loop_in_h  ,
15      output            pad_rstn_ch0   ,
16      output            pad_ddr_clk_w  ,
17      output            pad_ddr_clkn_w ,
18      output            pad_csn_ch0    ,
19      output [15:0]     pad_addr_ch0   ,
20      inout  [16-1:0]   pad_dq_ch0     ,
21      inout  [16/8-1:0] pad_dqs_ch0    ,
22      inout  [16/8-1:0] pad_dqsn_ch0   ,
23      output [16/8-1:0] pad_dm_rdqs_ch0,
24      output            pad_cke_ch0    ,
25      output            pad_odt_ch0    ,
26      output            pad_rasn_ch0   ,
27      output            pad_casn_ch0   ,
28      output            pad_wen_ch0    ,
29      output [2:0]      pad_ba_ch0     ,
30      output            pad_loop_out   ,
31      output            pad_loop_out_h ,
32      //lcd接口                        
33      output            lcd_hs         ,  //LCD 行同步信号
34      output            lcd_vs         ,  //LCD 场同步信号
35      output            lcd_de         ,  //LCD 数据输入使能
36      inout  [23:0]     lcd_rgb        ,  //LCD 颜色数据
37      output            lcd_bl         ,  //LCD 背光控制信号
38      output            lcd_rst        ,  //LCD 复位信号
39      output            lcd_pclk          //LCD 采样时钟
40      );
41  //parameter define
42  //开发板MAC地址 00-11-22-33-44-55
43  parameter  BOARD_MAC = 48'h00_11_22_33_44_55;
44  //开发板IP地址 192.168.1.10
45  parameter  BOARD_IP  = {8'd192,8'd168,8'd1,8'd10};
46  //目的MAC地址 ff_ff_ff_ff_ff_ff
47  parameter  DES_MAC   = 48'hff_ff_ff_ff_ff_ff;
48  //目的IP地址 192.168.1.102     
49  parameter  DES_IP    = {8'd192,8'd168,8'd1,8'd102};
50  
51  //wire define               
52  wire         clk_50m              ;  //50mhz时钟,提供给lcd驱动时钟
53  wire         locked               ;  //时钟锁定信号  
54  wire         sys_rst_n            ;  //系统复位信号
55  
56  //DDR
57  wire  [15:0] rd_data              ;  //DDR3控制器模块读数据
58  wire         fram_done            ;  //DDR中已经存入一帧画面标志
59  wire  [27:0] ddr3_addr_max        ;  //存入DDR3的最大读写地址
60  //LCD
61  wire         lcd_clk              ;  //分频产生的LCD 采样时钟
62  wire  [12:0] h_disp               ;  //LCD屏水平分辨率
63  wire  [12:0] v_disp               ;  //LCD屏垂直分辨率     
64  wire  [10:0] h_pixel              ;  //存入ddr3的水平分辨率        
65  wire  [10:0] v_pixel              ;  //存入ddr3的屏垂直分辨率
66  wire  [15:0] lcd_id               ;  //LCD屏的ID号
67  //ETH
68  wire         gmii_rx_clk          ;  //以太网125M时钟
69  wire [31:0]  rec_data             ;  //以太网接收的数据
70  //
71  wire [15:0]  picture_data         ;  //32_to_16bit图片数据
72  wire         picture_data_vld     ;  //图片数据有效信号
73  wire         picture_data_vld0    ;  //非480x272屏图片像素有效信号
74  wire         picture_data_vld1    ;  //480x272屏图片像素有效信号
75  wire         data_req_big         ;  //非480x272屏的LCD请求信号
76  wire         data_req_small       ;  //480x272LCD屏请求信号
77  
78  //*****************************************************
79  //**                    main code
80  //*****************************************************
81  //待PLL输出稳定之后,停止系统复位
82  assign sys_rst_n = rst_n & locked;
83  //系统初始化完成:DDR3初始化完成
84  assign sys_init_done = ddr_init_done;
85  //存入ddr3的最大读写地址
86  assign ddr3_addr_max =(lcd_id == 16'h4342)? 130560:384000;
87  //存入ddr3的一行数据(突发长度)
88  assign h_disp = 640;
89  
90  //时钟产生模块
91  clk_wiz_0 u_clk_wiz_0 (
92      .pll_rst            (~rst_n ), // input
93      .clkin1             (sys_clk), // input
94      .pll_lock           (locked ), // output
95      .clkout0            (clk_50m)  // output
96  );
97  
98  //480x272屏图片裁剪模块   
99  picture_tailor u_picture_tailor(
100     .gmii_rx_clk        (gmii_rx_clk      ), //图片输入像素时钟
101     .sys_rst_n          (sys_rst_n        ), //复位信号
102     
103     .picture_data_vld0  (picture_data_vld0), //480x272屏图片像素有效信号
104     .picture_data_vld1  (picture_data_vld1)  //非480x272屏图片像素有效信号
105 );
106
107 //ddr3
108 ddr3_top u_ddr3_top(
109     .refclk_in             (clk_50m         ),
110     .rst_n                 (sys_rst_n       ),
111     .ddr3_read_valid       (1'b1            ),
112     .ddr3_pingpang_en      (1'b0            ),
113
114     .app_addr_wr_min       (0),                 //写最小地址
115     .app_addr_wr_max       (ddr3_addr_max   ),  //写最大地址
116     .wr_bust_len           (h_disp[10:3]    ),  //一次写长度
117     .wr_clk                (gmii_rx_clk     ),  //写时钟
118     .wr_load               (),                  //写端更新信号
119     .datain_valid          (picture_data_vld),  //写使能
120     .datain                (picture_data    ),  //写数据
121      
122     .app_addr_rd_min       (0),                 //读最小地址
123     .app_addr_rd_max       (ddr3_addr_max   ),  //读最大地址
124     .rd_bust_len           (h_disp[10:3]    ),  //一次读长度
125     .rd_clk                (lcd_clk         ),  //读时钟
126     .rdata_req             (rdata_req       ),  //读使能  
127     .rd_load               (out_vsync       ),  //读端更新信号
128     .dataout               (rd_data         ),  //读数据
129
130     .fram_done             (fram_done       ),  //DDR中已经存入一帧画面标志
131     .pll_lock              (pll_lock        ),
132     .ddr_init_done         (ddr_init_done   ),
133     .ddrphy_rst_done       (),
134
135     .pad_loop_in           (pad_loop_in     ),
136     .pad_loop_in_h         (pad_loop_in_h   ),
137     .pad_rstn_ch0          (pad_rstn_ch0    ),
138     .pad_ddr_clk_w         (pad_ddr_clk_w   ),
139     .pad_ddr_clkn_w        (pad_ddr_clkn_w  ),
140     .pad_csn_ch0           (pad_csn_ch0     ),
141     .pad_addr_ch0          (pad_addr_ch0    ),
142     .pad_dq_ch0            (pad_dq_ch0      ),
143     .pad_dqs_ch0           (pad_dqs_ch0     ),
144     .pad_dqsn_ch0          (pad_dqsn_ch0    ),
145     .pad_dm_rdqs_ch0       (pad_dm_rdqs_ch0 ),
146     .pad_cke_ch0           (pad_cke_ch0     ),
147     .pad_odt_ch0           (pad_odt_ch0     ),
148     .pad_rasn_ch0          (pad_rasn_ch0    ),
149     .pad_casn_ch0          (pad_casn_ch0    ),
150     .pad_wen_ch0           (pad_wen_ch0     ),
151     .pad_ba_ch0            (pad_ba_ch0      ),
152     .pad_loop_out          (pad_loop_out    ),
153     .pad_loop_out_h        (pad_loop_out_h  )
154     );  
155
156 //LCD 顶层
157 lcd_rgb_top  u_lcd_rgb_top(
158     .sys_clk            (clk_50m      ),  //时钟
159     .sys_rst_n          (sys_rst_n    ),  //复位
160     .sys_init_done      (sys_init_done),  //初始化完成
161     //lcd接口
162     .lcd_id             (lcd_id  ),       //LCD屏的ID号
163     .lcd_hs             (lcd_hs  ),       //LCD 行同步信号
164     .lcd_vs             (lcd_vs  ),       //LCD 场同步信号
165     .lcd_de             (lcd_de  ),       //LCD 数据输入使能
166     .lcd_rgb            (lcd_rgb ),       //LCD 颜色数据
167     .lcd_bl             (lcd_bl  ),       //LCD 背光控制信号
168     .lcd_rst            (lcd_rst ),       //LCD 复位信号
169     .lcd_pclk           (lcd_pclk),       //LCD 采样时钟
170     .lcd_clk            (lcd_clk ),       //LCD 驱动时钟
171     //用户接口                  
172     .out_vsync          (out_vsync),      //lcd场信号
173     .h_disp             (),               //行分辨率 h_disp
174     .v_disp             (),               //场分辨率 v_disp
175     .pixel_xpos         (),
176     .pixel_ypos         (),      
177     .data_in            (rd_data       ), //fifo输出数据
178     .data_req           (rdata_req     ), //请求数据输入
179     .data_req_big       (data_req_big  ), //非480x272屏的LCD请求信号
180     .data_req_small     (data_req_small)  //480x272LCD屏请求信号
181     );   
182
183 //以太网顶层模块   
184 eth_top  #(
185     .BOARD_MAC          (BOARD_MAC),    //参数例化
186     .BOARD_IP           (BOARD_IP ),
187     .DES_MAC            (DES_MAC  ),
188     .DES_IP             (DES_IP   )
189     )                  
190     u_eth_top(            
191     .sys_rst_n          (sys_rst_n  ),  //系统复位信号,低电平有效
192     //以太网RGMII接口                  
193     .eth_rxc            (eth_rxc    ),  //RGMII接收数据时钟
194     .eth_rx_ctl         (eth_rx_ctl ),  //RGMII输入数据有效信号
195     .eth_rxd            (eth_rxd    ),  //RGMII输入数据
196     .eth_txc            (eth_txc    ),  //RGMII发送数据时钟   
197     .eth_tx_ctl         (eth_tx_ctl ),  //RGMII输出数据有效信号
198     .eth_txd            (eth_txd    ),  //RGMII输出数据         
199     .eth_rst_n          (eth_rst_n  ),  //以太网芯片复位信号,低电平有效
200                                         
201     .gmii_rx_clk        (gmii_rx_clk),  //以太网125M时钟
202     .rec_en             (rec_en     ),  //以太网32位图片数据接收完成
203     .rec_data           (rec_data   )   //以太网32位数据
204     );
205
206 //以太网32位图片数像素据转16位
207 udp_32_to_16bit u_udp_32_to_16bit(
208   .clk                 (gmii_rx_clk      ), //时钟信号
209   .rst_n               (sys_rst_n        ), //复位信号,低电平有效
210                                             
211   .rec_en              (rec_en           ), //UDP接收的数据使能信号
212   .picture_data_vld0   (picture_data_vld0), //非480x272屏图片像素有效
213   .picture_data_vld1   (picture_data_vld1), //480x272屏图片像素有效  
214   .lcd_id              (lcd_id           ), //LCD屏ID
215   .picture_data_vld    (picture_data_vld ), //图片像素有效  
216   .rec_data            (rec_data         ), //以太网32位图片像素数据
217   .picture_data        (picture_data     )  //以太网16位图片像素数据
218     );
219 endmodule
顶层模块主要实现了对各个子模块的例化,包括前文所提到的六个模块,还包括参数定义。绝大部分的内容我们在“OV772摄像头RGB-LCD显示实验”中有详细介绍。我们只介绍新添加的。
代码第69行,信号rec_data是从以太网模块直接接收到的32bit图片像素数据,本章没有进行缓存处理,注意它是gmii_rx_clk时钟域下的数据。
代码第71行,信号picture_data是欲存入DDR3的图片像素数据,包括裁剪的或者非裁剪的图片数据,16bit。
代码第72行,picture_data_vld,图片数据有效使能信号,该信号和picture_data对应,该信号拉高表明当前时钟下的picture_data是有效的。
代码第73行,picture_data_vld0,图片数据有效使能信号,该信号和picture_data_vld的区别是,它只是原始图片(800*480)数据的有效使能标记。
代码第74行,picture_data_vld1,图片数据有效使能信号,它是裁剪处理后图片(480*272)的有效使能标记。
以上信号的产生将在下文详细介绍。
代码第86行,定义了图片数据存入DDR3的最大地址。当遇到屏幕大小比图片大小(800*480)小的屏幕,也就是lcd_id等16'h4342时,我们需要对图片进行裁剪,此时的DDR3的最大地址就是按照实际屏幕大小来算的,也就是480*272等于130560,其他屏幕不需要裁剪,所以存入的地址是图片的大小都是800*480等于384000。
代码第88行,定义DDR3一次突发读写的长度,我们取所存入图片的一行作为突发长度,代码里面突发长度我们取640。
下文我们来介绍各个子模块,只介绍改动的部分。
首先是以太网顶层(eth_top),该部分代码我们基本移植了“以太网UDP测试实验”,我们所做的改动是去掉了FIFO缓存,直接把以太网UDP接收到的数据送给DDR3控制器模块,DDR3控制器有足够的速度和带宽接收这些数据,并不需额外的缓存。另外由于我们不需要发送以太网UDP数据,只是做一次性接收,所以发送模块并不需要。
        图片裁剪(picture_tailor)模块,该模块是我们新加入的模块,实现把上位机发来的(800*480)的图片裁剪成适合小屏幕(480*272)显示的图片。实现方式有别于“OV772摄像头RGB-LCD显示实验”,但是异曲同工。下面来具体看代码。
1  module picture_tailor(
2      input                 gmii_rx_clk          ,  //像素数据时钟
3      input                 sys_rst_n            ,  //复位信号                    
4     //用户接口
5      input                 picture_data_vld0    ,  //整张图片数据有效使能信号                              
6      output                picture_data_vld1       //裁剪后图片数据有效使能信号   
7      );
8  
9  //reg define                     
10 reg [10:0] picture_data_cntx;                     //整张图片横向像素点坐标
11 reg [10:0] picture_data_cnty;                     //整张图片纵向像素点坐标
12
13 //*****************************************************
14 //**                    main code
15 //*****************************************************
16
17 //产生裁剪后图片数据有效信号
18 assign picture_data_vld1 = ((160 <= picture_data_cntx) && (picture_data_cntx< 640)
19                           && (104 <= picture_data_cnty) && (picture_data_cnty < 376)
20                           && picture_data_vld0)?1'b1:1'b0;
21
22 //产生(800*480)图片横向像素点坐标
23 always@ (posedge gmii_rx_clk or negedge sys_rst_n) begin
24     if(!sys_rst_n)
25         picture_data_cntx <= 11'd0;
26     else if(picture_data_vld0)begin
27         if(picture_data_cntx == 800 - 1'b1)
28             picture_data_cntx <= 11'd0;
29         else
30             picture_data_cntx <= picture_data_cntx + 1'b1;           
31     end
32 end
33
34 //产生(800*480)图片纵向像素点坐标
35 always@ (posedge gmii_rx_clk or negedge sys_rst_n) begin
36     if(!sys_rst_n)
37         picture_data_cnty <= 11'd0;
38     else begin
39         if(picture_data_cntx == 800 - 1'b1) begin
40             if(picture_data_cnty ==480 - 1'b1)
41                 picture_data_cnty <= 11'd0;
42             else
43                 picture_data_cnty <= picture_data_cnty + 1'b1;   
44         end
45     end   
46 end
47   
48 endmodule
该模块实际上不是直接对图片数据进行裁剪,而是裁剪数据有效使能信号,把“picture_data_vld0”裁剪成“picture_data_vld1”由于图片像素数据需要配合数据有效使能信号才能写入下一个DDR3模块,所以也就相当于裁剪了图片数据。
代码第18行到20行,产生裁剪后图片数据有效使能信号picture_data_vld1。原理不难理解,用原图片的像素坐标和四个固定值相比较,这四个固定值实际上就是裁剪后图片(480*272)的四个顶点,在坐标范围之内picture_data_vld1的值等于1,否则等于0。实质上就是从(800*480)的大图片中间抠出(480*272)的这张小图片。这四个顶点的值计算并如下。
左上顶点:160,等于(800-480)/2,
右上顶为:640,等于(800-480)/2+480,
左上顶点:104,等于(480-272)/2,
右上顶为:376,等于480-272)/2+272,
注意这里除了去比较坐标外还需要与上picture_data_vld0,因为只有picture_data_vld0有效时picture_data_vld1才可能有效,其他时候是无效的。
代码第23到32行,产生(800*480)图片横向像素点坐标,这里使用picture_data_vld0作为使能信号。代码第35到46行,产生(800*480)图片纵向素点坐标。
接着看32bit转16bit模块(udp_32_to_16bit)
1  module udp_32_to_16bit(
2      input               clk,                    //时钟信号
3      input               rst_n,                  //复位信号,低电平有效
4      
5      input               rec_en,                 //UDP接收的数据使能信号
6      output              picture_data_vld0,      //以太网800*480图片像素数据有效使能信号
7      input               picture_data_vld1,      //裁剪后480*272像素数据有效使能信号
8      input  [15:0]       lcd_id,                 //LCD ID
9      output              picture_data_vld,       //写入DDR3图片像素数据有效使能信号
10     input  [31:0]       rec_data,               //以太网图片32位像素数据
11     output [15:0]       picture_data            //以太网图片16位像素数据
12     );
13  //wire define
14 wire [15:0] picture_data1 ;                     //以太网图片像素高16数据
15 wire [15:0] picture_data2 ;                     //以太网图片像素低16数据
16  //reg define      
17 reg rec_en_d0;                                  //接收数据有效延迟一拍
18
19 //*****************************************************
20 //**                    main code
21 //*****************************************************
22
23 //判断屏幕如果是480x272则将裁剪的图像数据有效使能赋值给像素数据有效信号,否则将不裁剪
24 //的图像数据有效使能赋给像素数据有效信号
25 assign picture_data_vld = (lcd_id==16'h4342)? picture_data_vld1:picture_data_vld0;
26 //产生以太网800*480图片像素数据有效使能信号,需要持续两个时钟周期
27 assign picture_data_vld0 = ((rec_en==1) ||(rec_en_d0==1 ))? 1'b1:1'b0;
28 //给以太网图片像素高16数据赋值
29 assign picture_data1 = rec_data[31:16];
30 //给以太网图片像素低16数据赋值
31 assign picture_data2 = rec_data[15:0];
32 //分别将太网图片像素高低16位赋值给下游数据
33 assign picture_data = rec_en? picture_data1:picture_data2;
34
35 //接收数据有效信号寄存一拍
36 always @(posedge clk or negedge rst_n) begin
37     if(~rst_n)begin
38        rec_en_d0 <=0;
39     end
40      else begin
41         rec_en_d0 <= rec_en;
42      end
43 end   
44      
45 endmodule
该模块主要负责把以太网接收的32位UDP数据转为16位,同时根据不同的大小的屏幕产生16位数据有效使能信号。
代码第25行,产生写入DDR3的16bit使能信号,具体做法是判断lcd_id等于16'h4342时,此时将“picture_data_vld1”赋值给“picture_data_vld”,也就是此时使能裁剪图片的数据有效,反之,将“picture_data_vld0” 赋值给“picture_data_vld”,也就是使能完整(不裁剪)的图片数据。
代码第27行,产生800*480图片像素数据有效使能信号“picture_data_vld0”,以太网UDP接收到的32bit数据和有效信号rec_en是同步对应的,但是只占用了一个时钟,我们需要分前后两个时钟把32bit数据拆分成两个16bit传输出去,所以使能需要持续两个时钟进行,所以就有了((rec_en==1) ||(rec_en_d0==1 ))这个条件。
代码第29到31行,将32bit数据拆分成两个16bit数据。
代码第33行,分两个时钟先后把高低16bit赋值给图像像素picture_data。
代码第36行开始的always模块,对rec_en信号寄存一拍。
至此,我们代码讲解完毕。
53.5下载验证
用FPC排线将ATK-7RGBLCD模块与开发板连接,然后将网线一端连接电脑网口,另一端与开发板上的网口连接;将下载器一端连电脑,另一端与开发板上对应端口连接,最后连接电源线并打开电源开关。
以太网传图片18100.png
图 53.5.1 开发板硬件连接

打开工程,并下载程序,程序下载完成后,由于还没有向DDR3中写入图片数据,所以DDR3中的数据是随机的,此时LCD显示器上显示的像素点颜色是随机的。接下来我们在上位机中将图片通过网口下载到开发板上的DDR3中。在此之前我们首先准备好图片,并制作成bin格式。具体操作如下:
打开工具Img2Lcd,该工具位于开发板所随附的资料“6_软件资料/1_软件/Img2Lcd”目录下,找到“Img2Lcd.exe”并双击打开,如下图所示:
以太网传图片18378.png
图 53.5.2 Img2Lcd工具使用界面

点击“打开”,导入一幅分辨率为800*480的jpg格式图片,按照上图进行参数设置,可以看到我们输出的图像大小也800*480,确定后是并导出bin文件。在弹出的界面中选择bin文件的保存路径并输入文件名。
到这里我们已经成功地将图片转成了bin文件,接下来需要借助网口调试助手将bin文件下载到开发板中。但是需要注意的是,由于发送的文件较大,需要先对网络适配器属性进行配置。
打开设备管理器,然后在网络适配器中找到网卡并右键选择属性,如下图所示。
902792DE-0DC7-4660-A790-6F20E5BAF8A4.png
图 53.5.3 网络适配器界面

在属性界面中选择“高级”,在属性栏中找到“巨型帧(Jumbo Frame)”,然后在右侧值中选择“9KB MTU”,最后点击确定,如下图所示。
以太网传图片18805.png
图 53.5.4 巨型帧设置

默认情况下,以太网的MTU(Maximum Transmission Unit,最大传输单元)是1500字节。而巨型帧的设置把以太网帧格式的数据段扩展到了9KB,从而在传输大文件时减少了数据帧的个数,减轻了网络设备处理帧头的额外开销,从而提高网络传输性能。
注意有时候可能找不到巨型帧选项,原因是网络适配器驱动软件过于老旧的问题,此时我们只需要更新驱动即可。还是在设备管理器的界面,操作如下:
以太网传图片19062.png
图 53.5.5更新驱动

        最后我们通过网络调试助手发送图片bin文件,如下图所示:
以太网传图片19150.png
图 53.5.6 网络调试助手发送bin文件

网络调试助手的设置和前面的以太网通信相关例程一样,在远程主机一栏选择开发板的IP地址和端口号“192.168.1.102 :1234”;然后在发送区设置一栏勾选“启用文件数据源”,在弹出的界面中选择刚刚生成的bin文件;最后点击右下角的“发送”按钮,即可将由图片生成的bin文件通过网线发送到开发板。
图片发送完成后液晶屏上显示的图片如下所示,说明基于DDR3的LCD显示实验下载验证成功:
以太网传图片19416.png
图 53.5.7  LCD液晶屏显示的图片
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-29 17:57

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表