From a0f8434f9382016db6f3b102051569b5cbaea2c0 Mon Sep 17 00:00:00 2001 From: Omar Chebib Date: Thu, 13 Apr 2023 13:05:24 +0800 Subject: [PATCH] i2c: fix a bug in sda sample timing * Closes https://github.com/espressif/esp-idf/issues/9777 This bug prevented SCL line to work properly after a NACK was received in master mode. --- components/hal/esp32c2/include/hal/i2c_ll.h | 7 ++++++- components/hal/esp32c3/include/hal/i2c_ll.h | 7 ++++++- components/hal/esp32c6/include/hal/i2c_ll.h | 9 +++++++-- components/hal/esp32h2/include/hal/i2c_ll.h | 7 ++++++- components/hal/esp32h4/include/hal/i2c_ll.h | 7 ++++++- components/hal/esp32s3/include/hal/i2c_ll.h | 7 ++++++- 6 files changed, 37 insertions(+), 7 deletions(-) diff --git a/components/hal/esp32c2/include/hal/i2c_ll.h b/components/hal/esp32c2/include/hal/i2c_ll.h index 83837dab564..a3271301426 100644 --- a/components/hal/esp32c2/include/hal/i2c_ll.h +++ b/components/hal/esp32c2/include/hal/i2c_ll.h @@ -10,6 +10,7 @@ #include #include "hal/misc.h" +#include "hal/assert.h" #include "soc/i2c_periph.h" #include "soc/soc_caps.h" #include "soc/i2c_struct.h" @@ -92,12 +93,16 @@ static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2 clk_cal->scl_wait_high = (bus_freq >= 80*1000) ? (half_cycle / 2 - 2) : (half_cycle / 4); clk_cal->scl_high = half_cycle - clk_cal->scl_wait_high; clk_cal->sda_hold = half_cycle / 4; - clk_cal->sda_sample = half_cycle / 2 + clk_cal->scl_wait_high; + clk_cal->sda_sample = half_cycle / 2; clk_cal->setup = half_cycle; clk_cal->hold = half_cycle; //default we set the timeout value to about 10 bus cycles // log(20*half_cycle)/log(2) = log(half_cycle)/log(2) + log(20)/log(2) clk_cal->tout = (int)(sizeof(half_cycle) * 8 - __builtin_clz(5 * half_cycle)) + 2; + + /* Verify the assumptions made by the hardware */ + HAL_ASSERT(clk_cal->scl_wait_high < clk_cal->sda_sample && + clk_cal->sda_sample < clk_cal->scl_high); } /** diff --git a/components/hal/esp32c3/include/hal/i2c_ll.h b/components/hal/esp32c3/include/hal/i2c_ll.h index c1035940388..a65aa00a812 100644 --- a/components/hal/esp32c3/include/hal/i2c_ll.h +++ b/components/hal/esp32c3/include/hal/i2c_ll.h @@ -10,6 +10,7 @@ #include "stdbool.h" #include "hal/misc.h" +#include "hal/assert.h" #include "soc/i2c_periph.h" #include "soc/soc_caps.h" #include "soc/i2c_struct.h" @@ -93,12 +94,16 @@ static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2 clk_cal->scl_wait_high = (bus_freq >= 80*1000) ? (half_cycle / 2 - 2) : (half_cycle / 4); clk_cal->scl_high = half_cycle - clk_cal->scl_wait_high; clk_cal->sda_hold = half_cycle / 4; - clk_cal->sda_sample = half_cycle / 2 + clk_cal->scl_wait_high; + clk_cal->sda_sample = half_cycle / 2; clk_cal->setup = half_cycle; clk_cal->hold = half_cycle; //default we set the timeout value to about 10 bus cycles // log(20*half_cycle)/log(2) = log(half_cycle)/log(2) + log(20)/log(2) clk_cal->tout = (int)(sizeof(half_cycle) * 8 - __builtin_clz(5 * half_cycle)) + 2; + + /* Verify the assumptions made by the hardware */ + HAL_ASSERT(clk_cal->scl_wait_high < clk_cal->sda_sample && + clk_cal->sda_sample < clk_cal->scl_high); } /** diff --git a/components/hal/esp32c6/include/hal/i2c_ll.h b/components/hal/esp32c6/include/hal/i2c_ll.h index c7bbc8f1893..bb7ce9e4b25 100644 --- a/components/hal/esp32c6/include/hal/i2c_ll.h +++ b/components/hal/esp32c6/include/hal/i2c_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,7 @@ #include #include "hal/misc.h" +#include "hal/assert.h" #include "soc/i2c_periph.h" #include "soc/soc_caps.h" #include "soc/i2c_struct.h" @@ -91,12 +92,16 @@ static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2 clk_cal->scl_wait_high = (bus_freq >= 80*1000) ? (half_cycle / 2 - 2) : (half_cycle / 4); clk_cal->scl_high = half_cycle - clk_cal->scl_wait_high; clk_cal->sda_hold = half_cycle / 4; - clk_cal->sda_sample = half_cycle / 2 + clk_cal->scl_wait_high; + clk_cal->sda_sample = half_cycle / 2; clk_cal->setup = half_cycle; clk_cal->hold = half_cycle; //default we set the timeout value to about 10 bus cycles // log(20*half_cycle)/log(2) = log(half_cycle)/log(2) + log(20)/log(2) clk_cal->tout = (int)(sizeof(half_cycle) * 8 - __builtin_clz(5 * half_cycle)) + 2; + + /* Verify the assumptions made by the hardware */ + HAL_ASSERT(clk_cal->scl_wait_high < clk_cal->sda_sample && + clk_cal->sda_sample < clk_cal->scl_high); } /** diff --git a/components/hal/esp32h2/include/hal/i2c_ll.h b/components/hal/esp32h2/include/hal/i2c_ll.h index 9e8fece1991..4266d93e523 100644 --- a/components/hal/esp32h2/include/hal/i2c_ll.h +++ b/components/hal/esp32h2/include/hal/i2c_ll.h @@ -10,6 +10,7 @@ #include #include "hal/misc.h" +#include "hal/assert.h" #include "soc/i2c_periph.h" #include "soc/soc_caps.h" #include "soc/i2c_struct.h" @@ -92,12 +93,16 @@ static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2 clk_cal->scl_wait_high = (bus_freq >= 80*1000) ? (half_cycle / 2 - 2) : (half_cycle / 4); clk_cal->scl_high = half_cycle - clk_cal->scl_wait_high; clk_cal->sda_hold = half_cycle / 4; - clk_cal->sda_sample = half_cycle / 2 + clk_cal->scl_wait_high; + clk_cal->sda_sample = half_cycle / 2; clk_cal->setup = half_cycle; clk_cal->hold = half_cycle; //default we set the timeout value to about 10 bus cycles // log(20*half_cycle)/log(2) = log(half_cycle)/log(2) + log(20)/log(2) clk_cal->tout = (int)(sizeof(half_cycle) * 8 - __builtin_clz(5 * half_cycle)) + 2; + + /* Verify the assumptions made by the hardware */ + HAL_ASSERT(clk_cal->scl_wait_high < clk_cal->sda_sample && + clk_cal->sda_sample < clk_cal->scl_high); } /** diff --git a/components/hal/esp32h4/include/hal/i2c_ll.h b/components/hal/esp32h4/include/hal/i2c_ll.h index f5af47eefc6..3ab1ccd6704 100644 --- a/components/hal/esp32h4/include/hal/i2c_ll.h +++ b/components/hal/esp32h4/include/hal/i2c_ll.h @@ -10,6 +10,7 @@ #include "stdbool.h" #include "hal/misc.h" +#include "hal/assert.h" #include "soc/i2c_periph.h" #include "soc/soc_caps.h" #include "soc/i2c_struct.h" @@ -95,12 +96,16 @@ static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2 clk_cal->scl_wait_high = (bus_freq >= 80*1000) ? (half_cycle / 2 - 2) : (half_cycle / 4); clk_cal->scl_high = half_cycle - clk_cal->scl_wait_high; clk_cal->sda_hold = half_cycle / 4; - clk_cal->sda_sample = half_cycle / 2 + clk_cal->scl_wait_high; + clk_cal->sda_sample = half_cycle / 2; clk_cal->setup = half_cycle; clk_cal->hold = half_cycle; //default we set the timeout value to about 10 bus cycles // log(20*half_cycle)/log(2) = log(half_cycle)/log(2) + log(20)/log(2) clk_cal->tout = (int)(sizeof(half_cycle) * 8 - __builtin_clz(5 * half_cycle)) + 2; + + /* Verify the assumptions made by the hardware */ + HAL_ASSERT(clk_cal->scl_wait_high < clk_cal->sda_sample && + clk_cal->sda_sample < clk_cal->scl_high); } /** diff --git a/components/hal/esp32s3/include/hal/i2c_ll.h b/components/hal/esp32s3/include/hal/i2c_ll.h index db84a72eace..b6c3689b490 100644 --- a/components/hal/esp32s3/include/hal/i2c_ll.h +++ b/components/hal/esp32s3/include/hal/i2c_ll.h @@ -10,6 +10,7 @@ #include "stdbool.h" #include "hal/misc.h" +#include "hal/assert.h" #include "soc/i2c_periph.h" #include "soc/soc_caps.h" #include "soc/i2c_struct.h" @@ -92,12 +93,16 @@ static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2 clk_cal->scl_wait_high = (bus_freq >= 80*1000) ? (half_cycle / 2 - 2) : (half_cycle / 4); clk_cal->scl_high = half_cycle - clk_cal->scl_wait_high; clk_cal->sda_hold = half_cycle / 4; - clk_cal->sda_sample = half_cycle / 2 + clk_cal->scl_wait_high; + clk_cal->sda_sample = half_cycle / 2; clk_cal->setup = half_cycle; clk_cal->hold = half_cycle; //default we set the timeout value to about 10 bus cycles // log(20*half_cycle)/log(2) = log(half_cycle)/log(2) + log(20)/log(2) clk_cal->tout = (int)(sizeof(half_cycle) * 8 - __builtin_clz(5 * half_cycle)) + 2; + + /* Verify the assumptions made by the hardware */ + HAL_ASSERT(clk_cal->scl_wait_high < clk_cal->sda_sample && + clk_cal->sda_sample < clk_cal->scl_high); } /**