基础设计五(LCD液晶屏)——FPGA学习笔记<6>

目录

一.TFT_LCD 液晶屏驱动设计

<1>简介

(1)HV 同步模式

(2)DE 同步模式

(3)整体设计

(4)TFT_LCD 显示时序控制模块

<2>程序设计

(1)tft_ctrl 时序控制模块

(2)tft_pic 图像数据生成模块

(3)顶层模块

二.TFT_LCD 液晶屏字符显示


前置学习:基础设计四——FPGA学习笔记<5>

参考书目:《野火FPGA Verilog 开发实战指南》

一.TFT_LCD 液晶屏驱动设计

<1>简介

液晶是一种介于固体和液体之间的特殊物质,它是一种有机化合物,常态下呈液态, 但是它的分子排列却和固体晶体一样非常规则,因此取名液晶。如果给液晶施加电场,会 改变它的分子排列,从而改变光线的传播方向,配合偏振光片,它就具有控制光线透过率 的作用,再配合彩色滤光片,改变加给液晶电压大小,就能改变某一颜色透光量的多少。

        ​常见的 LCD 按物理结构分为四种:扭曲向列型(TN-Twisted NemaTIc)、超扭曲向列型( STN - Super TN ) 、 双层超扭曲向列型 ( DSTN - Dual Scan Tortuosity Nomograph)、薄膜晶体管型(TFT-Thin Film Transistor)。

        TN-LCD、STN-LCD 和 DSYN-LCD 的基本显示原理都相同,只是液 晶分子的扭曲角度不同而已。而 TFT-LCD 则采用与 TN 系列 LCD 截然不同的显示方式。 TFT-LCD 全称 Thin Film Transistor-Liquid Crystal Display,译为薄膜晶体管液晶显示器。其中 TFT 就是 Thin Film Transistor 的简称,指的是薄膜晶体管(矩阵),可以“主动 的”对屏幕上的各个独立的像素进行控制,这也就是所谓的主动矩阵 TFT(active matrix TFT)的来历。图像产生的基本原理很简单:显示屏由许多可以发出任意颜色的光线的像素组成,只要控制各个像素显示相应的颜色就能达到目的了。在 TFT LCD 中一般采用背光 技术,为了能精确地控制每一个像素的颜色和亮度就需要在每一个像素之后安装一个类似百叶窗的半导体开关,以此做到完全的单独的控制一个像素点,液晶材料被夹在 TFT 玻璃层和颜色过滤层之间,通过改变刺激液晶的电压值就可以控制最后出现的光线强度与色彩。

        RGB 接口 TFT-LCD 时序 对于 RGB 接口 TFT-LCD 显示屏,它的图像显示的同步模式有两种,分别为 HV 同步模式、DE 同步模式。不同的同步模式对应不同的时序。

(1)HV 同步模式

        HV 同步模式下,图像的显示只需要行同步信号(hsync)和场同步信号(vsync)来确定显示时序。此时,RGB 接口的 TFT-LCD 液晶显示屏的显示时序和 VGA 时序标准类似。

        如图 30-3 所示,图中 RGB 代表图像信息,HSync 表示行同步信号,HSync 自上一个上升沿起到下一个上升沿止为一个完整周期,我们称之为行扫描周期,一个完整的行扫描周期,包含 4 部分:同步、后沿、有效图像、前沿基本单位为 pixel,即一个像素时钟周期。 在一个完整的行扫描周期中,RGB 图像信息在 HSync 行同步信号的同步下完成一行图像的显示,RGB 图像信息在有效图像阶段,图像信息有效,其他阶段图像信息无效; HSync 行同步信号在同步阶段,维持高电平,其他阶段均保持低电平,在下一个行扫描周期的同步阶段,HSync 行扫描信号拉高,其他阶段拉低,周而复始。

        如图 30-4 所示,图中 RGB 代表图像信息,VSync 表示场同步信号,VSync 自上一个上升沿起到下一个上升沿止为一个完整周期,我们称之为场扫描周期,一个完整的行扫描周期,包含 4 部分:同步、后沿、有效图像、前沿,基本单位为一个完整的行扫描周期。 在一个完整的行扫描周期中,RGB 图像信息在 VSync 行同步信号的同步下完成一帧图像的显示,RGB 图像信息在有效图像阶段,图像信息有效,其他阶段图像信息无效; VSync 行同步信号在同步阶段,维持高电平,其他阶段均保持低电平,在下一个行扫描周 期的同步阶段,VSync 行扫描信号拉高,其他阶段拉低,周而复始。

        图中的红色区域表示在一个完整的行扫描周期中,RGB 图像信息只在此区域有效;黄 色区域表示在一个完整的场扫描周期中,RGB 图像信息只在此区域有效,两者相交的橙色区域,就是 RGB 接口 TFT-LCD 显示屏的图像显示区域。

(2)DE 同步模式

        DE 同步模式下,图像的显示只需要数据使能信号确定显示时序,不需要行场同步信号。DE 同步模式下的 TFT 图像显示时序图如下。

        由图可知,当数据使能信号为高电平时,表示 TFT 显示屏扫描到了有效显示区域,此时输入到 TFT 显示屏的图像信息能够显示出来;当数据使能信号为低电平时,表示 TFT 显 示屏未扫描到有效显示区域。         

        对于两种不同的同步模式, DE 同步模式一般使用在大尺寸屏幕,小尺寸屏幕多使用 HV 同步模式。HV 同步模式地出现早于 DE 同步模式,当今的大部分显示屏均支持 HV 和 DE 两种同步模式。

        RGB 接口 TFT-LCD 分辨率 不同的分辨率的 TFT-LCD 显示屏在时序上是相似的,只是存在一些参数上的差异, 下面列举了部分分辨率的时序参数,刷新频率均为 60Hz

        

(3)整体设计

        设计编写 RGB 接口 TFT-LCD 液晶显示屏驱动,在 4.3 寸(480*272) TFT-LCD 显示屏上 横向依次显示等宽多色彩条,显示颜色自左向右依次为红、橙、黄、绿、青、蓝、紫、 黑、白、灰,图像像素格式为 RGB565,帧率为 60Hz。

注:本章节后文中涉及到的相关参数均与 4.3 寸(480*272) TFT-LCD 显示屏的的相关参数相对应,事先告知,后续不再声明。

升腾 mini 开发板 TFT_LCD 接口部分原理图:

注:在本实验工程中,输出信号中包含 HV 同步模式下需要的行、场同步信号 (hsync、vsync)和 DE 同步模式下的 tft_de 信号,各信号正确输出。读者若想要使用 HV 同 步模式进行图像显示,可在代码中注释掉 tft_de 信号;若想要使用 DE 同步模式进行图像 显示,可带代码中注释掉行、场同步信号。

        TFT 彩条显示工程的工作流程。

(1) 系统上电后,板卡传入系统时钟(sys_clk)和复位信号(sys_rst_n)到顶层模块;

(2) 系统时钟直接传入时钟生成模块(clk_gen),分频产生 TFT 显示屏工作时钟 (clk_in),作为图像数据生成模块(tft_pic)和 TFT 时序控制模块(tft_ctrl)的工作时 钟;

(3) 图像数据生成模块以 TFT 显示时序控制模块传入的像素点坐标(pix_x,pix_y)为约束条件,生成待显示彩条图像的色彩信息(pix_data)

(4) 图像数据生成模块生成的彩条图像色彩信息传入 TFT 时序控制模块,在模块内部使用使能信号滤除掉非图像显示有效区域的图像数据,产生 RGB 色彩信息 (rgb_tft),在行、场同步信号(hsync、vsync)或数据使能信号(tft_de)的同步作用下,将 RGB 色彩信息扫描显示到 TFT 显示屏,显示出彩条图像。

(4)TFT_LCD 显示时序控制模块

        data_in 为彩条图像 像素点色彩信息,由图像数据生成模块产生并传入,在 TFT_LCD 显示器有效图像显示区域赋值给信号 RGB 图像色彩信息(rgb_tft_16b)。

        输出信号(pix_x,pix_y)为 TFT_LCD 有效显示区域像素点坐标,由 TFT_LCD 时序控制模块生并传入图像数据生成模块;hsync、vsync 为 TFT_LCD 行、场同步信号 ,通过 TFT_LCD 接口传输给 TFT_LCD 显示屏;rgb_tft_16b 为显示器要显示的图像色彩信息,传输给 TFT_LCD 显示器;tft_bl 为 TFT 显示屏背光信号;tft_clk 为 TFT 显示屏工作时钟; tft_de 为 TFT 显示使能信号。

        第一部分:行同步信号(hsync)、场同步信号(vsync)。由时序图可知,行同步信号为周期性信号,信号变化周期为完整的行扫描周期,信号在同步阶段保持高电平,在其他阶段保持低电平,那么如何实现行同步信号的周期性变化呢? 我们想到了前文学过的计数器,因为一个完整行扫描周期为 525 个像素时钟周期 (480*272@60,见前表格),我们可以利用计数器以像素时钟周期进行计数,每一个像素时钟周期自加 1,计数范围为 0-524,共计数 525 次,与完整行扫描周期数相吻合。只要在行同步阶段(计数范围 0-40)赋值 hsync 信号为高电平,其他阶段为低电平,就可以实现符合时序要求的行同步信号 hsync。根据此设计思路,声明并绘制行扫描周期计数器 cnt_h、行同步信号 hsync 信号波形如下:

        同理,参考行同步信号波形的绘制思路,我们可以进行场同步信号波形的绘制。不过要注意的是,场扫描周期单位不是像素时钟周期,而是完整的行扫描周期,所以要添加场扫描周期计数器对行扫描周期进行计数(再525分频),声明并绘制场扫描周期计数器 cnt_v、场同步信号 vsync 信号波形如下:

        第二部分:图像显示有效信号(data_valid)波形绘制思路由上文可知,TFT 显示屏只有在有效的显示区域内送入图像数据,图像才会被正确显示。我们可以声明一个有效信号,在图像有效显示区域赋值高电平,在非图像有效显示区域赋值低电平,以此信号为约束条件,控制图像信号的正确输入,定义此信号为图像显示有效信号(rgb_valid)。 这里我们可以利用上一部分声明的 cnt_h、cnt_v 两个计数器,以其为约束条件,当两个计数器计数到图像有效显示区域时,data_valid 赋值高电平,否则赋值低电平。绘制图像显示有效信号(data_valid)波形如下:

        第三部分:图像信息请求信号(data_req)、TFT 显示屏有效显示区域像素点坐标 (pix_x,pix_y)波形绘制思路为了提高模块复用性,我们将图像数据生成功能独立出来,设计为图像数据生成模块 tft_pic,虽然模块复用性提高,但这样就产生一个问题,怎样保证 data_in 传输的图像数据与 TFT 显示屏时序相吻合呢?

        结合之前学习的知识,我们知道只有在 TFT 显示屏有效显示区域,data_in 传输的图像数据才会传输给 TFT 显示屏,那么我们可以只在 TFT 显示屏有效显示区域对 data_in 进行赋值,如何实现这一想法呢?

        我们可以使用 cnt_h、cnt_v 信号来确定 TFT 显示屏有效显示区域,将有效显示区域使用坐标法表示,针对不同坐标点对 data_in 进行赋值,所以我们声明 TFT 显示屏有效显示区域像素点坐标(pix_x,pix_y)。

        上面两个问题解决了,新的问题又来了,TFT 显示屏有效显示区域为 480*272,如何 使像素点坐标(pix_x,pix_y)实现(0,0) – (480,272)的坐标计数? 读者可能会想到使用已经声明的图像显示有效信号(data_valid),但在此处不能使用该信号。

        因为本次实验是 TFT 显示屏多色彩条的显示,图像数据生成模块 tft_pic 需要以坐标 (pix_x,pix_y)为约束条件对 data_in 信号进行赋值,只能使用时序逻辑的赋值方式,那么 data_in 的赋值时刻会滞后条件满足时刻一个时钟周期,显示图像会出现问题

        为了解决这一问题,我们需要声明新的图像数据请求信号 data_req,该信号要超前图像显示有效信号(data_valid)一个时钟周期,以抵消 data_in 时序逻辑赋值带来的问题。 综上所述,我们需要声明图像信息请求信号 data_req、TFT 显示屏有效显示区域像素点坐标(pix_x,pix_y)这三路信号来解决之前提到的若干问题。对于 data_req 信号的电平控制可参考 data_valid 信号的控制方式,以 cnt_h、cnt_v 信号为约束条件;坐标(pix_x,pix_y)则 以新声明的 data_req 信号为约束条件控制生成,三路信号绘制波形图如下:

        第四部分:RGB 色彩信息(rgb_tft_16b)波形绘制思路这一部分就比较简单了,TFT 显示屏图像显示是在行、场同步信号的作用下,将图像色彩信息以扫描显示的方式显示出来,所以 RGB 色彩信息必不可少,只要在有效显示区域写入正确图像数据即可。信号 rgb_tft_16b 绘制波形如下:

        第五部分: TFT 显示数据使能信号(tft_de)波形绘制思路数据使能信号为 DE 同步模式下的图像显示同步信号,只在有效图像显示区域为高电平,其他时刻为低电平。tft_de 信号的波形变化和 data_valid 信号相同,所以 tft_de 信号可 由 data_valid 信号使用组合逻辑进行赋值。数据使能信号(tft_de)波形如下图。

        第六部分: TFT 显示屏工作时钟(tft_clk)、TFT 显示屏背光信号(tft_bl)波形绘制思路 TFT 显示屏与 VGA 显示器不同,TFT 显示屏的正常工作离不开时钟信号,而且输入 TFT 显示屏的时钟信号,要与行场信号或数据使能信号的同步时钟相同,否者会出现图像显示的错误。 TFT 显示屏的背光信号作用是控制显示屏背光,为高电平时打开显示器背光,低电平时关闭背光,在本实验工程使用复位信号 sys_rst_n 信号为背光信号赋值。 上述两信号波形图如下。

        本设计思路只做参考,并非唯一方法,读者可利用所学知识,按照自己思路进行设计。 

<2>程序设计

(1)tft_ctrl 时序控制模块

module  tft_ctrl
(
    input   wire            clk_in      ,   //输入时钟
    input   wire            sys_rst_n   ,   //系统复位,低电平有效
    input   wire    [15:0]  data_in     ,   //待显示数据

    output  wire            data_req    ,   //数据请求信号
    output  wire    [10:0]  pix_x       ,   //输出TFT有效显示区域像素点X轴坐标
    output  wire    [10:0]  pix_y       ,   //输出TFT有效显示区域像素点Y轴坐标
    output  wire    [15:0]  rgb_tft_16b ,   //TFT显示数据
    output  wire    [23:0]  rgb_tft_24b ,   //TFT显示数据
    output  wire            hsync       ,   //TFT行同步信号
    output  wire            vsync       ,   //TFT场同步信号
    output  wire            tft_clk     ,   //TFT像素时钟
    output  wire            tft_de      ,   //TFT数据使能
    output  wire            tft_bl          //TFT背光信号
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//

//parameter define  5寸、七寸屏
// parameter   H_SYNC      =   11'd34  ,   //行同步
            // H_BACK      =   11'd46  ,   //行时序后沿
            // H_LEFT      =   11'd0   ,   //行时序左边框
            // H_VALID     =   11'd800 ,   //行有效数据
            // H_RIGHT     =   11'd0   ,   //行时序右边框
            // H_FRONT     =   11'd210 ,   //行时序前沿
            // H_TOTAL     =   11'd1090;   //行扫描周期
            
// parameter   V_SYNC      =   11'd10  ,   //场同步
            // V_BACK      =   11'd23  ,   //场时序后沿
            // V_TOP       =   11'd0   ,   //场时序左边框
            // V_VALID     =   11'd480 ,   //场有效数据
            // V_BOTTOM    =   11'd0   ,   //场时序右边框
            // V_FRONT     =   11'd22  ,   //场时序前沿
            // V_TOTAL     =   11'd535 ;   //场扫描周期
//parameter define  4.3寸屏
parameter H_SYNC    =   10'd41  ,   //行同步
          H_BACK    =   10'd2   ,   //行时序后沿
          H_LEFT    =   11'd0   ,   //行时序左边框
          H_VALID   =   10'd480 ,   //行有效数据
          H_FRONT   =   10'd2   ,   //行时序前沿
          H_RIGHT   =   11'd0   ,   //行时序右边框
          H_TOTAL   =   10'd525 ;   //行扫描周期
parameter V_SYNC    =   10'd10  ,   //场同步
          V_BACK    =   10'd2   ,   //场时序后沿
          V_TOP     =   11'd0   ,   //场时序左边框
          V_VALID   =   10'd272 ,   //场有效数据
          V_FRONT   =   10'd2   ,   //场时序前沿
          V_BOTTOM  =   11'd0   ,   //场时序右边框
          V_TOTAL   =   10'd286 ;   //场扫描周期
                                                                                                                                            
parameter   H_PIXEL     =   11'd480 ,   //水平方向有效图像像素个数
            V_PIXEL     =   11'd272 ;   //垂直方向有效图像像素个数
parameter   H_BLACK     =   ((H_VALID - H_PIXEL) / 2),  //水平方向黑色边框宽度
            V_BLACK     =   ((V_VALID - V_PIXEL) / 2);  //垂直方向黑色边框宽度

//wire  define
wire            data_valid  ;   //有效显示区域标志
wire    [15:0]  data_out    ;   //输出有效图像数据
wire    [7:0]   rgb_r;
wire    [7:0]   rgb_g;
wire    [7:0]   rgb_b;

//reg   define
reg     [10:0]   cnt_h       ;   //行扫描计数器
reg     [10:0]   cnt_v       ;   //场扫描计数器

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//tft_clk,tft_de,tft_bl:TFT像素时钟、数据使能、背光信号
assign  tft_clk = clk_in    ;
assign  tft_de  = data_valid;
assign  tft_bl  = sys_rst_n ;

//cnt_h:行扫描计数器
always@(posedge clk_in or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_h   <=  11'd0;
    else    if(cnt_h == H_TOTAL - 1'b1)
        cnt_h   <=  11'd0;
    else
        cnt_h   <=  cnt_h + 10'd1;

//cnt_v:场扫描计数器
always@(posedge clk_in or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_v   <=  11'd0;
    else    if(cnt_h == H_TOTAL - 1'b1) 
    begin
        if(cnt_v == V_TOTAL - 1'b1)
            cnt_v   <=  11'd0;
        else
            cnt_v   <=  cnt_v + 10'd1;
    end
    else 
        cnt_v   <=  cnt_v;

//data_valid:有效显示区域标志
assign  data_valid = ((cnt_h >= (H_SYNC + H_BACK + H_LEFT))
                    && (cnt_h < (H_SYNC + H_BACK + H_LEFT + H_VALID )))
                    &&((cnt_v >= (V_SYNC + V_BACK + V_TOP))
                    && (cnt_v < (V_SYNC + V_BACK + V_TOP + V_VALID)));

//data_req:图像数据请求
assign  data_req = ((cnt_h >= (H_SYNC + H_BACK + H_LEFT + H_BLACK - 1'b1)) 
                    && (cnt_h < ((H_SYNC + H_BACK + H_LEFT + H_BLACK + H_PIXEL - 1'b1))))
                    &&((cnt_v >= ((V_SYNC + V_BACK + V_TOP + V_BLACK)))
                    && (cnt_v < ((V_SYNC + V_BACK + V_TOP + V_BLACK + V_PIXEL))));

assign  pix_x = (data_req == 1'b1)
                ? (cnt_h - (H_SYNC + H_BACK + H_LEFT - 1'b1)) : 11'h3ff;
assign  pix_y = (data_req == 1'b1)
                ? (cnt_v - (V_SYNC + V_BACK + V_TOP)) : 11'h3ff;

//data_out:输出有效图像数据
assign  data_out = (data_req == 1'b1) ? data_in : 16'h0000;

//hsync,vsync,rgb_tft_16b:行、场同步信号、图像数据
assign  rgb_tft_16b = (data_valid == 1'b0) ? 16'hFFFF : data_out;
assign  hsync = (cnt_h  <=  H_SYNC - 1'd1) ? 1'b1 : 1'b0  ;
assign  vsync = (cnt_v  <=  V_SYNC - 1'd1) ? 1'b1 : 1'b0  ;

//rgb16 565转rgb24 888
assign rgb_r={rgb_tft_16b[15:11],3'd0};
assign rgb_g={rgb_tft_16b[10:5],2'd0};
assign rgb_b={rgb_tft_16b[4:0],3'd0}; 
assign rgb_tft_24b={rgb_r,rgb_g,rgb_b};

endmodule

        可以看出 data_req 信号超前 data_valid 信号一个时钟周期(这里H_BLACK=V_BLACK=0且 data_req  多减了一个 1 );data_req 考虑了黑边框,因为分辨率 480*272 对应行列有效周期 480 和 272 ,故黑边多少像素减去多少周期即可;另外 pix_x 和 pix_y 都已在此赋值。

(2)tft_pic 图像数据生成模块

        以 TFT 显示时序控制模块传入的图像有效显示区域像素点坐标(pix_x,pix_y)为约束条件,产生 TFT 彩条图像像素点色彩信息并回传给 TFT 显示时序控制模块。

module  tft_pic
(
    input   wire            tft_clk_9m  ,   //输入工作时钟,频率9MHz
    input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
    input   wire    [9:0]   pix_x       ,   //输入TFT有效显示区域像素点X轴坐标
    input   wire    [9:0]   pix_y       ,   //输入TFT有效显示区域像素点Y轴坐标

    output  reg     [15:0]  pix_data        //输出像素点色彩信息

);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//

parameter   H_VALID =   10'd480 ,   //行有效数据
            V_VALID =   10'd272 ;   //场有效数据

parameter   RED     =   16'hF800,   //红色
            ORANGE  =   16'hFC00,   //橙色
            YELLOW  =   16'hFFE0,   //黄色
            GREEN   =   16'h07E0,   //绿色
            CYAN    =   16'h07FF,   //青色
            BLUE    =   16'h001F,   //蓝色
            PURPPLE =   16'hF81F,   //紫色
            BLACK   =   16'h0000,   //黑色
            WHITE   =   16'hFFFF,   //白色
            GRAY    =   16'hD69A;   //灰色

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//pix_data:输出像素点色彩信息,根据当前像素点坐标指定当前像素点颜色数据
always@(posedge tft_clk_9m or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pix_data    <= 16'd0;
    else    if((pix_x >= 0) && (pix_x < (H_VALID/10)*1))
        pix_data    <=  RED;
    else    if((pix_x >= (H_VALID/10)*1) && (pix_x < (H_VALID/10)*2))
        pix_data    <=  ORANGE;
    else    if((pix_x >= (H_VALID/10)*2) && (pix_x < (H_VALID/10)*3))
        pix_data    <=  YELLOW;
    else    if((pix_x >= (H_VALID/10)*3) && (pix_x < (H_VALID/10)*4))
        pix_data    <=  GREEN;
    else    if((pix_x >= (H_VALID/10)*4) && (pix_x < (H_VALID/10)*5))
        pix_data    <=  CYAN;
    else    if((pix_x >= (H_VALID/10)*5) && (pix_x < (H_VALID/10)*6))
        pix_data    <=  BLUE;
    else    if((pix_x >= (H_VALID/10)*6) && (pix_x < (H_VALID/10)*7))
        pix_data    <=  PURPPLE;
    else    if((pix_x >= (H_VALID/10)*7) && (pix_x < (H_VALID/10)*8))
        pix_data    <=  BLACK;
    else    if((pix_x >= (H_VALID/10)*8) && (pix_x < (H_VALID/10)*9))
        pix_data    <=  WHITE;
    else    if((pix_x >= (H_VALID/10)*9) && (pix_x < H_VALID))
        pix_data    <=  GRAY;
    else
        pix_data    <=  BLACK;

endmodule

        每个时钟周期 tft_clk_9m 对 pix_data 赋值即可;由于 pix_data 由 pix_x、pix_y 的值确定,易知 pix_data 滞后 pix_x、pix_y 信号一个时钟周期

(3)顶层模块

module  tft_colorbar
(
    input   wire            sys_clk     ,   //输入工作时钟,频率50MHz
    input   wire            sys_rst_n   ,   //输入复位信号,低电平有效

    output  wire    [15:0]  rgb_tft     ,   //输出像素信息
    output  wire            hsync       ,   //输出行同步信号
    output  wire            vsync       ,   //输出场同步信号
    output  wire            tft_clk     ,   //输出TFT时钟信号
    output  wire            tft_de      ,   //输出TFT使能信号
    output  wire            tft_bl          //输出背光信号
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//

//wire  define
wire            tft_clk_9m  ;   //TFT工作时钟,频率9MHz
wire            locked      ;   //PLL locked信号
wire            rst_n       ;   //TFT模块复位信号
wire    [9:0]   pix_x       ;   //TFT有效显示区域X轴坐标
wire    [9:0]   pix_y       ;   //TFT有效显示区域Y轴坐标
wire    [15:0]  pix_data    ;   //TFT像素点色彩信息

//rst_n:TFT模块复位信号
assign  rst_n = (sys_rst_n & locked);

//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//

clk_wiz_0 clk_gen_inst
(
    .reset     (~sys_rst_n ),  //输入复位信号,高电平有效,1bit
    .clk_in1   (  sys_clk  ),  //输入50MHz晶振时钟,1bit
    .clk_out1  (tft_clk_9m ),  //输出TFT工作时钟,频率9Mhz,1bit

    .locked    (locked     )   //输出pll locked信号,1bit
);

//------------- tft_ctrl_inst -------------
tft_ctrl tft_ctrl_inst
(
    .clk_in     (tft_clk_9m ) ,   //输入时钟
    .sys_rst_n  (rst_n      ) ,   //系统复位,低电平有效
    .data_in    (pix_data   ) ,   //待显示数据
    .data_req   (           ) ,   //数据请求信号
    .pix_x      (pix_x      ) ,   //输出TFT有效显示区域像素点X轴坐标
    .pix_y      (pix_y      ) ,   //输出TFT有效显示区域像素点Y轴坐标
    .rgb_tft_16b(rgb_tft    ) ,   //TFT显示数据16bit
    .rgb_tft_24b(           ) ,   //TFT显示数据24bit
    .hsync      (hsync      ) ,   //TFT行同步信号
    .vsync      (vsync      ) ,   //TFT场同步信号
    .tft_clk    (tft_clk    ) ,   //TFT像素时钟
    .tft_de     (tft_de     ) ,   //TFT数据使能
    .tft_bl     (tft_bl     )     //TFT背光信号
);
//------------- tft_pic_inst -------------
tft_pic tft_pic_inst
(
    .tft_clk_9m  (tft_clk_9m),   //输入工作时钟,频率9MHz
    .sys_rst_n   (rst_n     ),   //输入复位信号,低电平有效
    .pix_x       (pix_x     ),   //输入TFT有效显示区域像素点X轴坐标
    .pix_y       (pix_y     ),   //输入TFT有效显示区域像素点Y轴坐标

    .pix_data    (pix_data  )    //输出像素点色彩信息

);

endmodule

二.TFT_LCD 液晶屏字符显示

        在 TFT 显示屏中心位置显示金色“野火科技”四个汉字,字符外的背景颜色为黑色。每个汉字大小为 56*56,字模点阵为 64*64,TFT 显示屏显示模式为 480*270@60。

        第一部分:字符点阵显示区域坐标信号的设计与实现在上面小节中,我们利用取模软件生成了要显示字符的字模,字模点阵的大小为 256*64(64*4*64),那么如何利用字模点阵进行字符显示呢? 首先确定字符有效显示区域,区域大小与字符点阵大小相同,显示区域的像素点与字模点阵中数据项一一对应,当字模点阵中的数据项数值为“1”时,赋值字符颜色给对应像素点;当字模点阵中的数据项数值为“0”时,赋值点阵背景颜色给对应像素点。 所以为了确定字符点阵显示区域,我们声明两个变量 char_x、char_y,两变量组成字 符点阵显示区域坐标,在字符点阵有效显示区域内,char_x 信号 0-255 循环计数,char_y 信号 0-63 循环计数 ,根据坐标(char_x,char_y)寻找字符点阵对应的数据项,根据数据项的数值,赋予对应坐标像素点颜色信息。char_x、char_y 信号波形具体见图。

module  tft_pic
(
    input   wire            tft_clk_9m  ,   //输入工作时钟,频率9MHz
    input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
    input   wire    [9:0]   pix_x       ,   //输入TFT有效显示区域像素点X轴坐标
    input   wire    [9:0]   pix_y       ,   //输入TFT有效显示区域像素点Y轴坐标

    output  reg     [15:0]  pix_data        //输出像素点色彩信息

);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//

parameter   H_VALID =   10'd480 ,   //行有效数据
            V_VALID =   10'd272 ;   //场有效数据

parameter   CHAR_B_H=   10'd112 ,   //字符开始X轴坐标
            CHAR_B_V=   10'd104 ;   //字符开始Y轴坐标

parameter   CHAR_W  =   10'd256 ,   //字符宽度
            CHAR_H  =   10'd64  ;   //字符高度

parameter   BLACK   =   16'h0000,   //黑色
            GOLDEN  =   16'hFEC0;   //金色

//wire  define
wire    [9:0]   char_x  ;   //字符显示X轴坐标
wire    [9:0]   char_y  ;   //字符显示Y轴坐标

//reg   define
reg     [255:0] char    [63:0]  ;   //字符数据

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//字符显示坐标
assign  char_x  =   (((pix_x >= CHAR_B_H) && (pix_x < (CHAR_B_H + CHAR_W)))
                    && ((pix_y >= CHAR_B_V) && (pix_y < (CHAR_B_V + CHAR_H))))
                    ? (pix_x - CHAR_B_H) : 10'h3FF;
assign  char_y  =   (((pix_x >= CHAR_B_H) && (pix_x < (CHAR_B_H + CHAR_W)))
                    && ((pix_y >= CHAR_B_V) && (pix_y < (CHAR_B_V + CHAR_H))))
                    ? (pix_y - CHAR_B_V) : 10'h3FF;

//char:字符数据
always@(posedge tft_clk_9m)
    begin
        char[0]     <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[1]     <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[2]     <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[3]     <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[4]     <=  256'h00000000003C0000000000000000000000000000000070000000000000000000;
        char[5]     <=  256'h0000000E003E00000000000000000000000000000000F0000000000000000000;
        char[6]     <=  256'h000000FF001F00000000000000000000000000000001F0000000000000400000;
        char[7]     <=  256'h000007FF000F00000000000000000000000010000001F8000000000000E00000;
        char[8]     <=  256'h00007FFE000F000000000000000000000003FE000001F8000000000000F00000;
        char[9]     <=  256'h0000FE7E003F00000000000000000000000FFF800001F80000003E0000F00000;
        char[10]    <=  256'h0000E07C01F8000000000000000000000007FF81F801FC0000003F0000F00000;
        char[11]    <=  256'h0000E0F80380000000000000000000000003FF80FE00780000003F0001E00000;
        char[12]    <=  256'h0000E0F80380000000000000000000000001FF80FF00780000003F0001E00000;
        char[13]    <=  256'h0780E1F003FC000000000000000000000000FF80FF80780000003E0001E00000;
        char[14]    <=  256'h07C0FFF003FE0000000000020000000000003F007F80780000003E0001E00000;
        char[15]    <=  256'h07E0FFE001FE0000000000070000000000000E007F00780000003C0001FF0000;
        char[16]    <=  256'h07F3FFE0000E00000000000700000000000000007E00F80000003C0001FF0000;
        char[17]    <=  256'h07F9FFC0000E00000000000F0000000000003E00CC01F80000007C0003FE0000;
        char[18]    <=  256'h03F9FFC0001C03E00000000F8000000000003F010001F80000007E0003F80000;
        char[19]    <=  256'h03F9FF8000781FF80000001F8000000000007F038001F8000000FF0007F00000;
        char[20]    <=  256'h03F9FF8001F07FF80000001F878000000000FE078001F8000000FF000FE00000;
        char[21]    <=  256'h03FDFF0007C3FFF00000003FFFC000000001FC07C001F8000001FF003FE00000;
        char[22]    <=  256'h03FDFF000F9F8FF00001C03FFFC000000007F807F001F8000007FE003FC00000;
        char[23]    <=  256'h03FFFE001FFF8FE00001E07FFFC00000001FF807FC01F800000FFC0003C00000;
        char[24]    <=  256'h01FFF0007FFF8FC00003E07FFC000000067FF007FE01FC00001FF80003800000;
        char[25]    <=  256'h01FFC000FFEF9F800003E0FE000000000FFFF003FC01FE00007FF00007800000;
        char[26]    <=  256'h01FF8001FF8F9F000007E0FE000000000FFFF041F803FC0000FFE00007800000;
        char[27]    <=  256'h01FF8007FC1F9E00001FE0FE000000000FFFF180F00FFC000001E00007000000;
        char[28]    <=  256'h00FF8007F01F3C00003FE1FC00000000007FF601E01FF8000001E000071C0000;
        char[29]    <=  256'h00FF8007C01FFC00003FE1FC00000000001FFC03C0FFF8000001E0000F3E0000;
        char[30]    <=  256'h00030002001FF800003FC3FC00000000003FF807C3FFF8000001E7800FFE0000;
        char[31]    <=  256'h00070000001FF000007FC3F800000000003FF80F9FFFF0000001FF000FFE0000;
        char[32]    <=  256'h0007F000001FE000007F83F800000000007FF01FFFC3F0000001FE000FFE0000;
        char[33]    <=  256'h001FF000001FC000003F83F00000000000FFF01FFE03F0000001FC001FFE0000;
        char[34]    <=  256'h007FE000001F8000003F07F00000000000FFE03FF003F0000003F8001F3E0000;
        char[35]    <=  256'h007FC000001F8000001807F00000000001FFE03F8003F0000003F0001F3C0000;
        char[36]    <=  256'h00078600001F000000000FF80000000003FFC07E0003F0000003F0001E3C0000;
        char[37]    <=  256'h000F1E00001F000000000FFC0000000007FFC0180003F0000007E003843C0000;
        char[38]    <=  256'h003FFC00001F800000001FDE0000000007FFC0000003F000000FF001E03C0000;
        char[39]    <=  256'h007FF800001F800000003FDF8000000007C7C0000003F00000FFF000F83C0000;
        char[40]    <=  256'h00FFF000001F800000007F9FF00000000787C0000003F00007FFF0007F3C0000;
        char[41]    <=  256'h01FFE000001F80000000FF0FFE0000000707C0000003F0001FF1F8003FFC0000;
        char[42]    <=  256'h03FF8000001F80000001FE0FFFE000000003C0000003F0003F81F8001FFC0000;
        char[43]    <=  256'h07FF0000003F80000003FC07FFFE0000000300000003F0003E01FC000FFE0000;
        char[44]    <=  256'h07FC0000003F80000007F803FFFFE000000000000003F0001F83FC0007FFF000;
        char[45]    <=  256'h07F80000003F8000000FF001FFFFFF80000000000003F0000FFFFC0003FFFF80;
        char[46]    <=  256'h03E00000007F8000001FC0007FFFFFC0000000000003F00003FFFE0007FFFFF0;
        char[47]    <=  256'h0000000000FF8000007F80001FFFFFE0000000000003F000007FFE003FBFFFF8;
        char[48]    <=  256'h0000000001FF800000FE000007FFFFE0000000000003E000000FFC03FE0FFFF8;
        char[49]    <=  256'h0000000007FF800001F8000001FFFFF0000000000003E0000000F8FFC003FFF8;
        char[50]    <=  256'h000000007FFF000003E00000001FFFC0000000000003C0000000000000007FF8;
        char[51]    <=  256'h00000007FFFE0000070000000001FFC0000000000003C0000000000000000FF0;
        char[52]    <=  256'h0000000200F800000000000000000F8000000000000300000000000000000060;
        char[53]    <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[54]    <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[55]    <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[56]    <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[57]    <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[58]    <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[59]    <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[60]    <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[61]    <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[62]    <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
        char[63]    <=  256'h0000000000000000000000000000000000000000000000000000000000000000;
    end

//pix_data:输出像素点色彩信息,根据当前像素点坐标指定当前像素点颜色数据
always@(posedge tft_clk_9m or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pix_data    <= BLACK;
    else    if(((pix_x >= CHAR_B_H) && (pix_x < (CHAR_B_H + CHAR_W)))
                && ((pix_y >= CHAR_B_V) && (pix_y < (CHAR_B_V + CHAR_H))))
        begin
            if(char[char_y][10'd255 - char_x] == 1'b1)
                pix_data    <=  GOLDEN;
            else
                pix_data    <=  BLACK;
        end
    else
        pix_data    <= BLACK;

endmodule

可知根据对应坐标的char二维数组值判定颜色。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
FPGA自学笔记——设计与验证JMB FPGA(可编程逻辑门阵列)是一种可编程的硬件平台,可以实现各种数字电路的设计与验证。本文将简要介绍使用FPGA自学设计与验证JMB(低功耗、高效能、集成度高的多媒体芯片)的过程。 首先,我们需要了解JMB的功能和特性。JMB是一种面向多媒体应用的芯片,具备低功耗、高效能和高集成度的优势。我们需要详细研究JMB的硬件架构和内部模块,包括处理器核、存储器模块、图像和音频处理模块等。 接下来,我们可以使用FPGA开发板来设计和验证JMB。首先,我们需要熟悉FPGA设计工具,例如Vivado或Quartus等。这些工具提供了图形化界面和硬件描述语言(HDL)等设计方法。我们可以使用HDL编写JMB的功能模块,并将其综合为FPGA可执行的位流文件。 在设计完成后,我们需要验证JMB的功能和性能。我们可以使用仿真工具(例如ModelSim或ISE Simulator)来模拟JMB在不同情况下的行为。通过设计测试程序并运行仿真,我们可以验证JMB的各个模块是否正确地工作,是否满足设计要求。 在验证完成后,我们可以将位流文件下载到FPGA开发板中进行智能芯片的物理实现和测试。通过与外部设备的连接以及相关测试程序的运行,我们可以验证JMB在实际硬件中的功能和性能。 总结起来,学习FPGA设计与验证JMB,我们需要熟悉JMB的硬件架构和内部模块,并使用FPGA开发工具进行设计与验证。通过仿真和物理实现测试,我们可以验证JMB的功能和性能。这些过程需要理论知识和实践经验的结合,希望这些笔记能够给你提供一些参考和指导。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

switch_swq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值