OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2251|回复: 6

【求助帖】关于CPLD+sram+stm32驱动TFT

[复制链接]

2

主题

20

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2019-5-5
在线时间
98 小时
发表于 2019-5-17 09:53:49 | 显示全部楼层 |阅读模式
5金钱
本帖最后由 charge 于 2019-5-17 09:53 编辑

最近刚学CPLD,看了论坛里的资源大多都是差不多一个模板,但是功力尚浅有些看不懂,还请各位过路的大侠指点迷津{:smile:}
参考了以下帖子http://www.openedv.com/forum.php ... 54&page=3#pid418769

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

20

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2019-5-5
在线时间
98 小时
 楼主| 发表于 2019-5-17 09:53:50 | 显示全部楼层
这个帖子里http://www.openedv.com/forum.php?mod=viewthread&tid=2254&page=3#pid418769li,这段CPLD的代码往下,我就开始看不懂了    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
回复

使用道具 举报

2

主题

20

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
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

回复

使用道具 举报

2

主题

20

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2019-5-5
在线时间
98 小时
 楼主| 发表于 2019-5-17 09:53:52 | 显示全部楼层
为了搞这个CPLD还注册了阿mo论坛的账号,八十大洋。。可是等级低居然不能发帖。还有大家要是有资料在阿mo论坛可以找我下载。等我完成这个,就把所有经验都写在这个帖子里。目前发现quartus13.1跑前面的代码提示资源不够,quartus9.1跑的画勉强够,删掉一些PWM调光就通过了。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165516
金钱
165516
注册时间
2010-12-1
在线时间
2116 小时
发表于 2019-5-18 02:42:32 | 显示全部楼层
charge 发表于 2019-5-17 09:53
为了搞这个CPLD还注册了阿mo论坛的账号,八十大洋。。可是等级低居然不能发帖。还有大家要是有资料在阿mo论 ...

欢迎
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

2

主题

20

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
331
金钱
331
注册时间
2019-5-5
在线时间
98 小时
 楼主| 发表于 2019-5-18 10:05:53 | 显示全部楼层

谢谢原子哥~可惜没人来回复~
回复

使用道具 举报

7

主题

16

帖子

0

精华

初级会员

Rank: 2

积分
110
金钱
110
注册时间
2013-7-8
在线时间
9 小时
发表于 2020-3-23 15:13:27 | 显示全部楼层
没人回复,我来了,我想问一下高手,现在你搞清楚了这个程序所有代码的意思了?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-23 04:52

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表