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.