解説

戻る



・液晶モジュールG2436について

 データシートはセイコーインスツルメントのホームページからダウンロードできます。

 このモジュールは5V単一電源で動くので楽です。端子の機能を簡単に説明すると、

D0〜D3

データ入力です。

FRM

フレーム開始信号です。厳密にイコールではありませんがテレビの垂直同期に該当します。

M

交流化信号です。フレームごとに0、1を反転させます。

CL1

ラインクロックです。厳密にイコールではありませんがテレビの水平同期に該当します。

CL2

データクロックです。周期は4ドット時間ぶんです。

Vdd,Vss

電源


※ CL1、CL2は、CPLD側の信号名は CP1、CP2になっています。白状すると、セイコーインスツルメンツからデータシートを入手するまでは、私はこのモジュールは日立のLM258Xと同じものと思いこんでおり、そのつもりでVHDL書いてました。

・リフレッシュコントローラ(CPLDの中身)

 よく使われているキャラクタ液晶モジュールには「液晶ドライバ」「RAMとリフレッシュコントローラ」が内蔵されており、簡単に使うことができるのですが、グラフィック液晶モジュールはほとんどの場合液晶ドライバしか内蔵されていないので(今回のG2436もそうです)リフレッシュコントローラを自作し、RAMを外付けしなければいけません。

・最初に考えたこと

 必要なRAM容量は約2Kバイト(240/8*64=1920)。H8/3052なら内蔵RAMは8Kバイトあるからそのうちの2KをLCD用RAMに割いてもなんとかなりそう。リフレッシュコントローラはタイミング発生だけにして、データはH8内蔵DMAコントローラで送ればよいのではないか?と考えました。
 しかし、液晶モジュールにはテレビで言うところの「ブランク期間」が存在せず、1フレーム表示した直後、切れ目なくすぐ次のフレームのデータを送らなければいけません。H8のDMAコントローラは、送るデータ量が256バイト以下なら「リピートモード」が使えるのですが、今回は1920バイトなので無理です。結局割り込みで定期的にDMAコントローラを再起動するしかないわけですが、時間的にかなり厳しいです。

 割り込み禁止にすると画面が出なくなるシステム、ってのも情けないので、H8内蔵のRAMは使わずにRAMを外付けし、リフレッシュコントローラにRAMのバス制御も含めることにしました。

・次に考えたこと

 RAMは2Kバイトあればよいのですが、いまどき6116なんて少容量のRAMのほうが入手は大変です。また、グラフィックを使うようなアプリケーションはデータもたくさん使うだろうからデータ用のRAMもあったほうがよいでしょう。しかし、データ用と液晶用に2つもRAMを積むのは大変なので1つで兼ねる事にしました。思いきって628512を積み、最初の2Kバイトだけ液晶用にし、残りは全てデータ用です。
 液晶用とデータ用が兼用なので、データ用RAM領域にもウエイトがかかってしまいます。しかし、176クロックに8クロックの割合でウエイトがはいるだけなので、そのデメリットはRAMを2つ積んで回路が複雑化するデメリットよりはるかに小さいと思いました。

 RAMはH8のエリア1(h’200000〜)に配置しました。ちなみに、回路を簡単にするため1ラインを32バイトとし(本来は30バイトあればいい)、末尾2バイトは表示されないようにしました。

・概要

 大体以下のようなブロックに分かれます。(カッコ内は主なVHDLの信号名)

・VHDLソース

 さっきも書いたように、日立のLM258Xを引きずっているので見づらいソースです。たとえば b:std_logic という信号名がありますが、最初はこれは b:std_logic_vector(2 downto 0) でした。LM258Xは1ビットづつシリアルで送るので、この変数はビット位置を表していました。G2436では4ビットづつ送るので、この変数は前半4ビットか、後半4ビットかを表す1ビットの変数になりました。

i で始まる信号名は Inner の意味で、 i の付いていない外部信号名に対応します。どうしてVHDLって外に出す信号名を内部で参照しちゃいけないんだろう。

 カウンタ div はCPUクロックの25MHzを44分周してデータクロック CP2 を作ります。1バイト=4ビット×2なので、b は CP2 のさらに半分の周波数です。

 b='1'のときの icp2 の立ちあがりでRAMからデータを q にとりこみ(ibsel='1',ma=アドレスカウンタ)、同時にアドレスカウンタをインクリメントします。またその前後の時間、CPUがRAMをアクセスしないようウエイトをかけます(iwait='1)。

 ma17 が ca17 の反転なのは、RAMに628128も使えるようにするためです。628512のA17は628128ではCS(アクティブH)なので、そのままではCPUがh’200000番地をアクセスしたときCS=Lとなり、アクセスできないからです。
-- G2436 Controller (c)2003 A.Hiramatsu

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity lcd4 is
    Port ( clk : in std_logic;
           ca : in std_logic_vector(18 downto 0);
           cd : inout std_logic_vector(7 downto 0);
           crd : in std_logic;
           cwr : in std_logic;
           ccs : in std_logic;
           cwait : out std_logic;
           ma : out std_logic_vector(18 downto 0);
           md : inout std_logic_vector(7 downto 0);
           mrd : out std_logic;
           mwr : out std_logic;
           cp1 : out std_logic;
           cp2 : out std_logic;
           do : out std_logic_vector(3 downto 0);
           frm : out std_logic;
           m : out std_logic);
end lcd4;

architecture behavioral of lcd4 is

signal div:std_logic_vector(5 downto 0);
signal icp1,icp2:std_logic;
signal b:std_logic;
signal x:std_logic_vector(4 downto 0);
signal y:std_logic_vector(5 downto 0);
signal q:std_logic_vector(7 downto 0);
signal iwait:std_logic;
signal ibsel:std_logic;
signal ima:std_logic_vector(18 downto 0);
signal ifrm:std_logic;
signal im:std_logic;
signal iadr:std_logic_vector(10 downto 0);

begin

  process(clk)
  begin
    if(clk'event and clk='1') then
      if(div="101011") then
        if(icp2='0') then
          icp1 <= '0';
          if(b='1') then
            q <= md;
            if(x="11101") then
              y <= y+1;
              x <= "00000";
            else
              x <= x+1;
            end if;
          else
            q(7 downto 4) <= q(3 downto 0);
          end if;
          b <= not b;
        else
          if(b='1' and x="00000") then
            icp1 <= '1';
          end if;
        end if;
        icp2 <= not icp2;
        div <= "000000";
      else
        div <= div+1;
      end if;
    end if;
  end process;

  cp1 <= icp1;
  cp2 <= icp2;
  do(3 downto 0) <= q(7 downto 4);
  iadr <= y & x;

  process(clk)
  begin
    if(clk'event and clk='1') then
      if(b='1' and icp2='0') then
        if(div="101001") then
          ibsel <= '1';
        elsif(div="101011") then
            ibsel <= '0';
        end if;
        if(div="100110") then
          iwait <= '1';
        end if;
      elsif(b='0' and icp2='1' and div="000000") then
        iwait <= '0';
      end if;
    end if;
  end process;

  process(crd,ccs,md)
  begin
    if(crd='1' or ccs='1') then cd <= "ZZZZZZZZ";
    else                        cd <= md;
    end if;
  end process;

  process(crd,ccs,ibsel,cd)
  begin
    if((crd='0' and ccs='0') or ibsel='1') then md <= "ZZZZZZZZ";
     else                                       md <= cd;
    end if;
  end process;

  process(ibsel,iadr,ca)
  begin
    if(ibsel='1') then
      ima <= "01000000" & iadr;
    else
      ima(18) <= ca(18);
      ima(17) <= not ca(17);
      ima(16 downto 0) <= ca(16 downto 0);
    end if;
  end process;

  cwait <= not( not ccs and iwait);
  ma <= ima;
  mrd <= not(ibsel or (not crd and not ccs));
  mwr <= not(not ibsel and not cwr and not ccs);

  process(clk)
  begin
    if(clk'event and clk='1') then
      if(iadr="00000000001" and b='0' and div="101011") then
        ifrm <= '1';
      else
        if(iadr="00000100001" and b='0' and div="101011") then
          ifrm <= '0';
        end if;
       end if;
    end if;
  end process;

  process(ifrm)
  begin
    if(ifrm'event and ifrm='0') then
      im <= not im;
    end if;
  end process;

  frm <= ifrm;
  m <= im;

end behavioral;