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;
-- 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;
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;
-- Frequncy Divider
-- 200KHz clock
-- マスタークロックを200KHzのop_enaに分周します。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity FreqDiv is
generic(
divisor : integer := 125
);
port(
clk, reset : in std_logic;
op_ena : out std_logic
);
end FreqDiv;
architecture RTL of FreqDiv is
signal lcnt : std_logic_vector(15 downto 0);
begin
process(clk) begin -- Enable frequency is 200KHz
if clk'event and clk='1' then
if reset='1' then
lcnt <= (others => '0');
elsif lcnt = conv_std_logic_vector(divisor, 16)-1 then
lcnt <= (others => '0');
else
lcnt <= lcnt + 1;
end if;
end if;
end process;
process(clk) begin
if clk'event and clk='1' then
if lcnt = conv_std_logic_vector(divisor, 16)-1 then
op_ena <= '1';
else
op_ena <= '0';
end if;
end if;
end process;
end RTL;
-- SCCB_reg_values_ROM.vhd
-- SCCBプロトコル・コントローラを実装してSCCBレジスタに書き込む値をセーブしてある ROM。書き込みデータは SCCB_reg_values.data にセーブしておく。
-- SCCB_reg_values.data のフォーマット"1280" 最初の2キャラクタが16進形式のアドレス、次の2キャラクタが16進形式のデータ。例は12番地に80を書く
-- SCCB_reg_values_ROM.data には必ず256行のデータを用意しておく。アドレスがFFの場合はレジスタ・アクセスはそこで終了する。
library IEEE, STD;
use IEEE.std_logic_1164.all;
use STD.textio.all;
use IEEE.std_logic_textio.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
-- pragma translate_off
library UNISIM;
use UNISIM.VCOMPONENTS.ALL;
-- pragma translate_on
entity SCCB_reg_values_ROM is
port(
clk : in std_logic; -- Clock
address : in std_logic_vector(7 downto 0);
dout : out std_logic_vector(15 downto 0)
);
end SCCB_reg_values_ROM;
architecture RTL of SCCB_reg_values_ROM is
type RamType is array(0 to 255) of std_logic_vector(15 downto 0);
impure function InitRamFromFile (RamFileName : in string) return RamType is
FILE RamFile : text is in RamFileName;
variable RamFileLine : line;
variable RAM : RamType;
begin
for I in RamType'range loop
readline (RamFile, RamFileLine);
hread (RamFileLine, RAM(I));
end loop;
return RAM;
end function;
signal RAM : RamType := InitRamFromFile("SCCB_reg_values.data");
begin
process(clk) begin
if clk'event and clk='1' then
dout <= RAM(conv_integer(address));
end if;
end process;
end RTL;
ACDF
FF00
0000
-- SCCB_Reg_Controller.vhd
-- SCCBレジスタのコントローラ
-- SCCB_reg_values_ROM.data には必ず256行のデータを用意しておく。アドレスがFFの場合はレジスタ・アクセスはそこで終了する。
-- 1行のデータは16ビット幅となっていて、上位8ビットがアドレス、下位8ビットがデータとなる。
-- One_Transaction_SCCBにアドレスとデータを渡して、1クロック分のstart_pules をアサートしSCCBレジスタに書き込む
-- One_Transaction_SCCBが書き込みを終了したら、end_pulseをアサートされるので、終了を検出できる。
-- SCCB_reg_values_ROM.dataのアドレスにFFが書いてあるエントリまで、上記の動作を実行する。
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
-- pragma translate_off
library UNISIM;
use UNISIM.VCOMPONENTS.ALL;
-- pragma translate_on
entity SCCB_Reg_Controller is
port(
clk : in std_logic; -- クロック
reset : in std_logic; -- リセット
SCL : out std_logic; -- SCCBのクロック
SDA : out std_logic -- SCCBのデータ
);
end SCCB_Reg_Controller;
-- SCCBのレジスタをセットするためのステートマシン
process(clk) begin
if clk'event and clk='1' then
if reset='1' then
cs_reg_set <= idle;
start_pulse <= '0';
else
case cs_reg_set is
when idle =>
if ROM_data(15 downto 8) = x"FF" then -- レジスタセット終了
cs_reg_set <= end_state;
start_pulse <= '0';
else -- アドレスがFFでないので、セットするレジスタがある
cs_reg_set <= start_pulse_state;
start_pulse <= '1';
end if;
when start_pulse_state =>
cs_reg_set <= wait_one_trans_SCCB;
start_pulse <= '0';
when wait_one_trans_SCCB =>
if end_pulse='1' then -- SCCBレジスタへの書き込みが終了
cs_reg_set <= next_address;
start_pulse <= '0';
end if;
when next_address =>
if ROM_address=x"FF" then -- 終了
cs_reg_set <= end_state;
start_pulse <= '0';
else
cs_reg_set <= idle;
start_pulse <= '0';
end if;
when end_state =>
cs_reg_set <= end_state;
start_pulse <= '0';
end case;
end if;
end if;
end process;
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | - | - |