制御信号の発生回路
このシステムでは,FPGA外部のスイッチにより動作の開始やリセットを制御しています。またFT232Hとデータをやり取りするための制御信号を生成します。これらの制御信号の発生回路について説明します。
PROCESS(START_SW, reset) -- Start with tact switch
BEGIN
IF(reset='0')THEN
RUN <= '0';
ELSE
IF(START_SW = '0')THEN
RUN <= '1';
END IF;
--IF(Samp_cnt = Samp_n)THEN
-- RUN <= '0';
--END IF;
END IF;
END PROCESS;
PROCESS(START_SW, reset) — 外部スイッチで動作開始
・・・
このプロセス文はRUN信号発生回路を記述している。RUN信号はreset=0で0となる。START_SWが0になると,RUN=0となり,reset=0とならない限り0を保ち続ける。
信号START_SWはFPGA外部のタクトスイッチを使って発生する。タクトスイッチは,2つの端子が通常は開放つまり切れている状態であり,ボタンを押すと短絡される。スイッチを押すことでSTART_SWは0になる。(PCからのコマンドによりリセットやスタートができるように改修をする予定。)
FT232H書込み制御信号WRの発生
FPGAはFT232Hにデータを渡している間はFT232Hへの書き込み制御信号WRを0に保持します。信号WRはFT232Hの内部FIFOの状態を表すフラグ信号TXFの値も考慮して生成しなければなりません。以前の回路とは異なり,組み合わせ論理を記述する「条件つき代入文」でWRを作っています。
-- WR control for FT232H
WR <= '1' WHEN (TXE = '1' OR RdEn ='0') ELSE
'0' WHEN (TXE = '0' AND RdEn = '1');
WR <= ‘1’ WHEN (TXE = ‘1’ OR WR_busy =’0′) ELSE
‘0’ WHEN (TXE = ‘0’ AND WR_busy = ‘1’);
この2行の記述は,WHENを使っていますがプロセス文ではなく,「条件付き代入文」と呼ばれる同時処理文になる。TXE = ‘1’ (FT232HのFIFOが満杯で書き込みできない状態)か,RdEn=’0’(FPGA内蔵のFIFOから読み出しできない状態)のときはWRを1にします。一方,TX=0かつRdEn=’1’のときはWR=’0’にしてFT232Hにデータを書き込むよう指示します。
FIFOの制御信号の発生
FPGAに内蔵するFIFOであるFIFO64to8は以下のような制御信号があります。
書き込みと読み出しを許可する制御信号:
- WrEn:’1’のとき,WrClockの立上りに同期してFIFOにデータが書き込まれる
- RdEn:’1’のとき,RdClockの立上りに同期してFIFOからデータが読み出される
また,FIFOの使用状況を示すフラグ信号が出力されています。
- AlmostEmpty:FIFO内のデータの量が閾値AmEmptyThreshで設定した値以下になると“1”になる
- AlmostFull:FIFO内のデータの量が閾値AmFullThreshで設定した値以上のとき“1”になる
- Full:データ量がFIFO容量の上限に達すると“1”になる
- Empty:データ量が0のとき“1”になる
以下に書き込み許可信号WrEnと読み出し許可信号RdEnを生成するコードを示します。
WrEn <= RUN AND NOT(Full);
PROCESS(clk_60MHz,reset) --State transition for RdEn
BEGIN
IF(reset='0')THEN
RdEn <= '0';
ELSIF(clk_60MHz'EVENT AND clk_60MHz='1')THEN
CASE RdEn is
WHEN '0' =>
IF(AmFull = '1')THEN
RdEn <= '1';
ELSE
RdEn <= '0';
END IF;
WHEN '1' =>
IF(AmEmpty = '1')THEN
RdEn <= '0';
ELSE
RdEn <= '1';
END IF;
WHEN OTHERS =>
RdEn <='0';
END CASE;
END IF;
END PROCESS;
- WrEn <= RUN AND NOT(Full);
動作状態(RUN=’1’)かつFIFOバッファがFullでないときに書き込み許可する。 - PROCESS(clk_60MHz,reset) –State transition for RdEn
BEGIN
・・・
RdEnを生成するステートマシンの記述である。リセットされた状態ではRdEn=’0’になっており,FIFOがAlmostFullになるまで読み出し許可はしない。AlmostFullまでデータが蓄積されると読み出し許可(RdEn=’1’)にする。一旦読み出し許可をすると,AlmostEmptyに達するまではRdEn=’1’を保持する。このように制御する理由は,FT232Hに渡すデータがなるべく途切れないようにするためである。しかし,この方法が動作の安定化に効果があるかどうかは未確認である。また,FIFOに2000サンプル分のデータが蓄積されるのを待ってからUSB転送を開始するので,遅延(レイテンシ)が大きくなってしまうことに注意が必要です。
その他
動作確認用の記述です。
PROCESS(mic_clk)
BEGIN
IF(mic_clk'EVENT AND mic_clk = '1')THEN
for n in 0 to N_CH-1 loop
temp <= temp AND mic_in(n);
END loop;
for n in 0 to 7 loop
dum_out <= dum_out AND temp(n);
END loop;
END IF;
END PROCESS;
-- Display signals with LED
PROCESS(mic_clk)
BEGIN
IF(mic_clk'EVENT AND mic_clk = '1')THEN
LED <= (others =>'1');
LED(7) <= NOT(RUN);
LED(0) <= dum_out;
END IF;
END PROCESS;
- PROCESS(mic_clk)
BEGIN
IF(mic_clk’EVENT AND mic_clk = ‘1’)THEN
・・・
このプロセス文は最終的な動作には関係のないものです。MEMSマイクからの信号mic_inを使ってダミー出力dum_outを作っています。
デバッグのため内部で生成したテスト信号をMEMSマイクの出力と置き換えるようにコードを変更すると,Lattice Diamondの処理系がMEMSマイクからの入力信号を無効として取り扱うため信号のピン割り当てが変化してしまいます。処理系への指示でピン配置が変化しないようにする方法があると思うのですが,調べる時間がありませんでした。
MEMSマイクの信号を内部で使うだけでは効果がなく,出力信号に影響を与えるようにしないといけないことがわかったので,無理やりMEMSマイクの信号をダミー信号の計算に使い,それをMachXO2評価基板上のLEDに出力するようにして対応しています。 - — Display signals with LED
PROCESS(mic_clk)
BEGIN
・・・
LED(0) <= dum_out;
・・・
LED(0)にdum_outを出力するようにしています。
トップレベル記述のコード全体
最後にARRAY_MIC.vhdのコード全体を示します。
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
USE ieee.std_logic_unsigned.all;
USE work.ARRAY_PKG.all;
-- TOP Level Hardware
ENTITY recording_mic IS
PORT(
clk_60MHz : in STD_LOGIC; -- Clock from FT232H USB interface
mic_clk : buffer STD_LOGIC; -- Clock for MEMS Mic
mic_in : in SIG_ARRAY; -- Connect to Mic Output
-- size of SIG_ARRAY is defined in ARRAY_PKG.vhd
RESET_SW : in STD_LOGIC; -- Connect to tact switch
START_SW : in STD_LOGIC; -- Connect to tact switch2
word_out : out STD_LOGIC_VECTOR(N_BYTE*8-1 downto 0);
-- send to USB UART/FIFO IC (FT232H)
-- Controll Signals
WR : out STD_LOGIC;
TXE : in STD_LOGIC;
RD : out STD_LOGIC;
RXF : in STD_LOGIC;
-- LED monitor
LED : out STD_LOGIC_VECTOR(7 downto 0)
);
END recording_mic;
ARCHITECTURE behavior OF recording_mic IS
signal clk_3MHz : STD_LOGIC; -- Clock
signal mic_clk_d: STD_LOGIC;
signal reset : STD_LOGIC;
signal Ch_cnt : STD_LOGIC_VECTOR(7 downto 0); -- Counter for mic-Channnel
signal Ch_n : STD_LOGIC_VECTOR(7 downto 0); -- number of ch-counter
signal Samp_cnt : STD_LOGIC_VECTOR(15 downto 0) := "0000000000000000";
-- conter for number of time samples
signal Samp_n : STD_LOGIC_VECTOR(15 downto 0); --upper limit of Samp_cnt
signal cnt_3M : STD_LOGIC_VECTOR(7 downto 0) := (others => '0');
signal RUN : STD_LOGIC := '0'; -- Flag indicating running
signal in_data_buffer : SIG_ARRAY; -- buffer for mic signal
signal in_data_dummy : SIG_ARRAY;
signal mic_inG : SIG_ARRAY; -- Internally generated mic signal for test
signal mic_data : STD_LOGIC_VECTOR(N_BYTE*8-1 downto 0);
-- signals for FIFO64to8
signal FIFO_in : STD_LOGIC_VECTOR(63 downto 0); -- to FIFO64to8
signal WrEn : STD_LOGIC; -- Write Enable
signal RdEn : STD_LOGIC; -- Read Enable
signal Empty : STD_LOGIC;
signal Full : STD_LOGIC;
signal AmEmpty : STD_LOGIC; -- Almost Empty
signal AmFull : STD_LOGIC; -- Almost Full
signal FIFO_reset : STD_LOGIC;
signal RPReset : STD_LOGIC;-- Read Pointer Reset signal
signal AmEmptyThresh : STD_LOGIC_VECTOR(13 downto 0);
signal AmFullThresh : STD_LOGIC_VECTOR(10 downto 0);
signal temp : STD_LOGIC_VECTOR(7 downto 0);
signal dum_out : STD_LOGIC;
COMPONENT FIFO64to8
port (
Data: in std_logic_vector(63 downto 0);
WrClock: in std_logic;
RdClock: in std_logic;
WrEn: in std_logic;
RdEn: in std_logic;
Reset: in std_logic;
RPReset: in std_logic;
AmEmptyThresh: in std_logic_vector(13 downto 0);
AmFullThresh: in std_logic_vector(10 downto 0);
Q: out std_logic_vector(7 downto 0);
Empty: out std_logic;
Full: out std_logic;
AlmostEmpty: out std_logic;
AlmostFull: out std_logic);
end COMPONENT;
BEGIN
FIFO:FIFO64to8
PORT MAP(
Data => FIFO_in,
WrClock => mic_clk_d,
RdClock => clk_60MHz,
WrEn => WrEn,
RdEn => RdEn,
Reset => FIFO_reset,
RPReset => RPReset,
AmEmptyThresh => AmEmptyThresh,
AmFullThresh => AmFullThresh,
Q => word_out,
Empty => Empty,
Full => Full,
AlmostEmpty => AmEmpty,
AlmostFull => AmFull
);
mic_clk <= clk_3MHz;
PROCESS(clk_60MHz)
BEGIN
IF(clk_60MHz'EVENT AND clk_60MHz = '1')THEN
mic_clk_d <= mic_clk;
END IF;
END PROCESS;
AmEmptyThresh <= CONV_std_logic_vector(128,14);
AmFullThresh <= CONV_std_logic_vector(2000,11);
PROCESS(clk_60MHz,mic_inG,reset) -- MEMS Mic 1bit output (Synchronized with mic_clk)
BEGIN
IF(reset = '0')THEN
in_data_buffer <= mic_inG;
ELSIF(clk_60MHz'EVENT AND clk_60MHz = '1')THEN
IF(cnt_3M = 19)THEN
IF(Samp_cnt <4)THEN
in_data_buffer <= mic_inG;
ELSE
in_data_buffer <= mic_in;
END IF;
END IF;
END IF;
END PROCESS;
mic_G: for n in 0 to 7 generate -- Generate mic signal for test
mic_inG(n) <= CONV_STD_LOGIC_VECTOR(7-n,8);
END generate;
--mic_inG(0) <= CONV_STD_LOGIC_VECTOR(1,8);
--mic_inG(1) <= CONV_STD_LOGIC_VECTOR(1,8);
--mic_inG(2) <= CONV_STD_LOGIC_VECTOR(0,8);
--mic_inG(3) <= CONV_STD_LOGIC_VECTOR(0,8);
--mic_inG(4) <= CONV_STD_LOGIC_VECTOR(0,8);
--mic_inG(5) <= CONV_STD_LOGIC_VECTOR(0,8);
--mic_inG(6) <= CONV_STD_LOGIC_VECTOR(0,8);
--mic_inG(7) <= CONV_STD_LOGIC_VECTOR(0,8);
reset <= RESET_SW; -- generated by tact switch
FIFO_reset <= NOT(reset);
RPReset <= NOT(reset);
Ch_n <= CONV_std_logic_vector(N_CH,8);
Samp_n <= CONV_std_logic_vector(8192,16);
PROCESS(clk_60MHz,reset) -- 60MHz → 3MHz
BEGIN
IF(reset ='0')THEN
cnt_3M <= (others => '0');
clk_3MHz <='0';
ELSIF(clk_60MHz'EVENT AND clk_60MHz='1')THEN
IF(cnt_3M < 19)THEN
cnt_3M <= cnt_3M + 1;
IF(cnt_3M < 10)THEN
clk_3MHz <= '0';
ELSE
clk_3MHz <= '1';
END IF;
ELSE
cnt_3M <= (others => '0');
END IF;
END IF;
END PROCESS;
PROCESS(clk_60MHz,reset) -- input signal to FIFO64to8
BEGIN
IF(reset = '0')THEN
FIFO_in <= (others => '0');
ELSIF(clk_60MHz'EVENT AND clk_60MHz='1')THEN
IF(cnt_3M = 19)THEN
FIFO_in(7 downto 0) <= mic_in(0);
for I in 1 to N_CH-1 loop
FIFO_in((I+1)*N_BYTE*8-1 downto I*N_BYTE*8)<=mic_in(I);
end loop;
END IF;
END IF;
END PROCESS;
PROCESS(mic_clk, RUN, reset) -- counter for time samples
BEGIN
IF(reset='0')THEN
Samp_cnt <= (others => '0');
ELSIF(mic_clk'EVENT AND mic_clk='1' AND RUN = '1')THEN
IF(Samp_cnt = Samp_n-1)THEN
Samp_cnt <= (others => '0');
ELSE
Samp_cnt <= Samp_cnt + 1;
END IF;
END IF;
END PROCESS;
PROCESS(START_SW, reset) -- Start with tact switch
BEGIN
IF(reset='0')THEN
RUN <= '0';
ELSE
IF(START_SW = '0')THEN
RUN <= '1';
END IF;
--IF(Samp_cnt = Samp_n)THEN
-- RUN <= '0';
--END IF;
END IF;
END PROCESS;
-- WR control for FT232H
WR <= '1' WHEN (TXE = '1' OR RdEn ='0') ELSE
'0' WHEN (TXE = '0' AND RdEn = '1');
WrEn <= RUN AND NOT(Full);
PROCESS(clk_60MHz,reset) --State transition for RdEn
BEGIN
IF(reset='0')THEN
RdEn <= '0';
ELSIF(clk_60MHz'EVENT AND clk_60MHz='1')THEN
CASE RdEn is
WHEN '0' =>
IF(AmFull = '1')THEN
RdEn <= '1';
ELSE
RdEn <= '0';
END IF;
WHEN '1' =>
IF(AmEmpty = '1')THEN
RdEn <= '0';
ELSE
RdEn <= '1';
END IF;
WHEN OTHERS =>
RdEn <='0';
END CASE;
END IF;
END PROCESS;
PROCESS(mic_clk)
BEGIN
IF(mic_clk'EVENT AND mic_clk = '1')THEN
for n in 0 to N_CH-1 loop
temp <= temp AND mic_in(n);
END loop;
for n in 0 to 7 loop
dum_out <= dum_out AND temp(n);
END loop;
END IF;
END PROCESS;
-- Display signals with LED
PROCESS(mic_clk)
BEGIN
IF(mic_clk'EVENT AND mic_clk = '1')THEN
LED <= (others =>'1');
LED(7) <= NOT(RUN);
LED(0) <= dum_out;
END IF;
END PROCESS;
END behavior;
コメント