Search code examples
vhdlfpgaquartus

Error (10028): Can't resolve multiple constant drivers for net "sda" at I2C_com.vhd(185)


i'm trying to make my own I2C communication and i have a problem with multiply drivers, it's not like i don't understand them i just don't see them (i'm still fresh at vhdl), so please just take a look at my code and tell mi why is there such mistake.

i try to operate on flags to have multiple signal drivers on bus but there's just something not right. The multiple drivers are on scl, sda, start_clk and stop_clk. Is it because those flags are for example in two different processes?

        library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;

    entity I2C_com is


    port (

    reset_en: in std_logic;  
    clk: in std_logic;  
    sda: inout std_logic;   
    scl: out std_logic;    
    RD:in std_logic;       
    WR: in std_logic;       
    addr: buffer std_logic_vector(7 downto 0) 


    );

    end I2C_com;



    architecture MAIN of I2C_com  is

    signal data :std_logic_vector (12 downto 0):="0000000000010"; 
    signal i2c_clk: std_logic ;  
    signal clk_count : unsigned(19 downto 0):="00000000000000000100"; 
    type program_state is (start,init,error_rd_wr,slave,ack);
    signal state: program_state;
    signal write_data: std_logic_vector (7 downto 0):=(others => '0'); 
   signal read_data: std_logic_vector (7 downto 0):=(others => '0'); 
    signal clk_enable: std_logic; 
    signal reset: std_logic:='1'; 
    signal start_clk: std_logic:= 'Z'; 
    signal stop_clk: std_logic:= 'Z';   
    signal strech: std_logic := '0';
    signal cnt_addr: integer := 0; 
    signal ack_error: std_logic; 
    signal sda_data: std_logic; 
    signal start_data: std_logic:= 'Z'; 

    begin



    i2c_clock: process(clk,reset_en,reset)

    begin



    if reset_en = '1' or reset = '1' then 



    elsif falling_edge(clk) then

    if clk_count < unsigned(data) then  
    clk_count <= clk_count + 1;
    clk_enable <= '1';
    else
    clk_count <= x"00000";
    clk_enable <= '0';
    end if;
    i2c_clk <= clk_enable;

    if start_clk = '1'  then

    sda <= '0';
    scl <= '0';
    start_clk <= '0';

    end if;

    if stop_clk = '1'  then

    sda <= '0';
    scl <= '0';
    stop_clk <= '0';

    end if;

    end if; 
    end process i2c_clock;

    --
    process(i2c_clk,reset_en,reset)



    begin


    if reset_en = '1' or reset = '1' then

    reset <= '0';       
    cnt_addr <= 0;
    state <= init;  


    elsif rising_edge(i2c_clk) then


    case state is


    when init =>                                    
    if RD = '1' or WR = '1' then      
    state <= start;
    else
    state <= error_rd_wr;
    end if;

    when start =>                   

    start_clk <= '1';
    state <= slave;


    when slave =>                               

    start_data <= '1';

    if cnt_addr < 8 then

    sda_data <= addr(cnt_addr);

    cnt_addr <= cnt_addr + 1;

    else

    cnt_addr <= 0;
    state <= ack;

    end if;

    when error_rd_wr =>             

    reset <= '1';

    when ack =>

    start_data <= '0';
    ack_error <= sda;

    if ack_error = '1' then         

    stop_clk <= '1';
    reset <= '1';

    else
    end if;

    if RD = '1' then                    



    elsif WR = '1' then             



    else                                    

    stop_clk <= '1';
    reset <= '1';

    end if;

    end case;

    end if;
    end process;



    sda <= sda_data when start_data = '1' else 'Z';

    scl <= i2c_clk when start_clk = '0' and stop_clk = '0' else 'Z';







    end MAIN;

Solution

  • A signal for synthesis can be driven from only one process or one continuous assign; for simulation multiple drivers are possible using resolved signals like std_logic.

    The scl and sda are driven both from the i2c_clock process and the continuous assign in the end of the file.

    The start_clk and stop_clk are driven both from the i2c_clock process and the other unnamed process.

    One possibility for scl and sda is to only drive these from the continuous assign, since synthesis tools often prefer tri-state output to be written like:

    q <= value when en = '1' else 'Z';