espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.8k stars 7.31k forks source link

I2C spikes on master init #393

Closed berkutta closed 7 years ago

berkutta commented 7 years ago

I'm using a own function names "i2c_master_init()" to initialize the i2c subsystem on the ESP32. After calling this function I get pulses/spikes on SDA/SCL which some Slaves interprets as an "START". This behaviour results in errors on later real "START"'s which prevents to directly use those Slaves. A workaround is to make a dummy request to those Slaves ("START", WRITE ADDRESS", "STOP")

My hardware consists of no external Pullups. I've used the Sparkfun ESP32 Thing together with an MPU-6050. I was able to reproduce the same Issue with a HTU21D Sensor.

My function "i2c_master_init()" consists of the following startup tasks:

void i2c_master_init()
{
    int i2c_master_port = I2C_MASTER_NUM;
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = I2C_MASTER_SDA_IO;
    conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
    conf.scl_io_num = I2C_MASTER_SCL_IO;
    conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
    conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
    i2c_param_config(i2c_master_port, &conf);
    i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}

My sequence to make those "dummy" requests is the following:

i2c_cmd_handle_t cmd_ping = i2c_cmd_link_create();
i2c_master_start(cmd_ping);
i2c_master_write_byte(cmd_ping, (0x68 << 1) | WRITE_BIT, ACK_CHECK_DIS);
i2c_master_stop(cmd_ping);
int ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd_ping, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd_ping);

After this "dummy" sequence I can normally talk to the slave device:

i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (0x68 << 1) | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, 0x6B, ACK_CHECK_EN);
i2c_master_write_byte(cmd, 0x00, ACK_CHECK_EN);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);

On this image you can see an overview of the spike (Trigger point) and the followed byte write's: ds1z_quickprint10

Here is a closeup of the spike: ds1z_quickprint11

This is a closeup of the "dummy" request + data write. You can clearly see that on the "dummy" request the sensor doesn't work properly (confused state machine due to the spike) and afterwords work perfectly with it's address: ds1z_quickprint12

costaud commented 7 years ago

Thanks for the very clear description. I think it might be related to "no external Pullups", I will try to look into this.

berkutta commented 7 years ago

I tried to reproduce this issue with strong Pullups on SDA and SCL (1kOhm). Exactly the same behaviour. I've even tried to use a Ferrite bead between ESP32 and Sensor on both lines. This helped in some situatons on the ESP8266. But no luck on the ESP32..

costaud commented 7 years ago

Add set level code in i2c_set_pin can fix the issue. Trying to merge to idf ASAP.

esp_err_t i2c_set_pin(i2c_port_t i2c_num, gpio_num_t sda_io_num, gpio_num_t scl_io_num, gpio_pullup_t sda_pullup_en, gpio_pullup_t scl_pullup_en, i2c_mode_t mode)
{
    .......
    if (sda_io_num >= 0) {
        gpio_set_level(sda_io_num, 1);
        PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[sda_io_num], PIN_FUNC_GPIO);
        ......
    }
    if (scl_io_num >= 0) {
        gpio_set_level(scl_io_num, 1);
        PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[scl_io_num], PIN_FUNC_GPIO);
        .......
    }
    ......   
}