JacquesKleynhans
Member level 2
Basic I2C, Need help
Hi I have written a I2C interface (I am actually busy interfacing a omnivision ov5620 camera, but im testing the sccb code on a simpler sensor ) in vhdl, for a little temperature sensor. I generate the clock for the scl by using parallel to serial converters clocking out predefined 101010 etc. I did all the timing correctly and verified it with the logic analyzer and its looks good but I cant seem to read anything back from the sensor.
The sensor i am trying to connect to is the tc74 from microchip, its on board a development kit, I removed the pic and connected my "sda and scl lines to it" with addition of power and ground. There are pull up resistors on board the dev kit.
I have attached a image of my modelsim waveform.
Ps I am ignoring ack bits im setting them high.
start-idsensor(0)-subaddress-start-idsensor(1)-readdata-stop
Hi I have written a I2C interface (I am actually busy interfacing a omnivision ov5620 camera, but im testing the sccb code on a simpler sensor ) in vhdl, for a little temperature sensor. I generate the clock for the scl by using parallel to serial converters clocking out predefined 101010 etc. I did all the timing correctly and verified it with the logic analyzer and its looks good but I cant seem to read anything back from the sensor.
The sensor i am trying to connect to is the tc74 from microchip, its on board a development kit, I removed the pic and connected my "sda and scl lines to it" with addition of power and ground. There are pull up resistors on board the dev kit.
I have attached a image of my modelsim waveform.
Ps I am ignoring ack bits im setting them high.
start-idsensor(0)-subaddress-start-idsensor(1)-readdata-stop
Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.NUMERIC_BIT.all;
use ieee.STD_LOGIC_ARITH.all;
entity sccb_write is
port( clk: in std_logic;
reset: in std_logic;
start_pulse: in std_logic;
scl: out std_logic;
sda: inout std_logic;
sda_out: out std_logic_vector(7 downto 0)
);
end sccb_write;
architecture behavioral of sccb_write is
--TYPEDEF DECLARATION
type state_type is
( idle, start_state1, id_address_write, sub_address,start_state2,id_address_read, read_data, stop_state);
--SIGNAL DECLARATION
signal state_next: state_type;
signal scl_shift_reg: std_logic_vector(17 downto 0);
signal sda_shift_reg: std_logic_vector(8 downto 0) := "000000000";
signal sda_shift_out: std_logic_vector(8 downto 0) := "000000000";
signal state_counter: std_logic_vector(4 downto 0);
signal sccb_div : std_logic_vector (4 downto 0):= "00000";
signal sccbclk : std_logic := '0';
signal output_enable :std_logic := '0';
signal state_reset: std_logic := '0';
--CONSTANT DECLARATION
constant SCL_start_pattern: std_logic_vector := "111111111111111111";
constant SCL_ida_sccbr_wd_pattern: std_logic_vector := "010101010101010101";
constant SCL_stop_pattern: std_logic_vector := "011111111111111111";
constant SDA_start_pattern: std_logic_vector:= "111111100";
constant SDA_stop_pattern: std_logic_vector := "001111111";
--PROGRAM STARTS HERE
begin
--PROCESS USED TO GENERATE A 800Khz CLOCK SIGNAL FOR THE SCCB SCL
--This clock signal is used on every rising edge thus resulting in clock split to 400khz
process(clk, reset)
begin
if reset = '1' then
sccbclk <= '0';
sccb_div <= "11000";
elsif rising_edge(clk) then
if sccb_div = "00000" then
sccbclk <= not(sccbclk);
sccb_div <= "11000";
else
sccb_div <= sccb_div-1;
end if;
end if;
end process;
--COUNTER USED TO COUNT FROM 0 TO 17
process(sccbclk, reset)
begin
if (reset = '1') then
state_counter <= (others => '0');
elsif rising_edge(sccbclk) then
state_counter <= state_counter + 1;
if state_counter = "10001" then
state_counter <= (others => '0');
end if;
end if;
end process;
--MAIN CASE LOOP
process(sccbclk,reset)
begin
if (reset = '1') then
state_next <= idle;
output_enable <= '0';
elsif rising_edge(sccbclk) then
case state_next is
when idle =>
if start_pulse = '1' then
state_next <= start_state1;
end if;
when start_state1 =>
if state_counter = "10001" then
state_next <= id_address_write;
output_enable <= '1';
end if;
when id_address_write =>
if state_counter = "10001" then
state_next <= sub_address;
output_enable <= '1';
end if;
when sub_address =>
if state_counter = "10001" then
state_next <= start_state2;
output_enable <= '1';
state_reset <= '0';
end if;
when start_state2 =>
if state_counter = "10001" then
state_next <= id_address_read;
output_enable <= '1';
end if;
when id_address_read =>
if state_counter = "10001" then
state_next <= read_data;
output_enable <= '0';
end if;
when read_data =>
if state_counter = "10001" then
state_next <= stop_state;
output_enable <= '1';
end if;
when stop_state =>
if state_counter = "10001" then
state_next <= idle;
output_enable <= '1';
end if;
end case;
end if;
end process;
--SCL CLOCK LOOP
process(sccbclk, reset)
begin
if (reset = '1') then
scl_shift_reg <= (others => '1');
elsif rising_edge(sccbclk) then
case state_next is
when idle =>
if start_pulse = '1' then
scl_shift_reg <= scl_start_pattern;
end if;
when start_state1 =>
if state_counter = "10001" then
scl_shift_reg <= SCL_ida_sccbr_wd_pattern;
else
scl_shift_reg <= scl_shift_reg(16 downto 0) & '1';
end if;
when id_address_write =>
if state_counter = "10001" then
scl_shift_reg <= SCL_ida_sccbr_wd_pattern;
else
scl_shift_reg <= scl_shift_reg(16 downto 0) & '1';
end if;
when sub_address =>
if state_counter = "10001" then
scl_shift_reg <= scl_start_pattern;
else
scl_shift_reg <= scl_shift_reg(16 downto 0) & '1';
end if;
when start_state2 =>
if state_counter = "10001" then
scl_shift_reg <= SCL_ida_sccbr_wd_pattern;
else
scl_shift_reg <= scl_shift_reg(16 downto 0) & '1';
end if;
when id_address_read =>
if state_counter = "10001" then
scl_shift_reg <= SCL_ida_sccbr_wd_pattern;
else
scl_shift_reg <= scl_shift_reg(16 downto 0) & '1';
end if;
when read_data =>
if state_counter = "10001" then
scl_shift_reg <= SCL_stop_pattern;
else
scl_shift_reg <= scl_shift_reg(16 downto 0) & '1';
end if;
when stop_state =>
scl_shift_reg <= scl_shift_reg(16 downto 0) & '1';
end case;
end if;
end process;
--SDA DATA LOOP FOR A READ OPERATION
-- loop consists of 2 write sequences and 2 read sequences
process(sccbclk, reset)
begin
if (reset = '1') then
sda_shift_reg <= (others => '1');
sda_shift_out <= (others => '1');
elsif rising_edge(sccbclk) then
case state_next is
when idle =>
if start_pulse = '1' then
sda_shift_reg <= sda_start_pattern;
end if;
when start_state1 =>
if state_counter(0) = '1' then
if state_counter = "10001" then
sda_shift_reg <= "10011010" & '1'; --THE DEVICE SLAVE ADDRESS FOR A WRITE OPERATION x"9A"
else
sda_shift_reg <= sda_shift_reg(7 downto 0) & '1';
end if;
end if;
when id_address_write =>
if state_counter(0) = '1' then
if state_counter = "10001" then
sda_shift_reg <= "00000000" & '1'; --COMMAND TO READ TeMP x"00"
else
sda_shift_reg <= sda_shift_reg(7 downto 0) & '1';
end if;
end if;
when sub_address =>
if state_counter(0) = '1' then
if state_counter = "10001" then
sda_shift_reg <= SDA_start_pattern;
else
sda_shift_reg <= sda_shift_reg(7 downto 0) & '1';
end if;
end if;
when start_state2 =>
if state_counter(0) = '1' then
if state_counter = "10001" then
sda_shift_reg <= "10011011" & '1'; --THE DEVICE SLAVE ADDRESS FOR A READ OPERATION x"9B"
else
sda_shift_reg <= sda_shift_reg(7 downto 0) & '1';
end if;
end if;
when id_address_read =>
if state_counter(0) = '1' then
if state_counter = "10001" then
sda_shift_out <= sda_shift_out(7 downto 0) & '1';
else
sda_shift_reg <= sda_shift_reg(7 downto 0) & '1';
end if;
end if;
when read_data =>
if state_counter(0) = '1' then
if state_counter = "10001" then
sda_shift_reg <= sda_stop_pattern;
else
sda_shift_out <= sda_shift_out(7 downto 0) & sda;
end if;
end if;
when stop_state =>
if state_counter(0) = '1' then
sda_shift_reg <= sda_shift_reg(7 downto 0) & '1';
end if;
end case;
end if;
end process;
sda <= sda_shift_reg(8);
scl <= scl_shift_reg(17);
sda_out <= sda_shift_out(8 downto 1) when(output_enable = '0') else "ZZZZZZZZ";
end behavioral;