I2C with spin: Actively Driving SDA (probable rehash)
tomcrawford
Posts: 1,129
in Propeller 1
I am fiddling with the HT16K33 16 by 8 LED controller. It has an I2C interface. I downloaded Mike Green's Basic I2C Driver . I used I2CStart, I2CStop, and I2CWriteByte. Here is the WriteByte snippet.
The screen grab ActiveHighSDA shows writing data to a LED. The slave address is $E0, the register address is 0, and the data written is $2120 (a nonsense glyph). Everything looks great; got ACKs, Start, Stop. And it functions just fine. Stuff shows up on the LEDs just like it should. But look a little closer (BusCrash.jpg) After the eight data bit of the $21 byte, there is 8.6 (or so) microseconds of the SDA line being about half high.
I believe what's happening is this: The slave device is driving SDA LOW (ACK) while the propellor is still driving SDA HIGH (the "1" in $21). Looking at the snippet above, spin cannot execute the dira[SDA]~ instantly after making the clock LOW. Now, is this really a problem? I think it would shorten the life of the two opposing output stages, and would cause some RFI.
The fix is really simple; be sure there is a pullup on SDA and only ever drive it LOW. Here is a modified WriteByte:
OpenCollSDA.jpg shows the bus with this code.
PUB I2cWriteByte(data)
data <<= 24 'align first bit
repeat 8
outa[SDA] := (data <-= 1) & 1 'send one bit, msb first
outa[SCL]~~
outa[SCL]~
dira[SDA]~ 'allow ack bit
outa[SCL]~~ 'ignore ack bit
outa[SCL]~
outa[SDA]~
dira[SDA]~~
The screen grab ActiveHighSDA shows writing data to a LED. The slave address is $E0, the register address is 0, and the data written is $2120 (a nonsense glyph). Everything looks great; got ACKs, Start, Stop. And it functions just fine. Stuff shows up on the LEDs just like it should. But look a little closer (BusCrash.jpg) After the eight data bit of the $21 byte, there is 8.6 (or so) microseconds of the SDA line being about half high.
I believe what's happening is this: The slave device is driving SDA LOW (ACK) while the propellor is still driving SDA HIGH (the "1" in $21). Looking at the snippet above, spin cannot execute the dira[SDA]~ instantly after making the clock LOW. Now, is this really a problem? I think it would shorten the life of the two opposing output stages, and would cause some RFI.
The fix is really simple; be sure there is a pullup on SDA and only ever drive it LOW. Here is a modified WriteByte:
PUB I2cWriteByte(data) 'modified to not drive SDA HIGH
'assumes it is driving SDA LOW when enters
data <<= 24 'align first bit
repeat 8
if ((data <-= 1) & 1) == 0 'extract one bit, msb first
dira[SDA]~~ 'drive it low
else
dira[SDA]~ 'pullup pulls high
outa[SCL]~~
outa[SCL]~
dira[SDA]~ 'allow ack bit
outa[SCL]~~ 'ignore ack bit
outa[SCL]~
outa[SDA]~
dira[SDA]~~
OpenCollSDA.jpg shows the bus with this code.

Comments
-Phil
Thanks.