FPGA Intellectual Property
PCI Express*, Networking and Connectivity, Memory Interfaces, DSP IP, and Video IP

I2C core issue

Altera_Forum
Honored Contributor II
1,305 Views

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?
0 Kudos
5 Replies
Altera_Forum
Honored Contributor II
322 Views

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?
0 Kudos
Altera_Forum
Honored Contributor II
322 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
322 Views

you can get this component premade in the nios linux git repo. 

 

git clone git://sopc.et.ntust.edu.tw/git/openip.git
0 Kudos
Altera_Forum
Honored Contributor II
322 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
322 Views

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.
0 Kudos
Reply