Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
12 years ago

I2C Help!

Hi,

I am new to VHDL. I am trying to write the I2C protocol to store the value '10101010' in EEPROM on my DE0 Nano board.

Would anyone please help me as to show where I am going wrong? I am getting compilation errors saying "can't resolve multiple constant drivers for net "I2C_SCLK" " etc.

Thanks alot in advance


Library IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.numeric_std.all;
---------------------------------------------------------------------------------------------
ENTITY i2c IS
PORT (  clock_50 : IN STD_LOGIC;
		  LED : OUT STD_LOGIC_VECTOR( 7 DOWNTO 0 );
		  Key : IN STD_LOGIC_VECTOR ( 1 DOWNTO 0);
		  I2C_SCLK : OUT STD_LOGIC;
		  I2C_SDAT : INOUT STD_LOGIC:= '1'
);
END i2c;
-------------------------------------------------------------------------------------------------
ARCHITECTURE behaviour OF i2c IS
SIGNAL GO  : STD_LOGIC:= '0';
SIGNAL ref_clk  : STD_LOGIC;
SIGNAL SDI : STD_LOGIC;
SIGNAL SCLK: STD_LOGIC;
SIGNAL SD_COUNTER : INTEGER := 0;
SIGNAL COUNT : INTEGER := 0;
BEGIN
I2C_SCLK<= NOT (ref_clk) WHEN (SD_COUNTER >=4 AND SD_COUNTER <= 32);
-----------------------------------------------
PROCESS (clock_50)
BEGIN
	IF (clock_50'event AND clock_50 = '1') THEN
		COUNT<= COUNT + 1;
	END IF;
	IF (COUNT >= 512) THEN
		COUNT<=0;
		ref_clk<= NOT(ref_clk);
	END IF;
END PROCESS;
----------------------------------------------
PROCESS (key)
BEGIN
	IF(key(0) = '0') THEN
		GO <= '0';
	END IF;
	IF(key(1) = '0') THEN
		GO <= '1';
		I2C_SCLK <= '1';	
		I2C_SDAT <= '1';
	END IF;
END PROCESS;
------------------------------------------------	
PROCESS (ref_clk)
BEGIN
	IF ( (ref_clk'EVENT AND ref_clk = '1') AND SD_COUNTER < 34 AND GO = '1') THEN
			SD_COUNTER<= SD_COUNTER + 1;
		CASE SD_COUNTER IS
			WHEN  1  =>
				I2C_SCLK <= '1';	
				I2C_SDAT <= '1';
			WHEN  2  =>  				
				I2C_SDAT <= '0';
			WHEN  3  =>  				
				I2C_SCLK <= '0';
				
			--Slave Addr
			WHEN  4  =>  				
				I2C_SDAT <= '1';
			WHEN  5  =>  				
				I2C_SDAT <= '0';
			WHEN  6  =>  				
				I2C_SDAT <= '1';
			WHEN  7  =>  				
				I2C_SDAT <= '0';
			WHEN  8  =>  				
				I2C_SDAT <= '0';
			WHEN  9  =>  				
				I2C_SDAT <= '0';
			WHEN  10  =>  				
				I2C_SDAT <= '0';
			WHEN  11  =>  				
				I2C_SDAT <= '0';
			WHEN  12  =>  				
				I2C_SDAT <= 'Z';
			--Reg Addr	
			WHEN  13  =>
				I2C_SDAT <= '0';
			WHEN  14  =>  				
				I2C_SDAT <= '0';
			WHEN  15  =>  				
				I2C_SDAT <= '0';
			WHEN  16  =>  				
				I2C_SDAT <= '0';
			WHEN  17  =>  				
				I2C_SDAT <= '0';
			WHEN  18  =>  				
				I2C_SDAT <= '0';
			WHEN  19  =>  				
				I2C_SDAT <= '0';
			WHEN  20  =>  				
				I2C_SDAT <= '0';
			WHEN  21  =>  				
				I2C_SDAT <= 'Z';
				
			--Data
			WHEN  22  =>
				I2C_SDAT <= '1';
			WHEN  23  =>  				
				I2C_SDAT <= '0';
			WHEN  24  =>  				
				I2C_SDAT <= '1';
			WHEN  25  =>  				
				I2C_SDAT <= '0';
			WHEN  26  =>  				
				I2C_SDAT <= '1';
			WHEN  27  =>  				
				I2C_SDAT <= '0';
			WHEN  28  =>  				
				I2C_SDAT <= '1';
			WHEN  29  =>  				
				I2C_SDAT <= '0';
			WHEN  30  =>  				
				I2C_SDAT <= 'Z';
				
			WHEN  31  =>  				
				I2C_SCLK <= '1';
				I2C_SDAT <= '1';
			WHEN  32  =>  				
				I2C_SDAT <= 'Z';
				GO <= '0';	
				
			WHEN OTHERS =>  
				I2C_SDAT <= 'X';
		END CASE;
		
	END IF;
	
END PROCESS;
------------------------------------------------------------------------------------------------------
END behaviour;

4 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    in your PROCESS(KEY) and PROCESS(reg_clk) both processes are writing to I2C_SCLK. Thats a big no no in VHDL.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    in your PROCESS(KEY) and PROCESS(reg_clk) both processes are writing to I2C_SCLK. Thats a big no no in VHDL.

    --- Quote End ---

    I removed the writing to I2_SCLK in PROCESS(KEY) but still get an error because of the assignment to I2C_SCLK in "I2C_SCLK<= NOT (ref_clk) WHEN (SD_COUNTER >=4 AND SD_COUNTER <= 32);" as PROCESS(reg_clk) is also writing to it.

    How would you suggest a better way to do this? I wish to assign ref_clock to I2C_SCLK only when SD_COUNTER >= 4 and <= 32? Many thanks.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    yes, since the line

    "I2C_SCLK<= NOT (ref_clk) WHEN (SD_COUNTER >=4 AND SD_COUNTER <= 32);"

    and both PROCESS(reg_clk) is modifying I2C_SCLK you'll still get the error.

    if you really only "wish to assign ref_clock to I2C_SCLK only when SD_COUNTER >= 4 and <= 32" then remove all modifications of I2C_SCLK <= from PROCESS(reg_clk) or remove the line I2C_SCLK<= NOT (ref_clk) WHEN (SD_COUNTER >=4 AND SD_COUNTER <= 32); I dont think you can just have a statement that uses when without putting it into a process.

    so,

    I'd suggest you use a state machine

    off the top of my head, without looking into detail as to what your overall goal is something like this may work:

    Library IEEE;
    USE IEEE.STD_LOGIC_1164.ALL;
    USE IEEE.STD_LOGIC_UNSIGNED.ALL;
    use ieee.numeric_std.all;
    ---------------------------------------------------------------------------------------------
    ENTITY i2c IS
    PORT (  clock_50 : IN STD_LOGIC;
              LED : OUT STD_LOGIC_VECTOR( 7 DOWNTO 0 );
              Key : IN STD_LOGIC_VECTOR ( 1 DOWNTO 0);
              I2C_SCLK : OUT STD_LOGIC;
              I2C_SDAT : INOUT STD_LOGIC:= '1'
    );
    END i2c;
    -------------------------------------------------------------------------------------------------
    ARCHITECTURE behaviour OF i2c IS
    SIGNAL GO  : STD_LOGIC:= '0';
    SIGNAL ref_clk  : STD_LOGIC;
    SIGNAL SDI : STD_LOGIC;
    SIGNAL SCLK: STD_LOGIC;
    SIGNAL SD_COUNTER : INTEGER := 0;
    SIGNAL COUNT : INTEGER := 0;
    type state is 
    (
        IN_RANGE, NOT_IN_RANGE
    );
    signal Status : state;
    BEGIN
    process (clock_50)
        begin
            if (clock_50'event AND clock_50 = '1') then
                case Status is
                    when IN_RANGE =>
                        I2C_SCLK<= NOT (ref_clk);
                        if NOT(SD_COUNTER >=4 AND SD_COUNTER <= 32) then
                            Status <= NOT_IN_RANGE;
                        end if;
                    when NOT_IN_RANGE =>
                        I2C_SCLK<=(ref_clk);
                        if (SD_COUNTER >=4 AND SD_COUNTER <= 32) then
                            Status <= IN_RANGE;
                        end if;
                end case;
            end if;
    end process;
    -----------------------------------------------
    PROCESS (clock_50)
    BEGIN
        IF (clock_50'event AND clock_50 = '1') THEN
            COUNT<= COUNT + 1;
        END IF;
        IF (COUNT >= 512) THEN
            COUNT<=0;
            ref_clk<= NOT(ref_clk);
        END IF;
    END PROCESS;
    ----------------------------------------------
    PROCESS (key)
    BEGIN
        IF(key(0) = '0') THEN
            GO <= '0';
        END IF;
        IF(key(1) = '0') THEN
            GO <= '1';
            I2C_SDAT <= '1';
        END IF;
    END PROCESS;
    ------------------------------------------------    
    PROCESS (ref_clk)
    BEGIN
        IF ( (ref_clk'EVENT AND ref_clk = '1') AND SD_COUNTER < 34 AND GO = '1') THEN
                SD_COUNTER<= SD_COUNTER + 1;
            CASE SD_COUNTER IS
                WHEN  1  =>
                    I2C_SDAT <= '1';
                WHEN  2  =>                  
                    I2C_SDAT <= '0';
                WHEN  3  =>                  
                    I2C_SDAT <= '0';
                --Slave Addr
                WHEN  4  =>                  
                    I2C_SDAT <= '1';
                WHEN  5  =>                  
                    I2C_SDAT <= '0';
                WHEN  6  =>                  
                    I2C_SDAT <= '1';
                WHEN  7  =>                  
                    I2C_SDAT <= '0';
                WHEN  8  =>                  
                    I2C_SDAT <= '0';
                WHEN  9  =>                  
                    I2C_SDAT <= '0';
                WHEN  10  =>                  
                    I2C_SDAT <= '0';
                WHEN  11  =>                  
                    I2C_SDAT <= '0';
                WHEN  12  =>                  
                    I2C_SDAT <= 'Z';
                --Reg Addr    
                WHEN  13  =>
                    I2C_SDAT <= '0';
                WHEN  14  =>                  
                    I2C_SDAT <= '0';
                WHEN  15  =>                  
                    I2C_SDAT <= '0';
                WHEN  16  =>                  
                    I2C_SDAT <= '0';
                WHEN  17  =>                  
                    I2C_SDAT <= '0';
                WHEN  18  =>                  
                    I2C_SDAT <= '0';
                WHEN  19  =>                  
                    I2C_SDAT <= '0';
                WHEN  20  =>                  
                    I2C_SDAT <= '0';
                WHEN  21  =>                  
                    I2C_SDAT <= 'Z';
                    
                --Data
                WHEN  22  =>
                    I2C_SDAT <= '1';
                WHEN  23  =>                  
                    I2C_SDAT <= '0';
                WHEN  24  =>                  
                    I2C_SDAT <= '1';
                WHEN  25  =>                  
                    I2C_SDAT <= '0';
                WHEN  26  =>                  
                    I2C_SDAT <= '1';
                WHEN  27  =>                  
                    I2C_SDAT <= '0';
                WHEN  28  =>                  
                    I2C_SDAT <= '1';
                WHEN  29  =>                  
                    I2C_SDAT <= '0';
                WHEN  30  =>                  
                    I2C_SDAT <= 'Z';
                    
                WHEN  31  =>                  
                    I2C_SDAT <= '1';
                WHEN  32  =>                  
                    I2C_SDAT <= 'Z';
                    GO <= '0';    
                    
                WHEN OTHERS =>  
                    I2C_SDAT <= 'X';
            END CASE;
            
        END IF;
        
    END PROCESS;
    ------------------------------------------------------------------------------------------------------
    END behaviour;