1 (edited by james_a_craig 2015-12-21 16:50:29)

Topic: [Solved] Bug in FPGA I2C slave in GPBB example

The example GPBB FPGA code has a bug where it slightly mangles the I2C bus - I think by tying the bus low when it's not being driven, although I can't see why as the IOBUF statement and constraints configuring it look right. Perhaps the level hold feature on the I/O pins on the Xilinx is stronger than the pullup on the board? I couldn't quickly see an obvious problem.

I noticed this because i2cdetect gives different answers before configuring the FPGA:

root@novena:/home/jamie/gpbb/novena-gpbb-example-master# i2cdetect -y 2
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- UU -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

and after:
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
10: 10 UU 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
20: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f

Bunnie's FPGA code explicitly instantiates an IOBUF to handle driving the I2C data signal, basically setting it up to either pull low or tristate at any given instant. The code for that looked OK, as did the code to switch between I2C_ACK_DADDR vs. I2C_WAITSTOP (i.e. send an acknowledge for the address vs. ignore someone else's address) so I'm not at all sure why this breaks.

Anyone already spotted and fixed this?

Re: [Solved] Bug in FPGA I2C slave in GPBB example

Found it. The I2C_DADDR's next state transition was slightly wrong, as it'd go into ACK_DADDR even if there was an address non-match. Since the ACK_DADDR state sets the pull-down on the I2C data line low, the result looks like an acknowledge to the iMX6. The quick and dirty fix is just to check the address when deciding on the next state from I2C_DADDR, rather than entering the ACK_DADDR state at all.

I2C_DADDR: begin // 8 bits to get the address
       I2C_nstate = ((I2C_bitcnt > 4'h7) && (SCL_cstate == SCL_FALL)) ?
        ( (I2C_daddr[7:1] == i2c_device_addr[7:1]) ? I2C_ACK_DADDR : I2C_WAITSTOP) : I2C_DADDR;
    end

This seems to do the trick and gives me the right output both for all other addresses and for directly accessing the FPGA.

Re: [Solved] Bug in FPGA I2C slave in GPBB example

Sweet! thanks for finding the bug and sharing the fix, very appreciated.

I'll be re-opening the GPBB project in the coming month and I'll pull your changes in then.