diff --git a/components/ulp/Kconfig b/components/ulp/Kconfig index 5997ea5ae6fd..ad1fba677a36 100644 --- a/components/ulp/Kconfig +++ b/components/ulp/Kconfig @@ -49,6 +49,19 @@ menu "Ultra Low Power (ULP) Co-processor" help The accuracy of the bitbanged UART driver is limited, it is not recommend to increase the value above 19200. + + config ULP_RISCV_I2C_RW_TIMEOUT + int + prompt "Set timeout for ULP RISC-V I2C transaction timeout in ticks." + default 500 + range -1 4294967295 + help + Set the ULP RISC-V I2C read/write timeout. Set this value to -1 + if the ULP RISC-V I2C read and write APIs should wait forever. + Please note that the tick rate of the ULP co-processor would be + different than the OS tick rate of the main core and therefore + can have different timeout value depending on which core the API + is invoked on. endmenu diff --git a/components/ulp/ulp_riscv/include/ulp_riscv_i2c.h b/components/ulp/ulp_riscv/include/ulp_riscv_i2c.h index 4ee4482a6a9d..503fa7b20ce6 100644 --- a/components/ulp/ulp_riscv/include/ulp_riscv_i2c.h +++ b/components/ulp/ulp_riscv/include/ulp_riscv_i2c.h @@ -52,6 +52,7 @@ typedef struct { .i2c_pin_cfg.sda_pullup_en = true, \ .i2c_pin_cfg.scl_pullup_en = true, \ +#if CONFIG_IDF_TARGET_ESP32S3 /* Nominal I2C bus timing parameters for I2C fast mode. Max SCL freq of 400 KHz. */ #define ULP_RISCV_I2C_FAST_MODE_CONFIG() \ .i2c_timing_cfg.scl_low_period = 1.4, \ @@ -59,7 +60,17 @@ typedef struct { .i2c_timing_cfg.sda_duty_period = 1, \ .i2c_timing_cfg.scl_start_period = 2, \ .i2c_timing_cfg.scl_stop_period = 1.3, \ - .i2c_timing_cfg.i2c_trans_timeout = 20, \ + .i2c_timing_cfg.i2c_trans_timeout = 20, +#elif CONFIG_IDF_TARGET_ESP32S2 +/* Nominal I2C bus timing parameters for I2C fast mode. Max SCL freq on S2 is about 233 KHz due to timing constraints. */ +#define ULP_RISCV_I2C_FAST_MODE_CONFIG() \ + .i2c_timing_cfg.scl_low_period = 2, \ + .i2c_timing_cfg.scl_high_period = 0.7, \ + .i2c_timing_cfg.sda_duty_period = 1.7, \ + .i2c_timing_cfg.scl_start_period = 2.4, \ + .i2c_timing_cfg.scl_stop_period = 1.3, \ + .i2c_timing_cfg.i2c_trans_timeout = 20, +#endif /* Nominal I2C bus timing parameters for I2C standard mode. Max SCL freq of 100 KHz. */ #define ULP_RISCV_I2C_STANDARD_MODE_CONFIG() \ diff --git a/components/ulp/ulp_riscv/ulp_core/ulp_riscv_i2c.c b/components/ulp/ulp_riscv/ulp_core/ulp_riscv_i2c.c index bfde23155165..99263d7c6b04 100644 --- a/components/ulp/ulp_riscv/ulp_core/ulp_riscv_i2c.c +++ b/components/ulp/ulp_riscv/ulp_core/ulp_riscv_i2c.c @@ -10,6 +10,7 @@ #include "soc/rtc_io_reg.h" #include "soc/sens_reg.h" #include "hal/i2c_ll.h" +#include "sdkconfig.h" #define I2C_CTRL_SLAVE_ADDR_MASK (0xFF << 0) #define I2C_CTRL_SLAVE_REG_ADDR_MASK (0xFF << 11) @@ -30,7 +31,7 @@ #endif // CONFIG_IDF_TARGET_ESP32S3 /* Read/Write timeout (number of iterationis) */ -#define ULP_RISCV_I2C_RW_TIMEOUT 500 +#define ULP_RISCV_I2C_RW_TIMEOUT CONFIG_ULP_RISCV_I2C_RW_TIMEOUT /* * The RTC I2C controller follows the I2C command registers to perform read/write operations. @@ -65,19 +66,19 @@ static void ulp_riscv_i2c_format_cmd(uint32_t cmd_idx, uint8_t op_code, uint8_t ((byte_num & 0xFF) << 0)); // Byte Num } -static inline int32_t ulp_riscv_i2c_wait_for_interrupt(uint32_t timeout) +static inline int32_t ulp_riscv_i2c_wait_for_interrupt(int32_t ticks_to_wait) { uint32_t status = 0; uint32_t to = 0; - while (to < timeout) { + while (1) { status = READ_PERI_REG(RTC_I2C_INT_ST_REG); - /* Return 0 if Tx or Rx data interrupt bits are set. -1 otherwise */ + /* Return 0 if Tx or Rx data interrupt bits are set. */ if ((status & RTC_I2C_TX_DATA_INT_ST) || (status & RTC_I2C_RX_DATA_INT_ST)) { return 0; - /* In case of errors return immidiately */ + /* In case of error status, break and return -1 */ #if CONFIG_IDF_TARGET_ESP32S2 } else if ((status & RTC_I2C_TIMEOUT_INT_ST) || #elif CONFIG_IDF_TARGET_ESP32S3 @@ -88,12 +89,17 @@ static inline int32_t ulp_riscv_i2c_wait_for_interrupt(uint32_t timeout) return -1; } - ulp_riscv_delay_cycles(ULP_RISCV_CYCLES_PER_MS); - to++; + if (ticks_to_wait > -1) { + /* If the ticks_to_wait value is not -1, keep track of ticks and + * break from the loop once the timeout is reached. + */ + ulp_riscv_delay_cycles(1); + to++; + if (to >= ticks_to_wait) { + return -1; + } + } } - - /* If we reach here, it is a timeout error */ - return -1; } void ulp_riscv_i2c_master_set_slave_addr(uint8_t slave_addr) @@ -169,10 +175,7 @@ void ulp_riscv_i2c_master_read_from_device(uint8_t *data_rd, size_t size) SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START); for (i = 0; i < size; i++) { - /* Poll for RTC I2C Rx Data interrupt bit to be set. - * Set a loop timeout of 500 msec to bail in case of any driver - * and/or hardware errors. - */ + /* Poll for RTC I2C Rx Data interrupt bit to be set */ if(!ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT)) { /* Read the data * @@ -253,10 +256,7 @@ void ulp_riscv_i2c_master_write_to_device(uint8_t *data_wr, size_t size) SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START); } - /* Poll for RTC I2C Tx Data interrupt bit to be set. - * Set a loop timeout of 500 msec to bail in case of any driver - * and/or hardware errors. - */ + /* Poll for RTC I2C Tx Data interrupt bit to be set */ if (!ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT)) { /* Clear the Tx data interrupt bit */ SET_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, RTC_I2C_TX_DATA_INT_CLR); diff --git a/components/ulp/ulp_riscv/ulp_riscv_i2c.c b/components/ulp/ulp_riscv/ulp_riscv_i2c.c index 0a23bef6d973..2a4b32669abb 100644 --- a/components/ulp/ulp_riscv/ulp_riscv_i2c.c +++ b/components/ulp/ulp_riscv/ulp_riscv_i2c.c @@ -15,6 +15,7 @@ #include "driver/rtc_io.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "sdkconfig.h" static const char *RTCI2C_TAG = "ulp_riscv_i2c"; @@ -43,7 +44,7 @@ rtc_io_dev_t *rtc_io_dev = &RTCIO; #define MICROSEC_TO_RTC_FAST_CLK(period) (period) * ((float)(SOC_CLK_RC_FAST_FREQ_APPROX) / (1000000.0)) /* Read/Write timeout (number of iterations)*/ -#define ULP_RISCV_I2C_RW_TIMEOUT 500 +#define ULP_RISCV_I2C_RW_TIMEOUT CONFIG_ULP_RISCV_I2C_RW_TIMEOUT static esp_err_t i2c_gpio_is_cfg_valid(gpio_num_t sda_io_num, gpio_num_t scl_io_num) { @@ -233,13 +234,13 @@ static void ulp_riscv_i2c_format_cmd(uint32_t cmd_idx, uint8_t op_code, uint8_t #endif // CONFIG_IDF_TARGET_ESP32S2 } -static inline esp_err_t ulp_riscv_i2c_wait_for_interrupt(uint32_t timeout) +static inline esp_err_t ulp_riscv_i2c_wait_for_interrupt(int32_t ticks_to_wait) { uint32_t status = 0; uint32_t to = 0; - esp_err_t ret = ESP_ERR_TIMEOUT; + esp_err_t ret = ESP_OK; - while (to < timeout) { + while (1) { status = READ_PERI_REG(RTC_I2C_INT_ST_REG); /* Return ESP_OK if Tx or Rx data interrupt bits are set. */ @@ -259,10 +260,17 @@ static inline esp_err_t ulp_riscv_i2c_wait_for_interrupt(uint32_t timeout) break; } - vTaskDelay(1); - - /* Loop timeout. If this expires, we return ESP_ERR_TIMEOUT */ - to++; + if (ticks_to_wait > -1) { + /* If the ticks_to_wait value is not -1, keep track of ticks and + * break from the loop once the timeout is reached. + */ + vTaskDelay(1); + to++; + if (to >= ticks_to_wait) { + ret = ESP_ERR_TIMEOUT; + break; + } + } } return ret; @@ -339,10 +347,7 @@ void ulp_riscv_i2c_master_read_from_device(uint8_t *data_rd, size_t size) SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START); for (i = 0; i < size; i++) { - /* Poll for RTC I2C Rx Data interrupt bit to be set. - * Set a loop timeout of 500 iterations to bail in case of any driver - * and/or hardware errors. - */ + /* Poll for RTC I2C Rx Data interrupt bit to be set */ ret = ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT); if (ret == ESP_OK) { @@ -426,10 +431,7 @@ void ulp_riscv_i2c_master_write_to_device(uint8_t *data_wr, size_t size) SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START); } - /* Poll for RTC I2C Tx Data interrupt bit to be set. - * Set a loop timeout of 500 iterations to bail in case of any driver - * and/or hardware errors. - */ + /* Poll for RTC I2C Tx Data interrupt bit to be set */ ret = ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT); if (ret == ESP_OK) {