エルシー:「ところで、あえて聞いてみるけど、あなたはこの液晶モジュールを動かすにはどうしたらいいと思う?」
僕:「うーん、データを1個送るごとにXSCLにパルスを入れて、1ライン毎にLP、1画面毎にYDにパルスを入れればよさそうだな、ってのはなんとなくわかるんだけど、具体的にどうしたらいいのかよくわかんないんだよ。さらにCPUやRAMも付けなきゃいけないと思うと、もうこんがらがっちゃって。」
エルシー:「最初はCPLDだけ使って動かしてみましょ。はじめからRAMやCPUまで考えると話がややこしくなるから。」
僕:「うーん。でもCPLDにクロックは必要だよね。CPUボードはあったほうがCPUのクロックが使えていいんじゃない?」
エルシー:「それだと、CPUのクロックが変わるとまたCPLDの設計をやり直しね。やっぱり自前のクロックを持ったほうがいいと思うの。あらっ! こんなところに16MHzのクロックモジュールが転がってるわ。これ使いましょ。」
僕:「な、なんかわざとらしい展開だけど、まぁいいや。じゃそれ使おう。」
エルシー:「で、XSCLはどのくらいの周波数にしたらいいと思う?」
僕:「えーっと、マニュアルで規定されてるのはLPの周期だけだよね。こっからどうやってXSCLの周波数を決めればいいんだろう?」
エルシー:「この液晶は1ライン640ドットよね。データ線は8本だから、1ラインあたりのXSCLの個数は決まるでしょ。そこから求められるわ。」
僕:「640÷8=80個か。LP周期が50μだとするとXSCLの周期は約625ナノ秒、120μ秒だとすると約1500ナノ秒だね。周波数はその逆数だから、0.66MHzから1.6MHzってことか。」
エルシー:「そう。せっかくだから、切りのいい1MHzにしましょ。」
僕:「うん。じゃあ、もとのクロックを16分周すればXSCLになるんだね。」
エルシー:「う〜ん、16分周はいいんだけど、ただ単純に16分周すればいいわけじゃないのよ。」
僕:「どうして?」
エルシー:「タイムチャートをよく見て。LPが出ているときはXSCLは出てないでしょ。」
僕:「そうか。でも、XSCLは80回出さなきゃいけないんだよね? その他にもLPを出すとなると・・・」
エルシー:「1ラインのクロックは80個と考えるより、XSCL80個とLP1個、合計81個と考えたほうが良さそうね。」
僕:「まず元のクロックを16で割って、それをさらに81で割ったのが1ライン分の周波数ってことだね。」
エルシー:「そして縦方向は200ラインあるから、結局液晶の基本タイミングを作るカウンタは前段、X位置、Y位置、の3つが必要ね。前段カウンタをdiv、X位置をx、Y位置をyって信号名にしてカウンタ部分のVHDL書いてみて。」
僕:「信号の定義がこうで」
signal div : std_logic_vector(3 downto 0);
signal x : std_logic_vector(6 downto 0);
signal y : std_logic_vector(7 downto 0);
|
僕:「カウンタの記述はこうかな?」
process(clk)
begin
if(clk'event and clk='1') then
if(div="1111") then -- divは16分周して1マイクロ秒をつくる
if(x="1010000") then -- 1ライン81μ秒
if(y="11000111") then -- yが199なら
y <= "00000000"; -- 0にする
else -- そうでなければ
y <= y + 1; -- yに1を足す
end if;
x <= "0000000"; -- xが80ならxを0にする
else -- そうでなければ
x <= x + 1; -- xに1を足す
end if;
end if;
div <= div + 1;
end if;
end process;
|
エルシー:「そうね。じゃ今度はXSCL、LP、YDを出してみましょ。」
僕:「LPってデータ80個送った後に出すの?」
エルシー:「タイムチャート見るとそう考えてもよさそうね。ついでにYDは最初のラインのLPを出すときに出せばいいみたい。」
僕:「するってぇと、こんな感じかな?」
process(clk)
begin
if(clk'event and clk='1') then
if(div="0111") then -- divが8〜15のとき
if(x="1010000") then -- xが80ならLPを1にする
lp <= '1';
else -- それ以外ならXSCLを1にする
xscl <= '1';
end if;
elsif(div="1111") then -- divが0〜7のとき
xscl <= '0'; -- XSCLもLPも0にする
lp <= '0';
end if;
end if;
end process;
process(clk)
begin
if(clk'event and clk='1') then
if((x="1010000")and(y="00000000")) then -- xが80でyが0のとき
if(div="0000") then -- divが1〜15の間
yd <='1'; -- YDを1にする
elsif(div="1111") then
yd <='0';
end if;
end if;
end if;
end process;
|
エルシー:「ちょっと待って。LPとYDが同時に0に落ちてるわね。データシートよく見て。LPの立下りに対してYDのホールドタイムが必要なはずよ。」
僕:「YDを引き伸ばせばいいのかな?」
エルシー:「それよりXSCLとLPを前にずらしたほうがいいわ。混乱するから今は説明しないけど、あとでRAMやCPUをつなぐことを考えるとその方がいいの。」
僕:「ふーん、そうなのか。タイムチャート見ると、LPはYDの真ん中あたりにきているね。それを真似すればいいのかな。というわけで、LPとXSCLのタイミングを直してみたよ。」
process(clk)
begin
if(clk'event and clk='1') then
if(div="0011") then -- divが4〜11のとき
if(x="1010000") then -- xが80ならLPを1にする
lp <= '1';
else
xscl <= '1'; -- それ以外ならXSCLを1にする
end if;
elsif(div="1011") then -- divが0〜3、12〜15のとき
xscl <= '0'; -- XSCLもLPも0にする
lp <= '0';
end if;
end if;
end process;
|
エルシー:「そうそう。じゃ、今度はデータを出して、パターンを表示しましょ。8×8ドットのパターンなら、yの下位3ビットをデコードしてXDに適当なデータを出せばいいから簡単ね。」