【红色飓风Nano二代测评】教你如何编写带FIFO的LCD接口
0赞桓公出品,转载请注明出处http://blog.chinaaet.com/songhuangong
之前写的一些博客,为这篇博客的诞生,打下了基础。
这篇文章,主要贴出完整的代码。所以想详细的了解所有的步骤,
可能需要复习下我之前的博客。
介绍了LCD驱动芯片的寄存器,以及时序。
介绍了FIFO读写需要注意的地方,以及如何在ISE中添加FIFO IP Core
介绍了如何用插补绘制任意斜率的直线。
话说FIFO作为模块之间的沟通工具“真真是极好的!”,桓公何处此言呢?
就拿这个LCD接口为例,它自带一个FIFO,FIFO的读部分为自己所用,FIFO
的写部分作为输入引脚,以供其他模块使用。
对于LCD接口而言,只需关注FIFO是否为空,有数据就读取数据画点。
对于外部控制模块而言,只负责产生数据,写入FIFO即可。这就是所谓
的“低耦合,高内聚”吧,呵呵!但是这还不是重点。重点是模块可以
利用这个缓冲区,腾出时间做其他事情。比如说LCD是需要一个初始化
过程的,而且这个过程的时间还不短,但是在初始化的时候,控制模块
可能已经开始产生数据了,而此时LCD还在初始化,无法画点,不过不要
紧,产生的数据被缓存到FIFO中,当LCD初始化完成了之后,就会自动去
读取FIFO中的数据。也就是说控制模块不用傻傻的等待着LCD完成初始化完
成,再去产生数据。(不然的话控制模块肯定还需要接收一个LCD初始
化的完成信号,这样的话耦合度也就上升了)。
同时这个方法也有需要注意的地方,比如说在LCD初始话的时候,控制
模块产生了10个数据,但是LCD的FIFO大小只有8,那么就会造成2个数据
的丢失。所以,这也需要设计者合理的设置FIFO的大小,以确保FIFO不会
溢出,导致数据的丢失。
先用一张结构图来表明大意:
以下程序就是通过按键模块,产生坐标,将坐标点写入FIFO。(之后会介绍用插补产生坐标)
LCD接口检测到FIFO中有数据,就会数据反映到LCD显示屏。
效果图:
代码结构图:
不要看代码文件似乎很多,其实很多是多次重复例化而来。
比如说按键模块,就是将一路按键,重复例化四次,再封装而成的四路按键模块。
这样做的好处就是方便代码的维护,以及拓展。
好了上完整的代码:
1、TOP_Control:总顶层文件,链接TFT_Interface和key_control
module TOP_Control ( input CLK, input RSTn, input key_before, input key_back, input key_left, input key_right, output [3:0]LED, output TFT_RST, output TFT_CS, output TFT_RS, output TFT_WR, output [15:0]TFT_Data ); wire Full_Sig; wire Write_Sig; wire [31:0]FIFO_Write_Data; key_control key_control ( //.LED(LED), .CLK(CLK), .RSTn(RSTn), .key_before(key_before), .key_back(key_back), .key_left(key_left), .key_right(key_right), //fifo写部分 .Full_Sig(Full_Sig), .Write_Sig(Write_Sig), .FIFO_Write_Data(FIFO_Write_Data) ); TFT_Interface TFT_Interface ( .LED(LED), .CLK(CLK), .RSTn(RSTn), //fifo写部分 .Full_Sig(Full_Sig), .Write_Sig(Write_Sig), .FIFO_Write_Data(FIFO_Write_Data), .TFT_RST(TFT_RST), .TFT_CS(TFT_CS), .TFT_RS(TFT_RS), .TFT_WR(TFT_WR), .TFT_Data(TFT_Data) ); endmodule
2、TFT_Interface:LCD顶层文件
module TFT_Interface
(
output [3:0]LED,
input CLK,
input RSTn,
//fifo写部分
output Full_Sig,
input Write_Sig,
input [31:0]FIFO_Write_Data,
output TFT_RST,
output TFT_CS,
output TFT_RS,
output TFT_WR,
output [15:0]TFT_Data
);
parameter WHITE = 16'hFFFF;
parameter BLACK = 16'h0000;
parameter GREY = 16'hF7DE;
parameter BLUE = 16'h001F;
parameter BLUE2 = 16'h051F;
parameter RED = 16'hF800;
parameter MAGENTA = 16'hF81F;
parameter GREEN = 16'h07E0;
parameter CYAN = 16'h7FFF;
parameter YELLOW = 16'hFFE0;
reg Init_Start;
wire Init_Done;
wire [18:0]Init_oData;
TFT_Init TFT_Init
(
.CLK(CLK),
.RSTn(RSTn),
.Start_Sig(Init_Start),
.Done(Init_Done),
.oData(Init_oData) //{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
);
reg Clear_Start;
wire Clear_Done;
wire [18:0]Clear_oData;
TFT_Clear TFT_Clear
(
.CLK(CLK),
.RSTn(RSTn),
.Start_Sig(Clear_Start),
.Done(Clear_Done),
.Color(BLACK),
.oData(Clear_oData)
);
reg Point_Start;
wire Point_Done;
wire [18:0]Point_oData;
reg [15:0]X_Pos = 16'd0;
reg [15:0]Y_Pos = 16'd0;
TFT_DrawPoint TFT_DrawPoint
(
.CLK(CLK),
.RSTn(RSTn),
.Start_Sig(Point_Start),
.Done(Point_Done),
.X_Pos(X_Pos),
.Y_Pos(Y_Pos),
.Color(RED),
.oData(Point_oData) //{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
);
//-------------------------FIFO例化部分-----------------------------------
//fifo读部分
wire Empty_Sig;
reg Read_Sig = 1'b0;
wire [31:0]FIFO_Read_Data;
//宽度为32,深度为512~~
fifo PosFIFO
(
.clk(CLK),
.din(FIFO_Write_Data), // Bus [31 : 0]
.wr_en(Write_Sig),
.rd_en(Read_Sig),
.dout(FIFO_Read_Data), // Bus [31 : 0]
.full(Full_Sig),
.empty(Empty_Sig)
);
//--------------------------------TFT总体控制---------------------------------------
reg [2:0]i;
always @(posedge CLK or negedge RSTn)
if(!RSTn)
begin
i <= 3'd0;
Init_Start <= 1'b0;
Clear_Start <= 1'b0;
Point_Start <= 1'b0;
end
else
case(i)
0://Initialization
begin
if(Init_Done)begin Init_Start <= 1'b0; i <= i + 1'b1; end
else begin Init_Start <= 1'b1; end
end
1://Clear the screen
begin
if(Clear_Done)begin Clear_Start <= 1'b0; i <= i + 1'b1; end
else begin Clear_Start <= 1'b1; end
end
//-----------------fifo读部分-----------------------
2://FIFO read
begin
if(!Empty_Sig)begin Read_Sig <= 1'b1; i <= i + 1'b1;end
else begin Read_Sig <= 1'b0; i <= i; end
end
3:
begin
Read_Sig <= 1'b0;
i <= i + 1'b1;
end
4://赋值将要绘制的点
begin
X_Pos <= FIFO_Read_Data[31:16];
Y_Pos <= FIFO_Read_Data[15:0];
i <= i + 1'b1;
end
5://draw
begin
if(Point_Done)begin Point_Start <= 1'b0; i <= 3'd2; end
else begin Point_Start <= 1'b1; end
end
default:
begin
i <= 3'd0;
Init_Start <= 1'b0;
Clear_Start <= 1'b0;
Point_Start <= 1'b0;
end
endcase
assign LED = i;
//--------------------------------TFT引脚驱动选择器--------------------------------
reg rTFT_CS = 1'b0;
reg rTFT_RS = 1'b0;
reg rTFT_WR = 1'b0;
reg [15:0]rTFT_Data = 16'd0;
always @(*)
case(i)
0://TFT初始化过程
begin
rTFT_CS = Init_oData[18];
rTFT_RS = Init_oData[17];
rTFT_WR = Init_oData[16];
rTFT_Data = Init_oData[15:0];
end
1://TFT清屏过程
begin
rTFT_CS = Clear_oData[18];
rTFT_RS = Clear_oData[17];
rTFT_WR = Clear_oData[16];
rTFT_Data = Clear_oData[15:0];
end
5://TFT打点过程
begin
rTFT_CS = Point_oData[18];
rTFT_RS = Point_oData[17];
rTFT_WR = Point_oData[16];
rTFT_Data = Point_oData[15:0];
end
default:
begin
rTFT_CS = 1'bz;
rTFT_RS = 1'bz;
rTFT_WR = 1'bz;
rTFT_Data = 16'bzzzz_zzzz_zzzz_zzzz;
end
endcase
assign TFT_CS = rTFT_CS;
assign TFT_RS = rTFT_RS;
assign TFT_WR = rTFT_WR;
assign TFT_Data = rTFT_Data;
assign TFT_RST = 1'b1;
endmodule
3、TFT_Init:LCD初始化模块
module TFT_Init
(
input CLK,
input RSTn,
input Start_Sig,
output reg Done,
output [18:0]oData //{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
);
reg [31:0]Write_reg_data;
reg Reg_Start;
wire Reg_Done;
Write_Reg Write_Reg
(
.CLK(CLK),
.RSTn(RSTn),
.Start_Sig(Reg_Start),
.Done(Reg_Done),
//--
.Write_reg_data(Write_reg_data), //{16'reg,16'COM}
.oData(oData) //{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
);
reg [5:0]i;
always @(posedge CLK or negedge RSTn)
if(!RSTn)
begin
i <= 6'd0;
Done <= 1'b0;
Write_reg_data <= 32'h0;
Reg_Start <= 1'b0;
end
else if(Start_Sig)
case(i)
0://打开晶振
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h0,16'h1}; end
end
1://电源控制1 ;0xA8A4
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h3,16'hA8A4}; end
end
2://电源控制2
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'hC,16'h0}; end
end
3://电源控制3
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'hD,16'h080C}; end
end
4://电源控制4
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'hE,16'h2B00}; end
end
5://电源控制5
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h1E,16'hB0}; end
end
6://控制液晶的扫描模式(这个设置比较讲究,可查看日记)
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h1,16'h2B3F}; end
end
7://液晶驱动AC控制
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h2,16'h600}; end
end
8://睡眠控制
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h10,16'h0}; end
end
9://设置为竖屏 //定义数据格式 16位色
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h11,16'h6070}; end
end
10://共享寄存器1
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h5,16'h0}; end
end
11://共享寄存器2
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h6,16'h0}; end
end
12://水平玄关,设置每行有效像素的数目。每行有效像素数等于到XL[7:0]+1
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h16,16'hEF1C}; end
end
13://垂直玄关
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h17,16'h3}; end
end
14://显示控制 0x0233
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h7,16'h233}; end
end
15://帧周期控制,??
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'hB,16'h0}; end
end
16://栅极扫描开始地址
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'hF,16'h0}; end
end
17://垂直卷轴控制 1
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h41,16'h0}; end
end
18://垂直卷轴控制 2
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h42,16'h0}; end
end
19://第一个局部显示的起始位置 SS1[8:0]
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h48,16'h0}; end
end
20://第一个局部显示的结束位置SE1[8:0] SS1<SE1<13EF
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h49,16'h13F}; end
end
21://第二个局部显示的起始位置
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h4A,16'h0}; end
end
22://第二个局部显示的结束位置
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h4B,16'h0}; end
end
23://水平RAM地址;水平RAM的起始-结束地址位置 (00~EF)
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h44,16'hEF00}; end
end
24://垂直RAM起始地址
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h45,16'h0}; end
end
25://垂直RAM结束地址
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h46,16'h13F}; end
end
26://伽马控制1
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h30,16'h0707}; end
end
27://伽马控制2
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h31,16'h0204}; end
end
28://伽马控制3
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h32,16'h0204}; end
end
29://伽马控制4
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h33,16'h0502}; end
end
30://伽马控制5
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h34,16'h0507}; end
end
31://伽马控制6
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h35,16'h0204}; end
end
32://伽马控制7
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h36,16'h0204}; end
end
33://伽马控制8
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h37,16'h0502}; end
end
34://伽马控制9
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h3A,16'h0302}; end
end
35://伽马控制10
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h3B,16'h0302}; end
end
36://RAM write data mask (1)
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h23,16'h0}; end
end
37://RAM write data mask (2)
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h24,16'h0}; end
end
38://帧频率 510K
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h25,16'h8000}; end
end
39://行首址0,设置GDDRAM Y的计数地址
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h4F,16'h0}; end
end
40://列首址0,设置GDDRAM X的计数地址
begin
if(Reg_Done)begin Reg_Start <= 1'b0; i <= i + 1'b1; end
else begin Reg_Start <= 1'b1; Write_reg_data <= {16'h4E,16'h0}; end
end
41://
begin
Done <= 1'b1;
i <= i + 1'b1;
end
42://
begin
Done <= 1'b0;
i <= 6'd0;
end
default:
begin
i <= 6'd0;
Done <= 1'b0;
Write_reg_data <= 32'hffff_ffff;;
Reg_Start <= 1'b0;
end
endcase
endmodule
4、Write_Reg:LCD写寄存器模块
module Write_Reg
(
input CLK,
input RSTn,
input Start_Sig,
output reg Done,
//--
input [31:0]Write_reg_data,//{16'reg,16'COM}
output [18:0]oData //{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
);
parameter RS_Com = 1'b0;
parameter RS_Data = 1'b1;
reg [16:0]Write_Data;
reg Write_Start;
wire Write_Done;
TFT_Write TFT_Write
(
.CLK(CLK),
//.RSTn(RSTn),
.iData(Write_Data),//{1'TFT_RS,16'TFT_Data}
.Start_Sig(Write_Start),
.oData(oData),//{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
.Done(Write_Done)
);
reg [1:0]i;
always @(posedge CLK or negedge RSTn)
if(!RSTn)
begin
i <= 2'd0;
Write_Start <= 1'b0;
Write_Data <= 17'd0;
Done <= 1'b0;
end
else if(Start_Sig)
case(i)
0://写寄存器地址
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Com, Write_reg_data[31:16] }; end
end
1://写命令
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Data, Write_reg_data[15:0] }; end
end
2:
begin
Done <= 1'b1;
i <= i + 1'b1;
end
3:
begin
Done <= 1'b0;
i <= 2'd0;
end
endcase
endmodule
5、TFT_Clear:LCD清屏模块
module TFT_Clear
(
input CLK,
input RSTn,
input Start_Sig,
output reg Done,
input [15:0]Color,
output [18:0]oData
);
parameter RS_Com = 1'b0;
parameter RS_Data = 1'b1;
reg [16:0]Write_Data;
reg Write_Start;
wire Write_Done;
TFT_Write TFT_Write
(
.CLK(CLK),
// .RSTn(RSTn),
.iData(Write_Data),//{1'TFT_RS,16'TFT_Data}
.Start_Sig(Write_Start),
.oData(oData),//{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
.Done(Write_Done)
);
reg [3:0]i;
reg [16:0]C0;
always @(posedge CLK or negedge RSTn)
if(!RSTn)
begin
i <= 4'd0;
Done <= 1'b0;
Write_Data <= 17'h0;
C0 <= 17'd0;
end
else if(Start_Sig)
case(i)
0://确定点的X坐标的寄存器
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Com, 16'h4E}; end
end
1://确定X的坐标
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Data, 16'h0 }; end
end
2://确定点的Y坐标的寄存器
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Com, 16'h4F}; end
end
3://确定Y的坐标
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Data, 16'h0 }; end
end
4://prepare to write to the LCD RAM
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Com, 16'h22}; end
end
5://确定点的颜色
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Data, Color}; end
end
6://循环~~76800 = 240*320
begin
if(C0 == 17'd76800) begin C0 <= 17'd0; i <= i + 1'b1; end
else begin C0 <= C0 + 1'b1; i <= i - 1'b1;end
end
7:
begin
Done <= 1'b1;
i <= i + 1'b1;
end
8:
begin
Done <= 1'b0;
i <= 4'd0;
end
default:
begin
i <= 4'd0;
Done <= 1'b0;
Write_Data <= 17'h1ffff;;
C0 <= 17'd0;
end
endcase
endmodule
6、TFT_DrawPoint:LCD画点模块
module TFT_DrawPoint
(
input CLK,
input RSTn,
input Start_Sig,
output reg Done,
input [15:0]X_Pos,
input [15:0]Y_Pos,
input [15:0]Color,
output [18:0]oData //{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
);
// parameter X_Pos = 16'd55;
// parameter Y_Pos = 16'd55;
parameter RS_Com = 1'b0;
parameter RS_Data = 1'b1;
reg [16:0]Write_Data;
reg Write_Start;
wire Write_Done;
TFT_Write TFT_Write
(
.CLK(CLK),
.iData(Write_Data),//{1'TFT_RS,16'TFT_Data}
.Start_Sig(Write_Start),
.oData(oData),//{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
.Done(Write_Done)
);
reg [2:0]i;
always @(posedge CLK or negedge RSTn)
if(!RSTn)
begin
i <= 3'd0;
Write_Data <= 17'h0;
Done <= 1'b0;
end
else if(Start_Sig)
case(i)
0://确定点的X坐标的寄存器
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Com, 16'h4E}; end
end
1://确定X的坐标
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Data, X_Pos }; end
end
2://确定点的Y坐标的寄存器
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Com, 16'h4F}; end
end
3://确定Y的坐标
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Data, Y_Pos }; end
end
4://prepare to write to the LCD RAM
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Com, 16'h22}; end
end
5://确定点的颜色
begin
if(Write_Done) begin Write_Start <=1'b0; i <= i + 1'b1; end
else begin Write_Start <=1'b1; Write_Data <= { RS_Data, Color }; end
end
6:
begin
Done <= 1'b1;
i <= i + 1'b1;
end
7:
begin
Write_Data <= 17'h1ffff;//为了消除警告,其实不加也不影响结果~~
Done <= 1'b0;
i <= 3'd0;
end
endcase
endmodule
7、TFT_Write:LCD写时序模块
module TFT_Write
(
input CLK,
input [16:0]iData,//{1'TFT_RS,16'TFT_Data}
input Start_Sig,
output [18:0]oData,//{1'TFT_CS,1'TFT_RS,1'TFT_WR,16'TFT_Data}
output reg Done
);
reg CS; //驱动TFT片选
reg WR; //驱动TFT写信号
reg [15:0]Data; //驱动TFT数据总线
reg [2:0]i;
always @(posedge CLK)
if(Start_Sig)
case(i)
0:
begin
CS <= 1'b0;
WR <= 1'b0;
i <= i + 1'b1;
end
1:
begin
Data <= iData[15:0];
i <= i + 1'b1;
end
2://延时20ns,拉底CS 60ns,CS的读周期,最小是100ns
begin
i <= i + 1'b1;
end
3,4,5://保证CS拉高60ns,这样读的CS周期就大于100ns了~
begin
CS <= 1'b1;
WR <= 1'b1; //WR的上升沿数据锁存
i <= i + 1'b1;
end
6:
begin
Done <= 1'b1;
i <= i + 1'b1;
end
7:
begin
Done <= 1'b0;
i <= 3'd0;
end
endcase
assign oData = {CS,iData[16],WR,Data};
endmodule
8、key_control:按键控制顶层模块
module key_control
(
input CLK,
input RSTn,
input key_before,
input key_back,
input key_left,
input key_right,
//output reg[3:0]LED,
//output [3:0]LED,
//fifo写部分
input Full_Sig,
output reg Write_Sig,
output reg [31:0]FIFO_Write_Data
);
reg [15:0]X_Pos = 16'd0;
reg [15:0]Y_Pos = 16'd0;
wire before_down;
wire before_up;
wire back_down;
wire back_up;
wire left_down;
wire left_up;
wire right_down;
wire right_up;
Key key
(
.CLK(CLK),
.RSTn(RSTn),
.key_before(key_before),
.key_back(key_back),
.key_left(key_left),
.key_right(key_right),
.before_down(before_down),
.before_up(before_up),
.back_down(back_down),
.back_up(back_up),
.left_down(left_down),
.left_up(left_up),
.right_down(right_down),
.right_up(right_up)
);
//-------------------------KEY按键绘图部分------------------------
//------------------------向FIFO中写数据-------------------------
reg [3:0]i;
reg [15:0]Xpos;
reg [15:0]Ypos;
reg [15:0]Ytemp = 16'd0;
reg [19:0]C0 = 20'd0;
always @(posedge CLK or negedge RSTn)
if(!RSTn)
begin
Write_Sig <= 1'b0;
FIFO_Write_Data <= 32'd0;
Xpos <= 16'd0;
Ypos <= 16'd0;
i <= 4'd0;
end
else
case(i)
0://start point
begin
Xpos <= 16'd55;
Ypos <= 16'd55;
i <= i + 1'b1;
end
1://TFT坐标系转换,(将原点定在竖屏的左下角)
begin
Ytemp <= 16'd319 - Ypos;
i <= i + 1'b1;
end
2://write a start point
begin
if(!Full_Sig)
begin
Write_Sig <= 1'b1;
FIFO_Write_Data <= {Xpos,Ytemp};
//FIFO_Write_Data <= {Xpos,Ypos};
i <= i + 1'b1;
end
else
begin
Write_Sig <= 1'b0;
FIFO_Write_Data <= FIFO_Write_Data;
i <= i;
end
end
3:
begin
Write_Sig<= 1'b0;
i <= i + 1'b1;
end
4://choose//判断按键是否按下
begin
if(before_down) i <= 4'd5;
else if(back_down) i <= 4'd6;
else if(left_down) i <= 4'd7;
else if(right_down) i <= 4'd8;
end
5://前进
begin
if(before_up)
begin
i <= 4'd4;
Write_Sig <= 1'b0;
C0 <= 20'd0;
end
else
begin
if(C0 == 20'hf_ffff)
begin
C0 <= 20'd0;
Write_Sig <= 1'b1;
Ypos <= Ypos + 1'b1;
FIFO_Write_Data <= {Xpos,(16'd319 - Ypos)};
i <= i;
end
else
begin
C0 <= C0 + 1'b1;
end
end
end
6://后退
begin
if(back_up)
begin
i <= 4'd4;
Write_Sig <= 1'b0;
C0 <= 20'd0;
end
begin
if(C0 == 20'hf_ffff)
begin
C0 <= 20'd0;
Write_Sig <= 1'b1;
Ypos <= Ypos - 1'b1;
FIFO_Write_Data <= {Xpos,(16'd319 - Ypos)};
i <= i;
end
else
begin
C0 <= C0 + 1'b1;
end
end
end
7://左转
begin
if(left_up)
begin
i <= 4'd4;
Write_Sig <= 1'b0;
C0 <= 20'd0;
end
begin
if(C0 == 20'hf_ffff)
begin
C0 <= 20'd0;
Write_Sig <= 1'b1;
Xpos <= Xpos - 1'b1;
FIFO_Write_Data <= {Xpos,(16'd319 - Ypos)};
i <= i;
end
else
begin
C0 <= C0 + 1'b1;
end
end
end
8://右转
begin
if(right_up)
begin
i <= 4'd4;
Write_Sig <= 1'b0;
C0 <= 20'd0;
end
begin
if(C0 == 20'hf_ffff)
begin
C0 <= 20'd0;
Write_Sig <= 1'b1;
Xpos <= Xpos + 1'b1;
FIFO_Write_Data <= {Xpos,(16'd319 - Ypos)};
i <= i;
end
else
begin
C0 <= C0 + 1'b1;
end
end
end
default
begin
Write_Sig <= 1'b0;
FIFO_Write_Data <= 32'd0;
Xpos <= 16'd0;
Ypos <= 16'd0;
i <= 4'd0;
end
endcase
endmodule
9、Key:4路按键封装模块
module Key ( input CLK, input RSTn, input key_before, input key_back, input key_left, input key_right, output before_down, output before_up, output back_down, output back_up, output left_down, output left_up, output right_down, output right_up ); key_moudle key_before_moudle ( .CLK(CLK), .RSTn(RSTn), .keypin(key_before), .key_down(before_down), .key_up(before_up) ); key_moudle key_back_moudle ( .CLK(CLK), .RSTn(RSTn), .keypin(key_back), .key_down(back_down), .key_up(back_up) ); key_moudle key_left_moudle ( .CLK(CLK), .RSTn(RSTn), .keypin(key_left), .key_down(left_down), .key_up(left_up) ); key_moudle key_right_moudle ( .CLK(CLK), .RSTn(RSTn), .keypin(key_right), .key_down(right_down), .key_up(right_up) ); endmodule
10、key_moudle:一路按键检测模块
module key_moudle ( input CLK, input RSTn, input keypin, output key_down, output key_up ); reg key_rst; always @( posedge CLK or negedge RSTn ) begin if( !RSTn ) key_rst <= 1'b1; else key_rst <= keypin; end reg key_rst_r; always @( posedge CLK or negedge RSTn ) begin if( !RSTn ) key_rst_r <= 1'b1; else key_rst_r <= key_rst; end wire key_an = key_rst_r & (~key_rst); //------------------------------------------ reg[19:0] cnt; always @( posedge CLK or negedge RSTn ) begin if( !RSTn ) cnt <= 20'd0; else if(key_an) cnt <= 20'd0;//一旦key_an有抖动的情况cnt都会重新计数 else cnt <= cnt + 1'b1; end //------------------------------------------ reg low_sw; always @( posedge CLK or negedge RSTn ) begin if( !RSTn ) low_sw <= 1'b1; else if( cnt == 20'hfffff ) low_sw <= keypin;//稳定之后的key值 end reg low_sw_r; always @( posedge CLK or negedge RSTn ) begin if( !RSTn ) low_sw_r <= 1'b1; else low_sw_r <= low_sw; end assign key_down = low_sw_r & (~low_sw); assign key_up = (~low_sw_r) & low_sw; endmodule
技术讨论欢迎加群~~电子技术协会 362584474


