Shop OBEX P1 Docs P2 Docs Learn Events
Question About I2C Start() — Parallax Forums

Question About I2C Start()

I've been studying the I2C standard and I know that to issue a start() command the SCL must be HIGH. My question is how long should I wait for the SCL to go high before aborting my attempt at a start() command and returning an error?

Comments

  • If SCL is begin pulled low then that is part of the bus arbitration but this wouldn't normally happen at this point, it normally happens only when you "select" it, that is issue the start condition followed by the address, and then only if the device needs to hold the bus, which is not normal for most devices either.
    So timeout is more device specific and if the SCL is being pulled low then there is normally nothing you can do about it anyway, other than to abort in some device dependent manner.
    Which device are you talking to?
  • Cluso99Cluso99 Posts: 18,066
    Usually the SCL and SDA lines are pulled high via 10K resistors. Most? Parallax pcbs don’t have a pull-up on SCL and rely on this pin being driven.

    Are you sure there is a pull down.
  • Actually, let me clarify that the I2C bus is working as expected under nominal conditions. I'm investigating a failure scenario I discovered by accident. I accidently disconnected the slave's Vdd and my application froze. What I discovered was the I2C driver's start() command was waiting for the SCL to go high. Because the slave device had pull-up resistors but no Vdd it was [basically] holding the SCL low and the driver was now in an infinite [waiting] loop. Nothing I've read discusses this type of failure mode. I was thinking there might be a 'timeout' period where the master would give up and report an bus error but I don't see one.

    I could just put the I2C calls in a separate cog and periodically poll the cog. If it becomes nonresponsive I could stop the cog and report a failure on the I2C bus.
  • You're not showing the code that you're using, but my P1 object would be have the same way.
    pub start
    
    '' Create I2C start sequence
    '' -- will wait if I2C bus SCL pin is held low
    
      dira[sdapin] := 0                                             ' float SDA (1)
      dira[sclpin] := 0                                             ' float SCL (1)
    
      waitpeq(sclmask, sclmask, 0)                                  ' allow "clock stretching"
    
      dira[sdapin] := 1                                             ' SDA low (0)
      dira[sclpin] := 1                                             ' SCL low (0)
    

    As you've demonstrated a potential failure mode in your system, you might want to modify your code to verify that SDA is high -- the slave should release the SDA line after providing its final data bit in a read command. If I were to add a return value, I might do it like this:
    pub start
    
    '' Create I2C start sequence
    '' -- will wait if I2C bus SCL pin is held low
    
      dira[sdapin] := 0                                             ' float SDA (1)
      dira[sclpin] := 0                                             ' float SCL (1)
    
      if (ina[sdapin] == 0)
        return false
    
      waitpeq(sclmask, sclmask, 0)                                  ' allow "clock stretching"
    
      dira[sdapin] := 1                                             ' SDA low (0)
      dira[sclpin] := 1                                             ' SCL low (0)
    
      return true
    
  • However pullups always need to be on the master anyway.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2020-09-25 01:49
    Cluso99 wrote:
    Usually the SCL and SDA lines are pulled high via 10K resistors.
    I think 4.7K is more standard for a 5V bus. I might even go lower than that for a 3.3V bus. 10K -- especially on a 3.3V bus -- is pretty wimpy. It's all about rise time.

    -Phil
  • @JonnyMac I'm actually using your P2 object and thank you, by the way. It's made my things a lot easier. I didn't want to open an issue until I was sure I actually had a problem. The slave I'm using is Micro Crystal's RTC, RV-3028-C7, development board and it has its own pullups. Should I also have pullups on the P2's pins? JonnyMac's driver has that option. My test code is very simple:

    con

    scl_pin = 8
    sda_pin = 9
    khz = 100

    obj

    i2c : "jm_i2c"

    PUB go() | result

    i2c.setup(scl_pin, sda_pin, khz, {pullup} i2c.PU_NONE)

    result := i2c.present($A5)

    if result
    PINL(56)
    else
    PINL(57)

    repeat

    I guess the bottom line is: I didn't expect the driver to go into an infinite loop if I loss power to the slave. I guess I was expected i2c.present($A5) to return false, but I don't see how that could be implemented without a timeout spec. I guess I could add pullups on the P2's pins and see what that buys me. I should have also tried JonnyMac's scanner code. I'll do both of those tonight if I get a chance.

    BTW, where is it documented that the P2's EVAL LEDs are active low? This was a head scratcher for a bit.
  • I don't think it's valid for any device to keep the scl low after.a transfer and according to the spec this stretching is only legal during the transfer iirc. I never check on a start condition, but the address ack is checked until the device is ready, so there is a timeout there especially for eeprom programming. The clock may be stretched by a device if a read is requested but the data is not yet available. However the rv3028 will never stretch the clock and I have tested it to over 3MHz speeds. Btw, I favour pull-ups as low as 1k as there is no problem with even much lower values but 1k is sufficient for high speed transfers. 10k is fine for very short lengths and know speeds.
  • JonnyMacJonnyMac Posts: 8,912
    edited 2020-09-25 02:45
    I guess the bottom line is: I didn't expect the driver to go into an infinite loop if I loss power to the slave.
    It's a choice I make: assume the circuit is working. It is my opinion that if one gets wrapped around the axle attempting to fend off every potential failure mode one will not have time to get any real work done. Now... if your device is going into a hospital on on a spaceship, you'll have a different set of criteria (and probably not be using my general-purpose drivers).

    After thinking about it, there's no reason to modify the I2C object. If losing power to a device on your bus is a possible problem, you can easily check the bus pins before entering into any I2C sequences. Both pins should be high. Something like this, perhaps:
      if (pinread(SCL_PIN addpin 1) <> %11)
        ' Houston, we have a problem
    
  • I agree. The object is fine. After reviewing the numerous problems and errors with the I2C bus, it's apparent there's no solution in the protocol. I like the pin check. Thanks. Your pun is funny considering I live just a few blocks from the Johnson Space Center. Unfortunately that's the world or rather "Space" I came from, where our three top concerns were: (1) Don't kill the crew, (2) Don't lose the vehicle, (3) Don't fail the mission. It's a difficult mindset to overcome. Thanks for all the help.
  • The development board uses 10K pullups. I'm using it at 3V3 but it can go as high as 5.5v. It works fine as long as you power it.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2020-09-25 06:23
    Unless I am designing a general-purpose be-all end-all driver, I do not worry about clock stretching. However even when you have the rare chip that may stretch the clock, even then it will only do it in-between a byte transfer, not during, and not only when it is selected. If I did a general-purpose routine I would at least allows the use of blocking and non-blocking calls or simply tie that in so that specific addresses which are known to stretch the clock, will test for clock stretching. Otherwise clock-stretching is unusual and non of my designs ever require it.

    Some excerpts from I2C Spec rev 6
    Table 2. Clock stretching is a feature of some slaves. If no slaves in a system can stretch the clock (hold SCL LOW),
    the master need not be designed to handle this procedure.

    3.1.1 For a single master application, the master’s SCL output can be a push-pull driver design
    if there are no devices on the bus which would stretch the clock.
    (my note: this means no pull-up required - so P1 EEPROM only systems don't really need it)

    3.1.9 Clock stretching
    Clock stretching pauses a transaction by holding the SCL line LOW. The transaction
    cannot continue until the line is released HIGH again. Clock stretching is optional and in
    fact, most slave devices do not include an SCL driver so they are unable to stretch the
    clock.

  • The main i2c device that I use with clock hold is the Sensirion SHT31 RHT sensor. That sensor also has a non-hold option, nevertheless, the hold mechanism is convenient for simple code and fast response. Also, I'm recalling an OMRON thermal array sensor where clock hold was obligatory. And the MAX11617, a burst mode ADC. Others too, where the clock stretch allowed an internal conversion process to take place and to release the hold immediately when finished.

    I put the hold timeout in Spin i2c code as follows with a timeout.
    PRI Hold | ticks
    ' this implements clock hold, with a timeout
    ' this method called from read and write only if scl is found to be low after master releases it
      ticks := cnt + maxHoldTicks.    ' default maxholdticks amounts to 10ms
      repeat until (ina[scl]==1) or (cnt - ticks > 0)
    

    The check for high levels on sda and scl is also a good idea, certainly as a part of the initialization, as well as a quick "hello" scan to verify that the expected devices are present on the bus. If multiple cogs are going to access one i2c bus, then something by design has to insure that they will not access and collide.
Sign In or Register to comment.