Basic I2C, Need help please :)

Status
Not open for further replies.

JacquesKleynhans

Member level 2
Joined
Jul 3, 2008
Messages
51
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Activity points
1,630
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

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;
 

The question becomes will this type of bit banging work for simple i2c, because I do not need complex stuff. For the SCCB i don't even need the second start transition.
 

Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…