パラレル接続型キャラクターLCD Displayモジュール処理
液晶ドライバについて
日立製(互換?)液晶コントローラーを使った液晶表示モジュールへの表示に成功しましたので、これについて記載します。
ドライバVerilogコードは、lcd_driver_8.vです。
ステートマシーンを作り、ステート毎に液晶モジュールへコマンドを
送出します。
1)入出力ポートの説明
ここでは、モジュールの入出力について説明します。
括弧()内の数値は、入出力、ビット数を表しています。I=入力、O=出力、IO=入出力
例)(I:1) 入力、1ビット
clk (I:1):入力クロック、外部で37usecのクロックを生成してこの端子へ入力します。
resetn (I:1):リセット入力、ロー入力でモジュールを初期化します。
addr (O:8):アドレス出力、外部LCDメモリバッファの内容を読み込むためにアドレス指定します。
data (I:8):データ入力、上記で指定したアドレスのデータを読み込みます。
rd (O:1):リード出力、リード時にハイにセットします。
sc1602_en (O:1):液晶モジュールイネーブル出力(H:イネーブル)。
sc1602_rs (O:1):液晶モジュールレジスタセレクト出力(L:インストラクションレジスタ、H:データレジスタ)。
sc1602_rw (O:1):液晶モジュールリードライト出力(L:書き込み)。
sc1602_data (IO:8):液晶モジュールデータバス
rfrsh_rate (O:1):リフレッシュレート出力。16x2文字を書き込む毎にデータを反転出力します。
2)動作説明
このモジュールは表示バッファのデータ内容を読み取り、外部に接続された
パラレル接続タイプの液晶モジュールに転送します。
液晶モジュールのデータレジスタ16x2の内容は常にリフレッシュされます。
動作内容)
- -外部に接続されているメモリの内容を読み出します。
- -メモリのアドレスと表示位置は次のようにマッピングしています。
メモリアドレス:00-0F - 液晶モジュール1行目の1桁目から16桁目
メモリアドレス:10-1F - 液晶モジュール2行目の1桁目から16桁目
- -メモリの内容を液晶モジュールのデータレジスタにセットします。
3)ステートの説明
モジュールは次のステートを持っています。
- 0-RESET:リセット処理開始ステート
- 1-WAIT:待ちステート(イネーブル出力をローにします)
- 2-HOLD:hold_timeで指定された値分ホールドします。
- 3-FNCSET:ファンクションレジスタ設定ステート
- 4-DSPOFF:ディスプレイオフステート
- 5-CLRDSP:クリアディスプレイステート
- 6-DSPON:ディスプレイオンステート
- 7-ENMODST:エントリモード設定ステート
- 8-RETHOM:リターンホーム設定ステート
- 9-REDCHR:データリード(外部LCDメモリバッファ)ステート
- 10-WRTCHR:データライト(液晶モジュール)ステート
- 11-DDRMADSET:DDRAMアドレス(液晶モジュール)設定ステート
stateレジスタが現在のステート、nextレジスタが次のレジスタになります。
state<-nextが実行されるのは、HOLDステートの時です。
4)ステート遷移
- リセット動作)
RESET->WAIT->HOLD->FNCSET->WAIT->HOLD->DSPOFF->WAIT->HOLD
->CLRDSP->WAIT->HOLD->DSPON->WAIT->HOLD->ENMODST->WAIT->HOLD
->RETHOM->WAIT->HOLD
- DDRAMリフレッシュ動作)
REDCHR->WAIT->HOLD->WRTCHR->WAIT->HOLD->DDRAMSET
->WAIT->HOLD
上記を繰り返します。
ただし、WRTCHR時にdidxの値が4FHだった場合には、RETHOMへ状態を遷移します。
5)レジスタ
- state : カレントステート
- next : 次ステート
- didx : DDRAMインデックスナンバー。00,01,..0F,40,41..4F,00..と遷移します。
- hold_time : HOLDステートでの滞在カウンタ
6)コード
lcd_driver_8.v
module lcd_driver_8(clk,resetn,addr,data,rd,sc1602_en,sc1602_rs,sc1602_rw,sc1602_data,rfrsh_rate);
input clk,resetn;
output [7:0] addr;
reg [7:0] addr;
input [7:0] data;
output rd;
reg rd;
output sc1602_en,sc1602_rs,sc1602_rw;
reg sc1602_en,sc1602_rs,sc1602_rw;
output [7:0] sc1602_data;
reg [7:0] sc1602_data;
output rfrsh_rate;
reg rfrsh_rate;
reg [7:0] state, next, didx, hold_time;
parameter RESET=0;
parameter WAIT=1;
parameter HOLD=2;
parameter FNCSET=3;
parameter DSPOFF=4;
parameter CLRDSP=5;
parameter DSPON=6;
parameter ENMODST=7;
parameter RETHOM=8;
parameter REDCHR=9;
parameter WRTCHR=10;
parameter DDRMADSET=11;
// DL=1:8bit, N=1:2-line, F=0:5x8 dot, D=0:disp off
// C=0:Cursor off, B=0:Blinking off
// I/D=1:Increment by 1, S=0:No shift
// clk = 37us
always @(posedge clk or negedge resetn) begin
if (!resetn)
begin
state <= RESET;
didx <= 0;
end
else
begin
case (state)
RESET:
begin
sc1602_en <= 1;
sc1602_rs <= 0;
sc1602_rw <= 0;
sc1602_data <= 8'h38; // DL=1, N=1, F=0
didx = didx + 1;
if (didx > 3)
next <= FNCSET;
else
next <= RESET;
state <= WAIT;
hold_time = 0;
end
WAIT:
begin
sc1602_en <= 0;
state <= HOLD;
end
HOLD:
begin
if (hold_time == 0)
state <= next;
else
begin
hold_time = hold_time - 1;
end
end
FNCSET: // Function set
// Sets interface data length(DL)
// number of display lines (N)
// and character font (F).
// DL : 1=8 bits, 0=4 bits
// N : 1=2-lines, 0=1-line
// F : 5x10 dots, 0=5x8 dots
begin
sc1602_en <= 1;
sc1602_rs <= 0;
sc1602_rw <= 0;
sc1602_data <= 8'h38; // 1, DL=1, N=1, F=0, 0, 0
state <= WAIT;
next <= DSPOFF;
hold_time = 0;
end
DSPOFF: // Display on/off
// D: 1=Display on, 0=off, C: 1=Cursor on, 0=off, B: 1=Cursor blinking, 0=off
begin
sc1602_en <= 1;
sc1602_rs <= 0;
sc1602_rw <= 0;
sc1602_data <= 8'h08; // D=0,C=0,B=0
state <= WAIT;
next <= CLRDSP;
hold_time = 0;
end
CLRDSP: // Clear display / 1.52ms
// Clear entire display and sets DDRAM address 0 in address counter.
begin
sc1602_en <= 1;
sc1602_rs <= 0;
sc1602_rw <= 0;
sc1602_data <= 8'h01; // Clear Display
state <= WAIT;
next <= DSPON;
hold_time = 42;
end
DSPON: // Display on/off
begin
sc1602_en <= 1;
sc1602_rs <= 0;
sc1602_rw <= 0;
sc1602_data <= 8'h0C; // D=1, C=0, B=0
state <= WAIT;
next <= ENMODST;
hold_time = 0;
end
ENMODST: // Entry Mode
// Sets cursor move direction and specifies display shift.
// These operations are performed during data write and read.
// I/D : 1=Increment, 0=Decrement, S : 1=Accompanies display shift
begin
sc1602_en <= 1;
sc1602_rs <= 0;
sc1602_rw <= 0;
sc1602_data <= 8'h06; // 1, I/D=1, S=0
state <= WAIT;
next <= RETHOM;
hold_time = 0;
end
RETHOM: // Return Home / 1.52ms
// Set DDRAM address to "00H"
// from AC and return cursor to its
// original position if shifted. The
// contents of DDRAM are not changed.
begin
sc1602_en <= 1;
sc1602_rs <= 0;
sc1602_rw <= 0;
sc1602_data <= 8'h02;
state <= WAIT;
next <= REDCHR;
didx <= 0;
rfrsh_rate <= ~rfrsh_rate; // output refresh rate;
hold_time = 42;
end
DDRMADSET: // Set DDRAM address
// Sets DDRAM address. DDRAM data is sent and
// received after this setting.
begin
sc1602_en <= 1;
sc1602_rs <= 0;
sc1602_rw <= 0;
sc1602_data <= 8'h80 | didx;
state <= WAIT;
next <= REDCHR;
hold_time = 0;
end
REDCHR:
begin
addr <= didx;
rd <= 1;
state <= WRTCHR;
end
WRTCHR:
begin
sc1602_data <= data;
rd <= 0;
sc1602_rs <= 1;
sc1602_rw <= 0;
sc1602_en <= 1;
didx = didx + 1;
if (didx == 16)
begin
didx = 8'H40;
next <= DDRMADSET;
end
else if (didx > 8'H4F)
begin
didx = 8'H00;
next <= RETHOM;
end
else
next <= REDCHR;
state <= WAIT;
hold_time = 0;
end
endcase
end
end
endmodule