您当前的位置: 首页 > 

lu-ming.xyz

暂无认证

  • 1浏览

    0关注

    115博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【TFT-LCD学习记录2】 R61509V3 彩屏 FPGA 驱动程序设计

lu-ming.xyz 发布时间:2021-02-13 22:47:45 ,浏览量:1

目录
  • 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 相关资料

1 功能

 使用 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位并口的时序输出。

3.1 .coe 文件的产生

 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 文件为:

原图 剪切后的图片 生成的 .coe 文件 3.2 模块设计 3.2.1 顶层模块

 顶层模块对应的 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             
关注
打赏
1655639048
查看更多评论
0.0390s