From 31b88a4c88a757d9afcd50b72c8aeefd0c5c70ac Mon Sep 17 00:00:00 2001 From: Cao Sen Miao Date: Wed, 24 Aug 2022 16:29:00 +0800 Subject: [PATCH] I2C: Refactor i2c hal and ll --- components/driver/i2c.c | 165 +++-- components/hal/esp32/include/hal/i2c_ll.h | 556 +++++++++-------- components/hal/esp32c2/include/hal/i2c_ll.h | 320 +++++----- components/hal/esp32c3/include/hal/i2c_ll.h | 501 ++++++++------- components/hal/esp32h2/include/hal/i2c_ll.h | 514 ++++++++-------- components/hal/esp32s2/include/hal/i2c_ll.h | 501 +++++++-------- components/hal/esp32s3/include/hal/i2c_ll.h | 569 +++++++++--------- components/hal/i2c_hal.c | 187 ++---- components/hal/i2c_hal_iram.c | 48 +- components/hal/include/hal/i2c_hal.h | 510 ++-------------- components/hal/include/hal/i2c_types.h | 32 + .../esp32c2/include/soc/Kconfig.soc_caps.in | 2 +- components/soc/esp32c2/include/soc/soc_caps.h | 2 +- 13 files changed, 1669 insertions(+), 2238 deletions(-) diff --git a/components/driver/i2c.c b/components/driver/i2c.c index fa0a2906e7..2889955ea4 100644 --- a/components/driver/i2c.c +++ b/components/driver/i2c.c @@ -34,8 +34,6 @@ #include "clk_ctrl_os.h" #endif - - static const char *I2C_TAG = "i2c"; /* DRAM_ATTR is required to avoid I2C array placed in flash, due to accessed from ISR */ @@ -376,8 +374,8 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_ } i2c_hw_enable(i2c_num); //Disable I2C interrupt. - i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK); - i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK); + i2c_ll_disable_intr_mask(i2c_context[i2c_num].hal.dev, I2C_LL_INTR_MASK); + i2c_ll_clear_intr_mask(i2c_context[i2c_num].hal.dev, I2C_LL_INTR_MASK); //hook isr handler ret = esp_intr_alloc(i2c_periph_signal[i2c_num].irq, intr_alloc_flags, i2c_isr_handler_default, p_i2c_obj[i2c_num], @@ -386,7 +384,7 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_ #if SOC_I2C_SUPPORT_SLAVE //Enable I2C slave rx interrupt if (mode == I2C_MODE_SLAVE) { - i2c_hal_enable_slave_rx_it(&(i2c_context[i2c_num].hal)); + i2c_ll_slave_enable_rx_it(i2c_context[i2c_num].hal.dev); } #endif // SOC_I2C_SUPPORT_SLAVE return ESP_OK; @@ -443,7 +441,7 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num) ESP_RETURN_ON_FALSE(p_i2c_obj[i2c_num] != NULL, ESP_FAIL, I2C_TAG, I2C_DRIVER_ERR_STR); i2c_obj_t *p_i2c = p_i2c_obj[i2c_num]; - i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK); + i2c_ll_disable_intr_mask(i2c_context[i2c_num].hal.dev, I2C_LL_INTR_MASK); esp_intr_free(p_i2c->intr_handle); p_i2c->intr_handle = NULL; @@ -500,7 +498,7 @@ esp_err_t i2c_reset_tx_fifo(i2c_port_t i2c_num) { ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_NUM_ERROR_STR); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_txfifo_rst(&(i2c_context[i2c_num].hal)); + i2c_ll_txfifo_rst(i2c_context[i2c_num].hal.dev); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -509,7 +507,7 @@ esp_err_t i2c_reset_rx_fifo(i2c_port_t i2c_num) { ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_NUM_ERROR_STR); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_rxfifo_rst(&(i2c_context[i2c_num].hal)); + i2c_ll_rxfifo_rst(i2c_context[i2c_num].hal.dev); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -522,7 +520,7 @@ static void IRAM_ATTR i2c_isr_handler_default(void *arg) // On C3 and S3 targets, the I2C may trigger a spurious interrupt, // in order to detect these false positive, check the I2C's hardware interrupt mask uint32_t int_mask; - i2c_hal_get_intsts_mask(&(i2c_context[i2c_num].hal), &int_mask); + i2c_ll_get_intr_mask(i2c_context[i2c_num].hal.dev, &int_mask); if (int_mask == 0) { return; } @@ -561,25 +559,25 @@ static void IRAM_ATTR i2c_isr_handler_default(void *arg) } #if SOC_I2C_SUPPORT_SLAVE else { - i2c_hal_slave_handle_event(&(i2c_context[i2c_num].hal), &evt_type); + i2c_ll_slave_get_event(i2c_context[i2c_num].hal.dev, &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(&(i2c_context[i2c_num].hal), &rx_fifo_cnt); - i2c_hal_read_rxfifo(&(i2c_context[i2c_num].hal), p_i2c->data_buf, rx_fifo_cnt); + i2c_ll_get_rxfifo_cnt(i2c_context[i2c_num].hal.dev, &rx_fifo_cnt); + i2c_ll_read_rxfifo(i2c_context[i2c_num].hal.dev, 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(&(i2c_context[i2c_num].hal)); + i2c_ll_clear_intr_mask(i2c_context[i2c_num].hal.dev, int_mask); } else if (evt_type == I2C_INTR_EVENT_TXFIFO_EMPTY) { uint32_t tx_fifo_rem; - i2c_hal_get_txfifo_cnt(&(i2c_context[i2c_num].hal), &tx_fifo_rem); + i2c_ll_get_txfifo_len(i2c_context[i2c_num].hal.dev, &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(&(i2c_context[i2c_num].hal), data, size); + i2c_ll_write_txfifo(i2c_context[i2c_num].hal.dev, data, size); vRingbufferReturnItemFromISR(p_i2c->tx_ring_buf, data, &HPTaskAwoken); } else { - i2c_hal_disable_slave_tx_it(&(i2c_context[i2c_num].hal)); + i2c_ll_slave_disable_tx_it(i2c_context[i2c_num].hal.dev); } - i2c_hal_slave_clr_tx_it(&(i2c_context[i2c_num].hal)); + i2c_ll_clear_intr_mask(i2c_context[i2c_num].hal.dev, int_mask); } } #endif // SOC_I2C_SUPPORT_SLAVE @@ -595,8 +593,8 @@ esp_err_t i2c_set_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t tx_trans_mode, ESP_RETURN_ON_FALSE(tx_trans_mode < I2C_DATA_MODE_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_TRANS_MODE_ERR_STR); ESP_RETURN_ON_FALSE(rx_trans_mode < I2C_DATA_MODE_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_TRANS_MODE_ERR_STR); 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_hal_update_config(&(i2c_context[i2c_num].hal)); + i2c_ll_set_data_mode(i2c_context[i2c_num].hal.dev, tx_trans_mode, rx_trans_mode); + i2c_ll_update(i2c_context[i2c_num].hal.dev); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -604,7 +602,7 @@ esp_err_t i2c_set_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t tx_trans_mode, 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) { ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_NUM_ERROR_STR); - i2c_hal_get_data_mode(&(i2c_context[i2c_num].hal), tx_trans_mode, rx_trans_mode); + i2c_ll_get_data_mode(i2c_context[i2c_num].hal.dev, tx_trans_mode, rx_trans_mode); return ESP_OK; } @@ -642,7 +640,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(&(i2c_context[i2c_num].hal)); + i2c_ll_master_clr_bus(i2c_context[i2c_num].hal.dev); #endif return ESP_OK; } @@ -656,36 +654,24 @@ static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num) // A workaround for avoiding cause timeout issue when using // hardware reset. #if !SOC_I2C_SUPPORT_HW_FSM_RST - int scl_low_period, scl_high_period, scl_wait_high_period; - int scl_start_hold, scl_rstart_setup; - int scl_stop_hold, scl_stop_setup; - int sda_hold, sda_sample; - int timeout; + i2c_hal_timing_config_t timing_config; uint8_t filter_cfg; - i2c_hal_get_scl_clk_timing(&(i2c_context[i2c_num].hal), &scl_high_period, &scl_low_period, &scl_wait_high_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); + i2c_hal_get_timing_config(&i2c_context[i2c_num].hal, &timing_config); + i2c_ll_get_filter(i2c_context[i2c_num].hal.dev, &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(&(i2c_context[i2c_num].hal), i2c_num); - i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK); - i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK); - i2c_hal_set_scl_clk_timing(&(i2c_context[i2c_num].hal), scl_high_period, scl_low_period, scl_wait_high_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); + i2c_hal_master_init(&(i2c_context[i2c_num].hal)); + i2c_ll_disable_intr_mask(i2c_context[i2c_num].hal.dev, I2C_LL_INTR_MASK); + i2c_ll_clear_intr_mask(i2c_context[i2c_num].hal.dev, I2C_LL_INTR_MASK); + i2c_hal_set_timing_config(&i2c_context[i2c_num].hal, &timing_config); + i2c_ll_set_filter(i2c_context[i2c_num].hal.dev, filter_cfg); #else - i2c_hal_master_fsm_rst(&(i2c_context[i2c_num].hal)); + i2c_ll_master_fsm_rst(i2c_context[i2c_num].hal.dev); i2c_master_clear_bus(i2c_num); #endif return ESP_OK; @@ -769,28 +755,29 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t *i2c_conf) } i2c_hw_enable(i2c_num); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK); - i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK); + i2c_ll_disable_intr_mask(i2c_context[i2c_num].hal.dev, I2C_LL_INTR_MASK); + i2c_ll_clear_intr_mask(i2c_context[i2c_num].hal.dev, I2C_LL_INTR_MASK); #if SOC_I2C_SUPPORT_SLAVE if (i2c_conf->mode == I2C_MODE_SLAVE) { //slave mode - i2c_hal_slave_init(&(i2c_context[i2c_num].hal), i2c_num); - i2c_hal_set_source_clk(&(i2c_context[i2c_num].hal), src_clk); - 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); + i2c_hal_slave_init(&(i2c_context[i2c_num].hal)); + i2c_ll_slave_tx_auto_start_en(i2c_context[i2c_num].hal.dev, true); + i2c_ll_set_source_clk(i2c_context[i2c_num].hal.dev, src_clk); + i2c_ll_set_slave_addr(i2c_context[i2c_num].hal.dev, i2c_conf->slave.slave_addr, i2c_conf->slave.addr_10bit_en); + i2c_ll_set_rxfifo_full_thr(i2c_context[i2c_num].hal.dev, I2C_FIFO_FULL_THRESH_VAL); + i2c_ll_set_txfifo_empty_thr(i2c_context[i2c_num].hal.dev, I2C_FIFO_EMPTY_THRESH_VAL); //set timing for data - 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_rx_it(&(i2c_context[i2c_num].hal)); + i2c_ll_set_sda_timing(i2c_context[i2c_num].hal.dev, I2C_SLAVE_SDA_SAMPLE_DEFAULT, I2C_SLAVE_SDA_HOLD_DEFAULT); + i2c_ll_set_tout(i2c_context[i2c_num].hal.dev, I2C_SLAVE_TIMEOUT_DEFAULT); + i2c_ll_slave_enable_rx_it(i2c_context[i2c_num].hal.dev); } else #endif // SOC_I2C_SUPPORT_SLAVE { - i2c_hal_master_init(&(i2c_context[i2c_num].hal), i2c_num); + i2c_hal_master_init(&(i2c_context[i2c_num].hal)); //Default, we enable hardware filter - i2c_hal_set_filter(&(i2c_context[i2c_num].hal), I2C_FILTER_CYC_NUM_DEF); + i2c_ll_set_filter(i2c_context[i2c_num].hal.dev, I2C_FILTER_CYC_NUM_DEF); i2c_hal_set_bus_timing(&(i2c_context[i2c_num].hal), i2c_conf->master.clk_speed, src_clk, s_get_src_clk_freq(src_clk)); } - i2c_hal_update_config(&(i2c_context[i2c_num].hal)); + i2c_ll_update(i2c_context[i2c_num].hal.dev); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -802,8 +789,8 @@ esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period) ESP_RETURN_ON_FALSE((low_period <= I2C_SCL_LOW_PERIOD_V) && (low_period > 0), ESP_ERR_INVALID_ARG, I2C_TAG, I2C_TIMING_VAL_ERR_STR); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_set_scl_timing(&(i2c_context[i2c_num].hal), high_period, low_period); - i2c_hal_update_config(&(i2c_context[i2c_num].hal)); + i2c_ll_set_scl_timing(i2c_context[i2c_num].hal.dev, high_period, low_period); + i2c_ll_update(i2c_context[i2c_num].hal.dev); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -812,7 +799,7 @@ esp_err_t i2c_get_period(i2c_port_t i2c_num, int *high_period, int *low_period) { ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX && high_period != NULL && low_period != NULL, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_NUM_ERROR_STR); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_get_scl_timing(&(i2c_context[i2c_num].hal), high_period, low_period); + i2c_ll_get_scl_timing(i2c_context[i2c_num].hal.dev, high_period, low_period); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -822,8 +809,8 @@ esp_err_t i2c_filter_enable(i2c_port_t i2c_num, uint8_t cyc_num) ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_NUM_ERROR_STR); ESP_RETURN_ON_FALSE(p_i2c_obj[i2c_num] != NULL, ESP_FAIL, I2C_TAG, I2C_DRIVER_ERR_STR); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_set_filter(&(i2c_context[i2c_num].hal), cyc_num); - i2c_hal_update_config(&(i2c_context[i2c_num].hal)); + i2c_ll_set_filter(i2c_context[i2c_num].hal.dev, cyc_num); + i2c_ll_update(i2c_context[i2c_num].hal.dev); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -832,8 +819,8 @@ esp_err_t i2c_filter_disable(i2c_port_t i2c_num) { ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_NUM_ERROR_STR); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_set_filter(&(i2c_context[i2c_num].hal), 0); - i2c_hal_update_config(&(i2c_context[i2c_num].hal)); + i2c_ll_set_filter(i2c_context[i2c_num].hal.dev, 0); + i2c_ll_update(i2c_context[i2c_num].hal.dev); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -845,8 +832,8 @@ esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time ESP_RETURN_ON_FALSE((setup_time <= I2C_SCL_RSTART_SETUP_TIME_V) && (setup_time > 0), ESP_ERR_INVALID_ARG, I2C_TAG, I2C_TIMING_VAL_ERR_STR); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_set_start_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time); - i2c_hal_update_config(&(i2c_context[i2c_num].hal)); + i2c_ll_set_start_timing(i2c_context[i2c_num].hal.dev, setup_time, hold_time); + i2c_ll_update(i2c_context[i2c_num].hal.dev); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -855,7 +842,7 @@ esp_err_t i2c_get_start_timing(i2c_port_t i2c_num, int *setup_time, int *hold_ti { ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX && setup_time != NULL && hold_time != NULL, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_NUM_ERROR_STR); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_get_start_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time); + i2c_ll_get_start_timing(i2c_context[i2c_num].hal.dev, setup_time, hold_time); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -867,8 +854,8 @@ esp_err_t i2c_set_stop_timing(i2c_port_t i2c_num, int setup_time, int hold_time) ESP_RETURN_ON_FALSE((hold_time <= I2C_SCL_STOP_HOLD_TIME_V) && (hold_time > 0), ESP_ERR_INVALID_ARG, I2C_TAG, I2C_TIMING_VAL_ERR_STR); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_set_stop_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time); - i2c_hal_update_config(&(i2c_context[i2c_num].hal)); + i2c_ll_set_stop_timing(i2c_context[i2c_num].hal.dev, setup_time, hold_time); + i2c_ll_update(i2c_context[i2c_num].hal.dev); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -877,7 +864,7 @@ esp_err_t i2c_get_stop_timing(i2c_port_t i2c_num, int *setup_time, int *hold_tim { ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX && setup_time != NULL && hold_time != NULL, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_NUM_ERROR_STR); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_get_stop_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time); + i2c_ll_get_stop_timing(i2c_context[i2c_num].hal.dev, setup_time, hold_time); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -889,8 +876,8 @@ esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time ESP_RETURN_ON_FALSE((hold_time <= I2C_SDA_HOLD_TIME_V) && (hold_time > 0), ESP_ERR_INVALID_ARG, I2C_TAG, I2C_TIMING_VAL_ERR_STR); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_set_sda_timing(&(i2c_context[i2c_num].hal), sample_time, hold_time); - i2c_hal_update_config(&(i2c_context[i2c_num].hal)); + i2c_ll_set_sda_timing(i2c_context[i2c_num].hal.dev, sample_time, hold_time); + i2c_ll_update(i2c_context[i2c_num].hal.dev); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -899,7 +886,7 @@ esp_err_t i2c_get_data_timing(i2c_port_t i2c_num, int *sample_time, int *hold_ti { ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX && sample_time != NULL && hold_time != NULL, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_NUM_ERROR_STR); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_get_sda_timing(&(i2c_context[i2c_num].hal), sample_time, hold_time); + i2c_ll_get_sda_timing(i2c_context[i2c_num].hal.dev, sample_time, hold_time); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -910,7 +897,7 @@ esp_err_t i2c_set_timeout(i2c_port_t i2c_num, int timeout) ESP_RETURN_ON_FALSE((timeout <= I2C_LL_MAX_TIMEOUT) && (timeout > 0), ESP_ERR_INVALID_ARG, I2C_TAG, I2C_TIMING_VAL_ERR_STR); I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_set_tout(&(i2c_context[i2c_num].hal), timeout); + i2c_ll_set_tout(i2c_context[i2c_num].hal.dev, timeout); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); return ESP_OK; } @@ -918,7 +905,7 @@ esp_err_t i2c_set_timeout(i2c_port_t i2c_num, int timeout) esp_err_t i2c_get_timeout(i2c_port_t i2c_num, int *timeout) { ESP_RETURN_ON_FALSE(i2c_num < I2C_NUM_MAX && timeout != NULL, ESP_ERR_INVALID_ARG, I2C_TAG, I2C_NUM_ERROR_STR); - i2c_hal_get_tout(&(i2c_context[i2c_num].hal), timeout); + i2c_ll_get_tout(i2c_context[i2c_num].hal.dev, timeout); return ESP_OK; } @@ -1363,7 +1350,7 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num, portBASE_T i2c_cmd_evt_t evt = { 0 }; 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(&(i2c_context[i2c_num].hal), cmd->data + cmd->bytes_used, p_i2c->rx_cnt); + i2c_ll_read_rxfifo(i2c_context[i2c_num].hal.dev, cmd->data + cmd->bytes_used, p_i2c->rx_cnt); /* rx_cnt bytes have just been read, increment the number of bytes used from the buffer */ cmd->bytes_used += p_i2c->rx_cnt; @@ -1425,10 +1412,10 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num, portBASE_T write_pr = (uint8_t*) &cmd->data_byte; } hw_cmd.byte_num = fifo_fill; - i2c_hal_write_txfifo(&(i2c_context[i2c_num].hal), write_pr, fifo_fill); - 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)); + i2c_ll_write_txfifo(i2c_context[i2c_num].hal.dev, write_pr, fifo_fill); + i2c_ll_write_cmd_reg(i2c_context[i2c_num].hal.dev, hw_cmd, p_i2c->cmd_idx); + i2c_ll_write_cmd_reg(i2c_context[i2c_num].hal.dev, hw_end_cmd, p_i2c->cmd_idx + 1); + i2c_ll_master_enable_tx_it(i2c_context[i2c_num].hal.dev); p_i2c->cmd_idx = 0; if (i2c_cmd_is_single_byte(cmd) || cmd->total_bytes == cmd->bytes_used) { p_i2c->cmd_link.head = p_i2c->cmd_link.head->next; @@ -1443,13 +1430,13 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num, portBASE_T fifo_fill = MIN(remaining_bytes, SOC_I2C_FIFO_LEN); p_i2c->rx_cnt = fifo_fill; hw_cmd.byte_num = fifo_fill; - 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)); + i2c_ll_write_cmd_reg(i2c_context[i2c_num].hal.dev, hw_cmd, p_i2c->cmd_idx); + i2c_ll_write_cmd_reg(i2c_context[i2c_num].hal.dev, hw_end_cmd, p_i2c->cmd_idx + 1); + i2c_ll_master_enable_rx_it(i2c_context[i2c_num].hal.dev); p_i2c->status = I2C_STATUS_READ; break; } else { - i2c_hal_write_cmd_reg(&(i2c_context[i2c_num].hal), hw_cmd, p_i2c->cmd_idx); + i2c_ll_write_cmd_reg(i2c_context[i2c_num].hal.dev, hw_cmd, p_i2c->cmd_idx); } p_i2c->cmd_idx++; p_i2c->cmd_link.head = p_i2c->cmd_link.head->next; @@ -1458,8 +1445,8 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num, portBASE_T break; } } - i2c_hal_update_config(&(i2c_context[i2c_num].hal)); - i2c_hal_trans_start(&(i2c_context[i2c_num].hal)); + i2c_ll_update(i2c_context[i2c_num].hal.dev); + i2c_ll_trans_start(i2c_context[i2c_num].hal.dev); return; } @@ -1513,7 +1500,7 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, #endif xQueueReset(p_i2c->cmd_evt_queue); if (p_i2c->status == I2C_STATUS_TIMEOUT - || i2c_hal_is_bus_busy(&(i2c_context[i2c_num].hal))) { + || i2c_ll_is_bus_busy(i2c_context[i2c_num].hal.dev)) { i2c_hw_fsm_reset(i2c_num); clear_bus_cnt[i2c_num] = 0; } @@ -1534,8 +1521,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(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK); - i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), I2C_LL_INTR_MASK); + i2c_ll_disable_intr_mask(i2c_context[i2c_num].hal.dev, I2C_LL_INTR_MASK); + i2c_ll_clear_intr_mask(i2c_context[i2c_num].hal.dev, I2C_LL_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, NULL); @@ -1616,7 +1603,7 @@ int i2c_slave_write_buffer(i2c_port_t i2c_num, const uint8_t *data, int size, Ti cnt = 0; } else { I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_enable_slave_tx_it(&(i2c_context[i2c_num].hal)); + i2c_ll_slave_enable_tx_it(i2c_context[i2c_num].hal.dev); I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock)); cnt = size; } @@ -1640,7 +1627,7 @@ int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t *data, size_t max_size, Ti TickType_t ticks_rem = ticks_to_wait; TickType_t ticks_end = xTaskGetTickCount() + ticks_to_wait; I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock)); - i2c_hal_enable_slave_rx_it(&(i2c_context[i2c_num].hal)); + i2c_ll_slave_enable_rx_it(i2c_context[i2c_num].hal.dev); 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); diff --git a/components/hal/esp32/include/hal/i2c_ll.h b/components/hal/esp32/include/hal/i2c_ll.h index af94151cf0..83b898b0dd 100644 --- a/components/hal/esp32/include/hal/i2c_ll.h +++ b/components/hal/esp32/include/hal/i2c_ll.h @@ -8,18 +8,18 @@ #pragma once +#include #include "hal/misc.h" #include "soc/i2c_periph.h" #include "soc/i2c_struct.h" #include "soc/clk_tree_defs.h" #include "hal/i2c_types.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif -#define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ - /** * @brief I2C hardware cmd register fields. */ @@ -36,33 +36,6 @@ typedef union { uint32_t val; } i2c_hw_cmd_t; -/** - * @brief I2C interrupt event - */ -typedef enum { - I2C_INTR_EVENT_ERR, - I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */ - I2C_INTR_EVENT_NACK, /*!< I2C NACK event */ - I2C_INTR_EVENT_TOUT, /*!< I2C time out event */ - I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */ - I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */ - I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */ - 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 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; - // I2C operation mode command #define I2C_LL_CMD_RESTART 0 /*!scl_low = half_cycle; @@ -114,7 +92,7 @@ static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2 * * @return None */ -static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg) +static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_hal_clk_config_t *bus_cfg) { /* SCL period. According to the TRM, we should always subtract 1 to SCL low period */ assert(bus_cfg->scl_low > 0); @@ -199,7 +177,8 @@ static inline void i2c_ll_set_scl_timing(i2c_dev_t *hw, int hight_period, int lo * * @return None */ -static inline void i2c_ll_clr_intsts_mask(i2c_dev_t *hw, uint32_t mask) +__attribute__((always_inline)) +static inline void i2c_ll_clear_intr_mask(i2c_dev_t *hw, uint32_t mask) { hw->int_clr.val = mask; } @@ -225,6 +204,7 @@ static inline void i2c_ll_enable_intr_mask(i2c_dev_t *hw, uint32_t mask) * * @return None */ +__attribute__((always_inline)) static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) { hw->int_ena.val &= (~mask); @@ -237,9 +217,10 @@ static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) * * @return I2C interrupt status */ -static inline uint32_t i2c_ll_get_intsts_mask(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_intr_mask(i2c_dev_t *hw, uint32_t *intr_status) { - return hw->int_status.val; + *intr_status = hw->int_status.val; } /** @@ -413,17 +394,6 @@ static inline void i2c_ll_get_sda_timing(i2c_dev_t *hw, int *sda_sample, int *sd *sda_sample = hw->sda_sample.time; } -/** - * @brief Get the I2C hardware version - * - * @param hw Beginning address of the peripheral registers - * - * @return The I2C hardware version - */ -static inline uint32_t i2c_ll_get_hw_version(i2c_dev_t *hw) -{ - return hw->date; -} /** * @brief Check if the I2C bus is busy @@ -437,18 +407,6 @@ static inline bool i2c_ll_is_bus_busy(i2c_dev_t *hw) return hw->status_reg.bus_busy; } -/** - * @brief Check if I2C is master mode - * - * @param hw Beginning address of the peripheral registers - * - * @return True if I2C is master mode, else false will be returned - */ -static inline bool i2c_ll_is_master_mode(i2c_dev_t *hw) -{ - return hw->ctr.ms_mode; -} - /** * @brief Get the rxFIFO readable length * @@ -456,9 +414,10 @@ static inline bool i2c_ll_is_master_mode(i2c_dev_t *hw) * * @return RxFIFO readable length */ -static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw, uint32_t *length) { - return hw->status_reg.rx_fifo_cnt; + *length = hw->status_reg.rx_fifo_cnt; } /** @@ -468,9 +427,10 @@ static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) * * @return TxFIFO writable length */ -static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_txfifo_len(i2c_dev_t *hw, uint32_t *length) { - return SOC_I2C_FIFO_LEN - hw->status_reg.tx_fifo_cnt; + *length = SOC_I2C_FIFO_LEN - hw->status_reg.tx_fifo_cnt; } /** @@ -480,9 +440,9 @@ static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) * * @return The I2C timeout value */ -static inline uint32_t i2c_ll_get_tout(i2c_dev_t *hw) +static inline void i2c_ll_get_tout(i2c_dev_t *hw, int *timeout) { - return hw->timeout.tout; + *timeout = hw->timeout.tout; } /** @@ -551,7 +511,8 @@ static inline void i2c_ll_get_scl_timing(i2c_dev_t *hw, int *high_period, int *l * * @return None. */ -static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) +__attribute__((always_inline)) +static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, const uint8_t *ptr, uint8_t len) { uint32_t fifo_addr = (hw == &I2C0) ? 0x6001301c : 0x6002701c; for(int i = 0; i < len; i++) { @@ -568,6 +529,7 @@ static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) * * @return None */ +__attribute__((always_inline)) static inline void i2c_ll_read_rxfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) { for(int i = 0; i < len; i++) { @@ -604,155 +566,9 @@ static inline void i2c_ll_set_filter(i2c_dev_t *hw, uint8_t filter_num) * * @return The hardware filter configuration */ -static inline uint8_t i2c_ll_get_filter(i2c_dev_t *hw) +static inline void i2c_ll_get_filter(i2c_dev_t *hw, uint8_t *filter_conf) { - return hw->sda_filter_cfg.thres; -} - -/** - * @brief Enable I2C master TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = ~0; - hw->int_ena.val = I2C_LL_MASTER_TX_INT; -} - -/** - * @brief Enable I2C master RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = ~0; - hw->int_ena.val = I2C_LL_MASTER_RX_INT; -} - -/** - * @brief Disable I2C master TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT); -} - -/** - * @brief Disable I2C master RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT); -} - -/** - * @brief Clear I2C master TX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_clr_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_MASTER_TX_INT; -} - -/** - * @brief Clear I2C master RX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_clr_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_MASTER_RX_INT; -} - -/** - * @brief - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_enable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val |= I2C_LL_SLAVE_TX_INT; -} - -/** - * @brief Enable I2C slave RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_enable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val |= I2C_LL_SLAVE_RX_INT; -} - -/** - * @brief Disable I2C slave TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_disable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_SLAVE_TX_INT); -} - -/** - * @brief Disable I2C slave RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_SLAVE_RX_INT); -} - -/** - * @brief Clear I2C slave TX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_clr_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_SLAVE_TX_INT; -} - -/** - * @brief Clear I2C slave RX interrupt status register. - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_clr_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_SLAVE_RX_INT; + *filter_conf = hw->sda_filter_cfg.thres; } /** @@ -795,54 +611,6 @@ static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_clock_source_t src_c ;//Not support on ESP32 } -/** - * @brief Get I2C master interrupt event - * - * @param hw Beginning address of the peripheral registers - * @param event Pointer to accept the interrupt event - * - * @return None - */ -static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) -{ - typeof(hw->int_status) int_sts = hw->int_status; - if (int_sts.arbitration_lost) { - *event = I2C_INTR_EVENT_ARBIT_LOST; - } else if (int_sts.ack_err) { - *event = I2C_INTR_EVENT_NACK; - } else if (int_sts.time_out) { - *event = I2C_INTR_EVENT_TOUT; - } else if (int_sts.end_detect) { - *event = I2C_INTR_EVENT_END_DET; - } else if (int_sts.trans_complete) { - *event = I2C_INTR_EVENT_TRANS_DONE; - } else { - *event = I2C_INTR_EVENT_ERR; - } -} - -/** - * @brief Get I2C slave interrupt event - * - * @param hw Beginning address of the peripheral registers - * @param event Pointer to accept the interrupt event - * - * @return None - */ -static inline void i2c_ll_slave_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) -{ - typeof(hw->int_status) int_sts = hw->int_status; - if (int_sts.tx_fifo_empty) { - *event = I2C_INTR_EVENT_TXFIFO_EMPTY; - } else if (int_sts.trans_complete) { - *event = I2C_INTR_EVENT_TRANS_DONE; - } else if (int_sts.rx_fifo_full) { - *event = I2C_INTR_EVENT_RXFIFO_FULL; - } else { - *event = I2C_INTR_EVENT_ERR; - } -} - /** * @brief Init I2C master * @@ -890,22 +658,60 @@ static inline void i2c_ll_update(i2c_dev_t *hw) } /** - * @brief Configure I2C SCL timing + * @brief Set whether slave should auto start, or only start with start signal from master * - * @param hw Beginning address of the peripheral registers - * @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2) - * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) - * @param wait_high_period The I2C SCL wait rising edge period. - * - * @return None. + * @param hw Beginning address of the peripheral registers + * @param slv_ex_auto_en 1 if slave auto start data transaction, otherwise, 0. */ -static inline void i2c_ll_set_scl_clk_timing(i2c_dev_t *hw, int high_period, int low_period, int wait_high_period) +static inline void i2c_ll_slave_tx_auto_start_en(i2c_dev_t *hw, bool slv_ex_auto_en) { - (void)wait_high_period; - hw->scl_low_period.period = low_period; - hw->scl_high_period.period = high_period; + ;// ESP32 do not support } +/** + * @brief Get I2C interrupt status register address + */ +static inline volatile void *i2c_ll_get_interrupt_status_reg(i2c_dev_t *dev) +{ + return &dev->int_status; +} + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Get the I2C hardware instance +#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == 0) ? &I2C0 : &I2C1) +// Get the I2C hardware FIFO address +#define I2C_LL_GET_FIFO_ADDR(i2c_num) (I2C_DATA_APB_REG(i2c_num)) +// I2C master TX interrupt bitmap +#define I2C_LL_MASTER_TX_INT (I2C_ACK_ERR_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) +// I2C master RX interrupt bitmap +#define I2C_LL_MASTER_RX_INT (I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) +// I2C slave TX interrupt bitmap +#define I2C_LL_SLAVE_TX_INT (I2C_TXFIFO_EMPTY_INT_ENA_M) +// I2C slave RX interrupt bitmap +#define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) +// I2C max timeout value +#define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_REG_V + +#define I2C_LL_INTR_MASK (0xffff) /*!< I2C all interrupt bitmap */ + +/** + * @brief I2C interrupt event + */ +typedef enum { + I2C_INTR_EVENT_ERR, + I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */ + I2C_INTR_EVENT_NACK, /*!< I2C NACK event */ + I2C_INTR_EVENT_TOUT, /*!< I2C time out event */ + I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */ + I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */ + I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */ + I2C_INTR_EVENT_TXFIFO_EMPTY, /*!< I2C txfifo empty event */ +} i2c_intr_event_t; + /** * @brief Get I2C SCL timing configuration * @@ -922,6 +728,186 @@ static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, in *low_period = hw->scl_low_period.period; } +/** + * @brief Configure I2C SCL timing + * + * @param hw Beginning address of the peripheral registers + * @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2) + * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) + * @param wait_high_period The I2C SCL wait rising edge period. + * + * @return None. + */ +static inline void i2c_ll_set_scl_clk_timing(i2c_dev_t *hw, int high_period, int low_period, int wait_high_period) +{ + (void)wait_high_period; + hw->scl_low_period.period = low_period; + hw->scl_high_period.period = high_period; +} + +/** + * @brief Get I2C slave interrupt event + * + * @param hw Beginning address of the peripheral registers + * @param event Pointer to accept the interrupt event + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) +{ + typeof(hw->int_status) int_sts = hw->int_status; + if (int_sts.tx_fifo_empty) { + *event = I2C_INTR_EVENT_TXFIFO_EMPTY; + } else if (int_sts.trans_complete) { + *event = I2C_INTR_EVENT_TRANS_DONE; + } else if (int_sts.rx_fifo_full) { + *event = I2C_INTR_EVENT_RXFIFO_FULL; + } else { + *event = I2C_INTR_EVENT_ERR; + } +} + +/** + * @brief Get I2C master interrupt event + * + * @param hw Beginning address of the peripheral registers + * @param event Pointer to accept the interrupt event + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) +{ + typeof(hw->int_status) int_sts = hw->int_status; + if (int_sts.arbitration_lost) { + *event = I2C_INTR_EVENT_ARBIT_LOST; + } else if (int_sts.ack_err) { + *event = I2C_INTR_EVENT_NACK; + } else if (int_sts.time_out) { + *event = I2C_INTR_EVENT_TOUT; + } else if (int_sts.end_detect) { + *event = I2C_INTR_EVENT_END_DET; + } else if (int_sts.trans_complete) { + *event = I2C_INTR_EVENT_TRANS_DONE; + } else { + *event = I2C_INTR_EVENT_ERR; + } +} + +/** + * @brief + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_enable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val |= I2C_LL_SLAVE_TX_INT; +} + +/** + * @brief Enable I2C slave RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_enable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val |= I2C_LL_SLAVE_RX_INT; +} + +/** + * @brief Disable I2C slave TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_disable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_SLAVE_TX_INT); +} + +/** + * @brief Disable I2C slave RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_SLAVE_RX_INT); +} + +/** + * @brief Enable I2C master TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw) +{ + hw->int_clr.val = UINT32_MAX; + hw->int_ena.val = I2C_LL_MASTER_TX_INT; +} + +/** + * @brief Enable I2C master RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw) +{ + hw->int_clr.val = UINT32_MAX; + hw->int_ena.val = I2C_LL_MASTER_RX_INT; +} + +/** + * @brief Disable I2C master TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT); +} + +/** + * @brief Disable I2C master RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT); +} + +/** + * @brief Get the I2C hardware version + * + * @param hw Beginning address of the peripheral registers + * + * @return The I2C hardware version + */ +static inline uint32_t i2c_ll_get_hw_version(i2c_dev_t *hw) +{ + return hw->date; +} + + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c2/include/hal/i2c_ll.h b/components/hal/esp32c2/include/hal/i2c_ll.h index 953e5d59a2..5a8db8aba5 100644 --- a/components/hal/esp32c2/include/hal/i2c_ll.h +++ b/components/hal/esp32c2/include/hal/i2c_ll.h @@ -8,6 +8,7 @@ #pragma once +#include #include "hal/misc.h" #include "soc/i2c_periph.h" #include "soc/soc_caps.h" @@ -16,13 +17,12 @@ #include "soc/rtc_cntl_reg.h" #include "soc/clk_tree_defs.h" #include "esp_rom_sys.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif -#define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ - /** * @brief I2C hardware cmd register fields. */ @@ -39,35 +39,6 @@ typedef union { uint32_t val; } i2c_hw_cmd_t; -/** - * @brief I2C interrupt event - */ -typedef enum { - I2C_INTR_EVENT_ERR, - I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */ - I2C_INTR_EVENT_NACK, /*!< I2C NACK event */ - I2C_INTR_EVENT_TOUT, /*!< I2C time out event */ - I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */ - I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */ - I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */ - 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 clkm_div; /*!< I2C core clock devider */ - 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; - // I2C operation mode command #define I2C_LL_CMD_RESTART 6 /*!ctr.conf_upgate = 1; @@ -142,7 +120,7 @@ static inline void i2c_ll_update(i2c_dev_t *hw) * * @return None */ -static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg) +static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_hal_clk_config_t *bus_cfg) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clk_conf, sclk_div_num, bus_cfg->clkm_div - 1); /* According to the Technical Reference Manual, the following timings must be subtracted by 1. @@ -216,7 +194,8 @@ static inline void i2c_ll_set_scl_timing(i2c_dev_t *hw, int hight_period, int lo * * @return None */ -static inline void i2c_ll_clr_intsts_mask(i2c_dev_t *hw, uint32_t mask) +__attribute__((always_inline)) +static inline void i2c_ll_clear_intr_mask(i2c_dev_t *hw, uint32_t mask) { hw->int_clr.val = mask; } @@ -242,6 +221,7 @@ static inline void i2c_ll_enable_intr_mask(i2c_dev_t *hw, uint32_t mask) * * @return None */ +__attribute__((always_inline)) static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) { hw->int_ena.val &= (~mask); @@ -254,9 +234,10 @@ static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) * * @return I2C interrupt status */ -static inline uint32_t i2c_ll_get_intsts_mask(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_intr_mask(i2c_dev_t *hw, uint32_t *intr_status) { - return hw->int_status.val; + *intr_status = hw->int_status.val; } /** @@ -458,9 +439,10 @@ static inline bool i2c_ll_is_master_mode(i2c_dev_t *hw) * * @return RxFIFO readable length */ -static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw, uint32_t *length) { - return hw->sr.rxfifo_cnt; + *length = hw->sr.rxfifo_cnt; } /** @@ -470,9 +452,10 @@ static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) * * @return TxFIFO writable length */ -static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_txfifo_len(i2c_dev_t *hw, uint32_t *length) { - return SOC_I2C_FIFO_LEN - hw->sr.txfifo_cnt; + *length = SOC_I2C_FIFO_LEN - hw->sr.txfifo_cnt; } /** @@ -482,9 +465,9 @@ static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) * * @return The I2C timeout value */ -static inline uint32_t i2c_ll_get_tout(i2c_dev_t *hw) +static inline void i2c_ll_get_tout(i2c_dev_t *hw, int *timeout) { - return hw->to.time_out_value; + *timeout = hw->to.time_out_value; } /** @@ -553,7 +536,8 @@ static inline void i2c_ll_get_scl_timing(i2c_dev_t *hw, int *high_period, int *l * * @return None. */ -static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) +__attribute__((always_inline)) +static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, const uint8_t *ptr, uint8_t len) { for (int i = 0; i< len; i++) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->data, fifo_rdata, ptr[i]); @@ -569,6 +553,7 @@ static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) * * @return None */ +__attribute__((always_inline)) static inline void i2c_ll_read_rxfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) { for(int i = 0; i < len; i++) { @@ -605,83 +590,9 @@ static inline void i2c_ll_set_filter(i2c_dev_t *hw, uint8_t filter_num) * * @return The hardware filter configuration */ -static inline uint8_t i2c_ll_get_filter(i2c_dev_t *hw) +static inline void i2c_ll_get_filter(i2c_dev_t *hw, uint8_t *filter_conf) { - return hw->filter_cfg.scl_filter_thres; -} - -/** - * @brief Enable I2C master TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = ~0; - hw->int_ena.val = I2C_LL_MASTER_TX_INT; -} - -/** - * @brief Enable I2C master RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = ~0; - hw->int_ena.val = I2C_LL_MASTER_RX_INT; -} - -/** - * @brief Disable I2C master TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT); -} - -/** - * @brief Disable I2C master RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT); -} - -/** - * @brief Clear I2C master TX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_clr_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_MASTER_TX_INT; -} - -/** - * @brief Clear I2C master RX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_clr_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_MASTER_RX_INT; + *filter_conf = hw->filter_cfg.scl_filter_thres; } /** @@ -693,6 +604,7 @@ static inline void i2c_ll_master_clr_rx_it(i2c_dev_t *hw) */ static inline void i2c_ll_master_fsm_rst(i2c_dev_t *hw) { + // fsm_rst is a self cleared bit. hw->ctr.fsm_rst = 1; } @@ -731,32 +643,6 @@ static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_clock_source_t src_c hw->clk_conf.sclk_sel = (src_clk == I2C_CLK_SRC_RC_FAST) ? 1 : 0; } -/** - * @brief Get I2C master interrupt event - * - * @param hw Beginning address of the peripheral registers - * @param event Pointer to accept the interrupt event - * - * @return None - */ -static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) -{ - i2c_int_status_reg_t int_sts = hw->int_status; - if (int_sts.arbitration_lost_int_st) { - *event = I2C_INTR_EVENT_ARBIT_LOST; - } else if (int_sts.nack_int_st) { - *event = I2C_INTR_EVENT_NACK; - } else if (int_sts.time_out_int_st) { - *event = I2C_INTR_EVENT_TOUT; - } else if (int_sts.end_detect_int_st) { - *event = I2C_INTR_EVENT_END_DET; - } else if (int_sts.trans_complete_int_st) { - *event = I2C_INTR_EVENT_TRANS_DONE; - } else { - *event = I2C_INTR_EVENT_ERR; - } -} - /** * @brief Init I2C master * @@ -775,6 +661,48 @@ static inline void i2c_ll_master_init(i2c_dev_t *hw) hw->ctr.val = ctrl_reg.val; } +/** + * @brief Get I2C interrupt status register address + */ +static inline volatile void *i2c_ll_get_interrupt_status_reg(i2c_dev_t *dev) +{ + return &dev->int_status; +} + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Get the I2C hardware instance +#define I2C_LL_GET_HW(i2c_num) (&I2C0) +// Get the I2C hardware FIFO address +#define I2C_LL_GET_FIFO_ADDR(i2c_num) (I2C_DATA_APB_REG(i2c_num)) +// I2C master TX interrupt bitmap +#define I2C_LL_MASTER_TX_INT (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) +// I2C master RX interrupt bitmap +#define I2C_LL_MASTER_RX_INT (I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) +// delay time after rtc_clk swiching on +#define DELAY_RTC_CLK_SWITCH (5) +// I2C max timeout value +#define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_VALUE + +#define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ + +/** + * @brief I2C interrupt event + */ +typedef enum { + I2C_INTR_EVENT_ERR, + I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */ + I2C_INTR_EVENT_NACK, /*!< I2C NACK event */ + I2C_INTR_EVENT_TOUT, /*!< I2C time out event */ + I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */ + I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */ + I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */ + I2C_INTR_EVENT_TXFIFO_EMPTY, /*!< I2C txfifo empty event */ +} i2c_intr_event_t; + /** * @brief Configure I2C SCL timing * @@ -808,6 +736,84 @@ static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, in *low_period = hw->scl_low_period.scl_low_period; } +/** + * @brief Get I2C master interrupt event + * + * @param hw Beginning address of the peripheral registers + * @param event Pointer to accept the interrupt event + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) +{ + i2c_int_status_reg_t int_sts = hw->int_status; + if (int_sts.arbitration_lost_int_st) { + *event = I2C_INTR_EVENT_ARBIT_LOST; + } else if (int_sts.nack_int_st) { + *event = I2C_INTR_EVENT_NACK; + } else if (int_sts.time_out_int_st) { + *event = I2C_INTR_EVENT_TOUT; + } else if (int_sts.end_detect_int_st) { + *event = I2C_INTR_EVENT_END_DET; + } else if (int_sts.trans_complete_int_st) { + *event = I2C_INTR_EVENT_TRANS_DONE; + } else { + *event = I2C_INTR_EVENT_ERR; + } +} + +/** + * @brief Enable I2C master TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw) +{ + hw->int_clr.val = UINT32_MAX; + hw->int_ena.val = I2C_LL_MASTER_TX_INT; +} + +/** + * @brief Enable I2C master RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw) +{ + hw->int_clr.val = UINT32_MAX; + hw->int_ena.val = I2C_LL_MASTER_RX_INT; +} + +/** + * @brief Disable I2C master TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT); +} + +/** + * @brief Disable I2C master RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c3/include/hal/i2c_ll.h b/components/hal/esp32c3/include/hal/i2c_ll.h index b796022860..e0a8b69eea 100644 --- a/components/hal/esp32c3/include/hal/i2c_ll.h +++ b/components/hal/esp32c3/include/hal/i2c_ll.h @@ -8,6 +8,7 @@ #pragma once +#include "stdbool.h" #include "hal/misc.h" #include "soc/i2c_periph.h" #include "soc/soc_caps.h" @@ -16,12 +17,12 @@ #include "soc/rtc_cntl_reg.h" #include "soc/clk_tree_defs.h" #include "esp_rom_sys.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif -#define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ /** * @brief I2C hardware cmd register fields. @@ -39,35 +40,6 @@ typedef union { uint32_t val; } i2c_hw_cmd_t; -/** - * @brief I2C interrupt event - */ -typedef enum { - I2C_INTR_EVENT_ERR, - I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */ - I2C_INTR_EVENT_NACK, /*!< I2C NACK event */ - I2C_INTR_EVENT_TOUT, /*!< I2C time out event */ - I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */ - I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */ - I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */ - 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 clkm_div; /*!< I2C core clock devider */ - 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; - // I2C operation mode command #define I2C_LL_CMD_RESTART 6 /*!ctr.conf_upgate = 1; @@ -146,7 +122,7 @@ static inline void i2c_ll_update(i2c_dev_t *hw) * * @return None */ -static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg) +static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_hal_clk_config_t *bus_cfg) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clk_conf, sclk_div_num, bus_cfg->clkm_div - 1); /* According to the Technical Reference Manual, the following timings must be subtracted by 1. @@ -220,7 +196,8 @@ static inline void i2c_ll_set_scl_timing(i2c_dev_t *hw, int hight_period, int lo * * @return None */ -static inline void i2c_ll_clr_intsts_mask(i2c_dev_t *hw, uint32_t mask) +__attribute__((always_inline)) +static inline void i2c_ll_clear_intr_mask(i2c_dev_t *hw, uint32_t mask) { hw->int_clr.val = mask; } @@ -246,6 +223,7 @@ static inline void i2c_ll_enable_intr_mask(i2c_dev_t *hw, uint32_t mask) * * @return None */ +__attribute__((always_inline)) static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) { hw->int_ena.val &= (~mask); @@ -258,9 +236,10 @@ static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) * * @return I2C interrupt status */ -static inline uint32_t i2c_ll_get_intsts_mask(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_intr_mask(i2c_dev_t *hw, uint32_t *intr_status) { - return hw->int_status.val; + *intr_status = hw->int_status.val; } /** @@ -477,9 +456,10 @@ static inline bool i2c_ll_is_master_mode(i2c_dev_t *hw) * * @return RxFIFO readable length */ -static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw, uint32_t *length) { - return hw->sr.rx_fifo_cnt; + *length = hw->sr.rx_fifo_cnt; } /** @@ -489,9 +469,10 @@ static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) * * @return TxFIFO writable length */ -static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_txfifo_len(i2c_dev_t *hw, uint32_t *length) { - return SOC_I2C_FIFO_LEN - hw->sr.tx_fifo_cnt; + *length = SOC_I2C_FIFO_LEN - hw->sr.tx_fifo_cnt; } /** @@ -501,9 +482,9 @@ static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) * * @return The I2C timeout value */ -static inline uint32_t i2c_ll_get_tout(i2c_dev_t *hw) +static inline void i2c_ll_get_tout(i2c_dev_t *hw, int *timeout) { - return hw->timeout.time_out_value; + *timeout = hw->timeout.time_out_value; } /** @@ -572,7 +553,8 @@ static inline void i2c_ll_get_scl_timing(i2c_dev_t *hw, int *high_period, int *l * * @return None. */ -static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) +__attribute__((always_inline)) +static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, const uint8_t *ptr, uint8_t len) { for (int i = 0; i< len; i++) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->fifo_data, data, ptr[i]); @@ -588,6 +570,7 @@ static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) * * @return None */ +__attribute__((always_inline)) static inline void i2c_ll_read_rxfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) { for(int i = 0; i < len; i++) { @@ -624,156 +607,12 @@ static inline void i2c_ll_set_filter(i2c_dev_t *hw, uint8_t filter_num) * * @return The hardware filter configuration */ -static inline uint8_t i2c_ll_get_filter(i2c_dev_t *hw) +static inline void i2c_ll_get_filter(i2c_dev_t *hw, uint8_t *filter_conf) { - return hw->filter_cfg.scl_thres; + *filter_conf = hw->filter_cfg.scl_thres; } -/** - * @brief Enable I2C master TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = ~0; - hw->int_ena.val = I2C_LL_MASTER_TX_INT; -} -/** - * @brief Enable I2C master RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = ~0; - hw->int_ena.val = I2C_LL_MASTER_RX_INT; -} - -/** - * @brief Disable I2C master TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT); -} - -/** - * @brief Disable I2C master RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT); -} - -/** - * @brief Clear I2C master TX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_clr_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_MASTER_TX_INT; -} - -/** - * @brief Clear I2C master RX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_clr_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_MASTER_RX_INT; -} - -/** - * @brief - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_enable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val |= I2C_LL_SLAVE_TX_INT; -} - -/** - * @brief Enable I2C slave RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_enable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val |= I2C_LL_SLAVE_RX_INT; -} - -/** - * @brief Disable I2C slave TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_disable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_SLAVE_TX_INT); -} - -/** - * @brief Disable I2C slave RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_SLAVE_RX_INT); -} - -/** - * @brief Clear I2C slave TX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_clr_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_SLAVE_TX_INT; -} - -/** - * @brief Clear I2C slave RX interrupt status register. - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_clr_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_SLAVE_RX_INT; -} /** * @brief Reste I2C master FSM. When the master FSM is stuck, call this function to reset the FSM @@ -784,6 +623,7 @@ static inline void i2c_ll_slave_clr_rx_it(i2c_dev_t *hw) */ static inline void i2c_ll_master_fsm_rst(i2c_dev_t *hw) { + // fsm_rst is a self cleared bit. hw->ctr.fsm_rst = 1; } @@ -822,53 +662,7 @@ static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_clock_source_t src_c hw->clk_conf.sclk_sel = (src_clk == I2C_CLK_SRC_RC_FAST) ? 1 : 0; } -/** - * @brief Get I2C master interrupt event - * - * @param hw Beginning address of the peripheral registers - * @param event Pointer to accept the interrupt event - * - * @return None - */ -static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) -{ - typeof(hw->int_status) int_sts = hw->int_status; - if (int_sts.arbitration_lost) { - *event = I2C_INTR_EVENT_ARBIT_LOST; - } else if (int_sts.nack) { - *event = I2C_INTR_EVENT_NACK; - } else if (int_sts.time_out) { - *event = I2C_INTR_EVENT_TOUT; - } else if (int_sts.end_detect) { - *event = I2C_INTR_EVENT_END_DET; - } else if (int_sts.trans_complete) { - *event = I2C_INTR_EVENT_TRANS_DONE; - } else { - *event = I2C_INTR_EVENT_ERR; - } -} -/** - * @brief Get I2C slave interrupt event - * - * @param hw Beginning address of the peripheral registers - * @param event Pointer to accept the interrupt event - * - * @return None - */ -static inline void i2c_ll_slave_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) -{ - typeof(hw->int_status) int_sts = hw->int_status; - if (int_sts.tx_fifo_wm) { - *event = I2C_INTR_EVENT_TXFIFO_EMPTY; - } else if (int_sts.trans_complete) { - *event = I2C_INTR_EVENT_TRANS_DONE; - } else if (int_sts.rx_fifo_wm) { - *event = I2C_INTR_EVENT_RXFIFO_FULL; - } else { - *event = I2C_INTR_EVENT_ERR; - } -} /** * @brief Init I2C master @@ -902,10 +696,64 @@ static inline void i2c_ll_slave_init(i2c_dev_t *hw) ctrl_reg.sda_force_out = 1; ctrl_reg.scl_force_out = 1; hw->ctr.val = ctrl_reg.val; - hw->ctr.slv_tx_auto_start_en = 1; hw->fifo_conf.fifo_addr_cfg_en = 0; } +/** + * @brief Set whether slave should auto start, or only start with start signal from master + * + * @param hw Beginning address of the peripheral registers + * @param slv_ex_auto_en 1 if slave auto start data transaction, otherwise, 0. + */ +static inline void i2c_ll_slave_tx_auto_start_en(i2c_dev_t *hw, bool slv_ex_auto_en) +{ + hw->ctr.slv_tx_auto_start_en = slv_ex_auto_en; +} + +/** + * @brief Get I2C interrupt status register address + */ +static inline volatile void *i2c_ll_get_interrupt_status_reg(i2c_dev_t *dev) +{ + return &dev->int_status; +} + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Get the I2C hardware instance +#define I2C_LL_GET_HW(i2c_num) (&I2C0) +// Get the I2C hardware FIFO address +#define I2C_LL_GET_FIFO_ADDR(i2c_num) (I2C_DATA_APB_REG(i2c_num)) +// I2C master TX interrupt bitmap +#define I2C_LL_MASTER_TX_INT (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) +// I2C master RX interrupt bitmap +#define I2C_LL_MASTER_RX_INT (I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) +// I2C slave TX interrupt bitmap +#define I2C_LL_SLAVE_TX_INT (I2C_TXFIFO_WM_INT_ENA_M) +// I2C slave RX interrupt bitmap +#define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) +// I2C max timeout value +#define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_REG_V + +#define I2C_LL_INTR_MASK (0xffff) /*!< I2C all interrupt bitmap */ + +/** + * @brief I2C interrupt event + */ +typedef enum { + I2C_INTR_EVENT_ERR, + I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */ + I2C_INTR_EVENT_NACK, /*!< I2C NACK event */ + I2C_INTR_EVENT_TOUT, /*!< I2C time out event */ + I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */ + I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */ + I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */ + I2C_INTR_EVENT_TXFIFO_EMPTY, /*!< I2C txfifo empty event */ +} i2c_intr_event_t; + /** * @brief Configure I2C SCL timing * @@ -939,6 +787,157 @@ static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, in *low_period = hw->scl_low_period.period; } +/** + * @brief Get I2C master interrupt event + * + * @param hw Beginning address of the peripheral registers + * @param event Pointer to accept the interrupt event + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) +{ + typeof(hw->int_status) int_sts = hw->int_status; + if (int_sts.arbitration_lost) { + *event = I2C_INTR_EVENT_ARBIT_LOST; + } else if (int_sts.nack) { + *event = I2C_INTR_EVENT_NACK; + } else if (int_sts.time_out||int_sts.scl_st_to||int_sts.scl_main_st_to) { + *event = I2C_INTR_EVENT_TOUT; + } else if (int_sts.end_detect) { + *event = I2C_INTR_EVENT_END_DET; + } else if (int_sts.trans_complete) { + *event = I2C_INTR_EVENT_TRANS_DONE; + } else { + *event = I2C_INTR_EVENT_ERR; + } +} + +/** + * @brief Get I2C slave interrupt event + * + * @param hw Beginning address of the peripheral registers + * @param event Pointer to accept the interrupt event + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) +{ + typeof(hw->int_status) int_sts = hw->int_status; + if (int_sts.tx_fifo_wm) { + *event = I2C_INTR_EVENT_TXFIFO_EMPTY; + } else if (int_sts.trans_complete) { + *event = I2C_INTR_EVENT_TRANS_DONE; + } else if (int_sts.rx_fifo_wm) { + *event = I2C_INTR_EVENT_RXFIFO_FULL; + } else { + *event = I2C_INTR_EVENT_ERR; + } +} + +/** + * @brief Enable I2C master TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw) +{ + hw->int_clr.val = UINT32_MAX; + hw->int_ena.val = I2C_LL_MASTER_TX_INT; +} + +/** + * @brief Enable I2C master RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw) +{ + hw->int_clr.val = UINT32_MAX; + hw->int_ena.val = I2C_LL_MASTER_RX_INT; +} + +/** + * @brief Disable I2C master TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT); +} + +/** + * @brief Disable I2C master RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT); +} + +/** + * @brief + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_enable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val |= I2C_LL_SLAVE_TX_INT; +} + +/** + * @brief Enable I2C slave RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_enable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val |= I2C_LL_SLAVE_RX_INT; +} + +/** + * @brief Disable I2C slave TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_disable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_SLAVE_TX_INT); +} + +/** + * @brief Disable I2C slave RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_SLAVE_RX_INT); +} + + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h2/include/hal/i2c_ll.h b/components/hal/esp32h2/include/hal/i2c_ll.h index 7ef4b9547d..88668d2e35 100644 --- a/components/hal/esp32h2/include/hal/i2c_ll.h +++ b/components/hal/esp32h2/include/hal/i2c_ll.h @@ -8,6 +8,7 @@ #pragma once +#include "stdbool.h" #include "hal/misc.h" #include "soc/i2c_periph.h" #include "soc/soc_caps.h" @@ -16,15 +17,14 @@ #include "soc/rtc_cntl_reg.h" #include "soc/clk_tree_defs.h" #include "esp_rom_sys.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif -#define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ - /** - * @brief I2C hardware cmd register filed. + * @brief I2C hardware cmd register fields. */ typedef union { struct { @@ -39,35 +39,6 @@ typedef union { uint32_t val; } i2c_hw_cmd_t; -/** - * @brief I2C interrupt event - */ -typedef enum { - I2C_INTR_EVENT_ERR, - I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */ - I2C_INTR_EVENT_NACK, /*!< I2C NACK event */ - I2C_INTR_EVENT_TOUT, /*!< I2C time out event */ - I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */ - I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */ - I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */ - 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 clkm_div; /*!< I2C core clock devider */ - 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; - // I2C operation mode command #define I2C_LL_CMD_RESTART 6 /*!ctr.conf_upgate = 1; @@ -146,7 +122,7 @@ static inline void i2c_ll_update(i2c_dev_t *hw) * * @return None */ -static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg) +static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_hal_clk_config_t *bus_cfg) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clk_conf, sclk_div_num, bus_cfg->clkm_div - 1); /* According to the Technical Reference Manual, the following timings must be subtracted by 1. @@ -220,7 +196,8 @@ static inline void i2c_ll_set_scl_timing(i2c_dev_t *hw, int hight_period, int lo * * @return None */ -static inline void i2c_ll_clr_intsts_mask(i2c_dev_t *hw, uint32_t mask) +__attribute__((always_inline)) +static inline void i2c_ll_clear_intr_mask(i2c_dev_t *hw, uint32_t mask) { hw->int_clr.val = mask; } @@ -246,6 +223,7 @@ static inline void i2c_ll_enable_intr_mask(i2c_dev_t *hw, uint32_t mask) * * @return None */ +__attribute__((always_inline)) static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) { hw->int_ena.val &= (~mask); @@ -258,9 +236,10 @@ static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) * * @return I2C interrupt status */ -static inline uint32_t i2c_ll_get_intsts_mask(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_intr_mask(i2c_dev_t *hw, uint32_t *intr_status) { - return hw->int_status.val; + *intr_status = hw->int_status.val; } /** @@ -477,9 +456,10 @@ static inline bool i2c_ll_is_master_mode(i2c_dev_t *hw) * * @return RxFIFO readable length */ -static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw, uint32_t *length) { - return hw->sr.rx_fifo_cnt; + *length = hw->sr.rx_fifo_cnt; } /** @@ -489,9 +469,10 @@ static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) * * @return TxFIFO writable length */ -static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_txfifo_len(i2c_dev_t *hw, uint32_t *length) { - return SOC_I2C_FIFO_LEN - hw->sr.tx_fifo_cnt; + *length = SOC_I2C_FIFO_LEN - hw->sr.tx_fifo_cnt; } /** @@ -501,9 +482,9 @@ static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) * * @return The I2C timeout value */ -static inline uint32_t i2c_ll_get_tout(i2c_dev_t *hw) +static inline void i2c_ll_get_tout(i2c_dev_t *hw, int *timeout) { - return hw->timeout.time_out_value; + *timeout = hw->timeout.time_out_value; } /** @@ -572,7 +553,8 @@ static inline void i2c_ll_get_scl_timing(i2c_dev_t *hw, int *high_period, int *l * * @return None. */ -static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) +__attribute__((always_inline)) +static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, const uint8_t *ptr, uint8_t len) { for (int i = 0; i< len; i++) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->fifo_data, data, ptr[i]); @@ -588,6 +570,7 @@ static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) * * @return None */ +__attribute__((always_inline)) static inline void i2c_ll_read_rxfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) { for(int i = 0; i < len; i++) { @@ -624,155 +607,9 @@ static inline void i2c_ll_set_filter(i2c_dev_t *hw, uint8_t filter_num) * * @return The hardware filter configuration */ -static inline uint8_t i2c_ll_get_filter(i2c_dev_t *hw) +static inline void i2c_ll_get_filter(i2c_dev_t *hw, uint8_t *filter_conf) { - return hw->filter_cfg.scl_thres; -} - -/** - * @brief Enable I2C master TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = ~0; - hw->int_ena.val = I2C_LL_MASTER_TX_INT; -} - -/** - * @brief Enable I2C master RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = ~0; - hw->int_ena.val = I2C_LL_MASTER_RX_INT; -} - -/** - * @brief Disable I2C master TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT); -} - -/** - * @brief Disable I2C master RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT); -} - -/** - * @brief Clear I2C master TX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_clr_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_MASTER_TX_INT; -} - -/** - * @brief Clear I2C master RX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_clr_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_MASTER_RX_INT; -} - -/** - * @brief - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_enable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val |= I2C_LL_SLAVE_TX_INT; -} - -/** - * @brief Enable I2C slave RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_enable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val |= I2C_LL_SLAVE_RX_INT; -} - -/** - * @brief Disable I2C slave TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_disable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_SLAVE_TX_INT); -} - -/** - * @brief Disable I2C slave RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_SLAVE_RX_INT); -} - -/** - * @brief Clear I2C slave TX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_clr_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_SLAVE_TX_INT; -} - -/** - * @brief Clear I2C slave RX interrupt status register. - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_clr_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_SLAVE_RX_INT; + *filter_conf = hw->filter_cfg.scl_thres; } /** @@ -800,9 +637,12 @@ static inline void i2c_ll_master_fsm_rst(i2c_dev_t *hw) static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw) { hw->scl_sp_conf.scl_rst_slv_num = 9; - hw->scl_sp_conf.scl_rst_slv_en = 0; - hw->ctr.conf_upgate = 1; hw->scl_sp_conf.scl_rst_slv_en = 1; + hw->ctr.conf_upgate = 1; + // hardward will clear scl_rst_slv_en after sending SCL pulses, + // and we should set conf_upgate bit to synchronize register value. + while (hw->scl_sp_conf.scl_rst_slv_en); + hw->ctr.conf_upgate = 1; } /** @@ -819,54 +659,6 @@ static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_clock_source_t src_c hw->clk_conf.sclk_sel = (src_clk == I2C_CLK_SRC_RC_FAST) ? 1 : 0; } -/** - * @brief Get I2C master interrupt event - * - * @param hw Beginning address of the peripheral registers - * @param event Pointer to accept the interrupt event - * - * @return None - */ -static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) -{ - typeof(hw->int_status) int_sts = hw->int_status; - if (int_sts.arbitration_lost) { - *event = I2C_INTR_EVENT_ARBIT_LOST; - } else if (int_sts.nack) { - *event = I2C_INTR_EVENT_NACK; - } else if (int_sts.time_out) { - *event = I2C_INTR_EVENT_TOUT; - } else if (int_sts.end_detect) { - *event = I2C_INTR_EVENT_END_DET; - } else if (int_sts.trans_complete) { - *event = I2C_INTR_EVENT_TRANS_DONE; - } else { - *event = I2C_INTR_EVENT_ERR; - } -} - -/** - * @brief Get I2C slave interrupt event - * - * @param hw Beginning address of the peripheral registers - * @param event Pointer to accept the interrupt event - * - * @return None - */ -static inline void i2c_ll_slave_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) -{ - typeof(hw->int_status) int_sts = hw->int_status; - if (int_sts.tx_fifo_wm) { - *event = I2C_INTR_EVENT_TXFIFO_EMPTY; - } else if (int_sts.trans_complete) { - *event = I2C_INTR_EVENT_TRANS_DONE; - } else if (int_sts.rx_fifo_wm) { - *event = I2C_INTR_EVENT_RXFIFO_FULL; - } else { - *event = I2C_INTR_EVENT_ERR; - } -} - /** * @brief Init I2C master * @@ -899,10 +691,64 @@ static inline void i2c_ll_slave_init(i2c_dev_t *hw) ctrl_reg.sda_force_out = 1; ctrl_reg.scl_force_out = 1; hw->ctr.val = ctrl_reg.val; - hw->ctr.slv_tx_auto_start_en = 1; hw->fifo_conf.fifo_addr_cfg_en = 0; } +/** + * @brief Set whether slave should auto start, or only start with start signal from master + * + * @param hw Beginning address of the peripheral registers + * @param slv_ex_auto_en 1 if slave auto start data transaction, otherwise, 0. + */ +static inline void i2c_ll_slave_tx_auto_start_en(i2c_dev_t *hw, bool slv_ex_auto_en) +{ + hw->ctr.slv_tx_auto_start_en = slv_ex_auto_en; +} + +/** + * @brief Get I2C interrupt status register address + */ +static inline volatile void *i2c_ll_get_interrupt_status_reg(i2c_dev_t *dev) +{ + return &dev->int_status; +} + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Get the I2C hardware instance +#define I2C_LL_GET_HW(i2c_num) (&I2C0) +// Get the I2C hardware FIFO address +#define I2C_LL_GET_FIFO_ADDR(i2c_num) (I2C_DATA_APB_REG(i2c_num)) +// I2C master TX interrupt bitmap +#define I2C_LL_MASTER_TX_INT (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) +// I2C master RX interrupt bitmap +#define I2C_LL_MASTER_RX_INT (I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) +// I2C slave TX interrupt bitmap +#define I2C_LL_SLAVE_TX_INT (I2C_TXFIFO_WM_INT_ENA_M) +// I2C slave RX interrupt bitmap +#define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) +// I2C max timeout value +#define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_REG_V + +#define I2C_LL_INTR_MASK (0xffff) /*!< I2C all interrupt bitmap */ + +/** + * @brief I2C interrupt event + */ +typedef enum { + I2C_INTR_EVENT_ERR, + I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */ + I2C_INTR_EVENT_NACK, /*!< I2C NACK event */ + I2C_INTR_EVENT_TOUT, /*!< I2C time out event */ + I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */ + I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */ + I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */ + I2C_INTR_EVENT_TXFIFO_EMPTY, /*!< I2C txfifo empty event */ +} i2c_intr_event_t; + /** * @brief Configure I2C SCL timing * @@ -936,6 +782,156 @@ static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, in *low_period = hw->scl_low_period.period; } +/** + * @brief Get I2C master interrupt event + * + * @param hw Beginning address of the peripheral registers + * @param event Pointer to accept the interrupt event + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) +{ + typeof(hw->int_status) int_sts = hw->int_status; + if (int_sts.arbitration_lost) { + *event = I2C_INTR_EVENT_ARBIT_LOST; + } else if (int_sts.nack) { + *event = I2C_INTR_EVENT_NACK; + } else if (int_sts.time_out) { + *event = I2C_INTR_EVENT_TOUT; + } else if (int_sts.end_detect) { + *event = I2C_INTR_EVENT_END_DET; + } else if (int_sts.trans_complete) { + *event = I2C_INTR_EVENT_TRANS_DONE; + } else { + *event = I2C_INTR_EVENT_ERR; + } +} + +/** + * @brief Get I2C slave interrupt event + * + * @param hw Beginning address of the peripheral registers + * @param event Pointer to accept the interrupt event + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) +{ + typeof(hw->int_status) int_sts = hw->int_status; + if (int_sts.tx_fifo_wm) { + *event = I2C_INTR_EVENT_TXFIFO_EMPTY; + } else if (int_sts.trans_complete) { + *event = I2C_INTR_EVENT_TRANS_DONE; + } else if (int_sts.rx_fifo_wm) { + *event = I2C_INTR_EVENT_RXFIFO_FULL; + } else { + *event = I2C_INTR_EVENT_ERR; + } +} + +/** + * @brief Enable I2C master TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw) +{ + hw->int_clr.val = UINT32_MAX; + hw->int_ena.val = I2C_LL_MASTER_TX_INT; +} + +/** + * @brief Enable I2C master RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw) +{ + hw->int_clr.val = UINT32_MAX; + hw->int_ena.val = I2C_LL_MASTER_RX_INT; +} + +/** + * @brief Disable I2C master TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT); +} + +/** + * @brief Disable I2C master RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT); +} + +/** + * @brief + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_enable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val |= I2C_LL_SLAVE_TX_INT; +} + +/** + * @brief Enable I2C slave RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_enable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val |= I2C_LL_SLAVE_RX_INT; +} + +/** + * @brief Disable I2C slave TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_disable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_SLAVE_TX_INT); +} + +/** + * @brief Disable I2C slave RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_SLAVE_RX_INT); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s2/include/hal/i2c_ll.h b/components/hal/esp32s2/include/hal/i2c_ll.h index 94f99116ad..19dd073f65 100644 --- a/components/hal/esp32s2/include/hal/i2c_ll.h +++ b/components/hal/esp32s2/include/hal/i2c_ll.h @@ -7,16 +7,18 @@ // The LL layer for I2C register operations #pragma once +#include #include "soc/i2c_periph.h" #include "soc/i2c_struct.h" #include "soc/clk_tree_defs.h" #include "hal/i2c_types.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif -#define I2C_LL_INTR_MASK (0x1ffff) /*!< I2C all interrupt bitmap */ + /** * @brief I2C hardware cmd register fields. @@ -34,34 +36,6 @@ typedef union { uint32_t val; } i2c_hw_cmd_t; -/** - * @brief I2C interrupt event - */ -typedef enum { - I2C_INTR_EVENT_ERR, - I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */ - I2C_INTR_EVENT_NACK, /*!< I2C NACK event */ - I2C_INTR_EVENT_TOUT, /*!< I2C time out event */ - I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */ - I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */ - I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */ - 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; - // I2C operation mode command #define I2C_LL_CMD_RESTART 0 /*!scl_low_period.period = bus_cfg->scl_low - 1; @@ -185,7 +165,8 @@ static inline void i2c_ll_set_scl_timing(i2c_dev_t *hw, int hight_period, int lo * * @return None */ -static inline void i2c_ll_clr_intsts_mask(i2c_dev_t *hw, uint32_t mask) +__attribute__((always_inline)) +static inline void i2c_ll_clear_intr_mask(i2c_dev_t *hw, uint32_t mask) { hw->int_clr.val = mask; } @@ -211,6 +192,7 @@ static inline void i2c_ll_enable_intr_mask(i2c_dev_t *hw, uint32_t mask) * * @return None */ +__attribute__((always_inline)) static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) { hw->int_ena.val &= (~mask); @@ -223,9 +205,10 @@ static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) * * @return I2C interrupt status */ -static inline uint32_t i2c_ll_get_intsts_mask(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_intr_mask(i2c_dev_t *hw, uint32_t *intr_status) { - return hw->int_status.val; + *intr_status = hw->int_status.val; } /** @@ -443,9 +426,10 @@ static inline bool i2c_ll_is_master_mode(i2c_dev_t *hw) * * @return RxFIFO readable length */ -static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw, uint32_t *length) { - return hw->status_reg.rx_fifo_cnt; + *length = hw->status_reg.rx_fifo_cnt; } /** @@ -455,9 +439,10 @@ static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) * * @return TxFIFO writable length */ -static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_txfifo_len(i2c_dev_t *hw, uint32_t *length) { - return SOC_I2C_FIFO_LEN - hw->status_reg.tx_fifo_cnt; + *length = SOC_I2C_FIFO_LEN - hw->status_reg.tx_fifo_cnt; } /** @@ -467,9 +452,9 @@ static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) * * @return The I2C timeout value */ -static inline uint32_t i2c_ll_get_tout(i2c_dev_t *hw) +static inline void i2c_ll_get_tout(i2c_dev_t *hw, int *timeout) { - return hw->timeout.tout; + *timeout = hw->timeout.tout; } /** @@ -538,7 +523,8 @@ static inline void i2c_ll_get_scl_timing(i2c_dev_t *hw, int *high_period, int *l * * @return None. */ -static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) +__attribute__((always_inline)) +static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, const uint8_t *ptr, uint8_t len) { uint32_t fifo_addr = (hw == &I2C0) ? 0x6001301c : 0x6002701c; for(int i = 0; i < len; i++) { @@ -555,6 +541,7 @@ static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) * * @return None */ +__attribute__((always_inline)) static inline void i2c_ll_read_rxfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) { uint32_t fifo_addr = (hw == &I2C0) ? 0x6001301c : 0x6002701c; @@ -592,155 +579,9 @@ static inline void i2c_ll_set_filter(i2c_dev_t *hw, uint8_t filter_num) * * @return The hardware filter configuration */ -static inline uint8_t i2c_ll_get_filter(i2c_dev_t *hw) +static inline void i2c_ll_get_filter(i2c_dev_t *hw, uint8_t *filter_conf) { - return hw->sda_filter_cfg.thres; -} - -/** - * @brief Enable I2C master TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = ~0; - hw->int_ena.val = I2C_LL_MASTER_TX_INT; -} - -/** - * @brief Enable I2C master RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = ~0; - hw->int_ena.val = I2C_LL_MASTER_RX_INT; -} - -/** - * @brief Disable I2C master TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT); -} - -/** - * @brief Disable I2C master RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT); -} - -/** - * @brief Clear I2C master TX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_clr_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_MASTER_TX_INT; -} - -/** - * @brief Clear I2C master RX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_clr_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_MASTER_RX_INT; -} - -/** - * @brief Enable I2C slave TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_enable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val |= I2C_LL_SLAVE_TX_INT; -} - -/** - * @brief Enable I2C slave RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_enable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val |= I2C_LL_SLAVE_RX_INT; -} - -/** - * @brief Disable I2C slave TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_disable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_SLAVE_TX_INT); -} - -/** - * @brief Disable I2C slave RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_SLAVE_RX_INT); -} - -/** - * @brief Clear I2C slave TX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_clr_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_SLAVE_TX_INT; -} - -/** - * @brief Clear I2C slave RX interrupt status register. - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_clr_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_SLAVE_RX_INT; + *filter_conf = hw->sda_filter_cfg.thres; } /** @@ -786,53 +627,6 @@ static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_clock_source_t src_c hw->ctr.ref_always_on = (src_clk == I2C_CLK_SRC_REF_TICK) ? 0 : 1; } -/** - * @brief Get I2C master interrupt event - * - * @param hw Beginning address of the peripheral registers - * @param event Pointer to accept the interrupt event - * - * @return None - */ -static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) -{ - typeof(hw->int_status) int_sts = hw->int_status; - if (int_sts.arbitration_lost) { - *event = I2C_INTR_EVENT_ARBIT_LOST; - } else if (int_sts.nack) { - *event = I2C_INTR_EVENT_NACK; - } else if (int_sts.time_out) { - *event = I2C_INTR_EVENT_TOUT; - } else if (int_sts.end_detect) { - *event = I2C_INTR_EVENT_END_DET; - } else if (int_sts.trans_complete) { - *event = I2C_INTR_EVENT_TRANS_DONE; - } else { - *event = I2C_INTR_EVENT_ERR; - } -} - -/** - * @brief Get I2C slave interrupt event - * - * @param hw Beginning address of the peripheral registers - * @param event Pointer to accept the interrupt event - * - * @return None - */ -static inline void i2c_ll_slave_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) -{ - typeof(hw->int_status) int_sts = hw->int_status; - if (int_sts.tx_fifo_wm) { - *event = I2C_INTR_EVENT_TXFIFO_EMPTY; - } else if (int_sts.trans_complete) { - *event = I2C_INTR_EVENT_TRANS_DONE; - } else if (int_sts.rx_fifo_wm) { - *event = I2C_INTR_EVENT_RXFIFO_FULL; - } else { - *event = I2C_INTR_EVENT_ERR; - } -} /** * @brief Init I2C master @@ -893,11 +687,67 @@ static inline void i2c_ll_slave_init(i2c_dev_t *hw) * * @return None */ +__attribute__((always_inline)) static inline void i2c_ll_update(i2c_dev_t *hw) { ;// ESP32S2 do not support } +/** + * @brief Set whether slave should auto start, or only start with start signal from master + * + * @param hw Beginning address of the peripheral registers + * @param slv_ex_auto_en 1 if slave auto start data transaction, otherwise, 0. + */ +static inline void i2c_ll_slave_tx_auto_start_en(i2c_dev_t *hw, bool slv_ex_auto_en) +{ + ;// ESP32-S2 do not support +} + +/** + * @brief Get I2C interrupt status register address + */ +static inline volatile void *i2c_ll_get_interrupt_status_reg(i2c_dev_t *dev) +{ + return &dev->int_status; +} + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Get the I2C hardware instance +#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == 0) ? &I2C0 : &I2C1) +// Get the I2C hardware FIFO address +#define I2C_LL_GET_FIFO_ADDR(i2c_num) (I2C_DATA_APB_REG(i2c_num)) +// I2C master TX interrupt bitmap +#define I2C_LL_MASTER_TX_INT (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) +// I2C master RX interrupt bitmap +#define I2C_LL_MASTER_RX_INT (I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) +// I2C slave TX interrupt bitmap +#define I2C_LL_SLAVE_TX_INT (I2C_TXFIFO_WM_INT_ENA_M) +// I2C slave RX interrupt bitmap +#define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) +// I2C max timeout value +#define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_REG_V + +#define I2C_LL_INTR_MASK (0x1ffff) /*!< I2C all interrupt bitmap */ + +/** + * @brief I2C interrupt event + */ +typedef enum { + I2C_INTR_EVENT_ERR, + I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */ + I2C_INTR_EVENT_NACK, /*!< I2C NACK event */ + I2C_INTR_EVENT_TOUT, /*!< I2C time out event */ + I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */ + I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */ + I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */ + I2C_INTR_EVENT_TXFIFO_EMPTY, /*!< I2C txfifo empty event */ +} i2c_intr_event_t; + /** * @brief Configure I2C SCL timing * @@ -931,6 +781,157 @@ static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, in *low_period = hw->scl_low_period.period; } +/** + * @brief Get I2C master interrupt event + * + * @param hw Beginning address of the peripheral registers + * @param event Pointer to accept the interrupt event + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) +{ + typeof(hw->int_status) int_sts = hw->int_status; + if (int_sts.arbitration_lost) { + *event = I2C_INTR_EVENT_ARBIT_LOST; + } else if (int_sts.nack) { + *event = I2C_INTR_EVENT_NACK; + } else if (int_sts.time_out) { + *event = I2C_INTR_EVENT_TOUT; + } else if (int_sts.end_detect) { + *event = I2C_INTR_EVENT_END_DET; + } else if (int_sts.trans_complete) { + *event = I2C_INTR_EVENT_TRANS_DONE; + } else { + *event = I2C_INTR_EVENT_ERR; + } +} + +/** + * @brief Get I2C slave interrupt event + * + * @param hw Beginning address of the peripheral registers + * @param event Pointer to accept the interrupt event + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) +{ + typeof(hw->int_status) int_sts = hw->int_status; + if (int_sts.tx_fifo_wm) { + *event = I2C_INTR_EVENT_TXFIFO_EMPTY; + } else if (int_sts.trans_complete) { + *event = I2C_INTR_EVENT_TRANS_DONE; + } else if (int_sts.rx_fifo_wm) { + *event = I2C_INTR_EVENT_RXFIFO_FULL; + } else { + *event = I2C_INTR_EVENT_ERR; + } +} + + +/** + * @brief Enable I2C master TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw) +{ + hw->int_clr.val = UINT32_MAX; + hw->int_ena.val = I2C_LL_MASTER_TX_INT; +} + +/** + * @brief Enable I2C master RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw) +{ + hw->int_clr.val = UINT32_MAX; + hw->int_ena.val = I2C_LL_MASTER_RX_INT; +} + +/** + * @brief Disable I2C master TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT); +} + +/** + * @brief Disable I2C master RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT); +} + +/** + * @brief Enable I2C slave TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_enable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val |= I2C_LL_SLAVE_TX_INT; +} + +/** + * @brief Enable I2C slave RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_enable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val |= I2C_LL_SLAVE_RX_INT; +} + +/** + * @brief Disable I2C slave TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_disable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_SLAVE_TX_INT); +} + +/** + * @brief Disable I2C slave RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_SLAVE_RX_INT); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/i2c_ll.h b/components/hal/esp32s3/include/hal/i2c_ll.h index 617e9f3856..38bd0762ba 100644 --- a/components/hal/esp32s3/include/hal/i2c_ll.h +++ b/components/hal/esp32s3/include/hal/i2c_ll.h @@ -8,18 +8,19 @@ #pragma once +#include "stdbool.h" #include "hal/misc.h" #include "soc/i2c_periph.h" #include "soc/soc_caps.h" #include "soc/i2c_struct.h" #include "soc/clk_tree_defs.h" #include "hal/i2c_types.h" +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif -#define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ /** * @brief I2C hardware cmd register fields. */ @@ -36,35 +37,6 @@ typedef union { uint32_t val; } i2c_hw_cmd_t; -/** - * @brief I2C interrupt event - */ -typedef enum { - I2C_INTR_EVENT_ERR, - I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */ - I2C_INTR_EVENT_NACK, /*!< I2C NACK event */ - I2C_INTR_EVENT_TOUT, /*!< I2C time out event */ - I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */ - I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */ - I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */ - 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 clkm_div; /*!< I2C core clock divider */ - 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; - // I2C operation mode command #define I2C_LL_CMD_RESTART 6 /*!ctr.conf_upgate = 1; @@ -141,7 +118,7 @@ static inline void i2c_ll_update(i2c_dev_t *hw) * * @return None */ -static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg) +static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_hal_clk_config_t *bus_cfg) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clk_conf, sclk_div_num, bus_cfg->clkm_div - 1); /* According to the Technical Reference Manual, the following timings must be subtracted by 1. @@ -208,23 +185,6 @@ static inline void i2c_ll_set_scl_timing(i2c_dev_t *hw, int high_period, int low hw->scl_high_period.scl_wait_high_period = high_period - high_period_output; } -/** - * @brief Configure I2C SCL timing - * - * @param hw Beginning address of the peripheral registers - * @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2) - * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) - * @param wait_high_period The I2C SCL wait rising edge period. - * - * @return None. - */ -static inline void i2c_ll_set_scl_clk_timing(i2c_dev_t *hw, int high_period, int low_period, int wait_high_period) -{ - hw->scl_low_period.scl_low_period = low_period; - hw->scl_high_period.scl_high_period = high_period; - hw->scl_high_period.scl_wait_high_period = wait_high_period; -} - /** * @brief Clear I2C interrupt status * @@ -233,7 +193,8 @@ static inline void i2c_ll_set_scl_clk_timing(i2c_dev_t *hw, int high_period, int * * @return None */ -static inline void i2c_ll_clr_intsts_mask(i2c_dev_t *hw, uint32_t mask) +__attribute__((always_inline)) +static inline void i2c_ll_clear_intr_mask(i2c_dev_t *hw, uint32_t mask) { hw->int_clr.val = mask; } @@ -259,6 +220,7 @@ static inline void i2c_ll_enable_intr_mask(i2c_dev_t *hw, uint32_t mask) * * @return None */ +__attribute__((always_inline)) static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) { hw->int_ena.val &= (~mask); @@ -271,9 +233,10 @@ static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) * * @return I2C interrupt status */ -static inline uint32_t i2c_ll_get_intsts_mask(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_intr_mask(i2c_dev_t *hw, uint32_t *intr_status) { - return hw->int_status.val; + *intr_status = hw->int_status.val; } /** @@ -493,9 +456,10 @@ static inline bool i2c_ll_is_master_mode(i2c_dev_t *hw) * * @return RxFIFO readable length */ -static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw, uint32_t *length) { - return hw->sr.rxfifo_cnt; + *length = hw->sr.rxfifo_cnt; } /** @@ -505,9 +469,10 @@ static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) * * @return TxFIFO writable length */ -static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) +__attribute__((always_inline)) +static inline void i2c_ll_get_txfifo_len(i2c_dev_t *hw, uint32_t *length) { - return SOC_I2C_FIFO_LEN - hw->sr.txfifo_cnt; + *length = SOC_I2C_FIFO_LEN - hw->sr.txfifo_cnt; } /** @@ -517,9 +482,9 @@ static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) * * @return The I2C timeout value */ -static inline uint32_t i2c_ll_get_tout(i2c_dev_t *hw) +static inline void i2c_ll_get_tout(i2c_dev_t *hw, int *timeout) { - return hw->to.time_out_value; + *timeout = hw->to.time_out_value; } /** @@ -579,22 +544,6 @@ static inline void i2c_ll_get_scl_timing(i2c_dev_t *hw, int *high_period, int *l *low_period = hw->scl_low_period.scl_low_period + 1; } -/** - * @brief Get I2C SCL timing configuration - * - * @param hw Beginning address of the peripheral registers - * @param high_period Pointer to accept the SCL high period - * @param low_period Pointer to accept the SCL low period - * - * @return None - */ -static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, int *low_period, int *wait_high_period) -{ - *high_period = hw->scl_high_period.scl_high_period; - *wait_high_period = hw->scl_high_period.scl_wait_high_period; - *low_period = hw->scl_low_period.scl_low_period; -} - /** * @brief Write the I2C hardware txFIFO * @@ -604,7 +553,8 @@ static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, in * * @return None. */ -static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) +__attribute__((always_inline)) +static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, const uint8_t *ptr, uint8_t len) { for (int i = 0; i< len; i++) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->data, fifo_rdata, ptr[i]); @@ -620,6 +570,7 @@ static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) * * @return None */ +__attribute__((always_inline)) static inline void i2c_ll_read_rxfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) { for(int i = 0; i < len; i++) { @@ -656,155 +607,9 @@ static inline void i2c_ll_set_filter(i2c_dev_t *hw, uint8_t filter_num) * * @return The hardware filter configuration */ -static inline uint8_t i2c_ll_get_filter(i2c_dev_t *hw) +static inline void i2c_ll_get_filter(i2c_dev_t *hw, uint8_t *filter_conf) { - return hw->filter_cfg.scl_filter_thres; -} - -/** - * @brief Enable I2C master TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = ~0; - hw->int_ena.val = I2C_LL_MASTER_TX_INT; -} - -/** - * @brief Enable I2C master RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = ~0; - hw->int_ena.val = I2C_LL_MASTER_RX_INT; -} - -/** - * @brief Disable I2C master TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT); -} - -/** - * @brief Disable I2C master RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT); -} - -/** - * @brief Clear I2C master TX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_clr_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_MASTER_TX_INT; -} - -/** - * @brief Clear I2C master RX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_master_clr_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_MASTER_RX_INT; -} - -/** - * @brief - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_enable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val |= I2C_LL_SLAVE_TX_INT; -} - -/** - * @brief Enable I2C slave RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_enable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val |= I2C_LL_SLAVE_RX_INT; -} - -/** - * @brief Disable I2C slave TX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_disable_tx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_SLAVE_TX_INT); -} - -/** - * @brief Disable I2C slave RX interrupt - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw) -{ - hw->int_ena.val &= (~I2C_LL_SLAVE_RX_INT); -} - -/** - * @brief Clear I2C slave TX interrupt status register - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_clr_tx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_SLAVE_TX_INT; -} - -/** - * @brief Clear I2C slave RX interrupt status register. - * - * @param hw Beginning address of the peripheral registers - * - * @return None - */ -static inline void i2c_ll_slave_clr_rx_it(i2c_dev_t *hw) -{ - hw->int_clr.val = I2C_LL_SLAVE_RX_INT; + *filter_conf = hw->filter_cfg.scl_filter_thres; } /** @@ -832,9 +637,8 @@ static inline void i2c_ll_master_fsm_rst(i2c_dev_t *hw) static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw) { hw->scl_sp_conf.scl_rst_slv_num = 9; - hw->scl_sp_conf.scl_rst_slv_en = 0; - hw->ctr.conf_upgate = 1; hw->scl_sp_conf.scl_rst_slv_en = 1; + hw->ctr.conf_upgate = 1; } /** @@ -850,54 +654,6 @@ static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_clock_source_t src_c hw->clk_conf.sclk_sel = (src_clk == I2C_CLK_SRC_RC_FAST) ? 1 : 0; } -/** - * @brief Get I2C master interrupt event - * - * @param hw Beginning address of the peripheral registers - * @param event Pointer to accept the interrupt event - * - * @return None - */ -static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) -{ - typeof(hw->int_status) int_sts = hw->int_status; - if (int_sts.arbitration_lost_int_st) { - *event = I2C_INTR_EVENT_ARBIT_LOST; - } else if (int_sts.nack_int_st) { - *event = I2C_INTR_EVENT_NACK; - } else if (int_sts.time_out_int_st) { - *event = I2C_INTR_EVENT_TOUT; - } else if (int_sts.end_detect_int_st) { - *event = I2C_INTR_EVENT_END_DET; - } else if (int_sts.trans_complete_int_st) { - *event = I2C_INTR_EVENT_TRANS_DONE; - } else { - *event = I2C_INTR_EVENT_ERR; - } -} - -/** - * @brief Get I2C slave interrupt event - * - * @param hw Beginning address of the peripheral registers - * @param event Pointer to accept the interrupt event - * - * @return None - */ -static inline void i2c_ll_slave_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) -{ - typeof(hw->int_status) int_sts = hw->int_status; - if (int_sts.txfifo_wm_int_st) { - *event = I2C_INTR_EVENT_TXFIFO_EMPTY; - } else if (int_sts.trans_complete_int_st) { - *event = I2C_INTR_EVENT_TRANS_DONE; - } else if (int_sts.rxfifo_wm_int_st) { - *event = I2C_INTR_EVENT_RXFIFO_FULL; - } else { - *event = I2C_INTR_EVENT_ERR; - } -} - /** * @brief Init I2C master * @@ -930,10 +686,247 @@ static inline void i2c_ll_slave_init(i2c_dev_t *hw) ctrl_reg.sda_force_out = 1; ctrl_reg.scl_force_out = 1; hw->ctr.val = ctrl_reg.val; - hw->ctr.slv_tx_auto_start_en = 1; hw->fifo_conf.fifo_addr_cfg_en = 0; } +/** + * @brief Set whether slave should auto start, or only start with start signal from master + * + * @param hw Beginning address of the peripheral registers + * @param slv_ex_auto_en 1 if slave auto start data transaction, otherwise, 0. + */ +static inline void i2c_ll_slave_tx_auto_start_en(i2c_dev_t *hw, bool slv_ex_auto_en) +{ + hw->ctr.slv_tx_auto_start_en = slv_ex_auto_en; +} + +/** + * @brief Get I2C interrupt status register address + */ +static inline volatile void *i2c_ll_get_interrupt_status_reg(i2c_dev_t *dev) +{ + return &dev->int_status; +} + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Get the I2C hardware instance +#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == 0) ? &I2C0 : &I2C1) +// Get the I2C hardware FIFO address +#define I2C_LL_GET_FIFO_ADDR(i2c_num) (I2C_DATA_APB_REG(i2c_num)) +// I2C master TX interrupt bitmap +#define I2C_LL_MASTER_TX_INT (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) +// I2C master RX interrupt bitmap +#define I2C_LL_MASTER_RX_INT (I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) +// I2C slave TX interrupt bitmap +#define I2C_LL_SLAVE_TX_INT (I2C_TXFIFO_WM_INT_ENA_M) +// I2C slave RX interrupt bitmap +#define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) +// I2C max timeout value +#define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_VALUE_V + +#define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ + +/** + * @brief I2C interrupt event + */ +typedef enum { + I2C_INTR_EVENT_ERR, + I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */ + I2C_INTR_EVENT_NACK, /*!< I2C NACK event */ + I2C_INTR_EVENT_TOUT, /*!< I2C time out event */ + I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */ + I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */ + I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */ + I2C_INTR_EVENT_TXFIFO_EMPTY, /*!< I2C txfifo empty event */ +} i2c_intr_event_t; + +/** + * @brief Get I2C SCL timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param high_period Pointer to accept the SCL high period + * @param low_period Pointer to accept the SCL low period + * + * @return None + */ +static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, int *low_period, int *wait_high_period) +{ + *high_period = hw->scl_high_period.scl_high_period; + *wait_high_period = hw->scl_high_period.scl_wait_high_period; + *low_period = hw->scl_low_period.scl_low_period; +} + +/** + * @brief Configure I2C SCL timing + * + * @param hw Beginning address of the peripheral registers + * @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2) + * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) + * @param wait_high_period The I2C SCL wait rising edge period. + * + * @return None. + */ +static inline void i2c_ll_set_scl_clk_timing(i2c_dev_t *hw, int high_period, int low_period, int wait_high_period) +{ + hw->scl_low_period.scl_low_period = low_period; + hw->scl_high_period.scl_high_period = high_period; + hw->scl_high_period.scl_wait_high_period = wait_high_period; +} + +/** + * @brief Get I2C master interrupt event + * + * @param hw Beginning address of the peripheral registers + * @param event Pointer to accept the interrupt event + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) +{ + typeof(hw->int_status) int_sts = hw->int_status; + if (int_sts.arbitration_lost_int_st) { + *event = I2C_INTR_EVENT_ARBIT_LOST; + } else if (int_sts.nack_int_st) { + *event = I2C_INTR_EVENT_NACK; + } else if (int_sts.time_out_int_st) { + *event = I2C_INTR_EVENT_TOUT; + } else if (int_sts.end_detect_int_st) { + *event = I2C_INTR_EVENT_END_DET; + } else if (int_sts.trans_complete_int_st) { + *event = I2C_INTR_EVENT_TRANS_DONE; + } else { + *event = I2C_INTR_EVENT_ERR; + } +} + +/** + * @brief Get I2C slave interrupt event + * + * @param hw Beginning address of the peripheral registers + * @param event Pointer to accept the interrupt event + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_get_event(i2c_dev_t *hw, i2c_intr_event_t *event) +{ + typeof(hw->int_status) int_sts = hw->int_status; + if (int_sts.txfifo_wm_int_st) { + *event = I2C_INTR_EVENT_TXFIFO_EMPTY; + } else if (int_sts.trans_complete_int_st) { + *event = I2C_INTR_EVENT_TRANS_DONE; + } else if (int_sts.rxfifo_wm_int_st) { + *event = I2C_INTR_EVENT_RXFIFO_FULL; + } else { + *event = I2C_INTR_EVENT_ERR; + } +} + +/** + * @brief Enable I2C master TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw) +{ + hw->int_clr.val = UINT32_MAX; + hw->int_ena.val = I2C_LL_MASTER_TX_INT; +} + +/** + * @brief Enable I2C master RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw) +{ + hw->int_clr.val = UINT32_MAX; + hw->int_ena.val = I2C_LL_MASTER_RX_INT; +} + +/** + * @brief Disable I2C master TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT); +} + +/** + * @brief Disable I2C master RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT); +} + +/** + * @brief + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_enable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val |= 0x2; +} + +/** + * @brief Enable I2C slave RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_enable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val |= I2C_LL_SLAVE_RX_INT; +} + +/** + * @brief Disable I2C slave TX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_disable_tx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_SLAVE_TX_INT); +} + +/** + * @brief Disable I2C slave RX interrupt + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw) +{ + hw->int_ena.val &= (~I2C_LL_SLAVE_RX_INT); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/i2c_hal.c b/components/hal/i2c_hal.c index a59ba0c519..7497cb206c 100644 --- a/components/hal/i2c_hal.c +++ b/components/hal/i2c_hal.c @@ -5,154 +5,12 @@ */ #include "hal/i2c_hal.h" - -void i2c_hal_txfifo_rst(i2c_hal_context_t *hal) -{ - i2c_ll_txfifo_rst(hal->dev); -} - -void i2c_hal_rxfifo_rst(i2c_hal_context_t *hal) -{ - i2c_ll_rxfifo_rst(hal->dev); -} - -void i2c_hal_set_data_mode(i2c_hal_context_t *hal, i2c_trans_mode_t tx_mode, i2c_trans_mode_t rx_mode) -{ - i2c_ll_set_data_mode(hal->dev, tx_mode, rx_mode); -} - -void i2c_hal_get_data_mode(i2c_hal_context_t *hal, i2c_trans_mode_t *tx_mode, i2c_trans_mode_t *rx_mode) -{ - i2c_ll_get_data_mode(hal->dev, tx_mode, rx_mode); -} - -void i2c_hal_set_filter(i2c_hal_context_t *hal, uint8_t filter_num) -{ - i2c_ll_set_filter(hal->dev, filter_num); -} - -void i2c_hal_get_filter(i2c_hal_context_t *hal, uint8_t *filter_num) -{ - *filter_num = i2c_ll_get_filter(hal->dev); -} - -void i2c_hal_set_scl_timing(i2c_hal_context_t *hal, int hight_period, int low_period) -{ - i2c_ll_set_scl_timing(hal->dev, hight_period, low_period); -} - -void i2c_hal_clr_intsts_mask(i2c_hal_context_t *hal, uint32_t mask) -{ - i2c_ll_clr_intsts_mask(hal->dev, mask); -} - -void i2c_hal_enable_intr_mask(i2c_hal_context_t *hal, uint32_t mask) -{ - i2c_ll_enable_intr_mask(hal->dev, mask); -} - -void i2c_hal_disable_intr_mask(i2c_hal_context_t *hal, uint32_t mask) -{ - i2c_ll_disable_intr_mask(hal->dev, mask); -} - -void i2c_hal_get_intsts_mask(i2c_hal_context_t *hal, uint32_t *mask) -{ - *mask = i2c_ll_get_intsts_mask(hal->dev); -} - -void i2c_hal_set_fifo_mode(i2c_hal_context_t *hal, bool fifo_mode_en) -{ - i2c_ll_set_fifo_mode(hal->dev, fifo_mode_en); -} - -void i2c_hal_set_tout(i2c_hal_context_t *hal, int tout_num) -{ - i2c_ll_set_tout(hal->dev, tout_num); -} - -void i2c_hal_set_stop_timing(i2c_hal_context_t *hal, int stop_setup, int stop_hold) -{ - i2c_ll_set_stop_timing(hal->dev, stop_setup, stop_hold); -} - -void i2c_hal_set_start_timing(i2c_hal_context_t *hal, int start_setup, int start_hold) -{ - i2c_ll_set_start_timing(hal->dev, start_setup, start_hold); -} - -void i2c_hal_set_sda_timing(i2c_hal_context_t *hal, int sda_sample, int sda_hold) -{ - i2c_ll_set_sda_timing(hal->dev, sda_sample, sda_hold); -} - -void i2c_hal_set_txfifo_empty_thr(i2c_hal_context_t *hal, uint8_t empty_thr) -{ - i2c_ll_set_txfifo_empty_thr(hal->dev, empty_thr); -} - -void i2c_hal_set_rxfifo_full_thr(i2c_hal_context_t *hal, uint8_t full_thr) -{ - i2c_ll_set_rxfifo_full_thr(hal->dev, full_thr); -} - -bool i2c_hal_is_bus_busy(i2c_hal_context_t *hal) -{ - return i2c_ll_is_bus_busy(hal->dev); -} - -void i2c_hal_get_sda_timing(i2c_hal_context_t *hal, int *sample_time, int *hold_time) -{ - i2c_ll_get_sda_timing(hal->dev, sample_time, hold_time); -} - -void i2c_hal_get_tout(i2c_hal_context_t *hal, int *tout_val) -{ - *tout_val = i2c_ll_get_tout(hal->dev); -} - -void i2c_hal_get_start_timing(i2c_hal_context_t *hal, int *setup_time, int *hold_time) -{ - i2c_ll_get_start_timing(hal->dev, setup_time, hold_time); -} - -void i2c_hal_get_stop_timing(i2c_hal_context_t *hal, int *setup_time, int *hold_time) -{ - i2c_ll_get_stop_timing(hal->dev, setup_time, hold_time); -} - -void i2c_hal_get_scl_timing(i2c_hal_context_t *hal, int *high_period, int *low_period) -{ - i2c_ll_get_scl_timing(hal->dev, high_period, low_period); -} - -bool i2c_hal_is_master_mode(i2c_hal_context_t *hal) -{ - return i2c_ll_is_master_mode(hal->dev); -} +#include "hal/i2c_ll.h" +#include "hal/i2c_types.h" #if SOC_I2C_SUPPORT_SLAVE -void i2c_hal_set_slave_addr(i2c_hal_context_t *hal, uint16_t slave_addr, bool addr_10bit_en) -{ - i2c_ll_set_slave_addr(hal->dev, slave_addr, addr_10bit_en); -} -void i2c_hal_enable_slave_tx_it(i2c_hal_context_t *hal) -{ - i2c_ll_slave_enable_tx_it(hal->dev); -} - -void i2c_hal_enable_slave_rx_it(i2c_hal_context_t *hal) -{ - i2c_ll_slave_enable_rx_it(hal->dev); -} - -void i2c_hal_disable_slave_rx_it(i2c_hal_context_t *hal) -{ - i2c_ll_slave_disable_rx_it(hal->dev); -} - -void i2c_hal_slave_init(i2c_hal_context_t *hal, i2c_port_t i2c_num) +void i2c_hal_slave_init(i2c_hal_context_t *hal) { i2c_ll_slave_init(hal->dev); //Use fifo mode @@ -168,24 +26,18 @@ void i2c_hal_slave_init(i2c_hal_context_t *hal, i2c_port_t i2c_num) void i2c_hal_set_bus_timing(i2c_hal_context_t *hal, int scl_freq, i2c_clock_source_t src_clk, int source_freq) { i2c_ll_set_source_clk(hal->dev, src_clk); - i2c_clk_cal_t clk_cal = {0}; + i2c_hal_clk_config_t clk_cal = {0}; i2c_ll_cal_bus_clk(source_freq, scl_freq, &clk_cal); i2c_ll_set_bus_timing(hal->dev, &clk_cal); } -void i2c_hal_master_clr_bus(i2c_hal_context_t *hal) -{ - i2c_ll_master_clr_bus(hal->dev); -} - void i2c_hal_master_fsm_rst(i2c_hal_context_t *hal) { i2c_ll_master_fsm_rst(hal->dev); } -void i2c_hal_master_init(i2c_hal_context_t *hal, i2c_port_t i2c_num) +void i2c_hal_master_init(i2c_hal_context_t *hal) { - hal->version = i2c_ll_get_hw_version(hal->dev); i2c_ll_master_init(hal->dev); //Use fifo mode i2c_ll_set_fifo_mode(hal->dev, true); @@ -195,3 +47,32 @@ void i2c_hal_master_init(i2c_hal_context_t *hal, i2c_port_t i2c_num) i2c_ll_txfifo_rst(hal->dev); i2c_ll_rxfifo_rst(hal->dev); } + +void i2c_hal_init(i2c_hal_context_t *hal, int i2c_port) +{ + hal->dev = I2C_LL_GET_HW(i2c_port); +} + +void i2c_hal_master_trans_start(i2c_hal_context_t *hal) +{ + i2c_ll_update(hal->dev); + i2c_ll_trans_start(hal->dev); +} + +void i2c_hal_get_timing_config(i2c_hal_context_t *hal, i2c_hal_timing_config_t *timing_config) +{ + i2c_ll_get_scl_clk_timing(hal->dev, &timing_config->high_period, &timing_config->low_period, &timing_config->wait_high_period); + i2c_ll_get_start_timing(hal->dev, &timing_config->rstart_setup, &timing_config->start_hold); + i2c_ll_get_stop_timing(hal->dev, &timing_config->stop_setup, &timing_config->stop_hold); + i2c_ll_get_sda_timing(hal->dev, &timing_config->sda_sample, &timing_config->sda_hold); + i2c_ll_get_tout(hal->dev, &timing_config->timeout); +} + +void i2c_hal_set_timing_config(i2c_hal_context_t *hal, i2c_hal_timing_config_t *timing_config) +{ + i2c_ll_set_scl_clk_timing(hal->dev, timing_config->high_period, timing_config->low_period, timing_config->wait_high_period); + i2c_ll_set_start_timing(hal->dev, timing_config->rstart_setup, timing_config->start_hold); + i2c_ll_set_stop_timing(hal->dev, timing_config->stop_setup, timing_config->stop_hold); + i2c_ll_set_sda_timing(hal->dev, timing_config->sda_sample, timing_config->sda_hold); + i2c_ll_set_tout(hal->dev, timing_config->timeout); +} diff --git a/components/hal/i2c_hal_iram.c b/components/hal/i2c_hal_iram.c index 303fda4546..d2d7e97e02 100644 --- a/components/hal/i2c_hal_iram.c +++ b/components/hal/i2c_hal_iram.c @@ -6,57 +6,41 @@ #include "hal/i2c_hal.h" + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void i2c_hal_master_handle_tx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event) { - if (i2c_ll_get_intsts_mask(hal->dev) != 0) { + uint32_t intr_status = 0; + i2c_ll_get_intr_mask(hal->dev, &intr_status); + if (intr_status != 0) { // If intr status is 0, no need to handle it. i2c_ll_master_get_event(hal->dev, event); if ((*event < I2C_INTR_EVENT_END_DET) || (*event == I2C_INTR_EVENT_TRANS_DONE)) { i2c_ll_master_disable_tx_it(hal->dev); - i2c_ll_master_clr_tx_it(hal->dev); + i2c_ll_clear_intr_mask(hal->dev, intr_status); } else if (*event == I2C_INTR_EVENT_END_DET) { - i2c_ll_master_clr_tx_it(hal->dev); + i2c_ll_clear_intr_mask(hal->dev, intr_status); } } } void i2c_hal_master_handle_rx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event) { - if (i2c_ll_get_intsts_mask(hal->dev) != 0) { + uint32_t intr_status = 0; + i2c_ll_get_intr_mask(hal->dev, &intr_status); + if (intr_status != 0) { i2c_ll_master_get_event(hal->dev, event); if ((*event < I2C_INTR_EVENT_END_DET) || (*event == I2C_INTR_EVENT_TRANS_DONE)) { i2c_ll_master_disable_rx_it(hal->dev); - i2c_ll_master_clr_rx_it(hal->dev); + i2c_ll_clear_intr_mask(hal->dev, intr_status); } else if (*event == I2C_INTR_EVENT_END_DET) { - i2c_ll_master_clr_rx_it(hal->dev); + i2c_ll_clear_intr_mask(hal->dev, intr_status); } } } -#if SOC_I2C_SUPPORT_SLAVE -void i2c_hal_slave_handle_event(i2c_hal_context_t *hal, i2c_intr_event_t *event) -{ - i2c_ll_slave_get_event(hal->dev, event); -} - -void i2c_hal_disable_slave_tx_it(i2c_hal_context_t *hal) -{ - i2c_ll_slave_disable_tx_it(hal->dev); -} -#endif // SOC_I2C_SUPPORT_SLAVE - -void i2c_hal_update_config(i2c_hal_context_t *hal) -{ - i2c_ll_update(hal->dev); -} - -void i2c_hal_get_rxfifo_cnt(i2c_hal_context_t *hal, uint32_t *len) -{ - *len = i2c_ll_get_rxfifo_cnt(hal->dev); -} - -void i2c_hal_get_txfifo_cnt(i2c_hal_context_t *hal, uint32_t *len) -{ - *len = i2c_ll_get_txfifo_len(hal->dev); -} diff --git a/components/hal/include/hal/i2c_hal.h b/components/hal/include/hal/i2c_hal.h index 9ec37d3150..2f3df91b10 100644 --- a/components/hal/include/hal/i2c_hal.h +++ b/components/hal/include/hal/i2c_hal.h @@ -13,95 +13,22 @@ // The HAL layer for I2C #pragma once + #include "hal/i2c_ll.h" #include "hal/i2c_types.h" +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief I2C hal Context definition */ typedef struct { i2c_dev_t *dev; - uint32_t version; } i2c_hal_context_t; -/** - * @brief Write the I2C rxfifo with the given length - * - * @param hal Context of the HAL layer - * @param wr_data Pointer to data buffer - * @param wr_size Amount of data needs write - * - * @return None - */ -#define i2c_hal_write_txfifo(hal,wr_data,wr_size) i2c_ll_write_txfifo((hal)->dev,wr_data,wr_size) - -/** - * @brief Read the I2C rxfifo with the given length - * - * @param hal Context of the HAL layer - * @param buf Pointer to data buffer - * @param rd_size Amount of data needs read - * - * @return None - */ -#define i2c_hal_read_rxfifo(hal,buf,rd_size) i2c_ll_read_rxfifo((hal)->dev,buf,rd_size) - -/** - * @brief Write I2C cmd register - * - * @param hal Context of the HAL layer - * @param cmd I2C hardware command - * @param cmd_idx The index of the command register, should be less than 16 - * - * @return None - */ -#define i2c_hal_write_cmd_reg(hal,cmd, cmd_idx) i2c_ll_write_cmd_reg((hal)->dev,cmd,cmd_idx) - -/** - * @brief Configure the I2C to triger a transaction - * - * @param hal Context of the HAL layer - * - * @return None - */ -#define i2c_hal_trans_start(hal) i2c_ll_trans_start((hal)->dev) - -/** - * @brief Enable I2C master RX interrupt - * - * @param hal Context of the HAL layer - * - * @return None - */ -#define i2c_hal_enable_master_rx_it(hal) i2c_ll_master_enable_rx_it((hal)->dev) - -/** - * @brief Enable I2C master TX interrupt - * - * @param hal Context of the HAL layer - * - * @return None - */ -#define i2c_hal_enable_master_tx_it(hal) i2c_ll_master_enable_tx_it((hal)->dev) - #if SOC_I2C_SUPPORT_SLAVE -/** - * @brief Clear I2C slave TX interrupt - * - * @param hal Context of the HAL layer - * - * @return None - */ -#define i2c_hal_slave_clr_tx_it(hal) i2c_ll_slave_clr_tx_it((hal)->dev) - -/** - * @brief Clear I2C slave RX interrupt - * - * @param hal Context of the HAL layer - * - * @return None - */ -#define i2c_hal_slave_clr_rx_it(hal) i2c_ll_slave_clr_rx_it((hal)->dev) /** * @brief Init the I2C slave. @@ -111,100 +38,10 @@ typedef struct { * * @return None */ -void i2c_hal_slave_init(i2c_hal_context_t *hal, i2c_port_t i2c_num); +void i2c_hal_slave_init(i2c_hal_context_t *hal); -/** - * @brief Configure the I2C slave address - * - * @param hal Context of the HAL layer - * @param slave_addr Slave address - * @param addr_10bit_en Set true to enable 10-bit slave address mode, Set false to enable 7-bit address mode - * - * @return None - */ -void i2c_hal_set_slave_addr(i2c_hal_context_t *hal, uint16_t slave_addr, bool addr_10bit_en); - - -/** - * @brief Enable I2C slave TX interrupt - * - * @param hal Context of the HAL layer - * - * @return None - */ -void i2c_hal_enable_slave_tx_it(i2c_hal_context_t *hal); - -/** - * @brief Disable I2C slave TX interrupt - * - * @param hal Context of the HAL layer - * - * @return None - */ -void i2c_hal_disable_slave_tx_it(i2c_hal_context_t *hal); - -/** - * @brief Enable I2C slave RX interrupt - * - * @param hal Context of the HAL layer - * - * @return None - */ -void i2c_hal_enable_slave_rx_it(i2c_hal_context_t *hal); - -/** - * @brief Disable I2C slave RX interrupt - * - * @param hal Context of the HAL layer - * - * @return None - */ -void i2c_hal_disable_slave_rx_it(i2c_hal_context_t *hal); - -/** - * @brief I2C slave handle interrupt event - * - * @param hal Context of the HAL layer - * @param event Pointer to accept the interrupt event - * - * @return None - */ -void i2c_hal_slave_handle_event(i2c_hal_context_t *hal, i2c_intr_event_t *event); #endif // SOC_I2C_SUPPORT_SLAVE -/** - * @brief Set the source clock. This function is meant to be used in - * slave mode, in order to select a source clock abe to handle - * the expected SCL frequency. - * - * @param hal Context of the HAL layer - * @param src_clk Source clock to use choosen from `i2c_clock_source_t` type - */ -#define i2c_hal_set_source_clk(hal, src_clk) i2c_ll_set_source_clk((hal)->dev, src_clk) - -/** - * @brief Configure I2C SCL timing - * - * @param hw Beginning address of the peripheral registers - * @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2) - * @param low_period The I2C SCL low period (in core clock cycle, low_period > 1) - * @param wait_high_period The I2C SCL wait rising edge period. - * - * @return None. - */ -#define i2c_hal_set_scl_clk_timing(hal, high_period, low_period, wait_high_period) i2c_ll_set_scl_clk_timing((hal)->dev, high_period, low_period, wait_high_period) - -/** - * @brief Get I2C SCL timing configuration - * - * @param hw Beginning address of the peripheral registers - * @param high_period Pointer to accept the SCL high period - * @param low_period Pointer to accept the SCL low period - * - * @return None - */ -#define i2c_hal_get_scl_clk_timing(hal, high_period, low_period, wait_high_period) i2c_ll_get_scl_clk_timing((hal)->dev, high_period, low_period, wait_high_period) - /** * @brief Init the I2C master. * @@ -213,273 +50,7 @@ void i2c_hal_slave_handle_event(i2c_hal_context_t *hal, i2c_intr_event_t *event) * * @return None */ -void i2c_hal_master_init(i2c_hal_context_t *hal, i2c_port_t i2c_num); - -/** - * @brief Reset the I2C hw txfifo - * - * @param hal Context of the HAL layer - * - * @return None - */ -void i2c_hal_txfifo_rst(i2c_hal_context_t *hal); - -/** - * @brief Reset the I2C hw rxfifo - * - * @param hal Context of the HAL layer - * - * @return None - */ -void i2c_hal_rxfifo_rst(i2c_hal_context_t *hal); - -/** - * @brief Configure the I2C data MSB bit shifted first or LSB bit shifted first. - * - * @param hal Context of the HAL layer - * @param tx_mode Data format of TX - * @param rx_mode Data format of RX - * - * @return None - */ -void i2c_hal_set_data_mode(i2c_hal_context_t *hal, i2c_trans_mode_t tx_mode, i2c_trans_mode_t rx_mode); - -/** - * @brief Configure the I2C hardware filter function. - * - * @param hal Context of the HAL layer - * @param filter_num If the glitch period on the line is less than this value(in APB cycle), it will be filtered out - * If `filter_num == 0`, the filter will be disabled - * - * @return None - */ -void i2c_hal_set_filter(i2c_hal_context_t *hal, uint8_t filter_num); - -/** - * @brief Get the I2C hardware filter configuration - * - * @param hal Context of the HAL layer - * @param filter_num Pointer to accept the hardware filter configuration - * - * @return None - */ -void i2c_hal_get_filter(i2c_hal_context_t *hal, uint8_t *filter_num); - -/** - * @brief Configure the I2C SCL timing - * - * @param hal Context of the HAL layer - * @param hight_period SCL high period - * @param low_period SCL low period - * - * @return None - */ -void i2c_hal_set_scl_timing(i2c_hal_context_t *hal, int hight_period, int low_period); - -/** - * @brief Configure the I2C master SCL frequency - * - * @param hal Context of the HAL layer - * @param src_clk The I2C Source clock frequency - * @param scl_freq The SCL frequency to be set - * - * @return None - */ -void i2c_hal_set_scl_freq(i2c_hal_context_t *hal, uint32_t src_clk, uint32_t scl_freq); - -/** - * @brief Clear the I2C interrupt status with the given mask - * - * @param hal Context of the HAL layer - * @param mask The interrupt bitmap needs to be clearned - * - * @return None - */ -void i2c_hal_clr_intsts_mask(i2c_hal_context_t *hal, uint32_t mask); - -/** - * @brief Enable the I2C interrupt with the given mask - * - * @param hal Context of the HAL layer - * @param mask The interrupt bitmap needs to be enabled - * - * @return None - */ -void i2c_hal_enable_intr_mask(i2c_hal_context_t *hal, uint32_t mask); - -/** - * @brief Disable the I2C interrupt with the given mask - * - * @param hal Context of the HAL layer - * @param mask The interrupt bitmap needs to be disabled - * - * @return None - */ -void i2c_hal_disable_intr_mask(i2c_hal_context_t *hal, uint32_t mask); - -/** - * @brief Configure the I2C memory access mode, FIFO mode or none FIFO mode - * - * @param hal Context of the HAL layer - * @param fifo_mode_en Set true to enable FIFO access mode, else set it false - * - * @return None - */ -void i2c_hal_set_fifo_mode(i2c_hal_context_t *hal, bool fifo_mode_en); - -/** - * @brief Configure the I2C timeout value - * - * @param hal Context of the HAL layer - * @param tout_val the timeout value to be set - * - * @return None - */ -void i2c_hal_set_tout(i2c_hal_context_t *hal, int tout_val); - -/** - * @brief Get the I2C time out configuration - * - * @param tout_val Pointer to accept the timeout configuration - * - * @return None - */ -void i2c_hal_get_tout(i2c_hal_context_t *hal, int *tout_val); - -/** - * @brief Configure the I2C stop timing - * - * @param hal Context of the HAL layer - * @param stop_setup The stop condition setup period (in APB cycle) - * @param stop_hold The stop condition hold period (in APB cycle) - * - * @return None - */ -void i2c_hal_set_stop_timing(i2c_hal_context_t *hal, int stop_setup, int stop_hold); - -/** - * @brief Configure the I2C start timing - * - * @param hal Context of the HAL layer - * @param start_setup The start condition setup period (in APB cycle) - * @param start_hold The start condition hold period (in APB cycle) - * - * @return None - */ -void i2c_hal_set_start_timing(i2c_hal_context_t *hal, int start_setup, int start_hold); - -/** - * @brief Configure the I2C sda sample timing - * - * @param hal Context of the HAL layer - * @param sda_sample The SDA sample time (in APB cycle) - * @param sda_hold The SDA hold time (in APB cycle) - * - * @return None - */ -void i2c_hal_set_sda_timing(i2c_hal_context_t *hal, int sda_sample, int sda_hold); - -/** - * @brief Configure the I2C txfifo empty threshold value - * - * @param hal Context of the HAL layer. - * @param empty_thr TxFIFO empty threshold value - * - * @return None - */ -void i2c_hal_set_txfifo_empty_thr(i2c_hal_context_t *hal, uint8_t empty_thr); - -/** - * @brief Configure the I2C rxfifo full threshold value - * - * @param hal Context of the HAL layer - * @param full_thr RxFIFO full threshold value - * - * @return None - */ -void i2c_hal_set_rxfifo_full_thr(i2c_hal_context_t *hal, uint8_t full_thr); - -/** - * @brief Get the I2C interrupt status - * - * @param hal Context of the HAL layer - * @param mask Pointer to accept the interrupt status - * - * @return None - */ -void i2c_hal_get_intsts_mask(i2c_hal_context_t *hal, uint32_t *mask); - -/** - * @brief Check if the I2C bus is busy - * - * @param hal Context of the HAL layer - * - * @return True if the bus is busy, otherwise, fale will be returned - */ -bool i2c_hal_is_bus_busy(i2c_hal_context_t *hal); - -/** - * @brief Get the I2C sda sample timing configuration - * - * @param hal Context of the HAL layer - * @param sample_time Pointer to accept the SDA sample time - * @param hold_time Pointer to accept the SDA hold time - * - * @return None - */ -void i2c_hal_get_sda_timing(i2c_hal_context_t *hal, int *sample_time, int *hold_time); - -/** - * @brief Get the I2C stop timing configuration - * - * @param hal Context of the HAL layer - * @param setup_time Pointer to accept the stop condition setup period - * @param hold_time Pointer to accept the stop condition hold period - * - * @return None - */ -void i2c_hal_get_stop_timing(i2c_hal_context_t *hal, int *setup_time, int *hold_time); - -/** - * @brief Get the I2C scl timing configuration - * - * @param hal Context of the HAL layer - * @param high_period Pointer to accept the scl high period - * @param low_period Pointer to accept the scl low period - * - * @return None - */ -void i2c_hal_get_scl_timing(i2c_hal_context_t *hal, int *high_period, int *low_period); - -/** - * @brief Get the I2C start timing configuration - * - * @param hal Context of the HAL layer - * @param setup_time Pointer to accept the start condition setup period - * @param hold_time Pointer to accept the start condition hold period - * - * @return None - */ -void i2c_hal_get_start_timing(i2c_hal_context_t *hal, int *setup_time, int *hold_time); - -/** - * @brief Check if the I2C is master mode - * - * @param hal Context of the HAL layer - * - * @return True if in master mode, otherwise, false will be returned - */ -bool i2c_hal_is_master_mode(i2c_hal_context_t *hal); - -/** - * @brief Get the rxFIFO readable length - * - * @param hal Context of the HAL layer - * @param len Pointer to accept the rxFIFO readable length - * - * @return None - */ -void i2c_hal_get_rxfifo_cnt(i2c_hal_context_t *hal, uint32_t *len); +void i2c_hal_master_init(i2c_hal_context_t *hal); /** * @brief Set I2C bus timing with the given frequency @@ -493,27 +64,6 @@ void i2c_hal_get_rxfifo_cnt(i2c_hal_context_t *hal, uint32_t *len); */ void i2c_hal_set_bus_timing(i2c_hal_context_t *hal, int scl_freq, i2c_clock_source_t src_clk, int source_freq); -/** - * @brief Get I2C txFIFO writeable length - * - * @param hal Context of the HAL layer - * @param len Pointer to accept the txFIFO writeable length - * - * @return None - */ -void i2c_hal_get_txfifo_cnt(i2c_hal_context_t *hal, uint32_t *len); - -/** - * @brief Check if the I2C is master mode - * - * @param hal Context of the HAL layer - * @param tx_mode Pointer to accept the TX data mode - * @param rx_mode Pointer to accept the RX data mode - * - * @return None - */ -void i2c_hal_get_data_mode(i2c_hal_context_t *hal, i2c_trans_mode_t *tx_mode, i2c_trans_mode_t *rx_mode); - /** * @brief I2C hardware FSM reset * @@ -523,15 +73,6 @@ void i2c_hal_get_data_mode(i2c_hal_context_t *hal, i2c_trans_mode_t *tx_mode, i2 */ void i2c_hal_master_fsm_rst(i2c_hal_context_t *hal); -/** - * @brief @brief Clear I2C bus - * - * @param hal Context of the HAL layer - * - * @return None - */ -void i2c_hal_master_clr_bus(i2c_hal_context_t *hal); - /** * @brief I2C master handle tx interrupt event * @@ -553,11 +94,36 @@ void i2c_hal_master_handle_tx_event(i2c_hal_context_t *hal, i2c_intr_event_t *ev void i2c_hal_master_handle_rx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event); /** - * @brief Synchronize I2C status - * - * @param hal Context of the HAL layer - * - * @return None + * @brief Init I2C hal layer * + * @param hal Context of the HAL + * @param i2c_port I2C port number. */ -void i2c_hal_update_config(i2c_hal_context_t *hal); +void i2c_hal_init(i2c_hal_context_t *hal, int i2c_port); + +/** + * @brief Start I2C master transaction + * + * @param hal Context of the HAL + */ +void i2c_hal_master_trans_start(i2c_hal_context_t *hal); + +/** + * @brief Get timing configuration + * + * @param hal Context of the HAL + * @param timing_config Pointer to timing config structure. + */ +void i2c_hal_get_timing_config(i2c_hal_context_t *hal, i2c_hal_timing_config_t *timing_config); + +/** + * @brief Set timing configuration + * + * @param hal Context of the HAL + * @param timing_config Timing config structure. + */ +void i2c_hal_set_timing_config(i2c_hal_context_t *hal, i2c_hal_timing_config_t *timing_config); + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/include/hal/i2c_types.h b/components/hal/include/hal/i2c_types.h index 553d80ab38..c5878737c0 100644 --- a/components/hal/include/hal/i2c_types.h +++ b/components/hal/include/hal/i2c_types.h @@ -26,6 +26,21 @@ typedef enum { I2C_NUM_MAX, /*!< I2C port max */ } i2c_port_t; +/** + * @brief Data structure for calculating I2C bus timing. + */ +typedef struct { + uint16_t clkm_div; /*!< I2C core clock devider */ + 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_hal_clk_config_t; + typedef enum{ #if SOC_I2C_SUPPORT_SLAVE I2C_MODE_SLAVE = 0, /*!< I2C slave mode */ @@ -58,6 +73,23 @@ typedef enum { I2C_MASTER_ACK_MAX, } i2c_ack_type_t; +/** + * @brief Timing configuration structure. Used for I2C reset internally. + */ +typedef struct { + int high_period; /*!< high_period time */ + int low_period; /*!< low_period time */ + int wait_high_period; /*!< wait_high_period time */ + int rstart_setup; /*!< restart setup */ + int start_hold; /*!< start hold time */ + int stop_setup; /*!< stop setup */ + int stop_hold; /*!< stop hold time */ + int sda_sample; /*!< high_period time */ + int sda_hold; /*!< sda hold time */ + int timeout; /*!< timeout value */ +} i2c_hal_timing_config_t; + + /** * @brief I2C group clock source */ diff --git a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in index f49f0c5629..ebecbda474 100644 --- a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in @@ -241,7 +241,7 @@ config SOC_I2C_NUM config SOC_I2C_FIFO_LEN int - default 32 + default 16 config SOC_I2C_SUPPORT_HW_CLR_BUS bool diff --git a/components/soc/esp32c2/include/soc/soc_caps.h b/components/soc/esp32c2/include/soc/soc_caps.h index 76f4e335be..77eb54e6d7 100644 --- a/components/soc/esp32c2/include/soc/soc_caps.h +++ b/components/soc/esp32c2/include/soc/soc_caps.h @@ -124,7 +124,7 @@ // ESP32-C2 has 1 I2C #define SOC_I2C_NUM (1U) -#define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */ +#define SOC_I2C_FIFO_LEN (16) /*!< I2C hardware FIFO depth */ // FSM_RST only resets the FSM, not using it. So SOC_I2C_SUPPORT_HW_FSM_RST not defined. #define SOC_I2C_SUPPORT_HW_CLR_BUS (1)