Merge branch 'bugfix/ulp_i2c_timeout_config' into 'master'

ulp-riscv-i2c: Add ULP RISC-V I2C read/write timeout config option

Closes IDFGH-9822

See merge request espressif/esp-idf!23470
This commit is contained in:
Sudeep Mohanty 2023-05-09 21:06:51 +08:00
commit 02d473615d
4 changed files with 61 additions and 35 deletions

View File

@ -49,6 +49,19 @@ menu "Ultra Low Power (ULP) Co-processor"
help help
The accuracy of the bitbanged UART driver is limited, it is not The accuracy of the bitbanged UART driver is limited, it is not
recommend to increase the value above 19200. 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 endmenu

View File

@ -52,6 +52,7 @@ typedef struct {
.i2c_pin_cfg.sda_pullup_en = true, \ .i2c_pin_cfg.sda_pullup_en = true, \
.i2c_pin_cfg.scl_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. */ /* Nominal I2C bus timing parameters for I2C fast mode. Max SCL freq of 400 KHz. */
#define ULP_RISCV_I2C_FAST_MODE_CONFIG() \ #define ULP_RISCV_I2C_FAST_MODE_CONFIG() \
.i2c_timing_cfg.scl_low_period = 1.4, \ .i2c_timing_cfg.scl_low_period = 1.4, \
@ -59,7 +60,17 @@ typedef struct {
.i2c_timing_cfg.sda_duty_period = 1, \ .i2c_timing_cfg.sda_duty_period = 1, \
.i2c_timing_cfg.scl_start_period = 2, \ .i2c_timing_cfg.scl_start_period = 2, \
.i2c_timing_cfg.scl_stop_period = 1.3, \ .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. */ /* Nominal I2C bus timing parameters for I2C standard mode. Max SCL freq of 100 KHz. */
#define ULP_RISCV_I2C_STANDARD_MODE_CONFIG() \ #define ULP_RISCV_I2C_STANDARD_MODE_CONFIG() \

View File

@ -10,6 +10,7 @@
#include "soc/rtc_io_reg.h" #include "soc/rtc_io_reg.h"
#include "soc/sens_reg.h" #include "soc/sens_reg.h"
#include "hal/i2c_ll.h" #include "hal/i2c_ll.h"
#include "sdkconfig.h"
#define I2C_CTRL_SLAVE_ADDR_MASK (0xFF << 0) #define I2C_CTRL_SLAVE_ADDR_MASK (0xFF << 0)
#define I2C_CTRL_SLAVE_REG_ADDR_MASK (0xFF << 11) #define I2C_CTRL_SLAVE_REG_ADDR_MASK (0xFF << 11)
@ -30,7 +31,7 @@
#endif // CONFIG_IDF_TARGET_ESP32S3 #endif // CONFIG_IDF_TARGET_ESP32S3
/* Read/Write timeout (number of iterationis) */ /* 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. * 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 ((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 status = 0;
uint32_t to = 0; uint32_t to = 0;
while (to < timeout) { while (1) {
status = READ_PERI_REG(RTC_I2C_INT_ST_REG); 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) || if ((status & RTC_I2C_TX_DATA_INT_ST) ||
(status & RTC_I2C_RX_DATA_INT_ST)) { (status & RTC_I2C_RX_DATA_INT_ST)) {
return 0; return 0;
/* In case of errors return immidiately */ /* In case of error status, break and return -1 */
#if CONFIG_IDF_TARGET_ESP32S2 #if CONFIG_IDF_TARGET_ESP32S2
} else if ((status & RTC_I2C_TIMEOUT_INT_ST) || } else if ((status & RTC_I2C_TIMEOUT_INT_ST) ||
#elif CONFIG_IDF_TARGET_ESP32S3 #elif CONFIG_IDF_TARGET_ESP32S3
@ -88,12 +89,17 @@ static inline int32_t ulp_riscv_i2c_wait_for_interrupt(uint32_t timeout)
return -1; return -1;
} }
ulp_riscv_delay_cycles(ULP_RISCV_CYCLES_PER_MS); 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++; to++;
} if (to >= ticks_to_wait) {
/* If we reach here, it is a timeout error */
return -1; return -1;
}
}
}
} }
void ulp_riscv_i2c_master_set_slave_addr(uint8_t slave_addr) 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); SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START);
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
/* Poll for RTC I2C Rx Data interrupt bit to be set. /* 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.
*/
if(!ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT)) { if(!ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT)) {
/* Read the data /* 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); SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START);
} }
/* Poll for RTC I2C Tx Data interrupt bit to be set. /* 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.
*/
if (!ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT)) { if (!ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT)) {
/* Clear the Tx data interrupt bit */ /* Clear the Tx data interrupt bit */
SET_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, RTC_I2C_TX_DATA_INT_CLR); SET_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, RTC_I2C_TX_DATA_INT_CLR);

View File

@ -15,6 +15,7 @@
#include "driver/rtc_io.h" #include "driver/rtc_io.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "sdkconfig.h"
static const char *RTCI2C_TAG = "ulp_riscv_i2c"; 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)) #define MICROSEC_TO_RTC_FAST_CLK(period) (period) * ((float)(SOC_CLK_RC_FAST_FREQ_APPROX) / (1000000.0))
/* Read/Write timeout (number of iterations)*/ /* 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) 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 #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 status = 0;
uint32_t to = 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); status = READ_PERI_REG(RTC_I2C_INT_ST_REG);
/* Return ESP_OK if Tx or Rx data interrupt bits are set. */ /* 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; break;
} }
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); vTaskDelay(1);
/* Loop timeout. If this expires, we return ESP_ERR_TIMEOUT */
to++; to++;
if (to >= ticks_to_wait) {
ret = ESP_ERR_TIMEOUT;
break;
}
}
} }
return ret; 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); SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START);
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
/* Poll for RTC I2C Rx Data interrupt bit to be set. /* 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.
*/
ret = ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT); ret = ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT);
if (ret == ESP_OK) { 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); SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START);
} }
/* Poll for RTC I2C Tx Data interrupt bit to be set. /* 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.
*/
ret = ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT); ret = ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT);
if (ret == ESP_OK) { if (ret == ESP_OK) {