I2C not stable when with NEO-M8N
zelll opened this issue · 4 comments
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
I can think of 2 scenarios where this change would help:
- slave performs clock stretching
- very weak pull-up on SCL
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?
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.
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.
PR now merged.