Skip to content

Try to fix bootloop#566

Merged
JF002 merged 3 commits intoInfiniTimeOrg:developfrom
Riksu9000:unblock_i2c
Aug 14, 2021
Merged

Try to fix bootloop#566
JF002 merged 3 commits intoInfiniTimeOrg:developfrom
Riksu9000:unblock_i2c

Conversation

@Riksu9000
Copy link
Contributor

If the device is reset while the i2c bus is used, the bus can get blocked. I suspect this might be what is causing the bootloop issue. Here I implemented code to attempt to unblock the bus. I don't know if this will actually fix the issue.

Bootloop issue #317

https://www.i2c-bus.org/i2c-primer/analysing-obscure-problems/blocked-bus/

@hubmartin
Copy link
Contributor

Hi, I did not studied #317 but I just wanted to add my 2c

We had similar issues with NRF52. We believe that some sensor was also stuck holding data line low. And your code seems very similar to ours, so I just paste it here for reference. This is part of our i2c_init function.

    // I2C declocking issue
    nrf_gpio_cfg_input(PIN_SDA, NRF_GPIO_PIN_PULLUP);

    int i = 0;

    while (nrf_gpio_pin_read(PIN_SDA) == 0)
    {
        nrf_gpio_cfg_output(PIN_SCL);
        nrf_gpio_pin_clear(PIN_SCL);
        os_task_delay(2);
        nrf_gpio_cfg_input(PIN_SCL, NRF_GPIO_PIN_PULLUP);
        os_task_delay(2);

        if (++i > 100)
        {
            log_error("I2C: Declocking failed");

            NVIC_SystemReset();
        }
    }

@hubmartin
Copy link
Contributor

I just was debugging my stuff, flashing like a every few minutes. In some point firmware freezed. I could run the code but I did not investigated what was the reason. I flashed many times firmware but with no luck. The screen was always black.
So I tried this PR and it instantly started working! Perfect.

@JF002 JF002 added this to the Version 1.4 milestone Aug 11, 2021
@JF002 JF002 merged commit 7c28de0 into InfiniTimeOrg:develop Aug 14, 2021
@hubmartin
Copy link
Contributor

@Riksu9000 Hi, I noticed during development and watch resets in-the-middle of I2C communication, that sometimes the screen is not responding and some sensor is stuck. I was able to fix it by at least 2 reboots. So I think we should toggle more bits. Since toggling 16 times actually sends 8 bits, but the sensor which is stuck obviously needs much more toggling.
What is your option of adding more toggles, or adding them even more but checking when the SDA/SCL will be back to logical 1 like I showed sample code above? (not sure I could discuss it here or open another issue/PR?)
Thanks

@Riksu9000
Copy link
Contributor Author

Reading SDA won't work because it will break from the loop early if in the middle of the byte there is a 1. I'm not familiar with i2c, but from what I've read, some people toggle less and some people toggle more "just in case". Every 8 bits the receiving device must acknowledge. When we manually toggle bits, we don't acknowledge the transmission and the sending device should give up. 16 toggles was mentioned in the link I posted.

With #568 merged, #583 issue behaviour changes so it doesn't freeze, but the screen might be black or show glitches, so I wonder if what you're experiencing is related to that.

@Riksu9000 Riksu9000 deleted the unblock_i2c branch August 19, 2021 08:40
@hubmartin
Copy link
Contributor

Reading SDA won't work because it will break from the loop early if in the middle of the byte there is a 1.

Not true. That's exactly what we need. We need to get SDA to 1 which is forced by pull-up, the stop toggling. I2C packet is not synchronized by some number of transfered bits, but the I2C start condition.
https://www.esacademy.com/en/library/technical-articles-and-documents/miscellaneous/i2c-bus/i2c-bus-events/start-and-stop-conditions.html

That's how code above works. If you release (only weak pull-up is pulling it high) the SDA you can issue start condition and all the I2C slaves starts listening for address match.

However today I had I2C stuck on my P8. No matter how many times I rebooted clock the SCL & SDA was in really weird state. On SCL I couldn't see any clocks, it was in logic hight. SDA was in logic low with some small 200 mV pulses every 100 ms.

image

The P8 has different accelerometer which I blame for this, because with connected battery I removed touch controller and it behaved the same, then I removed the heart rate sensor, it was the same. So I blame accelerometer SC7a20 for that.

This completely frozen I2C didnt happened on the PineTime. It always fixed somehow after 2-3 reboots. So with that condition on realeased SDA we wouldn't need to reboot Pine more than once to get I2C to proper state.

@Riksu9000
Copy link
Contributor Author

Are you sure the chips will listen to start and stop conditions during transfer? The link you posted doesn't completely verify that start would always be received, but stop probably is. Then why would everyone offer toggling the clock line as the solution if it wasn't a good solution? To me toggling the clock seems like the least effort to clear any leftover bits.

But if you can prove that this solution isn't good enough then please open a new PR.

@hubmartin
Copy link
Contributor

I'm using I2C looong enough to be sure.
The start and stop condition is the only time the SDA line is chaning when SCL is high.
During normal transfer you change SDA only when SCL is low.

So this is very easily implemented in the chips.

image

First I have to get PineTime to the I2C crash state, then investigate it with debugger and logic analyzer. But its hard to say when when it happens very infrequently. Then the PR will be on the way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants