总结:
模块例化思想: 例化1个定时器模块 + LCD驱动 +锁相环
根据自己思路编写代码,调试仿真代码,同时熟悉环境.加深细节理解
刚开始写得很乱,代码完全就是用modelsim仿真调试出来的
虽然项目开发过MCU的多种GUI,但通过编写verilog代码驱动LCD,对RGB LCD的行、场时序参数及屏幕怎么就亮了有了本质的理解、认识。
通过verilog并行代码来直接驱动外设 | 直观、深刻、简单 |
C语言配置寄存器去操作外设 | 复杂、抽象 |
写这个LCD驱动模块,其实可以完全参考STM32 LTDC框图来定义输入、输出(特别是输出 ), 一直觉得STM32的硬件架构设计得是相当牛比,这一点在这里再次得到了印证。
结合这些框图的理解,肯定可以写出更好的RTL代码。仔细看下面Figure 245这幅图,似乎看到了LTDC里面有跨时钟域,目前对这一块的理解只是停留在听说过,先留下 一篇帖子 后续再研究(54条消息) FPGA——浅谈跨时钟域_three_yanlili的博客-CSDN博客_fpga跨时钟域
将背光及复位信号单独抽出来
output lcd_bl,
output lcd_rst,
这样可以使ltdc模块功能更加独立
module LTDC_drv (
input ltdc_pclk,
input lcd_reset,
input en,
output lcd_de,
output lcd_hsync,
output lcd_vsync,
output reg [7:0] lcd_r,
output reg [7:0] lcd_g,
output reg [7:0] lcd_b
);
注意:
一. 实现的功能
使用FPGA开发板外接1024*600 7inch RGB LCD显示屏,循环刷颜色数据,间隔1S。
二. 功能框图
定时器模块1:加计数器,计数500ms到了产生overflow信号
LCD驱动控制模块功能分解:
1024*600屏,行、场时序参数定义
行、场计数器对像素时钟计数
刷数据使能信号、 行、场同步信号连续赋值
三段式状态机应用
锁相环IP核:产生33.3MHZ的LCD像素时钟
打开方法: tools -> netlist viewers -> rtl viewer
三. RTL代码
顶层模块 lcd_rgb_colorbar.v
module lcd_rgb_colorbar (
input sys_clk,
input sys_reset_n,
output lcd_de,
output lcd_hs,
output lcd_vs,
output lcd_pclk,
output lcd_bl,
output lcd_rst,
output [15:0] lcd_rgb565
);
parameter COUNT_OVERFLOW = 26'd25_000_000; //1s
//wire define
wire locked;
wire lcd_clk_w;
wire overflow;
//*****************************************************
//** main code
//*****************************************************
assign lcd_reset = sys_reset_n & locked;
assign lcd_pclk = lcd_clk_w;
// module instance
lcd_pll lcd_pll_inst(~sys_reset_n,sys_clk,lcd_clk_w,locked);
lcd_rgb_colorbar_drv lcd_rgb_colorbar_drv_inst(
.lcd_clk (lcd_clk_w),
.lcd_reset (lcd_reset),
.en (overflow),
.lcd_de (lcd_de),
.lcd_hs (lcd_hs),
.lcd_vs (lcd_vs),
.lcd_bl (lcd_bl),
.lcd_rst (lcd_rst),
.lcd_rgb565 (lcd_rgb565)
);
timer #(
.COUNT_OVERFLOW (COUNT_OVERFLOW)
)
timer_inst(
.clk (sys_clk),
.reset (sys_reset_n),
.overflow (overflow)
);
endmodule
定时器模块 timer.v
除将overflow <=修改为非阻塞赋值外,其它与led点灯工程的相同。
/*
********************************************************************************
*Copyright ©, 2018, CunXin_ All Rights Reserved
*文 件 名: key_led.v
*说 明:
程序功能无按键按下时, LED灯全灭;
按键1按下时, LED灯显示自右向左的流水效果;
按键2按下时, LED灯显示自左向右的流水效果;
按键3按下时,四个LED灯同时闪烁;
按键4按下时, LED灯全亮
*版 本: V000B00D00
*创建日期: 2018年4月3日 下午12:16:49
*创 建 人: wansaiyon
*修改信息:
================================================================================
*修 改 人 修改日期 修改内容
*<作者/修改者> <YYYY/MM/DD> <修改内容>
********************************************************************************
*/
module timer #(
parameter COUNT_OVERFLOW = 26'd10_000_000
) (
input clk,
input reset,
output reg overflow
);
localparam period = COUNT_OVERFLOW;
reg [25:0] cnt;
always @(posedge clk,negedge reset) begin
if(!reset) begin
cnt <= 26'd0;
overflow <= 1'b0;
end
else if(cnt < period) begin
cnt <= cnt + 1'd1;
overflow <= 1'b0;
end
else begin
cnt <= 26'd0;
overflow <= 1'b1;
end
end
endmodule
LCD驱动模块,lcd_rgb_colorbar_drv .v
主要功能点:
1024*600屏,行、场时序参数定义
行、场计数器对像素时钟计数
刷数据使能信号、 行、场同步信号连续赋值
三段式状态机应用
module lcd_rgb_colorbar_drv (
input lcd_clk,
input lcd_reset,
input en,
output lcd_de,
output lcd_hs,
output lcd_vs,
output lcd_bl,
output lcd_rst,
output reg [15:0] lcd_rgb565
);
`define THREE_FSM
//parameter define
localparam H_SYNC = 11'd20; //
localparam H_BACK = 11'd140; //
localparam H_DISP = 11'd1024; //
localparam H_FRONT = 11'd160; //
localparam H_TOTAL = 11'd1344; //
localparam V_SYNC = 11'd3; //
localparam V_BACK = 11'd20; //
localparam V_DISP = 11'd600; //
localparam V_FRONT = 11'd12; //
localparam V_TOTAL = 11'd635; //
localparam S0_WHITE = 16'b11111_111111_11111; //RGB565
localparam S1_BLACK = 16'b00000_000000_00000; //RGB565
localparam S2_RED = 16'b11111_000000_00000; //RGB565
localparam S3_GREEN = 16'b00000_111111_00000; //RGB565
localparam S4_BLUE = 16'b00000_000000_11111; //RGB565
//reg define
reg [10:0] cnt_h;
reg [10:0] cnt_v;
reg [15:0] state_now;
reg [15:0] state_next;
//wire define
wire lcd_en;
//*****************************************************
//** main code
//*****************************************************
assign lcd_en = (((cnt_h >= H_SYNC+H_BACK) && (cnt_h < H_SYNC+H_BACK+H_DISP))
&&((cnt_v >= V_SYNC+V_BACK) && (cnt_v < V_SYNC+V_BACK+V_DISP)))
? 1'b1 : 1'b0;
assign lcd_de = lcd_en;
assign lcd_bl = 1'b1;
assign lcd_rst = 1'b1;
assign lcd_hs = 1'b1;
assign lcd_vs = 1'b1;
always @(posedge lcd_clk or negedge lcd_reset) begin
if(!lcd_reset)begin
state_now <= S0_WHITE;
end
else begin
if(en) begin
state_now <= state_next;
end
end
end
always @(*) begin
case (state_now)
S0_WHITE:
state_next = S1_BLACK;
S1_BLACK:
state_next = S2_RED;
S2_RED:
state_next = S3_GREEN;
S3_GREEN:
state_next = S4_BLUE;
S4_BLUE:
state_next = S0_WHITE;
default:
state_next = S0_WHITE;
endcase
end
always @(*) begin
if(lcd_en)
lcd_rgb565 = state_now;
else ;
end
//行计数器对像素时钟计数
always @(posedge lcd_clk or negedge lcd_reset) begin
if (!lcd_reset)
cnt_h <= 11'd0;
else begin
if(cnt_h < H_TOTAL - 1'b1)
cnt_h <= cnt_h + 1'b1;
else
cnt_h <= 11'd0;
end
end
//场计数器对行计数
always @(posedge lcd_clk or negedge lcd_reset) begin
if (!lcd_reset)
cnt_v <= 11'd0;
else if(cnt_h == H_TOTAL - 1'b1) begin
if(cnt_v < V_TOTAL - 1'b1)
cnt_v <= cnt_v + 1'b1;
else
cnt_v <= 11'd0;
end
end
endmodule
四.modelsim前仿真(功能仿真)
每次打开modelsim时需要切换工作空间,否则可能创建工程添加的源码会是上一个仿真工程的代码,导致出错 。
使用vscode打开segled_static_top.v, ctrl+shift+p,输入testbench,在terminal生成了segled_static_top_tb.v代码,需要安装插件verilog_testbench, 初始生成时可能提示失败,需要安装 python 库(根据错误提示自行百度)。
生成的代码有点错误,需要自己再做点修改。
tb_segled_dy_top.v,
为了方便减小了计数器周期为4'd10,2'd2。
`timescale 1ns / 1ns
module tb_segled_dy_top;
// segled_static_top Parameters
parameter PERIOD = 10 ;
parameter COUNT_OVERFLOW = 4'd10;
parameter COUNT_OVERFLOW2 = 2'd2;
// segled_static_top Inputs
reg clk = 0 ;
reg reset = 0 ;
// segled_static_top Outputs
wire [5:0] sel ;
wire [7:0] seg_led ;
initial
begin
forever #(PERIOD/2) clk=~clk;
end
initial
begin
#(PERIOD*2) reset = 1;
end
segled_dy_top #(
.COUNT_OVERFLOW ( COUNT_OVERFLOW ),
.COUNT_OVERFLOW2 ( COUNT_OVERFLOW2 ))
u_segled_dy_top (
.clk ( clk ),
.reset ( reset ),
.sel ( sel [5:0] ),
.seg_led ( seg_led [7:0] )
);
endmodule
仿真波形
五.下载验证
FPGA开发板外接1024*600 7inch RGB LCD显示屏,循环刷颜色数据,间隔1S。
但是发现4个LED有微弱的亮度,需要配置好未使用管脚的状态为高阻输入,同时将nCEO管脚修改为Use as regular I/0,修改后LED变为熄灭状态了。
在 Quartus 软件中默认未使用管脚的状态为弱上拉输入,所以未使用到的管脚上也是有电压的,只是驱动能力很弱,这往往会导致一些不安全的隐患,所以我们需要将未使用管脚的状态设置为三态输入。
在左侧Category一栏中选择Dual-Purpose Pin。对于需要使用EPCS器件的引脚时,需要将下图页面中所有的引脚都改成Use as regular IO,如果大家不确定工程中是否用到EPCS器件时,可以全部修改。本次实验只修改了nCEO一栏中, 将Use as programming pin修改为Use as regular I/0。