发 帖  
原厂入驻New
首轮预售——FPGA软件无线电开发(全阶教程+开发板+实例源码)仅限23套!!!
[讨论] 【EG4S20-MINI-DEV 试用体验】+点阵LCD测试
2019-7-18 09:52:02  554 LCD FPGA
分享
1、测试说明:
       收到安路的开发板快一个月了,由于近期工作较忙,一直没时间试用,昨天正好抽空了半天时间想好好研究研究。本来计划的是将我之前Xilinx上的程序进行移植,但是由于资源问题无法实施,正好手头有一块12846的点阵LCD,就先拿它入手吧。
       为了尽量多的测试各种资源,我的设计思路是这样的:
       程序包含三个子模块,一个时钟分频模块,一个LCD的驱动控制模块,一个指令数据控制模块(该模块里还有一个BRAM,用来存储显示数据),结构如下图所示:
      
       LCD的控制时序如下所示:
     
2、测试代码:
       顶层模块
        module lcd_test(
        input clk_25M,
        input rst_n,
        input key_start,
        output lcd_e,
        output lcd_rs,
        output lcd_rw,
        output [7:0]lcd_db
         );

wire clk_1M;

clk_div U1(
        .clk_25M(clk_25M),
        .rst_n(rst_n),
        .clk_1M(clk_1M)
        );

wire over;
wire busy;
wire rw_select;  //r:1'b1   w:1'b0
wire di_select;  //d:1'b1   i:1'b0;
wire w_start;
wire [7:0]w_data;

lcd_ctrl U2(
        .clk(clk_1M),
        .rst_n(rst_n),
        .w_data(w_data),
        .rw_select(rw_select),
        .di_select(di_select),
        .start(w_start),
        .lcd_rs(lcd_rs),
        .lcd_rw(lcd_rw),
        .lcd_e(lcd_e),
        .DB_data(lcd_db),
        .over(over),
        .busy(busy)
        );

command_ctrl U3(
        .clk_25M(clk_25M),
        .rst_n(rst_n),
        .key_start(key_start),
        .busy(busy),
        .over(over),
        .rw_select(rw_select),
        .di_select(di_select),
        .w_start(w_start),
        .w_data(w_data)
         );

endmodule

         时钟分频子模块:
         module clk_div(
        input clk_25M,
        input rst_n,
        output reg  clk_1M
        );

reg[4:0]cnt;

always@(posedge clk_25M or negedge rst_n)
        IF(!rst_n)
                cnt[4:0] <= 5'd0;
        else if(cnt[4:0] <5'd25)        
                cnt[4:0] <= cnt[4:0] + 1'b1;
        else        
                cnt[4:0] <= 5'd0;

always@(posedge clk_25M or negedge rst_n)
        if(!rst_n)
                clk_1M <= 1'b0;
        else if(cnt[4:0] < 5'd12)
                clk_1M <= 1'b1;
        else        
                clk_1M <= 1'b0;

endmodule

         LCD驱动子模块:
        module lcd_ctrl(
        input clk,    //1M  1000ns
        input rst_n,
        input [7:0] w_data,
        input rw_select,
        input di_select,
        input start,
        output reg lcd_rs,
        output reg lcd_rw,
        output reg lcd_e,
        output reg [7:0]DB_data,
        output reg over,
        output reg busy
        );

reg[1:0]cnt;
reg[5:0]CS;
reg[5:0]NS;

parameter IDLE = 6'h1;
parameter PREPARE = 6'h2;
parameter SETSTATE = 6'h4;
parameter ENABLE = 6'h8;
parameter LOCKDATA = 6'h10;
parameter OVER = 6'h20;

//监测一次写操作的开始标识上升沿
reg start_r1;
reg start_r2;
wire start_u;

always@(posedge clk)
        begin
                start_r1 <= start;
                start_r2 <= start_r1;
        end
assign start_u = start_r1 && (~start_r2);

always@(posedge clk or negedge rst_n)
        if(!rst_n)
                CS[5:0] <= IDLE;
        else        
                CS[5:0] <= NS[5:0];

always@(CS[5:0] or start_u or cnt[1:0])
        begin
                NS[5:0] = IDLE;
                case(CS)
                        IDLE:
                                NS = start_u ? PREPARE : IDLE;
                        PREPARE:
                                NS = SETSTATE;
                        SETSTATE:
                                NS = ENABLE;
                        ENABLE:
                                NS = LOCKDATA;
                        LOCKDATA:
                                NS = cnt[0] ? OVER : LOCKDATA;
                        OVER:
                                NS = IDLE;
                        default:
                                NS = IDLE;
                endcase
        end

always@(posedge clk)
        begin        
                case(NS)
                        IDLE:
                                begin
                                        lcd_e <= 1'b0;
                                        lcd_rs <= 1'b0;
                                        lcd_rw <= 1'b0;
                                        DB_data[7:0] <= 8'h0;
                                        cnt[1:0] <= 2'd0;
                                        over <= 1'b0;
                                        busy <= 1'b0;
                                end
                        PREPARE:
                                begin
                                        lcd_e <= 1'b0;
                                        busy <= 1'b1;
                                        over <= 1'b0;
                                end
                        SETSTATE:
                                begin
                                        lcd_rs <= di_select ? 1'b1 : 1'b0;
                                        lcd_rw <= rw_select ? 1'b1 : 1'b0;
                                end
                        ENABLE:
                                begin
                                        lcd_e <= 1'b1;
                                        DB_data[7:0] <= w_data[7:0];
                                end
                        LOCKDATA:        
                                begin
                                        lcd_e <= 1'b0;
                                        cnt[1:0] <= cnt[1:0] + 1'b1;
                                end
                        OVER:
                                begin
                                        lcd_e <= 1'b0;
                                        cnt[1:0] <= 2'b00;
                                        over <= 1'b1;
                                        busy <= 1'b0;
                                end
                endcase
        end         


endmodule


        指令数据控制子模块:
         module command_ctrl(
        input clk_25M,
        input rst_n,
        input key_start,
        input busy,
        input over,
        output reg rw_select,
        output reg di_select,
        output reg w_start,
        output reg [7:0]w_data
         );

//检测开关下降沿
reg key_r1;
reg key_r2;
wire keystart;

always@(posedge clk_25M)
        begin
                key_r1 <= key_start;
                key_r2 <= key_r1;
        end
assign keystart = key_r2 && (~key_r1);

//监测一次写操作的结束标识上升沿
reg over_r1;
reg over_r2;
wire over_u;

always@(posedge clk_25M)
        begin
                over_r1 <= over;
                over_r2 <= over_r1;
        end
assign over_u = over_r1 && (~over_r2);

//LCD指令集
reg[7:0]command[8:0];
initial        
        begin
                command[0] = 8'h01; //清屏        
                command[1] = 8'h02; //地址归位        
                command[2] = 8'h07; //光标右移,整体显示移动        
                command[3] = 8'h0f; //整体显示、光标显示、光标位置反白且闪烁        
                command[4] = 8'h14; //光标右移        
                command[5] = 8'h30; //8b控制,基本指令动作集        
                command[6] = 8'h80; //设定DDRAM地址        
                command[7] = 8'hB8;//设置页地址,第一页
                command[8] = 8'h40;//设置列地址,第一列
        end

parameter IDLE = 6'h1;
parameter START_I = 6'h2;
parameter TURN_I = 6'h4;
parameter READ_DATA = 6'h8;
parameter START_D = 6'h10;
parameter TURN_D = 6'h20;


reg[5:0]CS;
reg[5:0]NS;
reg[3:0]cnt;
reg[1:0]cnt1;
reg[3:0]cnt2;
reg[3:0]cnt3;
reg[2:0]i;
reg clka;
reg [6:0]addra;
wire[7:0]ramdata;

always@(posedge clk_25M or negedge rst_n)
        if(!rst_n)
                CS <= IDLE;
        else        
                CS <= NS;

always@(CS or keystart or over_u or cnt[3:0] or cnt1[1:0] or cnt2[3:0] or cnt3[3:0])
        begin        
                NS = IDLE;
                case(CS)
                        IDLE:
                                NS = keystart ? START_I : IDLE;
                        START_I:
                                NS = over_u ? TURN_I : START_I;
                        TURN_I:
                                NS = (cnt2[3]) ? READ_DATA : START_I;
                        READ_DATA:
                                NS = (cnt1[1:0] == 2'b11) ? START_D : READ_DATA;
                        START_D:
                                NS = over_u ? TURN_D : START_D;
                        TURN_D:
                                NS = (cnt3[3:0] == 4'hf) ? IDLE : READ_DATA;
                        default:
                                NS = IDLE;
                endcase
        end

always@(posedge clk_25M)
        begin
                case(NS)
                        IDLE:
                                begin
                                        rw_select <= 1'b0;
                                        di_select <= 1'b0;
                                        w_start <= 1'b0;
                                        w_data[7:0] <= 8'd0;
                                        cnt[3:0] <= 4'd0;
                                        cnt1[1:0] <= 2'd0;
                                        cnt2[3:0] <= 4'd0;
                                        cnt3[3:0] <= 4'd0;
                                        i[2:0] <= 3'd0;
                                        clka <= 1'b0;
                                        addra[6:0] <= 7'd0;
                                end
                        START_I:
                                begin
                                        w_start <= 1'b1;
                                        rw_select <= 1'b0;
                                        di_select <= 1'b0;
                                        w_data[7:0] <= command;
                                end
                        TURN_I:
                                begin        
                                        i[2:0] <= i[2:0] + 1'b1;
                                        cnt2[2:0] <= cnt2[2:0] + 1'b1;
                                end
                        READ_DATA:
                                begin
                                        clka <= 1'b1;
                                        cnt1[1:0] <= cnt1[1:0] + 1'b1;
                                end
                        START_D:
                                begin
                                        w_start <= 1'b1;
                                        rw_select <= 1'b0;
                                        di_select <= 1'b1;
                                        w_data[7:0] <= ramdata[7:0];
                                        clka <= 1'b0;
                                end
                        TURN_D:
                                begin
                                        cnt3[3:0] <= cnt3[3:0] + 1'b1;
                                        cnt1[1:0] <= 2'd0;
                                        clka <= 1'b0;
                                        addra[6:0] <= addra[6:0] + 1'b1;
                                end
                endcase
        end


dataram U1(
        .doa(ramdata),
        .dia(),
        .addra(addra),
        .wea(),
        .clka(clka)
        );               
endmodule

3、调试
       由于时间紧张,这次的程序还没来得及进行板级调试,所以程序还未进行验证。好在还有一个月的试用期,争取下个月抽出多一些的时间进行调试验证,并再增加一些新的功能,丰富下测试内容。

4、体会
      关于这次安路的试用板测试,因为时间缘故只是短暂的体验,但也有几点体会。
      优点:
      1)安路的TD工具真小,安装特别方便快捷;
      2)编译速度也比较快,操作也算简单明了。
      缺点:
      1)不知道是我不会使用的缘故还是别的原因,我发现当程序综合或者布线等有错误的时候,根据报错信息进行修改,然后重新综合、布线等等,之前的 报错信息还在,这就优点头大;
      2)在编写代码的时候,对特定的标识有自动判断并补全的功能,但是用户自定义的一些信号,没有该功能。



0

LCD时序图

LCD时序图

程序结构

程序结构
2019-7-18 09:52:02   评论 分享淘帖

撰写讨论

你正在撰写讨论

如果你是对讨论或其他讨论精选点评或询问,请使用“评论”功能。

高级模式
您需要登录后才可以回帖 登录 | 注册

发讨论
课程
    关闭

    站长推荐 上一条 /10 下一条

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