Lcd 是LCD控制的顶层模块
Lcd_control_module 是控制初始化和显示图片的模块
Init_module 是初始化 LCD的模块
Draw 是显示图片的模块
3. Lcd_control_module 这模块负责首先初始化LCD,然后开始显示图片
rinit_start 是初始化开始信号,rdraw_start是显示图片开始信号
case(i)
0:if(init_done)begin rinit_start<=1'b0;i<=i+1'b1; end
else rinit_start<=1'b1;
1:if(draw_done)begin rdraw_start<=1'b0;i<=i+1'b1; end
else rdraw_start<=1'b1;
2:i<=2'd2;
Endcase
4. Init_module,写的最好的应该是下面的初始化模块,首先建立数据
Command[1] 是LCD的寄存器地址, data[1]是寄存器需要写入的数据,下面的数据把LCD的寄存器地址和数据一一对应起来。
command[1]=16'h00e5; data[1]=16'h78f0;
command[2]<=16'h0001; data[2]<=16'h0100;// set SS and SM bit
command[3]<=16'h0002; data[3]<=16'h0700;// set 1 line inversion
//command[4]<=16'h0003; data[4]<=16'h1008;// set GRAM write direc
tion and BGR=1.
command[4]<=16'h0003; data[4]<=16'h100c;
command[5]<=16'h0004; data[5]<=16'h0000;// Resize register
command[6]<=16'h0008; data[6]<=16'h0207;// set the back porch and front porch
command[7]<=16'h0009; data[7]<=16'h0000;// set non-display area refresh cycle
我只把前部分的寄存器写出来,具体的可以参考附件部分。
下面就是初始化的逻辑,使用了1个状态机,每次把对应的一组地址和数据写入LCD的寄存器里面。
else if(init_start)
begin
case(i)
0:if(count==16'd4999)begin wr_reset<=1'b1;i<=i+1'b1; end
1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,
51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,
101,103,105,107,109,111,113:
begin
if(wr_done) begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rdata<={2'b00,command[i/2+1]};rwr_start<=1'b1; end
end
2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,
52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,
102,104,106,108,110,112:
begin if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rdata<={2'b01,data[i/2]};rwr_start<=1'b1; end
end
5. 显示图片部分。
显示图片部分首先需要数据来源,如下图
lcd_RAM i2(
.address(draw_addr),
.clock(clk),
.q(draw_data)
);
本次系统使用的RAM ,主要使用赛灵思自带的IP核生成的。根据上一节的配置,摄像头采集的数据会先通过FIFI保存在外部RAM里面。我们需要记录保存RAM的其实地址,写到draw_addr里面。
6. Draw_module.v 这个模块主要负责把图片显示到TFT上面。也是一个状态机。状态机首先需要初始化一些图片参数,比如你将要写入的图片的长宽的像素点,然后依次从外部RAM空间读取数据,把数据写到TFT的内存中。
case(i)
0:if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rwr_data<={2'b00,16'h0020};rwr_start<=1'b1; end //
1:if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rwr_data<={2'b01,16'h0000};rwr_start<=1'b1; end
2:if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rwr_data<={2'b00,16'h0021};rwr_start<=1'b1; end //
3:if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rwr_data<={2'b01,16'h0000};rwr_start<=1'b1; end
4:if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rwr_data<={2'b00,16'h0050};rwr_start<=1'b1; end 5:if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rwr_data<={2'b01,16'h0040};rwr_start<=1'b1; end
6:if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rwr_data<={2'b00,16'h0052};rwr_start<=1'b1; end 7:if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rwr_data<={2'b01,16'h0040};rwr_start<=1'b1; end
8:if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rwr_data<={2'b00,16'h0051};rwr_start<=1'b1; end
9:if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rwr_data<={2'b01,16'h007F};rwr_start<=1'b1; end // 指定图片宽度 10:if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rwr_data<={2'b00,16'h0053};rwr_start<=1'b1; end // 图片长度 11:if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rwr_data<={2'b01,16'h00f1};rwr_start<=1'b1; end // 0X3F = 63
12:if(wr_done)begin rwr_start<=1'b0;i<=i+1'b1; end
else begin rwr_data<={2'b00,16'h0022};rwr_start<=1'b1; end
13:
if(y==320) //如果写到行尾,换一行
begin
if(x==240)begin i<=i+1'b1; end
//if(x==64)begin i<=i+1'b1; end
else begin y<=10'd0;x<=x+1'b1; end
end
else if(wr_done)begin rwr_start<=1'b0;y<=y+1'b1; end
else begin rwr_data<={2'b01,draw_data};rwr_start<=1'b1; end
7. 因为这次我需要添加整体的代码才能运行这个程序,所以我就先单独测试了一下这个代码,附件是我的C++语言写的一个mIf图片生产的工具和 TFT 的 verilog 部分关键代码。
8. 总结,我这次调试这个遇到了3个问题
(1) 显示的图片是斜的,这个是我计算宽度,少计算了1个像素点,导致图像斜的。
(2) 有一部分图片是 灰度条,是因为清屏的扫描行数不对,有些没清屏成功。
(3) 显示的图像,色彩是反的,比如本应该是绿色的,但是却是红色。这个问题是困扰我最长时间的,我最后实在没办法就直接去分析图像的每个像素的原始数据,然后换成2进制,去和真实的图片做对比,最后才发现是 三原色的位数不对,比如18位的像素,可能是RGB各6位,也有可能是565的划分(5位代表R红信号,6位代表G绿信号,5位代表B蓝信号)0,如果这个搞错了,就会出现图像颜色不对。
9.
下面是我用modelsim 仿真的数据,可以看到 11100101 是 0xe5, 0111100011110000 0x78f0, 如果和之前的代码 command[1]=16'h00e5 ,data[1]=16'h78f0; 对比一下,是不是就很清晰了。
10. 我本来前段时间拍了一个TFT显示图片,最近在出差找不到了。还是等全部搞完再重新拍一张。这一部分代码我单独试过是OK 的,等算法搞定加进去就可以全部测试
附件是工程里面的一些V文件,但是不是全部代码,因为有限制大小,所以把主要文件分享一下,如果想显示自己的图片的话,需要先把图像文件转换成coe文件才行,需要写个上位机转一下。
`