]> granicus.if.org Git - esp-idf/commitdiff
1. Slow down I2C to 100khz During Reset
authorchuck todd <stickbreaker@users.noreply.github.com>
Sun, 30 Sep 2018 20:47:05 +0000 (14:47 -0600)
committermorris <maoshengrong@espressif.com>
Fri, 30 Nov 2018 02:08:28 +0000 (10:08 +0800)
I am stealing this delay coding from @jeremyherbert #2493 pr.

2. Change Bus Reset to handle interrupted READ sequences.

The current code does not handle interrupted READ cycles.

 If a SLAVE device was in a read operation when the bus was interrupted, the SLAVE device is controlling SDA.

The only bit during the 9 clock cycles of a byte READ the MASTER(ESP32) is guaranteed control over, is during the ACK bit period.

If the SLAVE is sending a stream of ZERO bytes, it will only release SDA during the ACK bit period. The master(ESP32) cannot generate a STOP unless SDA is HIGH.

So, this reset code synchronizes the bit stream with, Either, the ACK bit, Or a 1 bit.

3. fix typo

correct `sda_id` to `sda_io` in `i2c_master_clear_bus()` @ryan-ma found it.  This typo was generated when I manually edited this patch on GitHub, I should have done a Copy/Paste operation!

components/driver/i2c.c

index b329a500808d2081af766d3d125bf2e0b3d5bb9e..d268eaab271dc3534b1afb29917a018d135d85b7 100644 (file)
@@ -537,27 +537,29 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
     int sda_io = GPIO.func_in_sel_cfg[sda_in_sig].func_sel;
     I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(scl_io)), I2C_SCL_IO_ERR_STR, ESP_ERR_INVALID_ARG);
     I2C_CHECK((GPIO_IS_VALID_GPIO(sda_io)), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG);
-    // We do not check whether the SDA line is low
-    // because after some serious interference, the bus may keep high all the time and the i2c bus is out of service.
     gpio_set_direction(scl_io, GPIO_MODE_OUTPUT_OD);
     gpio_set_direction(sda_io, GPIO_MODE_OUTPUT_OD);
-
+    // If a SLAVE device was in a read operation when the bus was interrupted, the SLAVE device is controlling SDA.
+    // The only bit during the 9 clock cycles of a READ byte the MASTER(ESP32) is guaranteed control over is during the ACK bit
+    // period. If the slave is sending a stream of ZERO bytes, it will only release SDA during the ACK bit period.
+    // So, this reset code needs to synchronize the bit stream with, Either, the ACK bit, Or a 1 bit to correctly generate
+    // a STOP condition.
     int scl_half_period = 5; // use standard 100kHz data rate
+    gpio_set_level(scl_io, 0);
     gpio_set_level(sda_io, 1);
     ets_delay_us(scl_half_period);
-    gpio_set_level(scl_io, 1);
-    ets_delay_us(scl_half_period);
-    for (int i = 0; i < 9; i++) {
-        gpio_set_level(scl_io, 0);
-        ets_delay_us(scl_half_period);
+    int i=0;
+    while( !gpio_get_level(sda_io) && (i<9)){ // cycle SCL until SDA is HIGH
         gpio_set_level(scl_io, 1);
         ets_delay_us(scl_half_period);
+        gpio_set_level(scl_io, 0);
+        ets_delay_us(scl_half_period);
+        i++;
     }
-    gpio_set_level(sda_io, 0); // setup stop condition (this is an implicit start condition)
+    gpio_set_level(sda_io,0); // setup for STOP
+    gpio_set_level(scl_io,1);
     ets_delay_us(scl_half_period);
-    gpio_set_level(sda_io, 1); // generate stop condition
-    ets_delay_us(scl_half_period);
-
+    gpio_set_level(sda_io, 1); // STOP, SDA low -> high while SCL is HIGH
     i2c_set_pin(i2c_num, sda_io, scl_io, 1, 1, I2C_MODE_MASTER);
     return ESP_OK;
 }