OpenCores
Issue List
Arbitration lost for slow I2C slaves #39
Open viktor_bergen opened this issue over 5 years ago
viktor_bergen commented over 5 years ago

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

a1exh commented over 5 years ago

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?

wzab commented over 4 years ago

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;

wzab commented over 4 years ago

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>

wzab commented over 4 years ago

Sorry, it seems that it is impossible to enter the VHDL code without having it corrupted


Assignee
No one
Labels
Request