目次

DAC emulator

 SPIインタフェースを利用したD/Aコンバータを
 入手する前に、マイクロコンピュータとの接続
 をテストするために、エミュレータを考えた。

 利用するDACは、Microchip Technologyのデバイス
 で、次のインタフェースを持つ。



 SPIのインタフェースと異なる点は、以下。

 他は、通常のSPIスレーブモード3と同じ。

 16ビットのデータ転送は、シフトレジスタに
 16ビットを用意しnSSの状態で、ビットデータ
 を保存する。


  process (nRESET,SCK)
  begin
    if ( nRESET = '0' ) then
      iMOSI_SFT <= X"0000" ;
    elsif rising_edge(SCK) then
      if ( iSS = '1' ) then
        iMOSI_SFT <= iMOSI_SFT(14 downto 0) & iMOSI ;
      end if ;
    end if ;
  end process ;


 CPLD/FPGA内部では、正論理で動かすとして
 SSを論理反転して扱う。

iSS <= not nSS ;

 正論理で扱えば、iSSが'1'のときに
 内部シフトレジスタにMOSIの信号を
 入力していく。




 内部シフトレジスタにデータが入った後
 制御コードとデータに分割してCPLD外部
 に出力する。

 nLOAD信号は、データ転送が終わるとH→L→Hと
 変化させて、出力に反映させる。変化を捉えて
 転送終了を、後処理回路に通知する。



 エッジを捉えるには、シフトレジスタを利用する。

  iLOAD <= not nLOAD ;

  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iLOAD_SFT <= "000" ;
    elsif rising_edge(CLOCK) then
      iLOAD_SFT <= iLOAD_SFT(1 downto 0) & iLOAD ;
    end if ;
  end process ;
  iSTRG <= '1' when ( iLOAD_SFT = "110" ) else '0' ;

 iSTRGを後処理回路の動作開始トリガーに利用。

  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iSTATE <= "00" ;
      iREG   <= (others => '0') ;
    elsif rising_edge(CLOCK) then
      case conv_integer(iSTATE) is
        -- wait trigger
        when 0 => if ( iSTRG = '1' ) then
                    iSTATE <= "01" ;
                  else
                    iSTATE <= "00" ;
                  end if ;
        -- copy
        when 1 => iSTATE <= "11" ;
                  iREG   <= iMOSI_SFT ;
        -- clear register
        when 3 => iSTATE <= "10" ;
                  iREG   <= (others => '0') ;
        -- return first state
        when 2 => iSTATE <= "00" ;
        -- default
        when others => 
                  iSTATE <= "00" ;
      end case ;
    end if ;
  end process ;

 まとめると以下。

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

entity dacemu is
  port (
    -- system
    nRESET : in  std_logic ;
    CLOCK  : in  std_logic ; -- 4MHz
    -- SPI
    SCK    : in  std_logic ;
    nSS    : in  std_logic ;
    MOSI   : in  std_logic ;
    nLOAD  : in  std_logic ;
    -- control code outpu
    CDOUT  : out std_logic_vector(3 downto 0) ;
    -- register output
    REGOUT : out std_logic_vector(11 downto 0) --;
  );
end dacemu ;

architecture behavioral of dacemu is
  -- BUS interface
  signal iSS   : std_logic ;
  signal iMOSI : std_logic ;
  signal iLOAD : std_logic ;
  -- synchronizer
  signal iLOAD_SFT : std_logic_vector(2 downto 0) ;
  signal iSTRG     : std_logic ;
  -- internal shift register
  signal iMOSI_SFT : std_logic_vector(15 downto 0) ;
  -- internal register
  signal iREG : std_logic_vector(15 downto 0) ;
  -- sequencer
  signal iSTATE  : std_logic_vector(1 downto 0) ;
begin
  -- input
  iSS   <= not nSS ;
  iMOSI <= MOSI ;
  iLOAD <= not nLOAD ;

  -- output
  CDOUT  <= iREG(15 downto 12) ;
  REGOUT <= iREG(11 downto 0) ;

  -- synchronizer
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iLOAD_SFT <= "000" ;
    elsif rising_edge(CLOCK) then
      iLOAD_SFT <= iLOAD_SFT(1 downto 0) & iLOAD ;
    end if ;
  end process ;
  iSTRG <= '1' when ( iLOAD_SFT = "110" ) else '0' ;

  -- internal register
  process (nRESET,SCK)
  begin
    if ( nRESET = '0' ) then
      iMOSI_SFT <= X"0000" ;
    elsif rising_edge(SCK) then
      if ( iSS = '1' ) then
        iMOSI_SFT <= iMOSI_SFT(14 downto 0) & iMOSI ;
      end if ;
    end if ;
  end process ;

  -- sequencer
  process (nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iSTATE <= "00" ;
      iREG   <= (others => '0') ;
    elsif rising_edge(CLOCK) then
      case conv_integer(iSTATE) is
        -- wait trigger
        when 0 => if ( iSTRG = '1' ) then
                    iSTATE <= "01" ;
                  else
                    iSTATE <= "00" ;
                  end if ;
        -- copy
        when 1 => iSTATE <= "11" ;
                  iREG   <= iMOSI_SFT ;
        -- clear register
        when 3 => iSTATE <= "10" ;
                  iREG   <= (others => '0') ;
        -- return first state
        when 2 => iSTATE <= "00" ;
        -- default
        when others => 
                  iSTATE <= "00" ;
      end case ;
    end if ;
  end process ;

end behavioral;

 DUTY比を格納したレジスタの値を確認できる
 ように、6ビットの出力を用意。左右を指定
 するためのセレクタビットを入れてある。

 ピンアサインは、以下。

# system
NET "CLOCK"  LOC = "P5"  ;
NET "nRESET" LOC = "P39" ;

# SPI interface
NET "nSS"   LOC = "P1" ;
NET "MOSI"  LOC = "P2" ;
NET "nLOAD" LOC = "P3" ;
NET "SCK"   LOC = "P6" ;

# register output
NET "REGOUT<0>"  LOC = "P11" ;
NET "REGOUT<1>"  LOC = "P12" ;
NET "REGOUT<2>"  LOC = "P13" ;
NET "REGOUT<3>"  LOC = "P14" ;
NET "REGOUT<4>"  LOC = "P18" ;
NET "REGOUT<5>"  LOC = "P19" ;
NET "REGOUT<6>"  LOC = "P20" ;
NET "REGOUT<7>"  LOC = "P22" ;
NET "REGOUT<8>"  LOC = "P24" ;
NET "REGOUT<9>"  LOC = "P25" ;
NET "REGOUT<10>" LOC = "P26" ;
NET "REGOUT<11>" LOC = "P27" ;

# code output
NET "CDOUT<0>" LOC = "P28" ;
NET "CDOUT<1>" LOC = "P29" ;
NET "CDOUT<2>" LOC = "P33" ;
NET "CDOUT<3>" LOC = "P34" ;

 ターゲットにしたDACは、MCP4922。



目次

inserted by FC2 system