アナログマルチプレクサテスト
CMOSの4051は、アナログマルチプレクサとして有名です。
パラレルデータをシーケンシャルデータに変換して
4ビットで、8ビットのデータを転送する用途での
利用を考えました。
半田付けした4051の基板は、以下。
回路図は、次のように単純です。
この基板をアダプタとして、路面センサーの8ビット
データをピン数の少ないワンチップマイコンで扱える
ようにしました。
基板の動作テストに、CPLDのXC9572を利用。
8ビットのDIPスイッチの情報を取得し、LEDアレイに
反映させることで、動作をチェックします。
テストは次のブロックで考えてみました。
CPLDは、外部トリガーを与えられると4051を動かして
シーケンシャルにデータを取得し、LEDに反映させます。
シーケンシャル処理をしたいので、トリガーを与えられたなら
一気に8ビットデータを取得することを考えました。
必要なブロックを定義していきます。
シンクロナイザ
シンクロナイザで、外部から与えられるトリガーを検出して
シーケンサが動くキッカケを生成。
シフトレジスタを利用して、立ち上がりエッジを捉えます。
VHDLコードにすると、以下。
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSFT <= "000" ;
elsif rising_edge(CLOCK) then
iSFT <= iSFT(1 downto 0) & XGTRG ;
end if ;
end process ;
iTRG <= '1' when ( iSFT = "011" ) else '0' ;
シーケンサ
トリガーを与えられたなら、4051のマルチプレクスで
使う(C、B、A)の3信号を出力し、1ビット情報
をレジスタに格納します。
トリガーを検出したなら、マルチプレクス信号出力と
データラッチの指令を出すだけに処理を限定します。
8ビットの情報を記憶すればよいので、シフトレジスタ
に対する指令を出すようにコードを組みます。
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSEQ <= 0 ;
elsif rising_edge(CLOCK) then
case iSEQ is
-- wait trigger
when 0 => if ( iTRG = '1' ) then
iSEQ <= 1 ;
else
iSEQ <= 0 ;
end if ;
-- send address <7>
when 1 => iSEQ <= 2 ;
-- latch data
when 2 => iSEQ <= 3 ;
-- send address <6>
when 3 => iSEQ <= 4 ;
-- latch data
when 4 => iSEQ <= 5 ;
-- send address <5>
when 5 => iSEQ <= 6 ;
-- latch data
when 6 => iSEQ <= 7 ;
-- send address <4>
when 7 => iSEQ <= 8 ;
-- latch data
when 8 => iSEQ <= 9 ;
-- send address <3>
when 9 => iSEQ <= 10 ;
-- latch data
when 10 => iSEQ <= 11 ;
-- send address <2>
when 11 => iSEQ <= 12 ;
-- latch data
when 12 => iSEQ <= 13 ;
-- send address <1>
when 13 => iSEQ <= 14 ;
-- latch data
when 14 => iSEQ <= 15 ;
-- send address <0>
when 15 => iSEQ <= 16 ;
-- latch data
when 16 => iSEQ <= 17 ;
-- copy
when 17 => iSEQ <= 18 ;
-- return first state
when 18 => iSEQ <= 0 ;
-- default
when others => iSEQ <= 0 ;
end case ;
end if ;
end process ;
4051に(C、B、A)の3信号を出力する処理と
シフトレジスタの処理は別途定義します。
4051制御信号生成
4051の3信号は、シーケンサの状態値を利用して
印加できるようにすれば充分と判断。
VHDLコードは、以下。
iAOUT <= "111" when ( iSEQ = 1 or iSEQ = 2 ) else
"110" when ( iSEQ = 3 or iSEQ = 4 ) else
"101" when ( iSEQ = 5 or iSEQ = 6 ) else
"100" when ( iSEQ = 7 or iSEQ = 8 ) else
"011" when ( iSEQ = 9 or iSEQ = 10 ) else
"010" when ( iSEQ = 11 or iSEQ = 12 ) else
"001" when ( iSEQ = 13 or iSEQ = 14 ) else
"000" ;
論理圧縮は、開発環境に任せてしまいます。
4051データ入力
4051からは、マルチプレクスの信号に合わせて1ビット
情報が出力されてくるので、シーケンサの状態値で記憶
します。
シフトレジスタは、次のように定義。
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSREG <= "00000000" ;
elsif rising_edge(CLOCK) then
if ( iEna = '1' ) then
iSREG <= iSREG(6 downto 0) & iDin ;
end if ;
end if ;
end process ;
シフトレジスタで、データを記憶するタイミングは
状態値で指定するので、デコーダの出力をトリガー
に利用。
iEna <= '1' when ( iSEQ = 2 ) else
'1' when ( iSEQ = 4 ) else
'1' when ( iSEQ = 6 ) else
'1' when ( iSEQ = 8 ) else
'1' when ( iSEQ = 10 ) else
'1' when ( iSEQ = 12 ) else
'1' when ( iSEQ = 14 ) else
'1' when ( iSEQ = 16 ) else
'0' ;
シーケンサの中でシフトレジスタに記憶するよりも
見通しがよくなるので、デコーダを使っています。
出力レジスタ
シーケンサが取得した情報は、あるタイミングで別の
レジスタに転送して、LEDでの目視がしやすいように
します。ちらつきを防ぐために、シフトレジスタとは
異なるレジスタを使います。
シーケンサの状態値を使えば、シフトレジスタから
レジスタへの転送タイミングがわかるので、以下と
します。
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iREG <= "00000000" ;
elsif rising_edge(CLOCK) then
if ( iSEQ = 17 ) then
iREG <= iSREG ;
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 t4051 is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
--
XGTRG : in std_logic ;
-- 4051
Din : in std_logic ;
AOUT : out std_logic_vector(2 downto 0) ;
-- monitor output
Dout : out std_logic_vector(7 downto 0) --;
);
end t4051 ;
architecture behavioral of t4051 is
--
CONSTANT SEQ_MAX : integer := 18 ;
-- internal trigger
signal iSFT : std_logic_vector(2 downto 0) ;
signal iTRG : std_logic ;
-- sequencer
signal iSEQ : integer range 0 to SEQ_MAX ;
signal iDin : std_logic ;
signal iEna : std_logic ;
signal iSREG : std_logic_vector(7 downto 0) ;
signal iREG : std_logic_vector(7 downto 0) ;
signal iAOUT : std_logic_vector(2 downto 0) ;
begin
-- input
iDin <= Din ;
-- output
AOUT <= iAOUT ;
Dout <= iREG ;
-- synchronizer
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSFT <= "000" ;
elsif rising_edge(CLOCK) then
iSFT <= iSFT(1 downto 0) & XGTRG ;
end if ;
end process ;
iTRG <= '1' when ( iSFT = "011" ) else '0' ;
-- latch data
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iREG <= "00000000" ;
elsif rising_edge(CLOCK) then
if ( iSEQ = 17 ) then
iREG <= iSREG ;
end if ;
end if ;
end process ;
-- decoder
iAOUT <= "111" when ( iSEQ = 1 or iSEQ = 2 ) else
"110" when ( iSEQ = 3 or iSEQ = 4 ) else
"101" when ( iSEQ = 5 or iSEQ = 6 ) else
"100" when ( iSEQ = 7 or iSEQ = 8 ) else
"011" when ( iSEQ = 9 or iSEQ = 10 ) else
"010" when ( iSEQ = 11 or iSEQ = 12 ) else
"001" when ( iSEQ = 13 or iSEQ = 14 ) else
"000" ;
-- shift register
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSREG <= "00000000" ;
elsif rising_edge(CLOCK) then
if ( iEna = '1' ) then
iSREG <= iSREG(6 downto 0) & iDin ;
end if ;
end if ;
end process ;
-- shift register decoder
iEna <= '1' when ( iSEQ = 2 ) else
'1' when ( iSEQ = 4 ) else
'1' when ( iSEQ = 6 ) else
'1' when ( iSEQ = 8 ) else
'1' when ( iSEQ = 10 ) else
'1' when ( iSEQ = 12 ) else
'1' when ( iSEQ = 14 ) else
'1' when ( iSEQ = 16 ) else
'0' ;
-- sequencer
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iSEQ <= 0 ;
elsif rising_edge(CLOCK) then
case iSEQ is
-- wait trigger
when 0 => if ( iTRG = '1' ) then
iSEQ <= 1 ;
else
iSEQ <= 0 ;
end if ;
-- send address <7>
when 1 => iSEQ <= 2 ;
-- latch data
when 2 => iSEQ <= 3 ;
-- send address <6>
when 3 => iSEQ <= 4 ;
-- latch data
when 4 => iSEQ <= 5 ;
-- send address <5>
when 5 => iSEQ <= 6 ;
-- latch data
when 6 => iSEQ <= 7 ;
-- send address <4>
when 7 => iSEQ <= 8 ;
-- latch data
when 8 => iSEQ <= 9 ;
-- send address <3>
when 9 => iSEQ <= 10 ;
-- latch data
when 10 => iSEQ <= 11 ;
-- send address <2>
when 11 => iSEQ <= 12 ;
-- latch data
when 12 => iSEQ <= 13 ;
-- send address <1>
when 13 => iSEQ <= 14 ;
-- latch data
when 14 => iSEQ <= 15 ;
-- send address <0>
when 15 => iSEQ <= 16 ;
-- latch data
when 16 => iSEQ <= 17 ;
-- copy
when 17 => iSEQ <= 18 ;
-- return first state
when 18 => iSEQ <= 0 ;
-- default
when others => iSEQ <= 0 ;
end case ;
end if ;
end process ;
end behavioral;
ピンアサインは、次のように指定。
# system
NET "CLOCK" LOC = "P5" ;
NET "nRESET" LOC = "P39" ;
# 4051
NET "Din" LOC = "P1" ;
NET "AOUT<0>" LOC = "P2" ;
NET "AOUT<1>" LOC = "P3" ;
NET "AOUT<2>" LOC = "P4" ;
# monitor
NET "Dout<0>" LOC = "P11" ;
NET "Dout<1>" LOC = "P12" ;
NET "Dout<2>" LOC = "P13" ;
NET "Dout<3>" LOC = "P14" ;
NET "Dout<4>" LOC = "P18" ;
NET "Dout<5>" LOC = "P19" ;
NET "Dout<6>" LOC = "P20" ;
NET "Dout<7>" LOC = "P22" ;
# tirgger
NET "XGTRG" LOC = "P24" ;
目次
前
次