Forum Update - Announcement about May 10th, 2018 update and your password.

I2C with spin: Actively Driving SDA (probable rehash)

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.
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.




Re-inventing the wheel is not a waste of time if, when you are done, you understand why it is round.
Cool, CA, USA 95614
1202 x 684 - 88K
1202 x 684 - 85K
1202 x 684 - 88K

Comments

  • 3 Comments sorted by Date Added Votes
  • The fix is really simple; be sure there is a pullup on SDA and only ever drive it LOW.
    Yes, that's the correct way to do it. Keep OUTA low, put a pull-up on SDA, and modulate SDA via DIRA.

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • I've attached my HT16K33 driver -- it may be helpful to compare files. I also have derivative objects for Adafruit displays (7-segment and 14-segment) if you're interested.
    Jon McPhalen
    Hollywood, CA
    It's Jon or JonnyMac -- please do not call me Jonny.
  • JonnyMac wrote: »
    I've attached my HT16K33 driver

    Thanks.

    Re-inventing the wheel is not a waste of time if, when you are done, you understand why it is round.
    Cool, CA, USA 95614
Sign In or Register to comment.