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
4 changed files with 61 additions and 35 deletions
+13
View File
@@ -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
@@ -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() \
@@ -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);
+18 -16
View File
@@ -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) {