ZY-FGD1442701V1, ST7735をMAX II CPLDで駆動

移転しました。

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


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


オプティマイズさんのところの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