Forum Discussion

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

Simulating the I2C Controller

Hello Everyone,

I am trying to simulate the I2C controller, but have problem as there is no slave to generate the acknowlege back.

Can Anyone tell me how to get around this.

Thanks in advance, and sorry if my question is a bit silly.

thanks in advance.

8 Replies

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

    It's not clear if "the I2C controller" refers to a particular example design. But for a full simulation, you should add a slave model to your testbench.

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

    hello sir, and thanks for your quick response.

    Yes I am trying to use the microphone to speak into the de2 board. so i need to create a controller(Master) in VHDL to control the slave(wm8731).

    Accordings the latter's data sheet, using a two wire transfer i need to send 3 bytes of codes, starting by: a start condition --> address of the slave --> ack(from the slave) --> register address --> ack (from the slave)--> data control--> ack(from the slave)-->stop condition.

    To do this i developed and FSM, that is going generates the proper clk and data signals.

    --> it specifies the start and stop conditions

    --> i created to counters to keep track of teh number of bits and bytes sent, and another one to divide the clk.

    --> to meet the timing requirements I divided cetain states to 2/3 states.

    --> since the sdin is bidirectional and open drain, to output logic one on the line it needs to be set to high impedence as follows

    sdin <= ‘z’ when sdin01 =’1’ else ‘0’

    I think my code is okay, but i don't know how to simulate the acknowledgement from the slave.

    Should you be familiar with this protocol, please kindly advice me.

    Best Regards.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Of course noone will know, what is causing the shown waveforms without seeing the code.

    Apparently you are simulating in Quartus built-in simulator. This means, that a testbench with I2C slave model isn't an option. In this case, driving the SDA line low at a precalculated time and releasing it afterwards is the only way to simulate the slave's ACK response.

    Seriously speaking, this kind of simulations demands for a full-featured simulator like Modelsim.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Definately doable in Modelsim. It can run Testbed scripts, which is where you bring in the entity that needs testing - then simulate whatever response the I2C would give.

    In my case I needed some MDIO response at 38527 ns.

    Here's one I just used myself:

    library IEEE; 
    use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_UNSIGNED.all;
    entity device_testbench is
    end;
    architecture test of device_testbench is
     component device is
    	PORT (
    		CLOCK_50			: IN 		STD_LOGIC;			-- 50 MHz
    		KEY				: IN		STD_LOGIC_VECTOR(3 downto 0);
    		SW 				: IN 		STD_LOGIC_VECTOR(17 downto 0);
    		LEDG				: OUT 	STD_LOGIC_VECTOR(7 downto 0);
    		LEDR				: OUT 	STD_LOGIC_VECTOR(17 downto 0);
    		LCD_RS, LCD_EN	: OUT		STD_LOGIC;
    		LCD_RW			: OUT		STD_LOGIC;
    		LCD_ON			: OUT		STD_LOGIC;
    		LCD_DATA			: INOUT	STD_LOGIC_VECTOR(7 DOWNTO 0);
    		ENET0_RST_N		: OUT		STD_LOGIC;
    		ENET0_MDC		: OUT		STD_LOGIC;
    		ENET0_MDIO 		: INOUT	STD_LOGIC;
    		ENET0_RX_CLK	: IN		STD_LOGIC;
    		ENET0_RX_DV		: IN		STD_LOGIC;
    		ENET0_RX_ER		: IN		STD_LOGIC;
    		ENET0_RX_CRS	: IN		STD_LOGIC;
    		ENET0_RX_COL	: IN		STD_LOGIC;
    		ENET0_RX_DATA	: IN		STD_LOGIC_VECTOR(3 DOWNTO 0);
    		ENET0_INT_N		: IN		STD_LOGIC		
        );
     end component;
      SIGNAL CLOCK_50			: STD_LOGIC;			-- 50 MHz
      SIGNAL KEY				: STD_LOGIC_VECTOR(3 downto 0);
      SIGNAL SW 				: STD_LOGIC_VECTOR(17 downto 0);
      SIGNAL LEDG				: STD_LOGIC_VECTOR(7 downto 0);
      SIGNAL LEDR				: STD_LOGIC_VECTOR(17 downto 0);
      SIGNAL LCD_RS, LCD_EN	: STD_LOGIC;
      SIGNAL LCD_RW			: STD_LOGIC;
      SIGNAL LCD_ON			: STD_LOGIC;
      SIGNAL LCD_DATA			: STD_LOGIC_VECTOR(7 DOWNTO 0);
      SIGNAL ENET0_RST_N		: STD_LOGIC;
      SIGNAL ENET0_MDC		: STD_LOGIC;
      SIGNAL ENET0_MDIO 		: STD_LOGIC;
      SIGNAL ENET0_RX_CLK	: STD_LOGIC;
      SIGNAL ENET0_RX_DV		: STD_LOGIC;
      SIGNAL ENET0_RX_ER		: STD_LOGIC;
      SIGNAL ENET0_RX_CRS	: STD_LOGIC;
      SIGNAL ENET0_RX_COL	: STD_LOGIC;
      SIGNAL ENET0_RX_DATA	: STD_LOGIC_VECTOR(3 DOWNTO 0);
      SIGNAL ENET0_INT_N		: STD_LOGIC;
    begin
      -- instantiate device to be tested
      device0: 	device 	port map(CLOCK_50, KEY, SW, LEDG, LEDR, LCD_RS, LCD_EN, LCD_RW, LCD_ON, LCD_DATA, 
    											ENET0_RST_N, ENET0_MDC, ENET0_MDIO, ENET0_RX_CLK, ENET0_RX_DV, ENET0_RX_ER, ENET0_RX_CRS, ENET0_RX_COL, ENET0_RX_DATA, ENET0_INT_N);
      -- Generate 50 MHz clock, 20 ns cycle
      process begin
        CLOCK_50 <= '1';
        wait for 10 ns; 
        CLOCK_50 <= '0';
        wait for 10 ns;
      end process;
      -- Operate switch
      process begin
        sw(17) <= '1';
        wait for 100 ns;
        sw(17) <= '0';
        wait;
      end process;
      
      -- MDIO Output from PHY chip
      process begin
        ENET0_MDIO <= 'Z';
        wait for 38527 ns; -- This is where we simulate response from the PHY
        report ("Faking PHY response");
        ENET0_MDIO <= '0';
        wait for 400 ns;
        ENET0_MDIO <= '1';
        wait for 400 ns;
        ENET0_MDIO <= '0';
        wait for 400 ns;
        ENET0_MDIO <= '0';
        wait for 400 ns;
        ENET0_MDIO <= '1';
        wait for 400 ns;
        ENET0_MDIO <= '0';
        wait for 400 ns;
        ENET0_MDIO <= '0';
        wait for 400 ns;
        ENET0_MDIO <= '0';
        wait for 400 ns;
        ENET0_MDIO <= '1';
        wait for 400 ns;
        ENET0_MDIO <= '0';
        wait for 400 ns;
        ENET0_MDIO <= '1';
        wait for 400 ns;
        ENET0_MDIO <= '0';
        wait for 400 ns;
        ENET0_MDIO <= '0';
        wait for 400 ns;
        ENET0_MDIO <= '0';
        wait for 400 ns;
        ENET0_MDIO <= '0';
        wait for 400 ns;
        ENET0_MDIO <= '1';
        wait for 400 ns;
        ENET0_MDIO <= 'Z';
        report ("Done faking PHY response");
        wait;
      end process;
      
    end;
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thank you very much for you answers, they were definitly helpful.

    I tried driving the sda line low, at the required time, and the controller seems to work fine.

    I am not familiar with testbenches however, and I am running out of time. could you please guide me to a good and quick tutorial.

    Thanks you for you help and time.