目次
前
次
SPI slave handler
マイクロコンピュータとCPLD/FPGAのインタフェースに
SPIを利用したいことがある。
SPIは、以下の4信号でデータ交換が可能。
- SCK
- MOSI(Master Out Slave In)
- MISO(Master In Slave Out)
- SS(Slave Select)
クロックを出力する側をマスター、入力する側を
スレーブと考えていけばよい。
CPLDに、DCモータ制御回路を2ブロック用意し
マイコンからDUTY比を渡すため、インタフェース
でSPIを利用してみる。
パラレルインタフェースでDUTY比を渡すと
10本以上のワイヤーが必要になり、ミスが
増えると考え、SPIを採用した。
SPIのインタフェースで、スレーブ利用するには
2つの方式がある。
タイミングチャートでみると、以下。
SPIのモード2、3がスレーブモードとなるが
シフトとラッチのどちらを先行させるかの違い
になる。
モード2では、falling_edgeで1ビットを記憶
モード3では、rising_edgeで1ビットを記憶。
今回は、モード3を採用した。
VHDLコードで記述すると、スレーブ側のシフト
レジスタは、次のようになる。
process (nRESET,SCK)
begin
if ( nRESET = '0' ) then
iMOSI_SFT <= X"00" ;
elsif rising_edge(SCK) then
if ( iSS = '1' ) then
iMOSI_SFT <= iMOSI_SFT(6 downto 0) & iMOSI ;
end if ;
end if ;
end process ;
SSは、マイコンがマスターになる場合
正論理、負論理のどちらもあるが負論理
で扱うことにする。
CPLD/FPGA内部では、正論理で動かすとして
SSを論理反転して扱う。
iSS <= not nSS ;
正論理で扱えば、iSSが'1'のときに
内部シフトレジスタにMOSIの信号を
入力していく。
内部シフトレジスタにデータが入った後
それを利用するためには、データ格納が
終了したことを捉え、後処理回路を起動
すればよい。
SS信号は、データ転送が終わるとL→Hと
変化するので、この変化を捉えて転送が
終わったことを、後処理回路に通知。
エッジを捉えるには、シフトレジスタを利用する。
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSS_SFT <= "000" ;
elsif rising_edge(CLOCK) then
iSS_SFT <= iSS_SFT(1 downto 0) & iSS ;
end if ;
end process ;
iSTRG <= '1' when ( iSS_SFT = "110" ) else '0' ;
iSTRGを後処理回路の動作開始トリガーに利用。
後処理回路は、シーケンサを利用し
与えられた情報を指定レジスタへと
転送すればよい。
シーケンサで、2チャネルのDCモータ制御
回路のレジスタにDUTY比率を転送。
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSTATE <= "00" ;
iREG <= X"00" ;
iLEFT <= "0000000" ;
iRIGHT <= "0000000" ;
elsif rising_edge(CLOCK) then
case conv_integer(iSTATE) is
-- wait trigger
when 0 => if ( iSTRG = '1' ) then
iSTATE <= "01" ;
iREG <= iMOSI_SFT ;
else
iSTATE <= "00" ;
end if ;
-- deliver
when 1 => iSTATE <= "11" ;
if ( iREG(7) = '1' ) then -- left register
iLEFT <= iREG(6 downto 0) ;
else
iRIGHT <= iREG(6 downto 0) ;
end if ;
-- clear register
when 3 => iSTATE <= "10" ;
iREG <= X"00" ;
-- return first state
when 2 => iSTATE <= "00" ;
-- default
when others =>
iSTATE <= "00" ;
end case ;
end if ;
end process ;
DUTY比は、0から99になるので、8ビットの
MSBをチャネル選択ビットとして利用。
チャネル数が多いときは、送信したデータを
分割してタグをつけ、1バイトにまとめる。
複数回の転送で、SPIスレーブに必要な情報を
与える方式を採用する。
DUTY比を制御回路に転送したなら、PWM波形
生成は、次のように簡単に構成する。
LPULSE <= '1' when ( iPCNT < iLEFTX ) else '0' ;
RPULSE <= '1' when ( iPCNT < iRIGHTX ) else '0' ;
process (nRESET,PCLK)
begin
if ( nRESET = '0' ) then
iPCNT <= 0 ;
iLEFTX <= 0 ;
iRIGHTX <= 0 ;
elsif rising_edge(PCLK) then
if ( iPCNT = 99 ) then
iPCNT <= 0 ;
iLEFTX <= conv_integer(iLEFT) ;
iRIGHTX <= conv_integer(iRIGHT) ;
else
iPCNT <= iPCNT + 1 ;
end if ;
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 tstspi 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 ;
MISO : out std_logic ;
-- register select
SEL : in std_logic ;
-- pulse clock
PCLK : in std_logic ; -- 10kHz
-- pulse out
LPULSE : out std_logic ;
RPULSE : out std_logic ;
-- register output
REGOUT : out std_logic_vector(6 downto 0) --;
);
end tstspi ;
architecture behavioral of tstspi is
-- BUS interface
signal iSS : std_logic ;
signal iMOSI : std_logic ;
-- synchronizer
signal iSS_SFT : std_logic_vector(2 downto 0) ;
signal iSTRG : std_logic ;
-- internal shift register
signal iMOSI_SFT : std_logic_vector(7 downto 0) ;
-- internal register
signal iREG : std_logic_vector(7 downto 0) ;
signal iLEFT : std_logic_vector(6 downto 0) ;
signal iRIGHT : std_logic_vector(6 downto 0) ;
-- sequencer
signal iSTATE : std_logic_vector(1 downto 0) ;
-- duty
signal iPCNT : integer range 0 to 99 ;
signal iLEFTX : integer range 0 to 99 ;
signal iRIGHTX : integer range 0 to 99 ;
begin
-- input
iSS <= not nSS ;
iMOSI <= MOSI ;
-- output
MISO <= iMOSI_SFT(7) ;
REGOUT <= iLEFT when ( SEL = '1' ) else iRIGHT ;
LPULSE <= '1' when ( iPCNT < iLEFTX ) else '0' ;
RPULSE <= '1' when ( iPCNT < iRIGHTX ) else '0' ;
-- synchronizer
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSS_SFT <= "000" ;
elsif rising_edge(CLOCK) then
iSS_SFT <= iSS_SFT(1 downto 0) & iSS ;
end if ;
end process ;
iSTRG <= '1' when ( iSS_SFT = "110" ) else '0' ;
-- internal register
process (nRESET,SCK)
begin
if ( nRESET = '0' ) then
iMOSI_SFT <= X"00" ;
elsif rising_edge(SCK) then
if ( iSS = '1' ) then
iMOSI_SFT <= iMOSI_SFT(6 downto 0) & iMOSI ;
end if ;
end if ;
end process ;
-- sequencer
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSTATE <= "00" ;
iREG <= X"00" ;
iLEFT <= "0000000" ;
iRIGHT <= "0000000" ;
elsif rising_edge(CLOCK) then
case conv_integer(iSTATE) is
-- wait trigger
when 0 => if ( iSTRG = '1' ) then
iSTATE <= "01" ;
iREG <= iMOSI_SFT ;
else
iSTATE <= "00" ;
end if ;
-- deliver
when 1 => iSTATE <= "11" ;
if ( iREG(7) = '1' ) then -- left register
iLEFT <= iREG(6 downto 0) ;
else
iRIGHT <= iREG(6 downto 0) ;
end if ;
-- clear register
when 3 => iSTATE <= "10" ;
iREG <= X"00" ;
-- return first state
when 2 => iSTATE <= "00" ;
-- default
when others =>
iSTATE <= "00" ;
end case ;
end if ;
end process ;
-- generate pulse
process (nRESET,PCLK)
begin
if ( nRESET = '0' ) then
iPCNT <= 0 ;
iLEFTX <= 0 ;
iRIGHTX <= 0 ;
elsif rising_edge(PCLK) then
if ( iPCNT = 99 ) then
iPCNT <= 0 ;
iLEFTX <= conv_integer(iLEFT) ;
iRIGHTX <= conv_integer(iRIGHT) ;
else
iPCNT <= iPCNT + 1 ;
end if ;
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 "MISO" LOC = "P3" ;
NET "SCK" LOC = "P6" ;
NET "PCLK" LOC = "P7" ;
# 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 "SEL" LOC = "P22" ;
# pulse output
NET "LPULSE" LOC = "P44" ;
NET "RPULSE" LOC = "P43" ;
動作確認したボードは、XC9572を利用。
SPIのマスターになるマイクロコンピュータは
次の仕様でSPIインタフェースを指定。
- マスターモードになる
- SCKのピンアサインは、出力設定
- MOSIのピンアサインは、出力設定
- MISOのピンアサインは、入力設定
- SSのピンアサインは、出力設定かつ負論理で利用
AVR、PICの内蔵モジュールを利用する場合
上の仕様をレジスタに設定する。
SPIのスレーブでD/Aコンバータを使うため
このハンドラをテストした。下の基板にて
実装するD/Aコンバータの動作テストとなった。
目次
前
次