Forum Discussion

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

I2C core issue

Hello.

I want to use Wishbone I2C core from OpenCores in my Nios project. Trying to send a byte, i write 0xA2 byte to TxR and set STA and WR bits, the TIP flag asserts high and then never negates until reset. The problem as i see might be in custom Wishbone to Avalon-MM wrapper i use with the following assignments:


signal scl_i,scl_o,sda_i,sda_o,scl_oen,sda_oen:std_logic;
signal s_clock,s_reset_n,s_waitrequest_n,s_irq,s_chipselect,s_write,s_read:std_logic;
signal s_address:std_logic_vector(2 downto 0);
signal s_readdata,s_writedata:std_logic_vector(7 downto 0);
begin
	SDA<=sda_o when sda_oen='0' else sda_i;
	SCL<=scl_o when scl_oen='0' else scl_i;
	s_clock<=clock;
	s_reset_n<=reset_n;
	waitrequest_n<=s_waitrequest_n;
	s_chipselect<=chipselect;
	irq<=s_irq;
	s_write<=write;
	s_read<=read;
	s_address<=address;
	readdata<=s_readdata;
	s_writedata<=writedata;
	l1:i2c_master_top 
	port map(
		wb_clk_i=>s_clock,
		wb_rst_i=>'0',
		arst_i=>s_reset_n,
		wb_adr_i=>s_address,
		wb_dat_i=>s_writedata,
		wb_dat_o=>s_readdata,
		wb_we_i=>s_write and (not s_read),
		wb_stb_i=>s_chipselect,
		wb_cyc_i=>s_write or s_read,
		wb_ack_o=>s_waitrequest_n, 
		wb_inta_o=>s_irq,
		scl_pad_i=>scl_i,
		scl_pad_o=>scl_o,
		scl_padoen_o=>scl_oen,
		sda_pad_i=>sda_i,
		sda_pad_o=>sda_o,
		sda_padoen_o=>sda_oen
	);
end architecture;

According to wikipedia http://en.wikipedia.org/wiki/wishbone_(computer_bus) it should be ok. Is that I2C core bug or me doing somthing wrong?

5 Replies

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

    Should the SDA and SCL be driven with 'Z' in the else condition? Looks pretty straight forward otherwise. I've used that core in the past without any problems but not hooked up to Nios.

    The only thing that was a little strange to me before was how you set the clock rate. IIRC it was a generic. Is your clock the same as the default clock the core is expecting?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I'm using the OpenCores block with a Nios. The only thing that was required was to combine read and write to make the wb_stb signal and inverting wb_ack as the waitreq.

    The problem is more likely that the I2C signals should be tristated when output enable negates or else the core will never see the ack from the slave device.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    skaneta,

    clock rate iss not a generic; it's programmed into a configuration register -- you configure the division factor.

    CosworthRS,

    as other have pointed out, you have the SDA and SCL signals wrong.

    First, you should take the sda_i, sda_o and sda_oen signals to the FPGA top level. Common practice is not to have internal tri-state signals in FPGA designs.

    Secondly, the correct way to handle it is:

    sda_i <= SDA;

    SDA <= '0' when sda_o = '0' and sda_oen = '0' else 'Z';

    Rinse and repeat for SCL.

    This will get Quartus to infer an open drain configuration for the SDA and SCL pins.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    It seem to solve the tip latching problem, but still there are some arbitration issues. The piece of schematic:

    http://i41.tinypic.com/2h3a32d.png

    And the code:

    
    int i2c_init(int prescaler,void* isr,int BASE,int IRQ,int IRQ_ICID){
    	int res=1;
    	IOWR_16DIRECT(BASE,OC_I2C_PRER_LO,prescaler);
    	if(IORD_16DIRECT(BASE,OC_I2C_PRER_LO)==prescaler){
    		IOWR_8DIRECT(BASE,OC_I2C_CTR,0xC0);
    		if(IORD_8DIRECT(BASE,OC_I2C_CTR)==0xC0){
    			if(alt_ic_isr_register(IRQ_ICID,IRQ,isr,NULL,NULL)==0){
    				res=0;
    			}
    		}
    	}
    	return res;
    }
    static void i2c_isr(void *context){
    	printf("Status register: %d\n",IORD_8DIRECT(I2C_BASE,OC_I2C_SR));
    	IOWR_8DIRECT(I2C_BASE,OC_I2C_CR,0x01);
    }
    int main()
    {
    	if(i2c_init(PreSC,(void*)i2c_isr,I2C_BASE,I2C_IRQ,I2C_IRQ_INTERRUPT_CONTROLLER_ID)==0){
    		IOWR_8DIRECT(I2C_BASE,OC_I2C_TXR,0x80);		//write slave address+write bit
    		IOWR_8DIRECT(I2C_BASE,OC_I2C_CR,0x90);			//set STA, set WR
    		IOWR_8DIRECT(I2C_BASE,OC_I2C_TXR,0x02);		//write subaddr
    		IOWR_8DIRECT(I2C_BASE,OC_I2C_CR,0x10);			//set WR
    		IOWR_8DIRECT(I2C_BASE,OC_I2C_TXR,0x81);		//write addr+read bit
    		IOWR_8DIRECT(I2C_BASE,OC_I2C_CR,0x90);		//set WR, set STA
    		IOWR_8DIRECT(I2C_BASE,OC_I2C_CR,0x68);		//set NACK, set STO, SET RD
    		printf("RxD=%d\n",IORD_8DIRECT(I2C_BASE,OC_I2C_RXR));
    	}else{
    		printf("I2C init fail!\n");
    	}
    	return 0;
    }

    Right after i register the ISR, the arbitration lost occures (once). Then not a single acknowledgement from slave (ADV7180) proceed.