Hello,
I'm using this core in a Lattice ECP3 FPGA and noticed that the core reports Arbitration lost errors when accessing a slow I2C slave device. Further analysis showed that the core is checking the SDA line during writes when it releases SDA and SCL to high regardless if the SCL on the i2c bus is really high. According the I2C specification the data on the I2C bus is only valid during SCL is high on the bus. Slow I2C devices do hold the SCL line low and might drive the SDA line longer than necessary. Example: for an acknowledge a slow slave would set SDA to low then release SCL and some time after SCL is low again it would release SDA. To fix this problem I modified the code in a way that write arbitration lost is only checked when the SCL line is really high on the i2c bus. For this I changed for me the Verilog code of i2c_master_bit_ctl.v line 295 this way: al <= #1 (sSCL & sda_chk & ~sSDA & sda_oen) | (sto_condition & ~cmd_stop);
Best regards, Viktor
You've posted in the wrong section. This should have been a bug report.
I also see your fix seems to have been eaten by the editor.
Could you please post it again?
I have faced the same problem using the VHDL implementation. The fix I have applied consisted of adding the sSCL to the condition below (lines 390 and next in i2c_master_bit.vhd Instead of: if (c_state = idle) then ial <= (sda_chk and not sSDA and isda_oen) or (sto_condition and not cmd_stop); else ial <= (sda_chk and not sSDA and isda_oen); end if;
I've done: if (c_state = idle) then ial <= (sda_chk and not sSDA and isda_oen and sSCL ) or (sto_condition and not cmd_stop); else ial <= (sda_chk and not sSDA and isda_oen and sSCL ); end if;
Unfortunately it seems, that the editor destroys the code (probably interpreting it as HTML) <code> instead of: if (c_state = idle) then ial <= (sda_chk and not sSDA and isda_oen ) or (sto_condition and not cmd_stop); else ial <= (sda_chk and not sSDA and isda_oen); end if;
there should be: if (c_state = idle) then ial <= (sda_chk and not sSDA and isda_oen and sSCL ) or (sto_condition and not cmd_stop); else ial <= (sda_chk and not sSDA and isda_oen and sSCL ); end if; </code>
Sorry, it seems that it is impossible to enter the VHDL code without having it corrupted