- 1 功能
- 2 环境
- 3 程序说明
- 3.1 .coe 文件的产生
- 3.2 模块设计
- 3.2.1 顶层模块
- 3.2.2 R61509V3 驱动模块
- 3.2.3 R61509V3 配置模块
- 3.2.4 80-16bit并口模块
- 3.2.5 图片显示模块
- 4 显示效果
- 5 相关资料
使用 FPGA 驱动 TFT-LCD 彩屏 R61509V3 显示彩色图片,屏幕分辨率为240*400,刷新速度100Hz。
2 环境硬件:
项目说明FPGAxc7a35tcsg324-1TFT-LCD驱动ICR61509V 软件: 项目说明vivadoVivado v2017.1 (64-bit)matlabR2018b 64-bitmodelsimModelSim SE-64 10.5 Revision: 2016.02 3 程序说明系统框图: fpga开发板输入时钟为100MHz,通过MMCM输出30MHz时钟作为工作时钟。R61509V3驱动模块完成器件的初始化和显示。R61509V 显示模块例化ROM IP核 ,利用片内存储资源存储图片信息,并根据驱动模块的请求输出数据。80-16bit并口模块将驱动模块输出的指令按照80系统16位并口的时序输出。
xilinx 家的 FPGA 例化单端口 ROM 时,要指定对应的初始化文件。产生coe文件的matlab代码(源文件在相关资料里面工程目录下的matlab文件夹):
clear all;
close all;
%lcd参数
P_lcd_X = 240; %宽
P_lcd_Y = 400; %高
%读取原图片
img_rgb = imread("./pic.jpg");
% figure;imshow(img_rgb);
%根据lcd的参数剪切与压缩图片
img_rgb_size = size(img_rgb);
img_rgb_cut = img_rgb(1:floor(img_rgb_size(1)/P_lcd_Y):400*floor(img_rgb_size(1)/P_lcd_Y),...
floor(img_rgb_size(2)/2-(P_lcd_X/2)*(img_rgb_size(1)/P_lcd_Y)):(img_rgb_size(1)/P_lcd_Y):floor(img_rgb_size(2)/2+(P_lcd_X/2)*(img_rgb_size(1)/P_lcd_Y))-1,:);
figure;imshow(img_rgb_cut);
%RGB数据转为2进制
img_rgb_cut_R = img_rgb_cut(:,:,1);
img_rgb_cut_G = img_rgb_cut(:,:,2);
img_rgb_cut_B = img_rgb_cut(:,:,3);
img_rgb_cut_bin_R = dec2bin(img_rgb_cut_R');
img_rgb_cut_bin_G = dec2bin(img_rgb_cut_G');
img_rgb_cut_bin_B = dec2bin(img_rgb_cut_B');
img_rgb_cut_bin_R = img_rgb_cut_bin_R(:,1:5);
img_rgb_cut_bin_G = img_rgb_cut_bin_G(:,1:6);
img_rgb_cut_bin_B = img_rgb_cut_bin_B(:,1:5);
%写到.coe文件,用来初始化rom
if(0)
coef_bin = [img_rgb_cut_bin_R img_rgb_cut_bin_G img_rgb_cut_bin_B];
fid = fopen('.\coe\pic1.coe','w');
fprintf(fid,'MEMORY_INITIALIZATION_RADIX=2;\n');
fprintf(fid,'MEMORY_INITIALIZATION_VECTOR=\n');
for i = 1:1:length(coef_bin)
fprintf(fid,'%s',coef_bin(i,:));
if i==length(coef_bin)
fprintf(fid,';');
else
fprintf(fid,',\n');
end
end
fclose(fid);
end
首先导入需要转换的图片,然后根据 LCD 的尺寸剪切与压缩图片,然后分别将范围为 0~255 的 RGB 数据转换为 8 位二进制数,最后根据 RGB565 的格式取 R 分量的高 5 位、 G 分量的高 6 位与B分量的高 5 位组合成对应像素点的数据,240*400 像素点对应 coe 文件初始化向量的长度位 96000。在本示例中,原图片,剪切后的图片,生成的 .coe 文件为:



顶层模块对应的 RTL 原理图为: 时钟管理器模块(mmcm_100M) 通过例化 MMCM 来实现。由后面 3.2.4 80-16bit并口模块 的说明可知本设计最大工作时钟受限于 写入低电平脉冲宽度(一个时钟周期,min(PWLW)=30ns),取工作时钟为 30MHz。 R61509V3 驱动模块(R61509V3_driver) 在上电后首先完成 R61509V3 的配置,配置完成后根据设置的刷新频率,输出对应像素点的坐标并且根据对应的 RGB 数据输入刷新屏幕。本模块只是输出80并口的 数据,数据类型,读写类型,触发信号。80并口的时序转换由“80-16bit并口模块”完成。 80-16bit并口模块(lcd_80_16b_dri) 根据用户接口输入的数据类型按照 80系统16位并口 的时序输出。 图片显示模块(pic_disp_rom) 例化rom IP核存储图片的 RGB 数据,根据输入的坐标将对应的数据输出。 顶层模块的代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer: w0shishabi
//
// Create Date: 2021/02/09 19:54:44
// Design Name:
// Module Name: top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module top(
input I_sys_clk ,
input I_reset_n ,
output O_lcd_cs ,
output O_lcd_rs ,
output O_lcd_wr ,
output O_lcd_rd ,
output O_lcd_reset_n ,
inout [15:0] IO_lcd_data
);
//wire define
wire W_reset_n ;
wire W_mmcm_locked ;
wire W_clk_100M ;
wire W_clk_30M ;
wire [15:0] W_data_w ;
wire W_datah_instl ;
wire W_rh_wl ;
wire W_80_exec ;
wire W_80_done ;
wire W_lcd_init_done ;
wire [15:0] W_rgb_data ;
wire [7:0] W_pixel_xpos ;
wire [8:0] W_pixel_ypos ;
wire W_pos_en ;
//main
assign W_reset_n = I_reset_n && W_mmcm_locked;
mmcm_100M mmcm_100M_u
(
// Clock out ports
.clk_out100M(W_clk_100M ), // output clk_out100M
.clk_out30M (W_clk_30M ), // output clk_out20M
// Status and control signals
.reset (~I_reset_n ), // input reset
.locked (W_mmcm_locked), // output locked
// Clock in ports
.clk_in1 (I_sys_clk ));// input clk_in1
pic_disp_rom pic_disp_rom_u(
.I_sys_clk (W_clk_30M ),
.I_reset_n (W_reset_n ),
.I_pos_x (W_pixel_xpos),
.I_pos_y (W_pixel_ypos),
.I_pos_en (W_pos_en ),
.O_data (W_rgb_data )
);
R61509V3_driver R61509V3_driver_u(
.I_sys_clk (W_clk_30M ),
.I_reset_n (W_reset_n ),
.I_rgb_data (W_rgb_data ),
.O_pixel_xpos (W_pixel_xpos ),
.O_pixel_ypos (W_pixel_ypos ),
.O_pos_en (W_pos_en ),
.O_data_w (W_data_w ),
.O_datah_instl (W_datah_instl ),
.O_rh_wl (W_rh_wl ),
.O_80_exec (W_80_exec ),
.I_80_done (W_80_done ),
.O_lcd_init_done(W_lcd_init_done)
);
lcd_80_16b_dri lcd_80_16b_dri_u(
.I_sys_clk (W_clk_30M ),
.I_reset_n (W_reset_n ),
.I_data_w (W_data_w ),
.O_data_r ( ),
.I_datah_instl (W_datah_instl),
.I_rh_wl (W_rh_wl ),
.I_80_exec (W_80_exec ),
.O_80_done (W_80_done ),
.O_lcd_cs (O_lcd_cs ),
.O_lcd_rs (O_lcd_rs ),
.O_lcd_wr (O_lcd_wr ),
.O_lcd_rd (O_lcd_rd ),
.O_lcd_reset_n (O_lcd_reset_n),
.IO_lcd_data (IO_lcd_data )
);
endmodule
顶层模块完成其余模块的例化,其中各模块的复位信号为 MMCM 的 locked 端口输出与系统复位的逻辑与,确保其他模块在时钟稳定后开始工作。
3.2.2 R61509V3 驱动模块R61509V3 驱动模块的代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer: w0shishabi
//
// Create Date: 2021/02/09 09:56:33
// Design Name:
// Module Name: R61509V3_driver
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module R61509V3_driver(
input I_sys_clk ,
input I_reset_n ,
input [15:0] I_rgb_data ,
output reg [7:0] O_pixel_xpos ,
output reg [8:0] O_pixel_ypos ,
output reg O_pos_en ,
output [15:0] O_data_w ,
output O_datah_instl ,
output O_rh_wl ,
output O_80_exec ,
input I_80_done ,
output O_lcd_init_done
);
localparam P_60FPS_CNT = 20'd333333 ;
localparam P_65FPS_CNT = 20'd307692 ;
localparam P_100FPS_CNT = 20'd290912 ;
localparam P_SIM_CNT = 20'd20000 ;//simulation
localparam P_FPS_CNT = P_100FPS_CNT ;
//reg define
reg [19:0] R_clk_div_cnt ;
reg [15:0] R_disp_data_w ;
reg R_disp_datah_instl ;
reg R_disp_rh_wl ;
reg R_disp_80_exec ;
reg R_disp_ena ;
//wire define
wire [15:0] W_init_data_w ;
wire W_init_datah_instl ;
wire W_init_rh_wl ;
wire W_init_80_exec ;
wire W_lcd_init_done ;
wire W_Refresh_frame_req;
//main
assign O_data_w = W_lcd_init_done ? R_disp_data_w : W_init_data_w ;
assign O_datah_instl = W_lcd_init_done ? R_disp_datah_instl : W_init_datah_instl;
assign O_rh_wl = W_lcd_init_done ? R_disp_rh_wl : W_init_rh_wl ;
assign O_80_exec = W_lcd_init_done ? R_disp_80_exec : W_init_80_exec ;
assign O_lcd_init_done = W_lcd_init_done;
R61509V3_config R61509V3_config_u(
.I_sys_clk (I_sys_clk ),
.I_reset_n (I_reset_n ),
.O_data_w (W_init_data_w ),
.O_datah_instl (W_init_datah_instl),
.O_rh_wl (W_init_rh_wl ),
.O_80_exec (W_init_80_exec ),
.I_80_done (I_80_done ),
.O_lcd_init_done(W_lcd_init_done )
);
always @ (posedge I_sys_clk or negedge I_reset_n)
begin
if(~I_reset_n)
begin
R_clk_div_cnt
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?