From aac935ec81324578e29606a70b4708a308863382 Mon Sep 17 00:00:00 2001 From: houwenxiang Date: Mon, 25 Nov 2019 17:10:36 +0800 Subject: [PATCH] bugfix(i2c): fix I2C driver breaking change issue. 1. Fixed I2C driver breaking change issue. 2. Add I2C UT test case. --- components/driver/i2c.c | 288 +++++++++--------- components/driver/test/test_i2c.c | 110 ++++++- components/soc/esp32/include/hal/i2c_ll.h | 62 +++- .../soc/esp32s2beta/include/hal/i2c_ll.h | 86 +++++- components/soc/include/hal/i2c_hal.h | 4 +- components/soc/src/hal/i2c_hal.c | 15 +- .../i2c/i2c_self_test/main/i2c_example_main.c | 8 +- 7 files changed, 401 insertions(+), 172 deletions(-) diff --git a/components/driver/i2c.c b/components/driver/i2c.c index 80466ff6c..d16c6469d 100644 --- a/components/driver/i2c.c +++ b/components/driver/i2c.c @@ -37,7 +37,6 @@ static const char* I2C_TAG = "i2c"; return (ret); \ } -static portMUX_TYPE i2c_spinlock[I2C_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED}; /* DRAM_ATTR is required to avoid I2C array placed in flash, due to accessed from ISR */ #define I2C_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux) @@ -84,6 +83,12 @@ static portMUX_TYPE i2c_spinlock[I2C_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, p #define I2C_CLR_BUS_SCL_NUM (9) #define I2C_CLR_BUS_HALF_PERIOD_US (5) +#define I2C_CONTEX_INIT_DEF(uart_num) {\ + .hal.dev = I2C_LL_GET_HW(uart_num),\ + .spinlock = portMUX_INITIALIZER_UNLOCKED,\ + .hw_enabled = false,\ +} + typedef struct { i2c_hw_cmd_t hw_cmd; uint8_t* data; /*!< data address */ @@ -115,7 +120,6 @@ typedef struct { } i2c_cmd_evt_t; typedef struct { - i2c_hal_context_t i2c_hal; /*!< I2C hal context */ int i2c_num; /*!< I2C port number */ int mode; /*!< I2C mode, master or slave */ intr_handle_t intr_handle; /*!< I2C interrupt handle*/ @@ -142,10 +146,23 @@ typedef struct { RingbufHandle_t rx_ring_buf; /*!< rx ringbuffer handler of slave mode */ size_t tx_buf_length; /*!< tx buffer length */ RingbufHandle_t tx_ring_buf; /*!< tx ringbuffer handler of slave mode */ - uint8_t scl_io_num; - uint8_t sda_io_num; } i2c_obj_t; +typedef struct { + i2c_hal_context_t hal; /*!< I2C hal context */ + portMUX_TYPE spinlock; + bool hw_enabled; +#if !I2C_SUPPORT_HW_CLR_BUS + int scl_io_num; + int sda_io_num; +#endif +} i2c_context_t; + +static i2c_context_t i2c_context[I2C_NUM_MAX] = { + I2C_CONTEX_INIT_DEF(I2C_NUM_0), + I2C_CONTEX_INIT_DEF(I2C_NUM_1), +}; + static i2c_obj_t *p_i2c_obj[I2C_NUM_MAX] = {0}; static void i2c_isr_handler_default(void* arg); static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num); @@ -153,12 +170,22 @@ static esp_err_t IRAM_ATTR i2c_hw_fsm_reset(i2c_port_t i2c_num); static void i2c_hw_disable(i2c_port_t i2c_num) { - periph_module_disable(i2c_periph_signal[i2c_num].module); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + if (i2c_context[i2c_num].hw_enabled != false){ + periph_module_disable(i2c_periph_signal[i2c_num].module); + i2c_context[i2c_num].hw_enabled = false; + } + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); } static void i2c_hw_enable(i2c_port_t i2c_num) { - periph_module_enable(i2c_periph_signal[i2c_num].module); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + if (i2c_context[i2c_num].hw_enabled != true){ + periph_module_enable(i2c_periph_signal[i2c_num].module); + i2c_context[i2c_num].hw_enabled = true; + } + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); } /* @@ -176,10 +203,6 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_ ESP_ERR_INVALID_ARG); if (p_i2c_obj[i2c_num] == NULL) { - // Reset the I2C hardware in case there is a soft reboot. - i2c_hw_disable(i2c_num); - i2c_hw_enable(i2c_num); - #if !CONFIG_SPIRAM_USE_MALLOC p_i2c_obj[i2c_num] = (i2c_obj_t*) calloc(1, sizeof(i2c_obj_t)); #else @@ -234,7 +257,6 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_ ESP_LOGE(I2C_TAG, I2C_SEM_ERR_STR); goto err; } - i2c_hal_slave_init(&(p_i2c->i2c_hal), i2c_num); } else { //semaphore to sync sending process, because we only have 32 bytes for hardware fifo. p_i2c->cmd_mux = xSemaphoreCreateMutex(); @@ -272,14 +294,14 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_ p_i2c->rx_buf_length = 0; p_i2c->tx_ring_buf = NULL; p_i2c->tx_buf_length = 0; - i2c_hal_master_init(&(p_i2c->i2c_hal), i2c_num); } } else { ESP_LOGE(I2C_TAG, I2C_DRIVER_ERR_STR); return ESP_FAIL; } + i2c_hw_enable(i2c_num); //Disable I2C interrupt. - i2c_hal_disable_intr_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK); + i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK); //hook isr handler i2c_isr_register(i2c_num, i2c_isr_handler_default, p_i2c_obj[i2c_num], intr_alloc_flags, &p_i2c_obj[i2c_num]->intr_handle); return ESP_OK; @@ -334,7 +356,7 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num) I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); i2c_obj_t* p_i2c = p_i2c_obj[i2c_num]; - i2c_hal_disable_intr_mask(&(p_i2c->i2c_hal), I2C_INTR_MASK); + i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK); esp_intr_free(p_i2c->intr_handle); p_i2c->intr_handle = NULL; @@ -386,20 +408,18 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num) esp_err_t i2c_reset_tx_fifo(i2c_port_t i2c_num) { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_txfifo_rst(&(p_i2c_obj[i2c_num]->i2c_hal)); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_txfifo_rst(&(i2c_context[i2c_num].hal)); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } esp_err_t i2c_reset_rx_fifo(i2c_port_t i2c_num) { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_rxfifo_rst(&(p_i2c_obj[i2c_num]->i2c_hal)); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_rxfifo_rst(&(i2c_context[i2c_num].hal)); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -411,9 +431,9 @@ static void IRAM_ATTR i2c_isr_handler_default(void *arg) portBASE_TYPE HPTaskAwoken = pdFALSE; if (p_i2c->mode == I2C_MODE_MASTER) { if (p_i2c->status == I2C_STATUS_WRITE) { - i2c_hal_master_handle_tx_event(&(p_i2c->i2c_hal), &evt_type); + i2c_hal_master_handle_tx_event(&(i2c_context[i2c_num].hal), &evt_type); } else if (p_i2c->status == I2C_STATUS_READ) { - i2c_hal_master_handle_rx_event(&(p_i2c->i2c_hal), &evt_type); + i2c_hal_master_handle_rx_event(&(i2c_context[i2c_num].hal), &evt_type); } if (evt_type == I2C_INTR_EVENT_NACK) { p_i2c_obj[i2c_num]->status = I2C_STATUS_ACK_ERROR; @@ -436,25 +456,25 @@ static void IRAM_ATTR i2c_isr_handler_default(void *arg) }; xQueueSendFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken); } else { - i2c_hal_slave_handle_event(&(p_i2c->i2c_hal), &evt_type); + i2c_hal_slave_handle_event(&(i2c_context[i2c_num].hal), &evt_type); if (evt_type == I2C_INTR_EVENT_TRANS_DONE || evt_type == I2C_INTR_EVENT_RXFIFO_FULL) { uint32_t rx_fifo_cnt; - i2c_hal_get_rxfifo_cnt(&(p_i2c->i2c_hal), &rx_fifo_cnt); - i2c_hal_read_rxfifo(&(p_i2c->i2c_hal), p_i2c->data_buf, rx_fifo_cnt); + i2c_hal_get_rxfifo_cnt(&(i2c_context[i2c_num].hal), &rx_fifo_cnt); + i2c_hal_read_rxfifo(&(i2c_context[i2c_num].hal), p_i2c->data_buf, rx_fifo_cnt); xRingbufferSendFromISR(p_i2c->rx_ring_buf, p_i2c->data_buf, rx_fifo_cnt, &HPTaskAwoken); - i2c_hal_slave_clr_rx_it(&(p_i2c->i2c_hal)); + i2c_hal_slave_clr_rx_it(&(i2c_context[i2c_num].hal)); } else if (evt_type == I2C_INTR_EVENT_TXFIFO_EMPTY) { uint32_t tx_fifo_rem; - i2c_hal_get_txfifo_cnt(&(p_i2c->i2c_hal), &tx_fifo_rem); + i2c_hal_get_txfifo_cnt(&(i2c_context[i2c_num].hal), &tx_fifo_rem); size_t size = 0; uint8_t *data = (uint8_t*) xRingbufferReceiveUpToFromISR(p_i2c->tx_ring_buf, &size, tx_fifo_rem); if (data) { - i2c_hal_write_txfifo(&(p_i2c->i2c_hal), data, size); + i2c_hal_write_txfifo(&(i2c_context[i2c_num].hal), data, size); vRingbufferReturnItemFromISR(p_i2c->tx_ring_buf, data, &HPTaskAwoken); } else { - i2c_hal_disable_slave_tx_it(&(p_i2c->i2c_hal)); + i2c_hal_disable_slave_tx_it(&(i2c_context[i2c_num].hal)); } - i2c_hal_slave_clr_tx_it(&(p_i2c->i2c_hal)); + i2c_hal_slave_clr_tx_it(&(i2c_context[i2c_num].hal)); } } //We only need to check here if there is a high-priority task needs to be switched. @@ -466,20 +486,18 @@ static void IRAM_ATTR i2c_isr_handler_default(void *arg) esp_err_t i2c_set_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t tx_trans_mode, i2c_trans_mode_t rx_trans_mode) { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); I2C_CHECK(tx_trans_mode < I2C_DATA_MODE_MAX, I2C_TRANS_MODE_ERR_STR, ESP_ERR_INVALID_ARG); I2C_CHECK(rx_trans_mode < I2C_DATA_MODE_MAX, I2C_TRANS_MODE_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_set_data_mode(&(p_i2c_obj[i2c_num]->i2c_hal), tx_trans_mode, rx_trans_mode); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_set_data_mode(&(i2c_context[i2c_num].hal), tx_trans_mode, rx_trans_mode); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode, i2c_trans_mode_t *rx_trans_mode) { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); - i2c_hal_get_data_mode(&(p_i2c_obj[i2c_num]->i2c_hal), tx_trans_mode, rx_trans_mode); + i2c_hal_get_data_mode(&(i2c_context[i2c_num].hal), tx_trans_mode, rx_trans_mode); return ESP_OK; } @@ -493,8 +511,8 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num) #if !I2C_SUPPORT_HW_CLR_BUS const int scl_half_period = I2C_CLR_BUS_HALF_PERIOD_US; // use standard 100kHz data rate int i = 0; - int scl_io = p_i2c_obj[i2c_num]->scl_io_num; - int sda_io = p_i2c_obj[i2c_num]->sda_io_num; + int scl_io = i2c_context[i2c_num].scl_io_num; + int sda_io = i2c_context[i2c_num].sda_io_num; gpio_set_direction(scl_io, GPIO_MODE_OUTPUT_OD); gpio_set_direction(sda_io, GPIO_MODE_INPUT_OUTPUT_OD); // If a SLAVE device was in a read operation when the bus was interrupted, the SLAVE device is controlling SDA. @@ -517,7 +535,7 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num) 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); #else - i2c_hal_master_clr_bus(&(p_i2c_obj[i2c_num]->i2c_hal)); + i2c_hal_master_clr_bus(&(i2c_context[i2c_num].hal)); #endif return ESP_OK; } @@ -536,29 +554,29 @@ static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num) int timeout; uint8_t filter_cfg; - i2c_hal_get_scl_timing(&(p_i2c_obj[i2c_num]->i2c_hal), &scl_high_period, &scl_low_period); - i2c_hal_get_start_timing(&(p_i2c_obj[i2c_num]->i2c_hal), &scl_rstart_setup, &scl_start_hold); - i2c_hal_get_stop_timing(&(p_i2c_obj[i2c_num]->i2c_hal), &scl_stop_setup, &scl_stop_hold); - i2c_hal_get_sda_timing(&(p_i2c_obj[i2c_num]->i2c_hal), &sda_sample, &sda_hold); - i2c_hal_get_tout(&(p_i2c_obj[i2c_num]->i2c_hal), &timeout); - i2c_hal_get_filter(&(p_i2c_obj[i2c_num]->i2c_hal), &filter_cfg); + i2c_hal_get_scl_timing(&(i2c_context[i2c_num].hal), &scl_high_period, &scl_low_period); + i2c_hal_get_start_timing(&(i2c_context[i2c_num].hal), &scl_rstart_setup, &scl_start_hold); + i2c_hal_get_stop_timing(&(i2c_context[i2c_num].hal), &scl_stop_setup, &scl_stop_hold); + i2c_hal_get_sda_timing(&(i2c_context[i2c_num].hal), &sda_sample, &sda_hold); + i2c_hal_get_tout(&(i2c_context[i2c_num].hal), &timeout); + i2c_hal_get_filter(&(i2c_context[i2c_num].hal), &filter_cfg); //to reset the I2C hw module, we need re-enable the hw i2c_hw_disable(i2c_num); i2c_master_clear_bus(i2c_num); i2c_hw_enable(i2c_num); - i2c_hal_master_init(&(p_i2c_obj[i2c_num]->i2c_hal), i2c_num); - i2c_hal_disable_intr_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK); - i2c_hal_clr_intsts_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK); - i2c_hal_set_scl_timing(&(p_i2c_obj[i2c_num]->i2c_hal), scl_high_period, scl_low_period); - i2c_hal_set_start_timing(&(p_i2c_obj[i2c_num]->i2c_hal), scl_rstart_setup, scl_start_hold); - i2c_hal_set_stop_timing(&(p_i2c_obj[i2c_num]->i2c_hal), scl_stop_setup, scl_stop_hold); - i2c_hal_set_sda_timing(&(p_i2c_obj[i2c_num]->i2c_hal), sda_sample, sda_hold); - i2c_hal_set_tout(&(p_i2c_obj[i2c_num]->i2c_hal), timeout); - i2c_hal_set_filter(&(p_i2c_obj[i2c_num]->i2c_hal), filter_cfg); + i2c_hal_master_init(&(i2c_context[i2c_num].hal), i2c_num); + i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK); + i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK); + i2c_hal_set_scl_timing(&(i2c_context[i2c_num].hal), scl_high_period, scl_low_period); + i2c_hal_set_start_timing(&(i2c_context[i2c_num].hal), scl_rstart_setup, scl_start_hold); + i2c_hal_set_stop_timing(&(i2c_context[i2c_num].hal), scl_stop_setup, scl_stop_hold); + i2c_hal_set_sda_timing(&(i2c_context[i2c_num].hal), sda_sample, sda_hold); + i2c_hal_set_tout(&(i2c_context[i2c_num].hal), timeout); + i2c_hal_set_filter(&(i2c_context[i2c_num].hal), filter_cfg); #else - i2c_hal_master_fsm_rst(&(p_i2c_obj[i2c_num]->i2c_hal)); + i2c_hal_master_fsm_rst(&(i2c_context[i2c_num].hal)); i2c_master_clear_bus(i2c_num); #endif return ESP_OK; @@ -567,7 +585,6 @@ static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num) esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf) { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); I2C_CHECK(i2c_conf != NULL, I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); I2C_CHECK(i2c_conf->mode < I2C_MODE_MAX, I2C_MODE_ERR_STR, ESP_ERR_INVALID_ARG); @@ -576,48 +593,48 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf) if (ret != ESP_OK) { return ret; } - p_i2c_obj[i2c_num]->mode = i2c_conf->mode; - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_disable_intr_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK); - i2c_hal_clr_intsts_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK); + i2c_hw_enable(i2c_num); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK); + i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK); if (i2c_conf->mode == I2C_MODE_SLAVE) { //slave mode - i2c_hal_set_slave_addr(&(p_i2c_obj[i2c_num]->i2c_hal), i2c_conf->slave.slave_addr, i2c_conf->slave.addr_10bit_en); - i2c_hal_set_rxfifo_full_thr(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_FIFO_FULL_THRESH_VAL); - i2c_hal_set_txfifo_empty_thr(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_FIFO_EMPTY_THRESH_VAL); + i2c_hal_slave_init(&(i2c_context[i2c_num].hal), i2c_num); + i2c_hal_set_slave_addr(&(i2c_context[i2c_num].hal), i2c_conf->slave.slave_addr, i2c_conf->slave.addr_10bit_en); + i2c_hal_set_rxfifo_full_thr(&(i2c_context[i2c_num].hal), I2C_FIFO_FULL_THRESH_VAL); + i2c_hal_set_txfifo_empty_thr(&(i2c_context[i2c_num].hal), I2C_FIFO_EMPTY_THRESH_VAL); //set timing for data - i2c_hal_set_sda_timing(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_SLAVE_SDA_SAMPLE_DEFAULT, I2C_SLAVE_SDA_HOLD_DEFAULT); - i2c_hal_set_tout(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_SLAVE_TIMEOUT_DEFAULT); - i2c_hal_enable_slave_tx_it(&(p_i2c_obj[i2c_num]->i2c_hal)); - i2c_hal_enable_slave_rx_it(&(p_i2c_obj[i2c_num]->i2c_hal)); + i2c_hal_set_sda_timing(&(i2c_context[i2c_num].hal), I2C_SLAVE_SDA_SAMPLE_DEFAULT, I2C_SLAVE_SDA_HOLD_DEFAULT); + i2c_hal_set_tout(&(i2c_context[i2c_num].hal), I2C_SLAVE_TIMEOUT_DEFAULT); + i2c_hal_enable_slave_tx_it(&(i2c_context[i2c_num].hal)); + i2c_hal_enable_slave_rx_it(&(i2c_context[i2c_num].hal)); } else { + i2c_hal_master_init(&(i2c_context[i2c_num].hal), i2c_num); //Default, we enable hardware filter - i2c_hal_set_filter(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_FILTER_CYC_NUM_DEF); - i2c_hal_set_bus_timing(&(p_i2c_obj[i2c_num]->i2c_hal), i2c_conf->master.clk_speed, I2C_SCLK_APB); + i2c_hal_set_filter(&(i2c_context[i2c_num].hal), I2C_FILTER_CYC_NUM_DEF); + i2c_hal_set_bus_timing(&(i2c_context[i2c_num].hal), i2c_conf->master.clk_speed, I2C_SCLK_APB); } - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period) { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); I2C_CHECK((high_period <= I2C_SCL_HIGH_PERIOD_V) && (high_period > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); I2C_CHECK((low_period <= I2C_SCL_LOW_PERIOD_V) && (low_period > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_set_scl_timing(&(p_i2c_obj[i2c_num]->i2c_hal), high_period, low_period); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_set_scl_timing(&(i2c_context[i2c_num].hal), high_period, low_period); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } esp_err_t i2c_get_period(i2c_port_t i2c_num, int* high_period, int* low_period) { I2C_CHECK(i2c_num < I2C_NUM_MAX && high_period != NULL && low_period != NULL, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_get_scl_timing(&(p_i2c_obj[i2c_num]->i2c_hal), high_period, low_period); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_get_scl_timing(&(i2c_context[i2c_num].hal), high_period, low_period); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -625,108 +642,99 @@ esp_err_t i2c_filter_enable(i2c_port_t i2c_num, uint8_t cyc_num) { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_set_filter(&(p_i2c_obj[i2c_num]->i2c_hal), cyc_num); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_set_filter(&(i2c_context[i2c_num].hal), cyc_num); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } esp_err_t i2c_filter_disable(i2c_port_t i2c_num) { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_set_filter(&(p_i2c_obj[i2c_num]->i2c_hal), 0); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_set_filter(&(i2c_context[i2c_num].hal), 0); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time) { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); I2C_CHECK((hold_time <= I2C_SCL_START_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); I2C_CHECK((setup_time <= I2C_SCL_RSTART_SETUP_TIME_V) && (setup_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_set_start_timing(&(p_i2c_obj[i2c_num]->i2c_hal), setup_time, hold_time); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_set_start_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } esp_err_t i2c_get_start_timing(i2c_port_t i2c_num, int* setup_time, int* hold_time) { I2C_CHECK(i2c_num < I2C_NUM_MAX && setup_time != NULL && hold_time != NULL, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_get_start_timing(&(p_i2c_obj[i2c_num]->i2c_hal), setup_time, hold_time); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_get_start_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } esp_err_t i2c_set_stop_timing(i2c_port_t i2c_num, int setup_time, int hold_time) { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); I2C_CHECK((setup_time <= I2C_SCL_STOP_SETUP_TIME_V) && (setup_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); I2C_CHECK((hold_time <= I2C_SCL_STOP_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_set_stop_timing(&(p_i2c_obj[i2c_num]->i2c_hal), setup_time, hold_time); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_set_stop_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } esp_err_t i2c_get_stop_timing(i2c_port_t i2c_num, int* setup_time, int* hold_time) { I2C_CHECK(i2c_num < I2C_NUM_MAX && setup_time != NULL && hold_time != NULL, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_get_stop_timing(&(p_i2c_obj[i2c_num]->i2c_hal), setup_time, hold_time); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_get_stop_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time) { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); I2C_CHECK((sample_time <= I2C_SDA_SAMPLE_TIME_V) && (sample_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); I2C_CHECK((hold_time <= I2C_SDA_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_set_sda_timing(&(p_i2c_obj[i2c_num]->i2c_hal), sample_time, hold_time); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_set_sda_timing(&(i2c_context[i2c_num].hal), sample_time, hold_time); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } esp_err_t i2c_get_data_timing(i2c_port_t i2c_num, int* sample_time, int* hold_time) { I2C_CHECK(i2c_num < I2C_NUM_MAX && sample_time != NULL && hold_time != NULL, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_get_sda_timing(&(p_i2c_obj[i2c_num]->i2c_hal), sample_time, hold_time); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_get_sda_timing(&(i2c_context[i2c_num].hal), sample_time, hold_time); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } esp_err_t i2c_set_timeout(i2c_port_t i2c_num, int timeout) { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); I2C_CHECK((timeout <= I2C_TIME_OUT_REG_V) && (timeout > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_set_tout(&(p_i2c_obj[i2c_num]->i2c_hal), timeout); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_set_tout(&(i2c_context[i2c_num].hal), timeout); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } esp_err_t i2c_get_timeout(i2c_port_t i2c_num, int* timeout) { I2C_CHECK(i2c_num < I2C_NUM_MAX && timeout != NULL, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); - i2c_hal_get_tout(&(p_i2c_obj[i2c_num]->i2c_hal), timeout); + i2c_hal_get_tout(&(i2c_context[i2c_num].hal), timeout); return ESP_OK; } @@ -794,8 +802,10 @@ esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, bool s } gpio_matrix_in(scl_io_num, scl_in_sig, 0); } - p_i2c_obj[i2c_num]->scl_io_num = scl_io_num; - p_i2c_obj[i2c_num]->sda_io_num = sda_io_num; +#if !I2C_SUPPORT_HW_CLR_BUS + i2c_context[i2c_num].scl_io_num = scl_io_num; + i2c_context[i2c_num].sda_io_num = sda_io_num; +#endif return ESP_OK; } @@ -998,7 +1008,7 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num) i2c_cmd_evt_t evt; if (p_i2c->cmd_link.head != NULL && p_i2c->status == I2C_STATUS_READ) { i2c_cmd_t *cmd = &p_i2c->cmd_link.head->cmd; - i2c_hal_read_rxfifo(&(p_i2c->i2c_hal), cmd->data, p_i2c->rx_cnt); + i2c_hal_read_rxfifo(&(i2c_context[i2c_num].hal), cmd->data, p_i2c->rx_cnt); cmd->data += p_i2c->rx_cnt; if (cmd->hw_cmd.byte_num > 0) { p_i2c->cmd_idx = 0; @@ -1043,10 +1053,10 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num) cmd->hw_cmd.byte_num--; } hw_cmd.byte_num = wr_filled; - i2c_hal_write_txfifo(&(p_i2c->i2c_hal), write_pr, wr_filled); - i2c_hal_write_cmd_reg(&(p_i2c->i2c_hal), hw_cmd, p_i2c->cmd_idx); - i2c_hal_write_cmd_reg(&(p_i2c->i2c_hal), hw_end_cmd, p_i2c->cmd_idx + 1); - i2c_hal_enable_master_tx_it(&(p_i2c->i2c_hal)); + i2c_hal_write_txfifo(&(i2c_context[i2c_num].hal), write_pr, wr_filled); + i2c_hal_write_cmd_reg(&(i2c_context[i2c_num].hal), hw_cmd, p_i2c->cmd_idx); + i2c_hal_write_cmd_reg(&(i2c_context[i2c_num].hal), hw_end_cmd, p_i2c->cmd_idx + 1); + i2c_hal_enable_master_tx_it(&(i2c_context[i2c_num].hal)); p_i2c->cmd_idx = 0; if (cmd->hw_cmd.byte_num == 0) { p_i2c->cmd_link.head = p_i2c->cmd_link.head->next; @@ -1058,13 +1068,13 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num) p_i2c->rx_cnt = cmd->hw_cmd.byte_num > SOC_I2C_FIFO_LEN ? SOC_I2C_FIFO_LEN : cmd->hw_cmd.byte_num; cmd->hw_cmd.byte_num -= p_i2c->rx_cnt; hw_cmd.byte_num = p_i2c->rx_cnt; - i2c_hal_write_cmd_reg(&(p_i2c->i2c_hal), hw_cmd, p_i2c->cmd_idx); - i2c_hal_write_cmd_reg(&(p_i2c->i2c_hal), hw_end_cmd, p_i2c->cmd_idx + 1); - i2c_hal_enable_master_rx_it(&(p_i2c->i2c_hal)); + i2c_hal_write_cmd_reg(&(i2c_context[i2c_num].hal), hw_cmd, p_i2c->cmd_idx); + i2c_hal_write_cmd_reg(&(i2c_context[i2c_num].hal), hw_end_cmd, p_i2c->cmd_idx + 1); + i2c_hal_enable_master_rx_it(&(i2c_context[i2c_num].hal)); p_i2c->status = I2C_STATUS_READ; break; } else { - i2c_hal_write_cmd_reg(&(p_i2c->i2c_hal), hw_cmd, p_i2c->cmd_idx); + i2c_hal_write_cmd_reg(&(i2c_context[i2c_num].hal), hw_cmd, p_i2c->cmd_idx); } p_i2c->cmd_idx++; p_i2c->cmd_link.head = p_i2c->cmd_link.head->next; @@ -1073,7 +1083,7 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num) break; } } - i2c_hal_trans_start(&(p_i2c->i2c_hal)); + i2c_hal_trans_start(&(i2c_context[i2c_num].hal)); return; } @@ -1125,7 +1135,7 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, } xQueueReset(p_i2c->cmd_evt_queue); if (p_i2c->status == I2C_STATUS_TIMEOUT - || i2c_hal_is_bus_busy(&(p_i2c->i2c_hal))) { + || i2c_hal_is_bus_busy(&(i2c_context[i2c_num].hal))) { i2c_hw_fsm_reset(i2c_num); clear_bus_cnt = 0; } @@ -1142,8 +1152,8 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, i2c_reset_rx_fifo(i2c_num); // These two interrupts some times can not be cleared when the FSM gets stuck. // so we disable them when these two interrupt occurs and re-enable them here. - i2c_hal_disable_intr_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK); - i2c_hal_clr_intsts_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK); + i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK); + i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK); //start send commands, at most 32 bytes one time, isr handler will process the remaining commands. i2c_master_cmd_begin_static(i2c_num); @@ -1222,9 +1232,9 @@ int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, TickType if (res == pdFALSE) { cnt = 0; } else { - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_enable_slave_tx_it(&(p_i2c->i2c_hal)); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_enable_slave_tx_it(&(i2c_context[i2c_num].hal)); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); cnt = size; } xSemaphoreGive(p_i2c->slv_tx_mux); @@ -1246,9 +1256,9 @@ int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, Ti } portTickType ticks_rem = ticks_to_wait; portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait; - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - i2c_hal_enable_slave_rx_it(&(p_i2c->i2c_hal)); - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); + I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); + i2c_hal_enable_slave_rx_it(&(i2c_context[i2c_num].hal)); + I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); while(size_rem && ticks_rem <= ticks_to_wait) { uint8_t* pdata = (uint8_t*) xRingbufferReceiveUpTo(p_i2c->rx_ring_buf, &size, ticks_to_wait, size_rem); if (pdata && size > 0) { @@ -1263,4 +1273,4 @@ int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, Ti } xSemaphoreGive(p_i2c->slv_rx_mux); return max_size - size_rem; -} \ No newline at end of file +} diff --git a/components/driver/test/test_i2c.c b/components/driver/test/test_i2c.c index 68755d9b0..1b6ba618f 100644 --- a/components/driver/test/test_i2c.c +++ b/components/driver/test/test_i2c.c @@ -15,6 +15,8 @@ #include "soc/i2c_periph.h" #include "esp_system.h" #include "driver/pcnt.h" +#include "soc/uart_struct.h" +#include "driver/periph_ctrl.h" #define DATA_LENGTH 512 /*!scl_low = half_cycle; + clk_cal->scl_high = half_cycle; + clk_cal->sda_hold = half_cycle / 2; + clk_cal->sda_sample = clk_cal->scl_high / 2; + clk_cal->setup = half_cycle; + clk_cal->hold = half_cycle; + clk_cal->tout = half_cycle * 20; //default we set the timeout value to 10 bus cycles. +} + +/** + * @brief Configure the I2C bus timing related register. + * + * @param hw Beginning address of the peripheral registers + * @param bus_cfg Pointer to the data structure holding the register configuration. + * + * @return None + */ +static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg) +{ + //scl period + hw->scl_low_period.period = bus_cfg->scl_low; + hw->scl_high_period.period = bus_cfg->scl_high; + //sda sample + hw->sda_hold.time = bus_cfg->sda_hold; + hw->sda_sample.time = bus_cfg->sda_sample; + //setup + hw->scl_rstart_setup.time = bus_cfg->setup; + hw->scl_stop_setup.time = bus_cfg->setup; + //hold + hw->scl_start_hold.time = bus_cfg->hold; + hw->scl_stop_hold.time = bus_cfg->hold; + hw->timeout.tout = bus_cfg->tout; +} + /** * @brief Reset I2C txFIFO * @@ -178,7 +238,7 @@ static inline void i2c_ll_set_fifo_mode(i2c_dev_t *hw, bool fifo_mode_en) */ static inline void i2c_ll_set_tout(i2c_dev_t *hw, int tout) { - hw->timeout.tout = tout; + hw->timeout.tout = tout; } /** diff --git a/components/soc/esp32s2beta/include/hal/i2c_ll.h b/components/soc/esp32s2beta/include/hal/i2c_ll.h index 13fdd1ad6..e3d080aa8 100644 --- a/components/soc/esp32s2beta/include/hal/i2c_ll.h +++ b/components/soc/esp32s2beta/include/hal/i2c_ll.h @@ -48,6 +48,20 @@ typedef enum { I2C_INTR_EVENT_TXFIFO_EMPTY, /*!< I2C txfifo empty event */ } i2c_intr_event_t; +/** + * @brief Data structure for calculating I2C bus timing. + */ +typedef struct { + uint16_t scl_low; /*!< I2C scl low period */ + uint16_t scl_high; /*!< I2C scl hight period */ + uint16_t scl_wait_high; /*!< I2C scl wait_high period */ + uint16_t sda_hold; /*!< I2C scl low period */ + uint16_t sda_sample; /*!< I2C sda sample time */ + uint16_t setup; /*!< I2C start and stop condition setup period */ + uint16_t hold; /*!< I2C start and stop condition hold period */ + uint16_t tout; /*!< I2C bus timeout period */ +} i2c_clk_cal_t; + // Get the I2C hardware instance #define I2C_LL_GET_HW(i2c_num) (((i2c_num) == 0) ? &I2C0 : &I2C1) // Get the I2C hardware FIFO address @@ -62,6 +76,58 @@ typedef enum { #define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) +/** + * @brief Calculate I2C bus frequency + * + * @param source_clk I2C source clock + * @param bus_freq I2C bus frequency + * @param clk_cal Pointer to accept the clock configuration + * + * @return None + */ +static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2c_clk_cal_t *clk_cal) +{ + uint32_t half_cycle = source_clk / bus_freq / 2; + //SCL + clk_cal->scl_low = half_cycle; + // default, scl_wait_high < scl_high + clk_cal->scl_high = half_cycle / 2 + 2; + clk_cal->scl_wait_high = half_cycle - clk_cal->scl_high; + clk_cal->sda_hold = half_cycle / 2; + // scl_wait_high < sda_sample <= scl_high + clk_cal->sda_sample = half_cycle / 2 - 1; + clk_cal->setup = half_cycle; + clk_cal->hold = half_cycle; + //default we set the timeout value to 10 bus cycles + clk_cal->tout = half_cycle * 20; +} + +/** + * @brief Configure the I2C bus timing related register. + * + * @param hw Beginning address of the peripheral registers + * @param bus_cfg Pointer to the data structure holding the register configuration. + * + * @return None + */ +static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg) +{ + //scl period + hw->scl_low_period.period = bus_cfg->scl_low - 1; + hw->scl_high_period.period = bus_cfg->scl_high; + hw->scl_high_period.scl_wait_high_period = bus_cfg->scl_wait_high; + //sda sample + hw->sda_hold.time = bus_cfg->sda_hold; + hw->sda_sample.time = bus_cfg->sda_sample; + //setup + hw->scl_rstart_setup.time = bus_cfg->setup; + hw->scl_stop_setup.time = bus_cfg->setup; + //hold + hw->scl_start_hold.time = bus_cfg->hold - 1; + hw->scl_stop_hold.time = bus_cfg->hold; + hw->timeout.tout = bus_cfg->tout; +} + /** * @brief Reset I2C txFIFO * @@ -92,16 +158,16 @@ static inline void i2c_ll_rxfifo_rst(i2c_dev_t *hw) * @brief Configure I2C SCL timing * * @param hw Beginning address of the peripheral registers - * @param hight_period The I2C SCL hight period (in APB cycle) - * @param low_period The I2C SCL low period (in APB cycle) + * @param hight_period The I2C SCL hight period (in APB cycle, hight_period > 2) + * @param low_period The I2C SCL low period (in APB cycle, low_period > 1) * * @return None. */ static inline void i2c_ll_set_scl_timing(i2c_dev_t *hw, int hight_period, int low_period) { - hw->scl_low_period.period = low_period; - hw->scl_high_period.period = hight_period; - hw->scl_high_period.scl_wait_high_period = 0; + hw->scl_low_period.period = low_period-1; + hw->scl_high_period.period = hight_period/2+2; + hw->scl_high_period.scl_wait_high_period = hight_period - hw->scl_high_period.period; } /** @@ -222,7 +288,7 @@ static inline void i2c_ll_write_cmd_reg(i2c_dev_t *hw, i2c_hw_cmd_t cmd, int cmd static inline void i2c_ll_set_start_timing(i2c_dev_t *hw, int start_setup, int start_hold) { hw->scl_rstart_setup.time = start_setup; - hw->scl_start_hold.time = start_hold; + hw->scl_start_hold.time = start_hold-1; } /** @@ -422,7 +488,7 @@ static inline void i2c_ll_trans_start(i2c_dev_t *hw) static inline void i2c_ll_get_start_timing(i2c_dev_t *hw, int *setup_time, int *hold_time) { *setup_time = hw->scl_rstart_setup.time; - *hold_time = hw->scl_start_hold.time; + *hold_time = hw->scl_start_hold.time+1; } /** @@ -451,8 +517,8 @@ static inline void i2c_ll_get_stop_timing(i2c_dev_t *hw, int *setup_time, int *h */ static inline void i2c_ll_get_scl_timing(i2c_dev_t *hw, int *high_period, int *low_period) { - *high_period = hw->scl_high_period.period; - *low_period = hw->scl_low_period.period; + *high_period = hw->scl_high_period.period + hw->scl_high_period.scl_wait_high_period; + *low_period = hw->scl_low_period.period + 1; } /** @@ -797,4 +863,4 @@ static inline void i2c_ll_slave_init(i2c_dev_t *hw) ctrl_reg.ref_always_on = 1; hw->ctr.val = ctrl_reg.val; hw->fifo_conf.fifo_addr_cfg_en = 0; -} \ No newline at end of file +} diff --git a/components/soc/include/hal/i2c_hal.h b/components/soc/include/hal/i2c_hal.h index a104ad51e..5b148e02a 100644 --- a/components/soc/include/hal/i2c_hal.h +++ b/components/soc/include/hal/i2c_hal.h @@ -111,7 +111,7 @@ typedef struct { #define i2c_hal_slave_clr_rx_it(hal) i2c_ll_slave_clr_rx_it((hal)->dev) /** - * @brief Get the I2C hardware instance and init the I2C master. Note that this function should be called before other hal layer function is called. + * @brief Init the I2C master. * * @param hal Context of the HAL layer * @param i2c_num I2C port number @@ -121,7 +121,7 @@ typedef struct { void i2c_hal_master_init(i2c_hal_context_t *hal, i2c_port_t i2c_num); /** - * @brief Get the I2C hardware instance and init the I2C slave. Note that this function should be called before other hal layer function is called. + * @brief Init the I2C slave. * * @param hal Context of the HAL layer * @param i2c_num I2C port number diff --git a/components/soc/src/hal/i2c_hal.c b/components/soc/src/hal/i2c_hal.c index 2d6625953..6c8a7770c 100644 --- a/components/soc/src/hal/i2c_hal.c +++ b/components/soc/src/hal/i2c_hal.c @@ -177,21 +177,13 @@ void i2c_hal_disable_slave_rx_it(i2c_hal_context_t *hal) void i2c_hal_set_bus_timing(i2c_hal_context_t *hal, uint32_t scl_freq, i2c_sclk_t src_clk) { uint32_t sclk = (src_clk == I2C_SCLK_REF_TICK) ? 1000000 : 80000000; - uint32_t cycle = sclk / scl_freq; - i2c_ll_set_source_clk(hal->dev, src_clk); - // Set SDA timing - i2c_ll_set_sda_timing(hal->dev, cycle/4, cycle/4); - // Set start timing - i2c_ll_set_start_timing(hal->dev, cycle/2, cycle/2); - i2c_ll_set_scl_timing(hal->dev, cycle/2, cycle/2); - i2c_ll_set_stop_timing(hal->dev, cycle/2, cycle/2); - //Set time out value - i2c_ll_set_tout(hal->dev, cycle * 9); + i2c_clk_cal_t clk_cal = {0}; + i2c_ll_cal_bus_clk(sclk, scl_freq, &clk_cal); + i2c_ll_set_bus_timing(hal->dev, &clk_cal); } void i2c_hal_slave_init(i2c_hal_context_t *hal, int i2c_num) { - hal->dev = I2C_LL_GET_HW(i2c_num); i2c_ll_slave_init(hal->dev); //Use fifo mode i2c_ll_set_fifo_mode(hal->dev, true); @@ -214,7 +206,6 @@ void i2c_hal_master_fsm_rst(i2c_hal_context_t *hal) void i2c_hal_master_init(i2c_hal_context_t *hal, int i2c_num) { - hal->dev = I2C_LL_GET_HW(i2c_num); hal->version = i2c_ll_get_hw_version(hal->dev); i2c_ll_master_init(hal->dev); //Use fifo mode diff --git a/examples/peripherals/i2c/i2c_self_test/main/i2c_example_main.c b/examples/peripherals/i2c/i2c_self_test/main/i2c_example_main.c index e5d8de7a3..ad70cbcba 100644 --- a/examples/peripherals/i2c/i2c_self_test/main/i2c_example_main.c +++ b/examples/peripherals/i2c/i2c_self_test/main/i2c_example_main.c @@ -151,8 +151,8 @@ static esp_err_t i2c_master_init(void) conf.scl_io_num = I2C_MASTER_SCL_IO; conf.scl_pullup_en = GPIO_PULLUP_ENABLE; conf.master.clk_speed = I2C_MASTER_FREQ_HZ; - i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); - return i2c_param_config(i2c_master_port, &conf); + i2c_param_config(i2c_master_port, &conf); + return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); } /** @@ -169,8 +169,8 @@ static esp_err_t i2c_slave_init(void) conf_slave.mode = I2C_MODE_SLAVE; conf_slave.slave.addr_10bit_en = 0; conf_slave.slave.slave_addr = ESP_SLAVE_ADDR; - i2c_driver_install(i2c_slave_port, conf_slave.mode, I2C_SLAVE_RX_BUF_LEN, I2C_SLAVE_TX_BUF_LEN, 0); - return i2c_param_config(i2c_slave_port, &conf_slave); + i2c_param_config(i2c_slave_port, &conf_slave); + return i2c_driver_install(i2c_slave_port, conf_slave.mode, I2C_SLAVE_RX_BUF_LEN, I2C_SLAVE_TX_BUF_LEN, 0); } /**