nodemcu / nodemcu-firmware

Lua based interactive firmware for ESP8266, ESP8285 and ESP32
https://nodemcu.readthedocs.io
MIT License
7.65k stars 3.12k forks source link

I2C not stable when with NEO-M8N #1586

Closed zelll closed 7 years ago

zelll commented 7 years ago

Expected behavior

Read/Write correctly

Actual behavior

SCL signal does not go up immediately sometime (maybe M8N does not release SCL).

I tried add a while loop to check SCL after set SCL to high in i2c_master_setDC(). It resolves the problem.

LOCAL void ICACHE_FLASH_ATTR
i2c_master_setDC(uint8 SDA, uint8 SCL)
{
    uint8 sclLevel;

    SDA &= 0x01;
    SCL &= 0x01;
    m_nLastSDA = SDA;
    m_nLastSCL = SCL;

    if ((0 == SDA) && (0 == SCL)) {
        I2C_MASTER_SDA_LOW_SCL_LOW();
    } else if ((0 == SDA) && (1 == SCL)) {
        I2C_MASTER_SDA_LOW_SCL_HIGH();
    } else if ((1 == SDA) && (0 == SCL)) {
        I2C_MASTER_SDA_HIGH_SCL_LOW();
    } else {
        I2C_MASTER_SDA_HIGH_SCL_HIGH();
    }
    if(1 == SCL) {
        do {
            sclLevel = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO));
        } while(sclLevel == 0);
    }
}

Test code

Code below prints wrong result from time to time

i2c.setup(0, 4, 5, i2c.SLOW)

M8U = 0x42

tmr.register(0, 100, tmr.ALARM_AUTO, function()
    i2c.start(0)
    has = i2c.address(0, M8U, i2c.TRANSMITTER)
    i2c.write(0, 0xFD)
    i2c.start(0)
    i2c.address(0, M8U, i2c.RECEIVER)
    c = i2c.read(0, 2)
    cnt = c:byte(1) * 256 + c:byte(2)
    i2c.stop(0)

    print(has, cnt, encoder.toHex(c))
end)
tmr.start(0)

NodeMCU version

1.5.4.1-master_20161001

Hardware

NodeMCU U-blox NEO-M8N GPS module

devsaurus commented 7 years ago

I can think of 2 scenarios where this change would help:

Can you please check which one applies to your hardware setup? I.e. does the NEO-M8N use clock stretching and which resistance have your pull-ups?

zelll commented 7 years ago

https://www.u-blox.com/sites/default/files/NEO-M8-FW3_DataSheet_%28UBX-15031086%29.pdf 4.5 DDC timing diagrams The DDC interface is I2C Fast Mode compliant. For timing parameters consult the I2C standard. The maximum bit rate is 400 kb/s. The interface stretches the clock when slowed down when serving interrupts, so real bit rates may be slightly lower.

Yes, it stretches the clock. I use 2.2K to pull-up (even tried 1K). I tried to slow down i2c with #define i2c_master_wait(us) os_delay_us(5*us), (maybe) improved, but not resolve completely.

pjsg commented 7 years ago

Your code change looks as though it would solve the clock stretching problem. I'm slightly nervous that it can loop infinitely. However, all that i2c code seems to ignore problems, so maybe it is OK. The watchdog will kill it anyway and restart the platform if something goes wrong.

Please submit a PR with your change.

pjsg commented 7 years ago

PR now merged.