FC2カウンター FPGAの部屋 SCCBインターフェース回路の説明3(One_Transaction_SCCB.vhd)
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

SCCBインターフェース回路の説明3(One_Transaction_SCCB.vhd)

今度はOne_Transaction_SCCB.vhdを説明する。これは、SCCB_Reg_Controller.vhd から渡されたアドレス(SCCB_address)とデータ(SCCB_data)を使って、渡されたアドレスのSCCBレジスタにデータを書き込むモジュールだ。entityの記述を下に示す。

entity One_Transaction_SCCB is
    port(
        clk : in std_logic; -- クロック
        reset : in std_logic; -- リセット
        SCCB_address : in std_logic_vector(7 downto 0); -- SCCBレジスタのアドレス
        SCCB_data : in std_logic_vector(7 downto 0); -- SCCBレジスタのデータ
        op_enable : in std_logic; -- 動作イネーブル(200KHz, 5usec間隔)
        start_pulse : in std_logic; -- スタートパルス(1クロック幅)
        end_pulse : out std_logic; -- エンドパルス(1クロック幅)
        SCL : out std_logic;
        SDA : out std_logic
    );
end One_Transaction_SCCB;


start_pulseを入れて、end_pulseが出力されると渡されたアドレスのSCCBレジスタにデータを書き込む操作が終了となる。op_enableはfreqdiv.vhdから出力されたop_enaを接続する。SCLとSDAはCMOSカメラへ。
最初にメインのステートマシン。構造を下に示す。
SCCB_block_fig_1_091216.png

VHDLコードを下に示す。

    -- Main State Machine
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                cs_main <= idle_main;
            else
                case cs_main is
                    when idle_main =>
                        if start_pulse='1' then -- スタートパルスが来たらスタート
                            cs_main <= start_state;
                        end if;
                    when start_state =>
                        if state_counter=17 and op_enable='1' then -- START ステートの最後で5us のイネーブルの時に遷移
                            cs_main <= ID_Address;
                        end if;
                    when ID_Address =>
                        if state_counter=17 and op_enable='1' then -- ID_Address ステートの最後で5us のイネーブルの時に遷移
                            cs_main <= SCCB_Reg_Addr;
                        end if;
                    when SCCB_Reg_Addr =>
                        if state_counter=17 and op_enable='1' then -- SCCB_Reg_Addr ステートの最後で5us のイネーブルの時に遷移
                            cs_main <= Write_Data;
                        end if;
                    when Write_Data =>
                        if state_counter=17 and op_enable='1' then -- Write_Data ステートの最後で5us のイネーブルの時に遷移
                            cs_main <= stop_state;
                        end if;
                    when stop_state =>
                        if state_counter=17 and op_enable='1' then -- stop_state ステートの最後で5us のイネーブルの時に遷移
                            cs_main <= idle_main;
                        end if;
                end case;
            end if;
        end if;
    end process;


state_counterが17でop_enaが1のときに遷移する。state_counter は0~17までカウントするカウンタで、op_enaが1の時にカウントアップする。
次にデータパスのブロック図を再度示す。
SCCB_block_fig_3_091216.png

SDAはSCLに比べて、必ず遅れるようにFFを2段入れた。SDAの最後のトラーステートバッファのイネーブルは必ずFFの出力とした方が良い。それは、イネーブルが組み合わせ回路だと、どの時点でひげが出て、思わぬ時にONしてしまうかわからないためだ。
下にconstant値と18ビット、9ビットのシフトレジスタのVHDLコードを示す。

constant START_PATTERN_SCL : std_logic_vector :=        "111111111111111111";
constant IDA_SCCBR_WD_PATTERN_SCL : std_logic_vector :=    "010101010101010101";
constant STOP_PATTERN_SCL : std_logic_vector :=            "011111111111111111";
constant START_PATTERN_SDA : std_logic_vector :=        "111111110";
constant ID_ADDRESS_PATTERN_SDA : std_logic_vector :=    "010000100";
constant STOP_PATTERN_SDA : std_logic_vector :=            "011111111";


    -- SLC 用18ビット・シフトレジスタ
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                SCL_shift_reg <= (others => '1');
            else
                case cs_main is
                    when idle_main =>
                        if start_pulse='1' then -- スタートパルスが来たらスタート
                            SCL_shift_reg <= START_PATTERN_SCL;
                        end if;
                    when start_state =>
                        if op_enable='1' then
                            if state_counter=17 then -- START ステートの最後で5us のイネーブルの時に遷移 
                                SCL_shift_reg <= IDA_SCCBR_WD_PATTERN_SCL;
                            else
                                SCL_shift_reg <= SCL_shift_reg(16 downto 0) & '1';
                            end if;
                        end if;
                    when ID_Address =>
                        if op_enable='1' then
                            if state_counter=17 then
                                SCL_shift_reg <= IDA_SCCBR_WD_PATTERN_SCL;
                            else
                                SCL_shift_reg <= SCL_shift_reg(16 downto 0) & '1';
                            end if;
                        end if;
                    when SCCB_Reg_Addr =>
                        if op_enable='1' then
                            if state_counter=17 then
                                SCL_shift_reg <= IDA_SCCBR_WD_PATTERN_SCL;
                            else
                                SCL_shift_reg <= SCL_shift_reg(16 downto 0) & '1';
                            end if;
                        end if;
                    when Write_Data =>
                        if op_enable='1' then
                            if state_counter=17 then
                                SCL_shift_reg <= STOP_PATTERN_SCL;
                            else
                                SCL_shift_reg <= SCL_shift_reg(16 downto 0) & '1';
                            end if;
                        end if;
                    when stop_state =>
                        if op_enable='1' then
                            SCL_shift_reg <=  SCL_shift_reg(16 downto 0) & '1';
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    -- SDA 用9ビット・シフトレジスタ
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                SDA_shift_reg <= (others => '1');
            else
                case cs_main is
                    when idle_main =>
                        if start_pulse='1' then -- スタートパルスが来たらスタート
                            SDA_shift_reg <= START_PATTERN_SDA;
                        end if;
                    when start_state =>
                        if op_enable='1' and state_counter(0)='1' then -- 2回に1回遷移
                            if state_counter=17 then -- START ステートの最後で5us のイネーブルの時に遷移 
                                SDA_shift_reg <= ID_ADDRESS_PATTERN_SDA;
                            else
                                SDA_shift_reg <= SDA_shift_reg(7 downto 0) & '1';
                            end if;
                        end if;
                    when ID_Address =>
                        if op_enable='1' and state_counter(0)='1' then -- 2回に1回遷移
                            if state_counter=17 then
                                SDA_shift_reg <= SCCB_address & '1';
                            else
                                SDA_shift_reg <= SDA_shift_reg(7 downto 0) & '1';
                            end if;
                        end if;
                    when SCCB_Reg_Addr =>
                        if op_enable='1' and state_counter(0)='1' then -- 2回に1回遷移
                            if state_counter=17 then
                                SDA_shift_reg <= SCCB_data & '1';
                            else
                                SDA_shift_reg <= SDA_shift_reg(7 downto 0) & '1';
                            end if;
                        end if;
                    when Write_Data =>
                        if op_enable='1' and state_counter(0)='1' then -- 2回に1回遷移
                            if state_counter=17 then
                                SDA_shift_reg <= STOP_PATTERN_SDA;
                            else
                                SDA_shift_reg <= SDA_shift_reg(7 downto 0) & '1';
                            end if;
                        end if;
                    when stop_state =>
                        if op_enable='1' and state_counter(0)='1' then -- 2回に1回遷移
                            SDA_shift_reg <=  SDA_shift_reg(7 downto 0) & '1';
                        end if;
                end case;
            end if;
        end if;
    end process;


これで大体説明できたと思う。これらのファイルを合わせて、テストベンチを書くと下のようなシミュレーション波形が得られる。
SCCB_simulation_091221.png
  1. 2009年12月23日 21:27 |
  2. 画像処理
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/1331-4ccc4019
この記事にトラックバックする(FC2ブログユーザー)