Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

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.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top