DE0の拡張キットにLCDがついていて、これ使えばいろいろ表示できるかなぽわわ〜んと気になっていたので、半田づけしてきた。
とはいえ、半田ごてとか持ってないし、そもそも半田づけするようなスペースの余裕はないので、今回も「博多図工室」で場所と道具を借りて作業した。
LCDを半田付けしてDE0の電源を入れると、回路を書き換えていなければ「Welcome to the Altera DE0 Board」と表示される。
ほんとなら、バックライトもつくはずなのだけど、もしかしたら半田づけに失敗したかもしれない・・・
ところで、LCDとはなんぞやという話だけど、見てのとおり液晶ディスプレイで、ここで取り付けたのはキャラクタ液晶なので、グラフィックは表示できないけどフォントを持っていて文字の出力が簡単にできる。
で、規格があるわけではないのだけど、だいたい同じコントローラICか互換品を使っているようなので、どの製品も同じように制御できるらしい。
そのあたりの説明はここが役に立った。
LCDモジュール SC162シリーズ
ただ、「文字の出力が簡単にできる」とはいえ、直接の制御はやっぱりめんどう。そのあたりの制御はここが役にたった。
2.3. キャラクタ液晶の利用
上のサイトや仕様書のコマンド発行手順には、コマンドを入れてしばらくたってENを立ち上げて、最後にアドレスを指定することになっているのだけど、今回は、一気にコマンドとアドレスを指定して同時にENも立ち上げてる。そして、一定時間たってENをおろす。それで動いた。DE0付属のサンプルもそのような処理になっていた。
ENを立ち上げてからおろすまでは、230nsということなので、12クロックほどウェイトを入れている。
if(cnt == 17'd0) begin param <= msgdata[26:25]; data <= msgdata[24:17]; en <= 1'b1; cnt <= cnt + 17'd1; end else if(cnt == 17'd12) begin en <= 1'b0; cnt <= 17'd0; phase <= `WAIT; end else begin cnt = cnt + 17'd1; end
msgdataには コマンドx2bit、アドレスx8bit、ウェイト時間x17bitというデータを入れてる。
はまったのが、起動時の挙動で、どうもうまくいかないと思ってボタンを押して起動するようにしたらうまくいった。DE0のCD-ROMに入ってるサンプルを見ると、20ビットのカウンタがいっぱいになるまでウェイトを入れてから起動処理をしているようだ。なので、同様の処理をいれてみたら、うまく動くようになった。
reg reset; reg [19:0] reset_delay; always @(posedge clk) begin if(reset_delay != 20'hfffff) begin reset_delay <= reset_delay + 20'd1; reset <= 1'b0; end else begin reset <= 1'b1; end end
あと、仕様書では画面クリアのあとの処理時間は1.53msで、50MHzのクロックだと1クロック20nsだから、76500クロックまてばいいはずなのだけど、2文字分表示されなかったので、2150クロック2文字分で4300クロック余分に待つようにしたら、ちゃんと一文字目から表示された。
1文字出力の処理時間は、仕様書どおり43μsで2150クロックのウェイトでいいようだ。
ということで、だいぶハードのスペックシートも読めるようになってきた。しかし、これを実際のアプリケーションで制御するのは、結構大変な気がする。
あと、このソースはDE0のサンプルが動いている前提なので、LCDの初期化を行っていないので注意。
`define COMM 3'd0 `define WAIT 3'd1 `define FIN 3'd2 module lcd( input clk, output lcd_rw, output lcd_rs, output lcd_en, output [7:0] lcd_data, output lcd_blon ); assign lcd_blon = 1'b1; reg [1:0] param; assign lcd_rs = param[1]; assign lcd_rw = param[0]; reg en; assign lcd_en = en; reg [7:0]data; assign lcd_data = data; reg [2:0] phase; reg [16:0] cnt; reg reset; reg [19:0] reset_delay; always @(posedge clk) begin if(reset_delay != 20'hfffff) begin reset_delay <= reset_delay + 20'd1; reset <= 1'b0; end else begin reset <= 1'b1; end end reg [26:0] msgdata; reg [3:0] msgindex; always @(posedge clk or negedge reset) begin if(!reset) begin cnt <= 17'd0; phase <= `COMM; msgindex <= 0; end else begin case(phase) `COMM:begin if(cnt == 17'd0) begin param <= msgdata[26:25];//2'b00; data <= msgdata[24:17];//8'h01; en <= 1'b1; cnt <= cnt + 17'd1; end else if(cnt == 17'd12) begin en <= 1'b0; cnt <= 17'd0; phase <= `WAIT; end else begin cnt = cnt + 17'd1; end end `WAIT:begin if(cnt == msgdata[16:0])begin if(msgindex == 4'h4)begin cnt = 17'd0; phase <= `FIN; end else begin cnt = 17'd0; phase <= `COMM; msgindex <= msgindex + 1; end end else begin cnt = cnt + 17'd1; end end default: begin end endcase end end always @(msgindex) begin case(msgindex) 4'h0: msgdata <= {2'b00, 8'h01, 17'd80800};//clear wait for 76500? 4'h1: msgdata <= {2'b10, 8'h40, 17'd2150};//'@' 4'h2: msgdata <= {2'b10, 8'h6b, 17'd2150};//'k' 4'h3: msgdata <= {2'b10, 8'h69, 17'd2150};//'i' 4'h4: msgdata <= {2'b10, 8'h73, 17'd2150};//'s' default: msgdata <= {2'b00, 8'h00, 17'd0}; endcase end endmodule