aitendoのTFT液晶モジュールZY-FGD1442701V1, ST7735をMAX II CPLDで駆動

aitendoで売っている(売っていた?)小型カラー液晶をCPLDでドライブするテストです。
4年ちょっと昔に売られ始めた時に買ったものです。その時はFT245RLあたりのICを使って、PCから制御していましたが、書き換えをもっと早くしたいというのと、CPLDのお勉強も兼ねて。
昔の記事//beiznotes.org/200911071257539777-2/

 

MAX IIのページにSC1602Bキャラクタ液晶の制御例がありましたが、Verilogコードが初心者が書いたみたいになっているのですが、なんなんでしょうか。とりあえずソースコード検索をしようとgoogle codeに行ったら404で、サービス終了で、Koderに行ったらこれもまたサービス移行していた。Ohlohコードサーチでverilogコードを探したらなんとかひとつ見つかって、それを参考にしました。
CPLDではCPUみたいに上から順番に処理するというのがめんどくさいです。ループばかりの本処理にはいってしまえばよいのですが、その前の初期化処理はひとつひとつにステートを割り当てて、ステートマシンで処理しています。

f:id:beiz23:20140208095934j:image:w360
オプティマイズさんのところのMAX II基板に接続しました。
ピンクを表示させたら発色が悪いので、ガンマとか、VCOMとかも設定することにしたけども、それでもまだ悪いです。まあそもそもバックライトムラなどもございますので、妥協すべきことがらなんでしょう。

Verilog HDLコードです。197LE


`timescale 1 ps / 1 ps
module lcdzy( RESX, CSX, D_CX, WRX, DATA );
//input rstx;
output reg [7:0] DATA;
output reg RESX;//reset
output reg CSX;//chip select low enable
output reg D_CX;//data / command
output reg WRX;//write enable
wire rstx;
assign rstx = 1'b1;

//output RDX; //-> always write
reg [3:0] state, next_st; //state reg.
reg [15:0] wait_ms;
reg [5:0] init_addr;
wire [7:0] init_in, data_in;
reg [15:0] data_addr;//16 bit  7+7+1 128*128*2
reg [13:0] wait_cnt;
reg [7:0] write_data;
wire init_dcx;

wire clk;
rc_osc rc_osc(1'b1, clk);

LCD_INIT_SEQ lcd_init_seq(init_addr, init_in, init_dcx);
LCD_DATA_SEQ lcd_data_seq(data_addr, data_in);

// BIDIRECTIONAL TRI STATE LCD DATA BUS
//assign DATA_BUS = (RDX? 8'bz: data_value);


`define IDOL 4'h1
`define INIT 4'h0
`define RESET1 4'h2
`define RESET2 4'h3
`define SLEEP_OUT 4'h4
`define DISP_ON 4'h5
`define INIT_SEQ 4'h6
`define RAM_WR 4'h7
`define DATA_SEQ 4'h8
`define WRITE 4'h9
`define WRITE_ENA 4'ha
`define WAIT 4'hb
`define SOFT_RST 4'hc

`define MS_CNT 14'd5555 // 1e-3 s * 5.5e6 Hz = 5.5e3
`define DATA_CNT_MAX 16'h7fff//


initial begin
    state = `INIT;
    wait_ms <= 8'h0;
    wait_cnt <= 1'b0;
    init_addr <= 6'h0;
    data_addr <= 16'h000;
    RESX <= 1'b1;
    CSX <= 1'b1;
    D_CX <= 1'b0;
    WRX <= 1'b0;
end

//clk gen -> slow enogh at 3.3 MHz
/*always @ posedge clk_3M3 or negede reset)
    if (!rst) begin
        clk_count_
        */


//state reg
/*always @ ( posedge clk or negedge rst ) begin
    if ( !rst )
        cur_st <= INIT;
    else
        cur_st <= next_st;
end*/

//state gen
always @ ( posedge clk or negedge rstx ) begin
    if ( !rstx ) begin
        state <= `INIT;
        wait_ms <= 16'h0;
        wait_cnt <= 1'b0;
        init_addr <= 6'h0;
        RESX <= 1'b1;
        CSX <= 1'b1;
        D_CX <= 1'b0;
        WRX <= 1'b0;
    end else begin
        case ( state )
            `IDOL: begin
                next_st <= `INIT;
                state <= `WAIT;
                wait_ms <= 16'h1000;
            end
            `INIT: begin //wait lcd pow on
                RESX <= 1'b1;
                CSX <= 1'b1;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                state <= `WAIT;
                next_st <= `RESET1;
                wait_ms <= 6'd50;//50ms
            end
            `RESET1: begin
                RESX <= 1'b0;//RESET
                CSX <= 1'b1;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                state <= `WAIT;
                wait_ms <= 6'd1;//more than 10us
                next_st <= `RESET2;
            end
            `RESET2: begin//WAIT stable
                RESX <= 1'b1;
                CSX <= 1'b1;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                state <= `WAIT;
                wait_ms <= 7'd120;//120ms
                next_st <= `SLEEP_OUT;
            end
            `SLEEP_OUT: begin//sleep out
                RESX <= 1'b1;
                CSX <= 1'b0;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                write_data <= 8'h11;
                state <= `WRITE;
                next_st <= `DISP_ON;
                wait_ms <= 7'd120;//120ms
            end
            `DISP_ON: begin//disp on
                RESX <= 1'b1;
                CSX <= 1'b0;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                write_data <= 8'h29;
                state <= `WRITE;
                next_st <= `INIT_SEQ;
                wait_ms <= 7'd120;//120ms
            end
            `INIT_SEQ: begin
                if ( init_in == 8'h00
                && init_dcx == 1'b0 ) begin //end init
                    RESX <= 1'b1;
                    CSX <= 1'b1;
                    D_CX <= 1'b0;
                    WRX <= 1'b1;
                    state <= `RAM_WR;
                    init_addr <= 4'h0;
                    //DATA <= 8'h00;
                end else begin
                    RESX <= 1'b1;
                    CSX <= 1'b0;
                    D_CX <= init_dcx;
                    WRX <= 1'b1;
                    write_data <= init_in;
                    state <= `WRITE;
                    next_st <= `INIT_SEQ;
                    init_addr <= init_addr + 1'b1;
                end
            end
            `RAM_WR: begin
                RESX <= 1'b1;
                CSX <= 1'b0;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                write_data <= 8'h2c;
                state <= `WRITE;
                next_st <= `DATA_SEQ;
                wait_ms <= 1'b0;//0 ms
            end
            `DATA_SEQ: begin
                if ( data_addr > `DATA_CNT_MAX ) begin
                    RESX <= 1'b1;
                    CSX <= 1'b1;
                    D_CX <= 1'b1;
                    WRX <= 1'b1;
                    DATA <= 8'h00;
                    state = `IDOL;
                    data_addr <= 16'h0000;
                end else begin
                    RESX <= 1'b1;
                    CSX <= 1'b0;
                    D_CX <= 1'b1;
                    WRX <= 1'b1;
                    write_data <= data_in;
                    state <= `WRITE;
                    next_st <= `DATA_SEQ;
                    data_addr <= data_addr + 1'b1;
                end
            end
            `WRITE: begin
                WRX <= 1'b0;//wait 30 ns
                DATA <= write_data;
                state <= `WRITE_ENA;
            end
            `WRITE_ENA: begin
                WRX <= 1'b1;//wait 30 ns
                if (wait_ms == 0)
                    state <= next_st;
                else
                    state <= `WAIT;
            end
            `WAIT: begin
                if ( wait_ms > 1'b0 ) begin
                    state <= `WAIT;
                    if ( wait_cnt < `MS_CNT ) begin
                        wait_cnt <= wait_cnt + 1'b1;
                    end else begin
                        wait_cnt <= 1'b0;
                        wait_ms <= wait_ms - 1'b1;
                    end
                end else begin
                    state <= next_st;
                    wait_cnt <= 1'b0;
                end
            end
            `SOFT_RST: begin //software reset
                RESX <= 1'b1;
                CSX <= 1'b0;
                D_CX <= 1'b0;
                WRX <= 1'b1;
                write_data <= 8'h01;
                state <= `WRITE;
                next_st <= `SLEEP_OUT;
                wait_ms <= 7'd120;
            end
        endcase
    end
end

endmodule


module LCD_INIT_SEQ ( addr, out, dcx );
input [5:0] addr;
output reg [7:0] out;
output reg dcx;

always
    case ( addr )// after soft_reset, sleep_out
        6'h00: begin out <= 8'h36; dcx <= 1'b0; end//Memory data acc
        6'h01: begin out <= 8'h88; dcx <= 1'b1; end//mirror xy BGR
        6'h02: begin out <= 8'h3a; dcx <= 1'b0; end//interface
        6'h03: begin out <= 8'h05; dcx <= 1'b1; end//16bit mode
        6'h04: begin out <= 8'h2a; dcx <= 1'b0; end//column addr set
        6'h05: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h06: begin out <= 8'h02; dcx <= 1'b1; end//02h
        6'h07: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h08: begin out <= 8'h81; dcx <= 1'b1; end//81h
        6'h09: begin out <= 8'h2b; dcx <= 1'b0; end//row addr set
        6'h0a: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h0b: begin out <= 8'h03; dcx <= 1'b1; end//03h
        6'h0c: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h0d: begin out <= 8'h82; dcx <= 1'b1; end//82h
        6'h0e: begin out <= 8'hc1; dcx <= 1'b0; end//POW CTL 2 VGHH VCLL
        6'h0f: begin out <= 8'h07; dcx <= 1'b1; end//14.7V, -12.25V
        6'h10: begin out <= 8'hc5; dcx <= 1'b0; end//VCOM CTL1
        6'h11: begin out <= 8'h3c; dcx <= 1'b1; end//VCOMH
        6'h12: begin out <= 8'h4f; dcx <= 1'b1; end//VCOML
        6'h13: begin out <= 8'he0; dcx <= 1'b0; end//gamma  +
        6'h14: begin out <= 8'h06; dcx <= 1'b1; end//
        6'h15: begin out <= 8'h0e; dcx <= 1'b1; end//
        6'h16: begin out <= 8'h05; dcx <= 1'b1; end//
        6'h17: begin out <= 8'h20; dcx <= 1'b1; end//
        6'h18: begin out <= 8'h27; dcx <= 1'b1; end//
        6'h19: begin out <= 8'h23; dcx <= 1'b1; end//
        6'h1a: begin out <= 8'h1c; dcx <= 1'b1; end//
        6'h1b: begin out <= 8'h21; dcx <= 1'b1; end//
        6'h1c: begin out <= 8'h20; dcx <= 1'b1; end//
        6'h1d: begin out <= 8'h1c; dcx <= 1'b1; end//
        6'h1e: begin out <= 8'h26; dcx <= 1'b1; end//
        6'h1f: begin out <= 8'h2f; dcx <= 1'b1; end//
        6'h20: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h21: begin out <= 8'h03; dcx <= 1'b1; end//
        6'h22: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h23: begin out <= 8'h24; dcx <= 1'b1; end//
        6'h24: begin out <= 8'he1; dcx <= 1'b0; end//gamma -
        6'h25: begin out <= 8'h06; dcx <= 1'b1; end//
        6'h26: begin out <= 8'h10; dcx <= 1'b1; end//
        6'h27: begin out <= 8'h05; dcx <= 1'b1; end//
        6'h28: begin out <= 8'h21; dcx <= 1'b1; end//
        6'h29: begin out <= 8'h27; dcx <= 1'b1; end//
        6'h2a: begin out <= 8'h22; dcx <= 1'b1; end//
        6'h2b: begin out <= 8'h1c; dcx <= 1'b1; end//
        6'h2c: begin out <= 8'h21; dcx <= 1'b1; end//
        6'h2d: begin out <= 8'h1f; dcx <= 1'b1; end//
        6'h2e: begin out <= 8'h1d; dcx <= 1'b1; end//
        6'h2f: begin out <= 8'h27; dcx <= 1'b1; end//
        6'h30: begin out <= 8'h2f; dcx <= 1'b1; end//
        6'h31: begin out <= 8'h05; dcx <= 1'b1; end//
        6'h32: begin out <= 8'h03; dcx <= 1'b1; end//
        6'h33: begin out <= 8'h00; dcx <= 1'b1; end//
        6'h34: begin out <= 8'h3f; dcx <= 1'b1; end//

        default: begin out <= 8'h00; dcx <= 1'b0; end//nop -> end
    endcase
endmodule

module LCD_DATA_SEQ ( addr, out );
input [15:0] addr;
output reg [7:0] out;
always if ( (addr & 16'h0001) == 0 )
    out <= {5'h1f, 3'b011};//ff719c
    //out <= {2'hf, ( ( addr >> 9 ) & 6'hff )}; //0x8000
else
    out <= {3'b100, 5'b10011};
    //out <= ( ( addr >> 1 ) & 8'hff );

endmodule

「aitendoのTFT液晶モジュールZY-FGD1442701V1, ST7735をMAX II CPLDで駆動」への1件のフィードバック

  1. ピンバック: aitendoのTFT液晶モジュール ZY-FGD1442701V1を、パソコンから制御する方法

コメントは受け付けていません。