2010年03月04日

CPLD の回路設計

(前の記事:2.8インチ液晶 EGO028Q02から分岐)

ようやく CPLD で作りたいものが決まった。なにかというと SPI to パラレル変換器。単純なものは シフトレジスタ + αで作れるわけだが、多少機能を付ける。

機能は、制御バイト + データ のプロトコル のサポート。

データを送る前に 制御バイトを送る。こうすることで SPI だけで制御できるようになり XMEGA だと DMA が使えるようになる。AVR の SPI でも パラレル出力 並の性能にできる。

制御バイトを使うやり方は、i2c液晶の設計で参考にした ST7032i のものをベースに拡張する。

制御バイトの定義:

    bit7 CONT 0: CS=L の間は 次からデータのみ。(制御バイト固定)
    bit6 RS RS ピンに出力 ( LCD では 1: DATA 0: CMD )
    :
    bit2 RD 1: READ 0: WRITE

    補足:

    RD のビットが離れているのは、RD を受け取った時点で処理するため。機能拡張する場合 bit5 - bit3 で定義して 状態を確定させておかないといけない。
    また、制御バイトが来たとき 1 回 READ するだけなので、CONT=0 は READ には使えない。


さてこういうものを作りたいわけだが、まず前提として

ということにする。

まずは、外部仕様の定義:

    SCK : in STD_LOGIC;
    MOSI : in STD_LOGIC;
    MISO : out STD_LOGIC;
    CS : in STD_LOGIC;
    RS : out STD_LOGIC;
    WR : out STD_LOGIC;
    RD : out STD_LOGIC;
    DB : inout STD_LOGIC_VECTOR (7 downto 0) bus

8080 インターフェイスと SPI だから 基本的な説明はしない。ここでは制御の仕方のポイントだけ。

  • DB は、tri-state で、CS=H のとき 無条件に Z にする。出力は、WRITE するときのみ。
  • CS は L で active 。H にする毎に初期状態にする。
  • READ の場合、前のバイトで RD を↓ にしておいて、読み込みを指示する。最後に読み込んで RD ↑ 。
  • 使おうとしている LCD は、WR のパルス幅 50ns 以上。RD のパルス幅 150 ns 以上。という条件がある。SPI のクロックを 16MHz にした場合これをクリアするには、WR 1 クロック、RD 3 クロックのパルスにする必要がある。

次に内部状態の定義:

    signal spireg : std_logic_vector(7 downto 0) := "00000000";
    signal rdreg : std_logic_vector(7 downto 0) := "00000000";
    signal spicnt : std_logic_vector(2 downto 0) := "000";
    signal sWR : std_logic := '1'; -- WRITE 指示、負論理
    signal sOE : std_logic := '1'; -- 出力 指示、負論理
    signal sRD : std_logic := '1'; -- READ 指示、負論理
    signal sRS : std_logic := '1'; -- RS のラッチ
    signal sCB : std_logic := '1'; -- 制御バイトかどうか
    signal sCONT : std_logic; -- CONT のラッチ

READ 用 レジスタを分けている。うまくすれば不要だと思えるが、とりあえず。spireg は、SPI からの 入力専用。spicnt は、何 bit 目かを数えるカウンタ。

スタティックな制御

    WR <= sWR;
    RD <= sRD;
    RS <= sRS;
    DB <= spireg when (sOE = '0') else "ZZZZZZZZ";
    MISO <= rdreg(7);

基本的に内部状態がそのまま外に出ている。DB は tri-state なので、上記のように記述。

次は、同期動作。process (CS, SCK)

まず CS が H になったときの動作から

    sWR <= '1';
    sOE <= '1';
    sRD <= '1';
    sRS <= '1';
    sCB <= '1';
    spicnt <= "000";
    spireg <= "00000000";
    rdreg <= "00000000";

-- 初期状態にしているだけ。sOE が 1 になるので、DB も Z になる。

次に SCK が H になったとき(↑)

    -- シフト動作
    spireg(7 downto 1) <= spireg(6 downto 0);
    spireg(0) <= MOSI;

    -- RS の 受け取り (= 出力変更)
    if ((spicnt = 1) and (sCB = '1')) then
    sRS <= MOSI;
    end if;
    -- RD の制御
    if ((spicnt = 5) and (sCB = '1')) then
    sRD <= not MOSI;
    end if;
    if (spicnt = 0) then
    sRD <= '1';
    end if;
    -- CB と CONT の制御
    if (spicnt = 7) then
    if (sCB = '1') then
    sCB <= '0';
    sCONT <= spireg(6);
    else
    sCB <= sCONT;
    end if;
    end if;
    -- sOE の 制御
    if ((spicnt = 7) and (sRD = '1') and (sCB = '0')) then
    sOE <= '0';
    else
    sOE <= '1';
    end if;

    補足:
  • RS の 受け取り (= 出力変更)

    RD を変化させる前に 変化させておく必要があるので、データが来たらすぐに変化させる。

  • RD の制御

    データの読み込みをしておいて、次の バイトで送り出したいので、データが来たらすぐに変化(↓)させる。↑ するタイミングは、次の バイトに入ったとき。

    RD のパルス幅は 3 クロック。例えば ↓を 1 クロック遅らせるには、(spicnt = 6) のとき、 入力を spireg(0) にして処理する。

  • CB と CONT の制御

    最後のデータが来たとき、次の制御を決める。sCB = 1 なら、次は sCB = 0 でデータ処理。sCB = 0 で データ処理が終わったなら、次は、sCONT で決める。sCONT = 0 なら次もデータ処理。

  • sOE の 制御

    最後のデータが来たら、RD でも CB でもなければ、DBに出力するために、sOE = 0 にする。


最後、SCK が L になったとき(↓)

    -- カウンタ ++
    spicnt <= spicnt + 1;
    -- rdreg の ロード/シフト動作
    if (spicnt = 7) and (sCB = '0') and (sRD = '0') then
    rdreg <= DB;
    else
    rdreg(7 downto 1) <= rdreg(6 downto 0);
    rdreg(0) <= '0';
    end if;
    -- sWR の 制御
    if ((spicnt = 6) and (sRD = '1') and (sCB = '0')) then
    sWR <= '0';
    else
    sWR <= '1';
    end if;

    補足:
  • sWR の 制御

    最後のデータの1つ前で、RD でも CB でもなければ、WR のパルスを出すために、sWR = 0 にする。

    WR の↑で データが採取される。L にする 期間は 1 クロック。↑のあと 半クロックデータを保持する必要がある。(15ns 以上)

以上は、とりあえず書いてみただけのもの。合成できたものを ベースにしているが、バグっているかも。思った通りに動作するのかどうかの検証はこれから。

タイミングの検証


    CS ~|________________________________________...._|~
    _ _ _ _ _ _ _ _ _
    SCK ___| |_| |_| |_| |_| |_| |_| |_| |_| |_
    : :
    MOSI |MSB| D6| D5| D4| D3| D2| D1| D0|
    spireg S S S S S S S S S (S: SHIFT)
    : : :
    spicnt 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0
    rdreg S S S S S S S L (L: LOAD)
    MISO MSB| D6| D5| D4| D3| D2| D1| D0| MSB
    : : : :
    (WRITE) : : : :
    ________________________________ _____
    sOE : : |___|
    _____________________________ _____
    WR : : |___|
    : :
    DB[7..0] ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ| |ZZZZZ
    : : spireg
    (READ) : : :
    ________________________ _____
    RD : |___________|

    DB[7..0] ZZZZZZZZZZZZZZZZZZZZZZZ| READ DATA |ZZZZZ
    :
    _______ ________________________
    RS _______X________________________



バグを直したらこのページも直しておく予定。

ソースコードは、spi2par.vhd だが、これも直したら ファイル名そのままで 更新する予定。

あと、ピンアサイン spi2par.ucf

    ピン19 〜 38 の bank 2 メインで割り当ててみた。順番は LCD の ピン 1 からの順番。ただし、DB[765] は離れているので間に SPI の信号を割り込ませている。あと、CS は、GCR で SCK は GCK から選んでいる。

    あと、変更した設定は、I/O Voltage Standard を LVCMOS33 に。(→ 参考)


結果:

************************* Mapped Resource Summary **************************

Macrocells Product Terms Function Block Registers Pins
Used/Tot Used/Tot Inps Used/Tot Used/Tot Used/Tot
26 /32 ( 81%) 38 /112 ( 34%) 37 /80 ( 46%) 25 /32 ( 78%) 15 /33 ( 45%)
posted by すz at 19:09| Comment(0) | TrackBack(0) | CPLD
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス: [必須入力]

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/35979935
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック