基于FPGA实现正点原子LCD显示屏的驱动

正点原子的显示器4342的参数,来源于正点原子datasheet:
工作频率:9MHz
行周期:525个时钟周期
行显示区域:480个时钟周期
行后沿:40个时钟周期
行前沿:5个时钟周期
列周期:288行
列显示区域:272行
列后沿:8行
列前沿:8行
设计回顾:
最开始以为正点原子的显示屏跟咱们用的显示器一样,只需要行同步信号和列同步信号,写完底层代码,下板验证发现没有图像,啥也没有,就开始检查是不是代码写错了,中间也查出一写小问题。解决完之后还是老样子,没有图像显示,最后去看了正点原子给的LCD的底层源码,发现了很多新奇的地方。

  1. 正点原子的显示器会有固定的ID,而且这个ID直接可以拿回来,根据ID可以识别该显示器的分辨率。因为我只有一个显示屏,所以直接就把参数写到模块里面了。
  2. 正点原子的显示器需要将要显示的数据给到每个像素点,这样才能显示。当然像素点的位置也是根据时序计算出来的。原理跟其他的显示器是一样的。话不多说,上代码!
    module LCD_derive (
    input wire I_use_clk ,//9MHz时钟
    input wire I_use_rst_n ,//低电平有效的复位
    input wire [23:0] I_data ,//需要显示的24bit数据
    output wire O_valid_en ,//数据有效信号
    output wire O_vsync ,//列同步信号
    output wire O_hsync ,//行同步信号
    output wire O_back_enable ,//背光控制
    output wire O_lcd_clk ,//像素时钟
    output wire O_lcd_rst ,//LCD的复位
    output reg [23:0] O_data //输出显示的数据
    );
    /-------------------定义所需参数-------------------------/
    localparam hsync_num = 524 ;//水平显示区域525个时钟周期
    localparam hsync_fir_num = 4 ;//水平显示前消隐区5个时钟周期
    localparam hsync_end_num = 40 ;//水平显示后消隐区40个时钟周期
    localparam vsync_num = 287 ;//垂直显示区域288行
    localparam vsync_fir_num = 7 ;//垂直显示上消隐区8行
    localparam vsync_end_num = 8 ;//垂直显示下消隐区8行
    /---------------定义水平垂直两个计数器-------------------/
    reg [9:0] hsync_cnt ;//水平同步计数器:共计525个数,需要2^10次方才能满足条件
    reg [8:0] vsync_cnt ;//垂直同步计数器:共计288个数,需要2^9次方才能满足条件
    wire [9:0] hsync_pos ;//像素点水平坐标
    wire [8:0] vsync_pos ;//像素点垂直坐标
    /-------------------定义要用的信号-----------------------/
    reg hsync_en ;//水平同步有效信号
    reg vsync_en ;//垂直同步有效信号
    /-------------------输出端口定义-------------------------/
    assign O_lcd_clk = I_use_clk;
    assign O_lcd_rst = 1’b1;
    assign O_back_enable = 1’b1;

/-------------------水平同步计数器-----------------------/
always @ ( posedge I_use_clk or negedge I_use_rst_n )
begin
if ( I_use_rst_n == 1’b0 )
hsync_cnt <= 10’d0;
else
if ( hsync_cnt == hsync_num )
hsync_cnt <= 10’d0;
else
hsync_cnt <= hsync_cnt + 1’b1;
end
/------------------垂直同步计数器------------------------/
always @ ( posedge I_use_clk or negedge I_use_rst_n )
begin
if ( I_use_rst_n == 1’b0 )
vsync_cnt <= 9’d0;
else
if ( ( vsync_cnt == vsync_num ) && ( hsync_cnt == hsync_num ) )
vsync_cnt <= 9’d0;
else
if ( hsync_cnt == hsync_num )
vsync_cnt <= vsync_cnt + 1’b1;
else
vsync_cnt <= vsync_cnt;
end
/------------------标记显示区域--------------------------/

/-----------------水平显示有效信号-----------------------/
always @ ( posedge I_use_clk or negedge I_use_rst_n )
begin
if ( I_use_rst_n == 1’b0 )
hsync_en <= 1’b0;
else
if (( hsync_cnt > ( hsync_fir_num - 10’d1 ) ) && ( hsync_cnt < ( hsync_num - hsync_end_num - 1’b1)))
hsync_en <= 1’b1;
else
hsync_en <= 1’b0;
end

/-----------------垂直显示有效信号-----------------------/
always @ ( posedge I_use_clk or negedge I_use_rst_n )
begin
if ( I_use_rst_n == 1’b0 )
vsync_en <= 1’b0;
else
if ( (vsync_cnt > ( vsync_fir_num )) && ( vsync_cnt < ( vsync_num - vsync_end_num + 9’d1 ) ) )
vsync_en <= 1’b1;
else
vsync_en <= 1’b0;
end
/-----------------有效显示------------------------------/
assign O_valid_en = (vsync_en == 1’b1 ) && ( hsync_en == 1’b1 );
/-----------------行像素点坐标--------------------------/

assign hsync_pos = hsync_en ? (hsync_cnt - hsync_fir_num) : 10’d0;
/-----------------列像素点坐标--------------------------/
assign vsync_pos = vsync_en ? ( vsync_cnt - vsync_fir_num ) : 9’d0;
assign O_vsync = 1’b1;
assign O_hsync = 1’b1;
/-----------------显示数据------------------------------/
always @ ( posedge I_use_clk or negedge I_use_rst_n )
begin
if ( I_use_rst_n == 1’b0 )
O_data <= 24’d0;
else
if ( ( hsync_pos > 10’d0 ) && ( vsync_pos > 9’d0 ) )
O_data <= I_data;
else
O_data <= 24’d0;
end
endmodule
仿真代码:
`timescale 1ns/1ps
module LCD_derive_TB;
reg I_use_clk ;
reg I_use_rst_n ;
reg [23:0] I_data ;
wire O_vsync ;
wire O_hsync ;
wire O_valid_en ;
wire [23:0] O_data ;
wire O_back_enable ;//背光控制
wire O_lcd_clk ;//像素时钟
wire O_lcd_rst ;//LCD的复位
LCD_derive UUT_LCD_derive
(
.I_use_clk (I_use_clk),//9MHz时钟
.I_use_rst_n (I_use_rst_n),//低电平有效的复位
.I_data (I_data),//需要显示的24bit数据
.O_valid_en (O_valid_en),//数据有效信号
.O_vsync (O_vsync),//列同步信号
.O_hsync (O_hsync),//行同步信号
.O_back_enable (O_back_enable),//背光控制
.O_lcd_clk (O_lcd_clk),//像素时钟
.O_lcd_rst (O_lcd_rst),//LCD的复位
.O_data (O_data) //输出显示的数据
);

always # 50 I_use_clk = ~I_use_clk;
initial
begin
I_use_clk = 0;
I_use_rst_n = 0;
I_data = 16’d0;
#200
I_use_rst_n = 1;
end

endmodule
仿真图像:
基于FPGA实现正点原子LCD显示屏的驱动_第1张图片
好了,基本写完了,最后记得一定要把被光端口置高,不然你根本看不到现象。还请各位大佬指正。

你可能感兴趣的:(fpga开发,单片机,stm32)