中级会员
 
- 积分
- 331
- 金钱
- 331
- 注册时间
- 2019-5-5
- 在线时间
- 98 小时
|

楼主 |
发表于 2019-5-17 09:53:51
|
显示全部楼层
本帖最后由 charge 于 2019-5-17 09:46 编辑
贴一个CPLD的源码,里面我写了很多备注帮助理解,可能有错,后期改正有些备注写的很模糊是因为我还不明白,先写下字面意思
/**********************************************************************
通用4.3寸tft驱动
地址1位
-----------------------------------------------------------------——----
A0=0寄存器,寄存器0-7
0 SRAM数据
1 xIdex x轴寄存器
2 yIdex y轴寄存器
3 yend 结束寄存器,用于窗口绘图加速
4 前景颜色
5 背景色
6
7 系统状态0-15位
bo-b2 b3 b4-b6 b7-b9 b10-b12
背光 显示开/关 显示方式 要写入的页 当前显示页
必须位x00 必须位x00
x可改变(b7) x可改变(b10)
-----------------------------------------------------------------------
AO=1数据
2011.12.5
***********************************************************************/
/*
接口说明:
Clk54:系统晶振,选择54M晶振
SysRst:系统复位线.
/-------STM32-------/
ExDataBus:外部16位数据总线
ExCs:控制器片选,
ExRs:数据批令选择
ExWr:写信号
ExRd:读信号
/-------SRAM-------/
RamAddrBus:显存地址线.
RamDataBus:显存数据总线
RamCs:显存片选
RamWe:显存写选通.
Ramoe:输出使能
/--------TFT-------/
LedOn:背光控制PWM
DE:TFT屏
VSync:TFT屏,
HSync:TFT屏
RGB:TFT屏
Pclk:TFT屏);
*/
module QD_Tft43(Clk54, SysRst, ExDataBus, ExCs, ExRs, ExWr, ExRd, RamAddrBus,
RamDataBus, RamCs, RamWe, RamOe, LedOn, DE, VSync, HSync, RGB, Pclk);
input Clk54, SysRst, ExCs, ExRs, ExRd, ExWr;
inout [15:0] ExDataBus;
inout [15:0] RamDataBus;
output [17 : 0] RamAddrBus;
output [15:0] RGB;
output RamCs, RamWe,RamOe, LedOn, DE, VSync, HSync, Pclk;
reg [2:0] ClkCnt_Q3;
reg DotClkEn_Q;
reg Pclk_Q;
reg WrEn_Q;
reg [15:0]ExBusOut_Q;
reg [15:0] ExOutM;
reg [15:0] WriteRgb_Q;
reg ExWrClk_Q;
reg ExRsR_Q;
reg ExCsR_Q;
reg ExRdClk_Q;
reg ExRdClk_Q1;
reg ExRdClk_Q2;
reg ExWrClk_Q1;
reg ExWrClk_Q2;
reg [12:0] SramAddr;
reg [15:0] PrePareData;
reg [7:0] IndexData;
reg InRamWe;
reg IncAddr;
reg XRegOver;
reg YRegOver;
reg AskWr;
reg [15:0] RGB_Q;
reg [15:0] InBusOut_Q;
reg [8:0] XRegValue_Q;
reg [8:0] YRegValue_Q;
reg [15:0] SysCmdValue_Q;
reg [2:0] RegAddr_Q;
reg RamWeReg_Q;
reg RamTriState_Q;
reg [2:0] FillCount_Q;
reg [15:0] BRGBValue_Q;
reg [15:0] FRGBValue_Q;
reg [17:0] RamAddrBus_Q;
reg FillHead_Q;
reg [8:0] HsCount_Q;
reg [8:0] DotCount_Q;
reg SelDispRam_Q;
reg RamCsReg_Q;
reg DsMark;
reg HsMark;
reg [1:0]DsState_Q;
reg [1:0]HsState_Q;
reg DE_Q;
reg [4:0]LedCount_Q;
reg LedOn_Q,LedOn_W;
assign Pclk = Pclk_Q;
assign RGB = RGB_Q;
assign RamAddrBus = {RamAddrBus_Q};
assign RamWe = RamWeReg_Q;
assign RamCs = RamCsReg_Q;
assign RamOe = RamCsReg_Q;
assign RamDataBus = (RamTriState_Q | Clk54)?16'bzzzzzzzzzzzzzzzz:InBusOut_Q;
assign VSync = DE_Q;
assign HSync = DE_Q;//1'b0;
assign DE = DE_Q;
assign LedOn = LedOn_Q;
assign ExDataBus = ExOutM;
/*
--1.将54M主时钟6分频,产生9M时钟并输出至引脚Pclk
--2.输出DotClkEn为9M信号同步其他进程.高电平为1个主时钟周期,低电平5个主时钟周期
--3.技巧: 001,010,011,100,101,110.共6个状态,高位刚好是6分频等宽.
*/
always @(posedge Clk54 or negedge SysRst)
begin
if (!SysRst) begin
ClkCnt_Q3 = 3'd1;
Pclk_Q = 1'b0;
DotClkEn_Q = 1'b0;
end else begin
if (ClkCnt_Q3[2] & ClkCnt_Q3[1]) begin
ClkCnt_Q3 <= 3'd1;
end else begin
ClkCnt_Q3 <= ClkCnt_Q3 + 3'd1;
end
Pclk_Q <= (SysCmdValue_Q[3])?1'b0:ClkCnt_Q3[2]; //SysCmdValue_Q是一个多用值,是传输各类数据的载体
DotClkEn_Q <= ((~ClkCnt_Q3[2]) & ClkCnt_Q3[1] & ClkCnt_Q3[0]);
end
end
/*
--外部接口在RD及CS低电平期间输出内部数据
--RS为0时输出忙信号.RS为1时输出当前地址的内部数据
*/
always @(SysRst or ExBusOut_Q or WrEn_Q or ExCs or ExRs or ExWr or ExRd)
begin
if (!SysRst) begin
ExOutM = 16'bzzzzzzzzzzzzzzzz;
end else begin
if ((~ExCs) & ExWr & (~ExRd)) begin
ExOutM = (ExRs)?ExBusOut_Q: ({15'd0,WrEn_Q}); //RS为1,输出总线数据(SRAM数据;RS为0,输出忙信号
end else begin
ExOutM = 16'bzzzzzzzzzzzzzzzz; //不确定状态
end
end
end
/*
--外部异步WR写入数据.(给sram写数据)
*/
always @(posedge ExWr or negedge SysRst) //写入信号上升沿
begin
if (!SysRst) begin
WriteRgb_Q = 16'd0;
ExWrClk_Q = 1'b0;
RegAddr_Q = 3'd0;
end else begin
if (!ExCs) begin //片选
if (!ExRs) begin //数据类型选择
RegAddr_Q <= ExDataBus[2:0]; //控制信号
end else begin
WriteRgb_Q <= ExDataBus; //32直接给CPLD送数据,再让CPLD送到SRAM,目前看到是这样。(为什么不直接32给SRAM呢)
ExWrClk_Q <= ~ExWrClk_Q; //送入RGB数据的同时还产生写入时钟
end
end
end
end
/*
--外部异步RD读出数据.(CPLD从SRAM读数据)
*/
always @(negedge ExRd or negedge SysRst) //下降沿读出CS,RS
begin
if (!SysRst) begin
ExRsR_Q = 1'b0;
ExCsR_Q = 1'b1;
end else begin
ExCsR_Q <= ExCs;
ExRsR_Q <= ExRs;
end
end
always @(posedge ExRd or negedge SysRst) //ExRd上升沿
begin
if (!SysRst) begin
ExRdClk_Q = 1'b0;
end else begin
if ((~ExCsR_Q) & ExRsR_Q) begin
ExRdClk_Q <= ~ExRdClk_Q; //当ExRd上升沿到来,并且CS = 0;RS = 1,产生读取时钟
end
end
end
/******************************************
--主时钟打两拍同步采用外部读写信号
******************************************/
always @(posedge Clk54 or negedge SysRst)
begin
if (!SysRst) begin
ExRdClk_Q1 = 1'b0;
ExRdClk_Q2 = 1'b0;
ExWrClk_Q1 = 1'b0;
ExWrClk_Q2 = 1'b0;
end else begin
ExRdClk_Q1 <= ExRdClk_Q; //检测上升/下降沿
ExRdClk_Q2 <= ExRdClk_Q1;
ExWrClk_Q1 <= ExWrClk_Q;
ExWrClk_Q2 <= ExWrClk_Q1;
end
end
/*
*/
always @(posedge Clk54 or negedge SysRst)
begin
if (!SysRst) begin //系统复位
InBusOut_Q = 16'd0;
ExBusOut_Q = 16'd0;
XRegValue_Q = 9'd0;
YRegValue_Q = 9'd0;
SysCmdValue_Q = 16'b0000000000110000;
WrEn_Q = 1'b0;
RamWeReg_Q = 1'b1;
RamTriState_Q = 1'b1;
RGB_Q = 16'd0;
FillCount_Q = 3'd7;
BRGBValue_Q = 16'd0;
FRGBValue_Q = 16'd0;
RamAddrBus_Q = 18'd0;
RamCsReg_Q = 1'b1;
PrePareData = 16'd0;
end else begin
if (ExRdClk_Q2 ^ ExRdClk_Q1) begin //当ExRdClk_Q出现上升沿或下降沿
IncAddr = 1'b1;
end else begin
IncAddr = 1'b0;
end
if (ExWrClk_Q2 ^ ExWrClk_Q1) begin //当ExWrClk_Q出现上升沿或者下降沿
AskWr = 1'b1;
end else begin
AskWr = WrEn_Q; //为了循环和单次触发设置的位
end
XRegOver = (XRegValue_Q == 9'b111011111)?1'b1:1'b0; //检查是否完毕
YRegOver = (YRegValue_Q == 9'b100001111)?1'b1:1'b0; //这些最大值是哪里来的 x479y271,写的应该是屏幕的大小
PrePareData = WriteRgb_Q;
IndexData[7:0] = WriteRgb_Q[7:0];
InRamWe = 1'b1;
if (!ClkCnt_Q3[0]) begin //54/2,27M,相当于ClkCnt_Q3[1]
if (AskWr) begin //要求写入
case (RegAddr_Q)
3'b000:begin
XRegValue_Q <= PrePareData[8:0]; //X坐标数据
WrEn_Q <= 1'b0;
end
3'b001:begin
YRegValue_Q <= PrePareData[8:0]; //Y坐标数据
WrEn_Q <= 1'b0;
end
3'b010:begin
InRamWe = 1'b0; //给ram写数据的开关
IncAddr = 1'b1; //更换显示方式的开关
WrEn_Q <= 1'b0; //给CPLD写入数据的开关
end
3'b100:begin
FRGBValue_Q <= PrePareData; //前景色颜色数据
WrEn_Q <= 1'b0;
end
3'b101:begin
BRGBValue_Q <= PrePareData; //背景色颜色数据
WrEn_Q <= 1'b0;
end
3'b110:begin
SysCmdValue_Q <= PrePareData; //SysCmdValue_Q数据更新
WrEn_Q <= 1'b0;
end
3'b011:begin //这段语法上看得懂,但意义不明,下标都超过数组长度了
if (!IndexData[FillCount_Q]) begin
PrePareData = BRGBValue_Q;
InRamWe = SysCmdValue_Q[12];
end else begin
PrePareData = FRGBValue_Q;
InRamWe = 1'b0;
end
IncAddr = 1'b1;
WrEn_Q <= (FillCount_Q[0] | FillCount_Q[1] | FillCount_Q[2]); //WrEn_Q是有可能为0的,但需要FillCount_Q溢出很多次
FillCount_Q <= FillCount_Q + 3'd7; //FillCount_Q不断+7,不就超出IndexData的数组长度了吗
end
3'b111:begin
if (FillHead_Q) begin
IncAddr = 1'b1; //为了循环更新像素坐标
InRamWe = 1'b0;
if (YRegOver & XRegOver) begin
WrEn_Q <= 1'b0;
end
end else begin
WrEn_Q <= 1'b1; //这里就是设置WrEn_Q的意义
end
end
endcase
end
RGB_Q <= (SysCmdValue_Q[3])?16'd0:RamDataBus;
SramAddr[12:4] = YRegValue_Q[8:0];
SramAddr[3:0] = XRegValue_Q[8:5];
RamAddrBus_Q[4:0] <= XRegValue_Q[4:0];
RamAddrBus_Q[17] <= SysCmdValue_Q[7];
end else begin
if (AskWr) begin
WrEn_Q <= 1'b1;
end
ExBusOut_Q <= RamDataBus;
SramAddr[12:4] = HsCount_Q[8:0];
SramAddr[3:0] = DotCount_Q[8:5];
RamAddrBus_Q[4:0] <= DotCount_Q[4:0];
RamAddrBus_Q[17] <= SelDispRam_Q;
end
InBusOut_Q <= PrePareData;
RamTriState_Q <= InRamWe;
RamWeReg_Q <= InRamWe;
SramAddr[12:0] = SramAddr[12:0] - {4'd0,SramAddr[12:4]};
RamAddrBus_Q[16:5] <= SramAddr[11:0];
/*根据配置字调整XY*/
if (IncAddr) begin
case (SysCmdValue_Q[6:4]) //bit4 - bit6显示方式
3'b001:begin
if (XRegOver) begin
XRegValue_Q <= 9'd0;
end else begin
XRegValue_Q <= XRegValue_Q + 9'd1;
end
end
3'b011:begin
if (XRegOver) begin
XRegValue_Q <= 9'd0;
if (YRegOver) begin
YRegValue_Q <= 9'd0;
end else begin
YRegValue_Q <= YRegValue_Q + 9'd1;
end
end else begin
XRegValue_Q <= XRegValue_Q + 9'd1;
end
end
3'b110:begin
if (YRegOver) begin
YRegValue_Q <= 9'd0;
end else begin
YRegValue_Q <= YRegValue_Q + 9'd1;
end
end
3'b111:begin
if (YRegOver) begin
YRegValue_Q <= 9'd0;
if (XRegOver) begin
XRegValue_Q <= 9'd0;
end else begin
XRegValue_Q <= XRegValue_Q + 9'd1;
end
end else begin
YRegValue_Q <= YRegValue_Q + 9'd1;
end
end
default:begin
end
endcase
end
RamCsReg_Q <= SysCmdValue_Q[3]; //bit3显示开关
end
end
/*--产生TFT行同步*/
always @(posedge Clk54 or negedge SysRst)
begin
if (!SysRst) begin
DotCount_Q = 9'd0;
DsState_Q = 2'd0;
DsMark = 1'b0;
end else begin
if (DotClkEn_Q) begin //9M,一个高电平,五个低电平
case (DsState_Q)
2'd0:/*=>--41 相当于<= 40*/
DsMark = (DotCount_Q[5] & DotCount_Q[3]); //DotCount_Q加到101000,进入下一阶段
2'd1:/*when "01" =>--2 相当于<= 1*/
DsMark = DotCount_Q[0]; //DotCount_Q加到1,进入下一阶段
2'd2:/*=>--480 相当于<= 479*/
DsMark = (DotCount_Q[0] & DotCount_Q[1] & DotCount_Q[2] & DotCount_Q[3] &
DotCount_Q[4] & DotCount_Q[6] & DotCount_Q[7] & DotCount_Q[8]); //DotCount_Q加到111011111进入下一阶段
2'd3:/*--2 相当于<= 1*/
DsMark = DotCount_Q[0];
endcase
DsState_Q <= DsState_Q + {1'b0,DsMark};
DotCount_Q <= (DsMark)?9'd0: (DotCount_Q + 9'd1);
end
end
end
/*--产生TFT帧同步信号*/
always @(posedge Clk54 or negedge SysRst)
begin
if (!SysRst) begin
DE_Q = 1'b0;
end else begin
DE_Q <= (SysCmdValue_Q[3])?1'b0: (HsState_Q[1] & (~HsState_Q[0]) & DsState_Q[1] & (~DsState_Q[0]));
end
end
/*--产生帧同步时钟*/
always @(posedge Clk54 or negedge SysRst)
begin
if (!SysRst) begin
HsCount_Q = 9'd0;
HsState_Q = 2'd0;
FillHead_Q = 1'b0;
SelDispRam_Q = 1'b0;
LedCount_Q = 5'd0;
end else begin
if (DsState_Q[0] & DsState_Q[1] & DotCount_Q[0] & DotClkEn_Q) begin
case (HsState_Q)
2'd0:/*--10相当于<= 9*/
HsMark = (HsCount_Q[0] & HsCount_Q[3]);
2'd1:/*--2相当于<= 1*/
begin
HsMark = HsCount_Q[0];
FillHead_Q <= (RegAddr_Q[2] & RegAddr_Q[1] & RegAddr_Q[0] & WrEn_Q);
SelDispRam_Q <= SysCmdValue_Q[10];
end
2'd2:/*--272相当于<= 271*/
HsMark = (HsCount_Q[0] & HsCount_Q[1] & HsCount_Q[2] & HsCount_Q[3] & HsCount_Q[8]);
2'd3:/*--2相当于<= 1*/
HsMark = HsCount_Q[0];
endcase
HsState_Q <= HsState_Q + {1'b0,HsMark};
HsCount_Q <= (HsMark)?9'd0: (HsCount_Q + 9'd1);
LedCount_Q <= LedCount_Q + 5'd1;
end
end
end
/*LED调光进程*/
always @(posedge Clk54 or negedge SysRst)
begin
if (!SysRst) begin
LedOn_W = 1'b0;
LedOn_Q = 1'b0;
end else begin
case (SysCmdValue_Q[2:0])
3'd0:
LedOn_W = 1'b0;
3'd1:
LedOn_W = (LedCount_Q < 5'd8)?1'b1:1'b0;
3'd2:
LedOn_W = (LedCount_Q < 5'd12)?1'b1:1'b0;
3'd3:
LedOn_W = (LedCount_Q < 5'd16)?1'b1:1'b0;
3'd4:
LedOn_W = (LedCount_Q < 5'd20)?1'b1:1'b0;
3'd5:
LedOn_W = (LedCount_Q < 5'd24)?1'b1:1'b0;
3'd6:
LedOn_W = (LedCount_Q < 5'd28)?1'b1:1'b0;
default:
LedOn_W = 1'b1;
endcase
LedOn_Q <= (SysCmdValue_Q[3])?1'b0: LedOn_W;
end
end
endmodule
|
|