Merge branch 'bugfix/fix_i2c_driver_breakingchange_issue' into 'master'

bugfix(i2c): fix I2C driver breaking change issue

See merge request espressif/esp-idf!6809
This commit is contained in:
Wang Jia Lin 2019-12-06 16:50:16 +08:00
commit f5e60524ac
7 changed files with 401 additions and 172 deletions

View file

@ -37,7 +37,6 @@ static const char* I2C_TAG = "i2c";
return (ret); \
}
static portMUX_TYPE i2c_spinlock[I2C_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
/* DRAM_ATTR is required to avoid I2C array placed in flash, due to accessed from ISR */
#define I2C_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux)
@ -84,6 +83,12 @@ static portMUX_TYPE i2c_spinlock[I2C_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, p
#define I2C_CLR_BUS_SCL_NUM (9)
#define I2C_CLR_BUS_HALF_PERIOD_US (5)
#define I2C_CONTEX_INIT_DEF(uart_num) {\
.hal.dev = I2C_LL_GET_HW(uart_num),\
.spinlock = portMUX_INITIALIZER_UNLOCKED,\
.hw_enabled = false,\
}
typedef struct {
i2c_hw_cmd_t hw_cmd;
uint8_t* data; /*!< data address */
@ -115,7 +120,6 @@ typedef struct {
} i2c_cmd_evt_t;
typedef struct {
i2c_hal_context_t i2c_hal; /*!< I2C hal context */
int i2c_num; /*!< I2C port number */
int mode; /*!< I2C mode, master or slave */
intr_handle_t intr_handle; /*!< I2C interrupt handle*/
@ -142,10 +146,23 @@ typedef struct {
RingbufHandle_t rx_ring_buf; /*!< rx ringbuffer handler of slave mode */
size_t tx_buf_length; /*!< tx buffer length */
RingbufHandle_t tx_ring_buf; /*!< tx ringbuffer handler of slave mode */
uint8_t scl_io_num;
uint8_t sda_io_num;
} i2c_obj_t;
typedef struct {
i2c_hal_context_t hal; /*!< I2C hal context */
portMUX_TYPE spinlock;
bool hw_enabled;
#if !I2C_SUPPORT_HW_CLR_BUS
int scl_io_num;
int sda_io_num;
#endif
} i2c_context_t;
static i2c_context_t i2c_context[I2C_NUM_MAX] = {
I2C_CONTEX_INIT_DEF(I2C_NUM_0),
I2C_CONTEX_INIT_DEF(I2C_NUM_1),
};
static i2c_obj_t *p_i2c_obj[I2C_NUM_MAX] = {0};
static void i2c_isr_handler_default(void* arg);
static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num);
@ -153,12 +170,22 @@ static esp_err_t IRAM_ATTR i2c_hw_fsm_reset(i2c_port_t i2c_num);
static void i2c_hw_disable(i2c_port_t i2c_num)
{
periph_module_disable(i2c_periph_signal[i2c_num].module);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
if (i2c_context[i2c_num].hw_enabled != false){
periph_module_disable(i2c_periph_signal[i2c_num].module);
i2c_context[i2c_num].hw_enabled = false;
}
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
}
static void i2c_hw_enable(i2c_port_t i2c_num)
{
periph_module_enable(i2c_periph_signal[i2c_num].module);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
if (i2c_context[i2c_num].hw_enabled != true){
periph_module_enable(i2c_periph_signal[i2c_num].module);
i2c_context[i2c_num].hw_enabled = true;
}
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
}
/*
@ -176,10 +203,6 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
ESP_ERR_INVALID_ARG);
if (p_i2c_obj[i2c_num] == NULL) {
// Reset the I2C hardware in case there is a soft reboot.
i2c_hw_disable(i2c_num);
i2c_hw_enable(i2c_num);
#if !CONFIG_SPIRAM_USE_MALLOC
p_i2c_obj[i2c_num] = (i2c_obj_t*) calloc(1, sizeof(i2c_obj_t));
#else
@ -234,7 +257,6 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
ESP_LOGE(I2C_TAG, I2C_SEM_ERR_STR);
goto err;
}
i2c_hal_slave_init(&(p_i2c->i2c_hal), i2c_num);
} else {
//semaphore to sync sending process, because we only have 32 bytes for hardware fifo.
p_i2c->cmd_mux = xSemaphoreCreateMutex();
@ -272,14 +294,14 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
p_i2c->rx_buf_length = 0;
p_i2c->tx_ring_buf = NULL;
p_i2c->tx_buf_length = 0;
i2c_hal_master_init(&(p_i2c->i2c_hal), i2c_num);
}
} else {
ESP_LOGE(I2C_TAG, I2C_DRIVER_ERR_STR);
return ESP_FAIL;
}
i2c_hw_enable(i2c_num);
//Disable I2C interrupt.
i2c_hal_disable_intr_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK);
i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK);
//hook isr handler
i2c_isr_register(i2c_num, i2c_isr_handler_default, p_i2c_obj[i2c_num], intr_alloc_flags, &p_i2c_obj[i2c_num]->intr_handle);
return ESP_OK;
@ -334,7 +356,7 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num)
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
i2c_hal_disable_intr_mask(&(p_i2c->i2c_hal), I2C_INTR_MASK);
i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK);
esp_intr_free(p_i2c->intr_handle);
p_i2c->intr_handle = NULL;
@ -386,20 +408,18 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num)
esp_err_t i2c_reset_tx_fifo(i2c_port_t i2c_num)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_txfifo_rst(&(p_i2c_obj[i2c_num]->i2c_hal));
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_txfifo_rst(&(i2c_context[i2c_num].hal));
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
esp_err_t i2c_reset_rx_fifo(i2c_port_t i2c_num)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_rxfifo_rst(&(p_i2c_obj[i2c_num]->i2c_hal));
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_rxfifo_rst(&(i2c_context[i2c_num].hal));
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
@ -411,9 +431,9 @@ static void IRAM_ATTR i2c_isr_handler_default(void *arg)
portBASE_TYPE HPTaskAwoken = pdFALSE;
if (p_i2c->mode == I2C_MODE_MASTER) {
if (p_i2c->status == I2C_STATUS_WRITE) {
i2c_hal_master_handle_tx_event(&(p_i2c->i2c_hal), &evt_type);
i2c_hal_master_handle_tx_event(&(i2c_context[i2c_num].hal), &evt_type);
} else if (p_i2c->status == I2C_STATUS_READ) {
i2c_hal_master_handle_rx_event(&(p_i2c->i2c_hal), &evt_type);
i2c_hal_master_handle_rx_event(&(i2c_context[i2c_num].hal), &evt_type);
}
if (evt_type == I2C_INTR_EVENT_NACK) {
p_i2c_obj[i2c_num]->status = I2C_STATUS_ACK_ERROR;
@ -436,25 +456,25 @@ static void IRAM_ATTR i2c_isr_handler_default(void *arg)
};
xQueueSendFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken);
} else {
i2c_hal_slave_handle_event(&(p_i2c->i2c_hal), &evt_type);
i2c_hal_slave_handle_event(&(i2c_context[i2c_num].hal), &evt_type);
if (evt_type == I2C_INTR_EVENT_TRANS_DONE || evt_type == I2C_INTR_EVENT_RXFIFO_FULL) {
uint32_t rx_fifo_cnt;
i2c_hal_get_rxfifo_cnt(&(p_i2c->i2c_hal), &rx_fifo_cnt);
i2c_hal_read_rxfifo(&(p_i2c->i2c_hal), p_i2c->data_buf, rx_fifo_cnt);
i2c_hal_get_rxfifo_cnt(&(i2c_context[i2c_num].hal), &rx_fifo_cnt);
i2c_hal_read_rxfifo(&(i2c_context[i2c_num].hal), p_i2c->data_buf, rx_fifo_cnt);
xRingbufferSendFromISR(p_i2c->rx_ring_buf, p_i2c->data_buf, rx_fifo_cnt, &HPTaskAwoken);
i2c_hal_slave_clr_rx_it(&(p_i2c->i2c_hal));
i2c_hal_slave_clr_rx_it(&(i2c_context[i2c_num].hal));
} else if (evt_type == I2C_INTR_EVENT_TXFIFO_EMPTY) {
uint32_t tx_fifo_rem;
i2c_hal_get_txfifo_cnt(&(p_i2c->i2c_hal), &tx_fifo_rem);
i2c_hal_get_txfifo_cnt(&(i2c_context[i2c_num].hal), &tx_fifo_rem);
size_t size = 0;
uint8_t *data = (uint8_t*) xRingbufferReceiveUpToFromISR(p_i2c->tx_ring_buf, &size, tx_fifo_rem);
if (data) {
i2c_hal_write_txfifo(&(p_i2c->i2c_hal), data, size);
i2c_hal_write_txfifo(&(i2c_context[i2c_num].hal), data, size);
vRingbufferReturnItemFromISR(p_i2c->tx_ring_buf, data, &HPTaskAwoken);
} else {
i2c_hal_disable_slave_tx_it(&(p_i2c->i2c_hal));
i2c_hal_disable_slave_tx_it(&(i2c_context[i2c_num].hal));
}
i2c_hal_slave_clr_tx_it(&(p_i2c->i2c_hal));
i2c_hal_slave_clr_tx_it(&(i2c_context[i2c_num].hal));
}
}
//We only need to check here if there is a high-priority task needs to be switched.
@ -466,20 +486,18 @@ static void IRAM_ATTR i2c_isr_handler_default(void *arg)
esp_err_t i2c_set_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t tx_trans_mode, i2c_trans_mode_t rx_trans_mode)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_CHECK(tx_trans_mode < I2C_DATA_MODE_MAX, I2C_TRANS_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(rx_trans_mode < I2C_DATA_MODE_MAX, I2C_TRANS_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_set_data_mode(&(p_i2c_obj[i2c_num]->i2c_hal), tx_trans_mode, rx_trans_mode);
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_data_mode(&(i2c_context[i2c_num].hal), tx_trans_mode, rx_trans_mode);
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode, i2c_trans_mode_t *rx_trans_mode)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
i2c_hal_get_data_mode(&(p_i2c_obj[i2c_num]->i2c_hal), tx_trans_mode, rx_trans_mode);
i2c_hal_get_data_mode(&(i2c_context[i2c_num].hal), tx_trans_mode, rx_trans_mode);
return ESP_OK;
}
@ -493,8 +511,8 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
#if !I2C_SUPPORT_HW_CLR_BUS
const int scl_half_period = I2C_CLR_BUS_HALF_PERIOD_US; // use standard 100kHz data rate
int i = 0;
int scl_io = p_i2c_obj[i2c_num]->scl_io_num;
int sda_io = p_i2c_obj[i2c_num]->sda_io_num;
int scl_io = i2c_context[i2c_num].scl_io_num;
int sda_io = i2c_context[i2c_num].sda_io_num;
gpio_set_direction(scl_io, GPIO_MODE_OUTPUT_OD);
gpio_set_direction(sda_io, GPIO_MODE_INPUT_OUTPUT_OD);
// If a SLAVE device was in a read operation when the bus was interrupted, the SLAVE device is controlling SDA.
@ -517,7 +535,7 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
gpio_set_level(sda_io, 1); // STOP, SDA low -> high while SCL is HIGH
i2c_set_pin(i2c_num, sda_io, scl_io, 1, 1, I2C_MODE_MASTER);
#else
i2c_hal_master_clr_bus(&(p_i2c_obj[i2c_num]->i2c_hal));
i2c_hal_master_clr_bus(&(i2c_context[i2c_num].hal));
#endif
return ESP_OK;
}
@ -536,29 +554,29 @@ static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num)
int timeout;
uint8_t filter_cfg;
i2c_hal_get_scl_timing(&(p_i2c_obj[i2c_num]->i2c_hal), &scl_high_period, &scl_low_period);
i2c_hal_get_start_timing(&(p_i2c_obj[i2c_num]->i2c_hal), &scl_rstart_setup, &scl_start_hold);
i2c_hal_get_stop_timing(&(p_i2c_obj[i2c_num]->i2c_hal), &scl_stop_setup, &scl_stop_hold);
i2c_hal_get_sda_timing(&(p_i2c_obj[i2c_num]->i2c_hal), &sda_sample, &sda_hold);
i2c_hal_get_tout(&(p_i2c_obj[i2c_num]->i2c_hal), &timeout);
i2c_hal_get_filter(&(p_i2c_obj[i2c_num]->i2c_hal), &filter_cfg);
i2c_hal_get_scl_timing(&(i2c_context[i2c_num].hal), &scl_high_period, &scl_low_period);
i2c_hal_get_start_timing(&(i2c_context[i2c_num].hal), &scl_rstart_setup, &scl_start_hold);
i2c_hal_get_stop_timing(&(i2c_context[i2c_num].hal), &scl_stop_setup, &scl_stop_hold);
i2c_hal_get_sda_timing(&(i2c_context[i2c_num].hal), &sda_sample, &sda_hold);
i2c_hal_get_tout(&(i2c_context[i2c_num].hal), &timeout);
i2c_hal_get_filter(&(i2c_context[i2c_num].hal), &filter_cfg);
//to reset the I2C hw module, we need re-enable the hw
i2c_hw_disable(i2c_num);
i2c_master_clear_bus(i2c_num);
i2c_hw_enable(i2c_num);
i2c_hal_master_init(&(p_i2c_obj[i2c_num]->i2c_hal), i2c_num);
i2c_hal_disable_intr_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK);
i2c_hal_clr_intsts_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK);
i2c_hal_set_scl_timing(&(p_i2c_obj[i2c_num]->i2c_hal), scl_high_period, scl_low_period);
i2c_hal_set_start_timing(&(p_i2c_obj[i2c_num]->i2c_hal), scl_rstart_setup, scl_start_hold);
i2c_hal_set_stop_timing(&(p_i2c_obj[i2c_num]->i2c_hal), scl_stop_setup, scl_stop_hold);
i2c_hal_set_sda_timing(&(p_i2c_obj[i2c_num]->i2c_hal), sda_sample, sda_hold);
i2c_hal_set_tout(&(p_i2c_obj[i2c_num]->i2c_hal), timeout);
i2c_hal_set_filter(&(p_i2c_obj[i2c_num]->i2c_hal), filter_cfg);
i2c_hal_master_init(&(i2c_context[i2c_num].hal), i2c_num);
i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK);
i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK);
i2c_hal_set_scl_timing(&(i2c_context[i2c_num].hal), scl_high_period, scl_low_period);
i2c_hal_set_start_timing(&(i2c_context[i2c_num].hal), scl_rstart_setup, scl_start_hold);
i2c_hal_set_stop_timing(&(i2c_context[i2c_num].hal), scl_stop_setup, scl_stop_hold);
i2c_hal_set_sda_timing(&(i2c_context[i2c_num].hal), sda_sample, sda_hold);
i2c_hal_set_tout(&(i2c_context[i2c_num].hal), timeout);
i2c_hal_set_filter(&(i2c_context[i2c_num].hal), filter_cfg);
#else
i2c_hal_master_fsm_rst(&(p_i2c_obj[i2c_num]->i2c_hal));
i2c_hal_master_fsm_rst(&(i2c_context[i2c_num].hal));
i2c_master_clear_bus(i2c_num);
#endif
return ESP_OK;
@ -567,7 +585,6 @@ static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num)
esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_CHECK(i2c_conf != NULL, I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(i2c_conf->mode < I2C_MODE_MAX, I2C_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
@ -576,48 +593,48 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf)
if (ret != ESP_OK) {
return ret;
}
p_i2c_obj[i2c_num]->mode = i2c_conf->mode;
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_disable_intr_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK);
i2c_hal_clr_intsts_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK);
i2c_hw_enable(i2c_num);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK);
i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK);
if (i2c_conf->mode == I2C_MODE_SLAVE) { //slave mode
i2c_hal_set_slave_addr(&(p_i2c_obj[i2c_num]->i2c_hal), i2c_conf->slave.slave_addr, i2c_conf->slave.addr_10bit_en);
i2c_hal_set_rxfifo_full_thr(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_FIFO_FULL_THRESH_VAL);
i2c_hal_set_txfifo_empty_thr(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_FIFO_EMPTY_THRESH_VAL);
i2c_hal_slave_init(&(i2c_context[i2c_num].hal), i2c_num);
i2c_hal_set_slave_addr(&(i2c_context[i2c_num].hal), i2c_conf->slave.slave_addr, i2c_conf->slave.addr_10bit_en);
i2c_hal_set_rxfifo_full_thr(&(i2c_context[i2c_num].hal), I2C_FIFO_FULL_THRESH_VAL);
i2c_hal_set_txfifo_empty_thr(&(i2c_context[i2c_num].hal), I2C_FIFO_EMPTY_THRESH_VAL);
//set timing for data
i2c_hal_set_sda_timing(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_SLAVE_SDA_SAMPLE_DEFAULT, I2C_SLAVE_SDA_HOLD_DEFAULT);
i2c_hal_set_tout(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_SLAVE_TIMEOUT_DEFAULT);
i2c_hal_enable_slave_tx_it(&(p_i2c_obj[i2c_num]->i2c_hal));
i2c_hal_enable_slave_rx_it(&(p_i2c_obj[i2c_num]->i2c_hal));
i2c_hal_set_sda_timing(&(i2c_context[i2c_num].hal), I2C_SLAVE_SDA_SAMPLE_DEFAULT, I2C_SLAVE_SDA_HOLD_DEFAULT);
i2c_hal_set_tout(&(i2c_context[i2c_num].hal), I2C_SLAVE_TIMEOUT_DEFAULT);
i2c_hal_enable_slave_tx_it(&(i2c_context[i2c_num].hal));
i2c_hal_enable_slave_rx_it(&(i2c_context[i2c_num].hal));
} else {
i2c_hal_master_init(&(i2c_context[i2c_num].hal), i2c_num);
//Default, we enable hardware filter
i2c_hal_set_filter(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_FILTER_CYC_NUM_DEF);
i2c_hal_set_bus_timing(&(p_i2c_obj[i2c_num]->i2c_hal), i2c_conf->master.clk_speed, I2C_SCLK_APB);
i2c_hal_set_filter(&(i2c_context[i2c_num].hal), I2C_FILTER_CYC_NUM_DEF);
i2c_hal_set_bus_timing(&(i2c_context[i2c_num].hal), i2c_conf->master.clk_speed, I2C_SCLK_APB);
}
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_CHECK((high_period <= I2C_SCL_HIGH_PERIOD_V) && (high_period > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((low_period <= I2C_SCL_LOW_PERIOD_V) && (low_period > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_set_scl_timing(&(p_i2c_obj[i2c_num]->i2c_hal), high_period, low_period);
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_scl_timing(&(i2c_context[i2c_num].hal), high_period, low_period);
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
esp_err_t i2c_get_period(i2c_port_t i2c_num, int* high_period, int* low_period)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX && high_period != NULL && low_period != NULL, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_get_scl_timing(&(p_i2c_obj[i2c_num]->i2c_hal), high_period, low_period);
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_get_scl_timing(&(i2c_context[i2c_num].hal), high_period, low_period);
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
@ -625,108 +642,99 @@ esp_err_t i2c_filter_enable(i2c_port_t i2c_num, uint8_t cyc_num)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_set_filter(&(p_i2c_obj[i2c_num]->i2c_hal), cyc_num);
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_filter(&(i2c_context[i2c_num].hal), cyc_num);
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
esp_err_t i2c_filter_disable(i2c_port_t i2c_num)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_set_filter(&(p_i2c_obj[i2c_num]->i2c_hal), 0);
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_filter(&(i2c_context[i2c_num].hal), 0);
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_CHECK((hold_time <= I2C_SCL_START_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((setup_time <= I2C_SCL_RSTART_SETUP_TIME_V) && (setup_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_set_start_timing(&(p_i2c_obj[i2c_num]->i2c_hal), setup_time, hold_time);
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_start_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time);
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
esp_err_t i2c_get_start_timing(i2c_port_t i2c_num, int* setup_time, int* hold_time)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX && setup_time != NULL && hold_time != NULL, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_get_start_timing(&(p_i2c_obj[i2c_num]->i2c_hal), setup_time, hold_time);
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_get_start_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time);
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
esp_err_t i2c_set_stop_timing(i2c_port_t i2c_num, int setup_time, int hold_time)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_CHECK((setup_time <= I2C_SCL_STOP_SETUP_TIME_V) && (setup_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((hold_time <= I2C_SCL_STOP_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_set_stop_timing(&(p_i2c_obj[i2c_num]->i2c_hal), setup_time, hold_time);
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_stop_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time);
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
esp_err_t i2c_get_stop_timing(i2c_port_t i2c_num, int* setup_time, int* hold_time)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX && setup_time != NULL && hold_time != NULL, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_get_stop_timing(&(p_i2c_obj[i2c_num]->i2c_hal), setup_time, hold_time);
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_get_stop_timing(&(i2c_context[i2c_num].hal), setup_time, hold_time);
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_CHECK((sample_time <= I2C_SDA_SAMPLE_TIME_V) && (sample_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK((hold_time <= I2C_SDA_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_set_sda_timing(&(p_i2c_obj[i2c_num]->i2c_hal), sample_time, hold_time);
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_sda_timing(&(i2c_context[i2c_num].hal), sample_time, hold_time);
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
esp_err_t i2c_get_data_timing(i2c_port_t i2c_num, int* sample_time, int* hold_time)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX && sample_time != NULL && hold_time != NULL, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_get_sda_timing(&(p_i2c_obj[i2c_num]->i2c_hal), sample_time, hold_time);
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_get_sda_timing(&(i2c_context[i2c_num].hal), sample_time, hold_time);
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
esp_err_t i2c_set_timeout(i2c_port_t i2c_num, int timeout)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
I2C_CHECK((timeout <= I2C_TIME_OUT_REG_V) && (timeout > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_set_tout(&(p_i2c_obj[i2c_num]->i2c_hal), timeout);
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_set_tout(&(i2c_context[i2c_num].hal), timeout);
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
return ESP_OK;
}
esp_err_t i2c_get_timeout(i2c_port_t i2c_num, int* timeout)
{
I2C_CHECK(i2c_num < I2C_NUM_MAX && timeout != NULL, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL);
i2c_hal_get_tout(&(p_i2c_obj[i2c_num]->i2c_hal), timeout);
i2c_hal_get_tout(&(i2c_context[i2c_num].hal), timeout);
return ESP_OK;
}
@ -794,8 +802,10 @@ esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, bool s
}
gpio_matrix_in(scl_io_num, scl_in_sig, 0);
}
p_i2c_obj[i2c_num]->scl_io_num = scl_io_num;
p_i2c_obj[i2c_num]->sda_io_num = sda_io_num;
#if !I2C_SUPPORT_HW_CLR_BUS
i2c_context[i2c_num].scl_io_num = scl_io_num;
i2c_context[i2c_num].sda_io_num = sda_io_num;
#endif
return ESP_OK;
}
@ -998,7 +1008,7 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
i2c_cmd_evt_t evt;
if (p_i2c->cmd_link.head != NULL && p_i2c->status == I2C_STATUS_READ) {
i2c_cmd_t *cmd = &p_i2c->cmd_link.head->cmd;
i2c_hal_read_rxfifo(&(p_i2c->i2c_hal), cmd->data, p_i2c->rx_cnt);
i2c_hal_read_rxfifo(&(i2c_context[i2c_num].hal), cmd->data, p_i2c->rx_cnt);
cmd->data += p_i2c->rx_cnt;
if (cmd->hw_cmd.byte_num > 0) {
p_i2c->cmd_idx = 0;
@ -1043,10 +1053,10 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
cmd->hw_cmd.byte_num--;
}
hw_cmd.byte_num = wr_filled;
i2c_hal_write_txfifo(&(p_i2c->i2c_hal), write_pr, wr_filled);
i2c_hal_write_cmd_reg(&(p_i2c->i2c_hal), hw_cmd, p_i2c->cmd_idx);
i2c_hal_write_cmd_reg(&(p_i2c->i2c_hal), hw_end_cmd, p_i2c->cmd_idx + 1);
i2c_hal_enable_master_tx_it(&(p_i2c->i2c_hal));
i2c_hal_write_txfifo(&(i2c_context[i2c_num].hal), write_pr, wr_filled);
i2c_hal_write_cmd_reg(&(i2c_context[i2c_num].hal), hw_cmd, p_i2c->cmd_idx);
i2c_hal_write_cmd_reg(&(i2c_context[i2c_num].hal), hw_end_cmd, p_i2c->cmd_idx + 1);
i2c_hal_enable_master_tx_it(&(i2c_context[i2c_num].hal));
p_i2c->cmd_idx = 0;
if (cmd->hw_cmd.byte_num == 0) {
p_i2c->cmd_link.head = p_i2c->cmd_link.head->next;
@ -1058,13 +1068,13 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
p_i2c->rx_cnt = cmd->hw_cmd.byte_num > SOC_I2C_FIFO_LEN ? SOC_I2C_FIFO_LEN : cmd->hw_cmd.byte_num;
cmd->hw_cmd.byte_num -= p_i2c->rx_cnt;
hw_cmd.byte_num = p_i2c->rx_cnt;
i2c_hal_write_cmd_reg(&(p_i2c->i2c_hal), hw_cmd, p_i2c->cmd_idx);
i2c_hal_write_cmd_reg(&(p_i2c->i2c_hal), hw_end_cmd, p_i2c->cmd_idx + 1);
i2c_hal_enable_master_rx_it(&(p_i2c->i2c_hal));
i2c_hal_write_cmd_reg(&(i2c_context[i2c_num].hal), hw_cmd, p_i2c->cmd_idx);
i2c_hal_write_cmd_reg(&(i2c_context[i2c_num].hal), hw_end_cmd, p_i2c->cmd_idx + 1);
i2c_hal_enable_master_rx_it(&(i2c_context[i2c_num].hal));
p_i2c->status = I2C_STATUS_READ;
break;
} else {
i2c_hal_write_cmd_reg(&(p_i2c->i2c_hal), hw_cmd, p_i2c->cmd_idx);
i2c_hal_write_cmd_reg(&(i2c_context[i2c_num].hal), hw_cmd, p_i2c->cmd_idx);
}
p_i2c->cmd_idx++;
p_i2c->cmd_link.head = p_i2c->cmd_link.head->next;
@ -1073,7 +1083,7 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
break;
}
}
i2c_hal_trans_start(&(p_i2c->i2c_hal));
i2c_hal_trans_start(&(i2c_context[i2c_num].hal));
return;
}
@ -1125,7 +1135,7 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
}
xQueueReset(p_i2c->cmd_evt_queue);
if (p_i2c->status == I2C_STATUS_TIMEOUT
|| i2c_hal_is_bus_busy(&(p_i2c->i2c_hal))) {
|| i2c_hal_is_bus_busy(&(i2c_context[i2c_num].hal))) {
i2c_hw_fsm_reset(i2c_num);
clear_bus_cnt = 0;
}
@ -1142,8 +1152,8 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
i2c_reset_rx_fifo(i2c_num);
// These two interrupts some times can not be cleared when the FSM gets stuck.
// so we disable them when these two interrupt occurs and re-enable them here.
i2c_hal_disable_intr_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK);
i2c_hal_clr_intsts_mask(&(p_i2c_obj[i2c_num]->i2c_hal), I2C_INTR_MASK);
i2c_hal_disable_intr_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK);
i2c_hal_clr_intsts_mask(&(i2c_context[i2c_num].hal), I2C_INTR_MASK);
//start send commands, at most 32 bytes one time, isr handler will process the remaining commands.
i2c_master_cmd_begin_static(i2c_num);
@ -1222,9 +1232,9 @@ int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, TickType
if (res == pdFALSE) {
cnt = 0;
} else {
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_enable_slave_tx_it(&(p_i2c->i2c_hal));
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_enable_slave_tx_it(&(i2c_context[i2c_num].hal));
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
cnt = size;
}
xSemaphoreGive(p_i2c->slv_tx_mux);
@ -1246,9 +1256,9 @@ int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, Ti
}
portTickType ticks_rem = ticks_to_wait;
portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait;
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
i2c_hal_enable_slave_rx_it(&(p_i2c->i2c_hal));
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
I2C_ENTER_CRITICAL(&(i2c_context[i2c_num].spinlock));
i2c_hal_enable_slave_rx_it(&(i2c_context[i2c_num].hal));
I2C_EXIT_CRITICAL(&(i2c_context[i2c_num].spinlock));
while(size_rem && ticks_rem <= ticks_to_wait) {
uint8_t* pdata = (uint8_t*) xRingbufferReceiveUpTo(p_i2c->rx_ring_buf, &size, ticks_to_wait, size_rem);
if (pdata && size > 0) {
@ -1263,4 +1273,4 @@ int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, Ti
}
xSemaphoreGive(p_i2c->slv_rx_mux);
return max_size - size_rem;
}
}

View file

@ -15,6 +15,8 @@
#include "soc/i2c_periph.h"
#include "esp_system.h"
#include "driver/pcnt.h"
#include "soc/uart_struct.h"
#include "driver/periph_ctrl.h"
#define DATA_LENGTH 512 /*!<Data buffer length for test buffer*/
@ -66,8 +68,8 @@ static i2c_config_t i2c_master_init(void)
{
i2c_config_t conf_master = {
.mode = I2C_MODE_MASTER,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
.sda_io_num = I2C_MASTER_SDA_IO,
.scl_io_num = I2C_MASTER_SCL_IO,
@ -81,8 +83,8 @@ static i2c_config_t i2c_slave_init(void)
.mode = I2C_MODE_SLAVE,
.sda_io_num = I2C_SLAVE_SDA_IO,
.scl_io_num = I2C_SLAVE_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.slave.addr_10bit_en = 0,
.slave.slave_addr = ESP_SLAVE_ADDR,
};
@ -304,3 +306,103 @@ TEST_CASE("test i2c_slave_write_buffer is not blocked when ticks_to_wait=0", "[i
}
TEST_ESP_OK(i2c_driver_delete(I2C_SLAVE_NUM));
}
TEST_CASE("I2C general API test", "[i2c]")
{
const int i2c_num = 1;
i2c_config_t conf_master = {
.mode = I2C_MODE_MASTER,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
.sda_io_num = I2C_MASTER_SDA_IO,
.scl_io_num = I2C_MASTER_SCL_IO,
};
TEST_ESP_OK(i2c_param_config( i2c_num, &conf_master));
int time_get0, time_get1;
for(int i = 10; i < 0x3ff; i++) {
//set period test
TEST_ESP_OK(i2c_set_period(i2c_num, i, i));
TEST_ESP_OK(i2c_get_period(i2c_num, &time_get0, &time_get1));
TEST_ASSERT((time_get0 == i) && (time_get1 == i));
//set start timing test
TEST_ESP_OK(i2c_set_start_timing(i2c_num, i, i));
TEST_ESP_OK(i2c_get_start_timing(i2c_num, &time_get0, &time_get1));
TEST_ASSERT((time_get0 == i) && (time_get1 == i));
//set stop timing test
TEST_ESP_OK(i2c_set_stop_timing(i2c_num, i, i));
TEST_ESP_OK(i2c_get_stop_timing(i2c_num, &time_get0, &time_get1));
TEST_ASSERT((time_get0 == i) && (time_get1 == i));
//set data timing test
TEST_ESP_OK(i2c_set_data_timing(i2c_num, i, i));
TEST_ESP_OK(i2c_get_data_timing(i2c_num, &time_get0, &time_get1));
TEST_ASSERT((time_get0 == i) && (time_get1 == i));
//set time out test
TEST_ESP_OK(i2c_set_timeout(i2c_num, i));
TEST_ESP_OK(i2c_get_timeout(i2c_num, &time_get0));
TEST_ASSERT(time_get0 == i);
}
}
//Init uart baud rate detection
static void uart_aut_baud_det_init(int rxd_io_num)
{
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rxd_io_num], PIN_FUNC_GPIO);
gpio_set_direction(rxd_io_num, GPIO_MODE_INPUT_OUTPUT);
gpio_matrix_out(rxd_io_num, I2CEXT1_SCL_OUT_IDX, 0, 0);
gpio_matrix_in(rxd_io_num, U1RXD_IN_IDX, 0);
periph_module_enable(PERIPH_UART1_MODULE);
UART1.int_ena.val = 0;
UART1.int_clr.val = ~0;
UART1.auto_baud.en = 1;
}
//Calculate I2C scl freq
static void i2c_scl_freq_cal(void)
{
const int i2c_source_clk_freq = 80000000;
const float i2c_cource_clk_period = 0.0125;
int edg_cnt = UART1.rxd_cnt.edge_cnt;
int pospulse_cnt = UART1.pospulse.min_cnt;
int negpulse_cnt = UART1.negpulse.min_cnt;
int high_period_cnt = UART1.highpulse.min_cnt;
int low_period_cnt = UART1.lowpulse.min_cnt;
if(edg_cnt != 542) {
printf("\nedg_cnt != 542, test fail\n");
return;
}
printf("\nDetected SCL frequency: %d Hz\n", i2c_source_clk_freq / ((pospulse_cnt + negpulse_cnt) / 2) );
printf("\nSCL high period %.3f (us), SCL low_period %.3f (us)\n\n", (float)(i2c_cource_clk_period * high_period_cnt), (float)(i2c_cource_clk_period * low_period_cnt));
UART1.auto_baud.en = 0;
periph_module_disable(PERIPH_UART1_MODULE);
}
TEST_CASE("I2C SCL freq test (local test)", "[i2c][ignore]")
{
//Use the UART baud rate detection function to detect the I2C SCL frequency.
const int i2c_num = 1;
const int uart1_rxd_io = 5;
i2c_config_t conf_master = {
.mode = I2C_MODE_MASTER,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 400000,
.sda_io_num = I2C_MASTER_SDA_IO,
.scl_io_num = I2C_MASTER_SCL_IO,
};
uint8_t *data = (uint8_t *)malloc(30);
TEST_ESP_OK(i2c_param_config( i2c_num, &conf_master));
TEST_ESP_OK(i2c_driver_install(i2c_num, I2C_MODE_MASTER, 0, 0, 0));
memset(data, 0, 0);
uart_aut_baud_det_init(uart1_rxd_io);
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write(cmd, data, 30, ACK_CHECK_DIS);
i2c_master_stop(cmd);
i2c_master_cmd_begin(i2c_num, cmd, 5000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
i2c_scl_freq_cal();
free(data);
TEST_ESP_OK(i2c_driver_delete(i2c_num));
}

View file

@ -48,6 +48,19 @@ typedef enum {
I2C_INTR_EVENT_TXFIFO_EMPTY, /*!< I2C txfifo empty event */
} i2c_intr_event_t;
/**
* @brief Data structure for calculating I2C bus timing.
*/
typedef struct {
uint16_t scl_low; /*!< I2C scl low period */
uint16_t scl_high; /*!< I2C scl hight period */
uint16_t sda_hold; /*!< I2C scl low period */
uint16_t sda_sample; /*!< I2C sda sample time */
uint16_t setup; /*!< I2C start and stop condition setup period */
uint16_t hold; /*!< I2C start and stop condition hold period */
uint16_t tout; /*!< I2C bus timeout period */
} i2c_clk_cal_t;
// Get the I2C hardware instance
#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == 0) ? &I2C0 : &I2C1)
// Get the I2C hardware FIFO address
@ -63,6 +76,53 @@ typedef enum {
//I2C base clock freq 80M
#define I2C_BASE_CLK_FREQ (80000000)
/**
* @brief Calculate I2C bus frequency
*
* @param source_clk I2C source clock
* @param bus_freq I2C bus frequency
* @param clk_cal Pointer to accept the clock configuration
*
* @return None
*/
static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2c_clk_cal_t *clk_cal)
{
uint32_t half_cycle = source_clk / bus_freq / 2;
clk_cal->scl_low = half_cycle;
clk_cal->scl_high = half_cycle;
clk_cal->sda_hold = half_cycle / 2;
clk_cal->sda_sample = clk_cal->scl_high / 2;
clk_cal->setup = half_cycle;
clk_cal->hold = half_cycle;
clk_cal->tout = half_cycle * 20; //default we set the timeout value to 10 bus cycles.
}
/**
* @brief Configure the I2C bus timing related register.
*
* @param hw Beginning address of the peripheral registers
* @param bus_cfg Pointer to the data structure holding the register configuration.
*
* @return None
*/
static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg)
{
//scl period
hw->scl_low_period.period = bus_cfg->scl_low;
hw->scl_high_period.period = bus_cfg->scl_high;
//sda sample
hw->sda_hold.time = bus_cfg->sda_hold;
hw->sda_sample.time = bus_cfg->sda_sample;
//setup
hw->scl_rstart_setup.time = bus_cfg->setup;
hw->scl_stop_setup.time = bus_cfg->setup;
//hold
hw->scl_start_hold.time = bus_cfg->hold;
hw->scl_stop_hold.time = bus_cfg->hold;
hw->timeout.tout = bus_cfg->tout;
}
/**
* @brief Reset I2C txFIFO
*
@ -178,7 +238,7 @@ static inline void i2c_ll_set_fifo_mode(i2c_dev_t *hw, bool fifo_mode_en)
*/
static inline void i2c_ll_set_tout(i2c_dev_t *hw, int tout)
{
hw->timeout.tout = tout;
hw->timeout.tout = tout;
}
/**

View file

@ -48,6 +48,20 @@ typedef enum {
I2C_INTR_EVENT_TXFIFO_EMPTY, /*!< I2C txfifo empty event */
} i2c_intr_event_t;
/**
* @brief Data structure for calculating I2C bus timing.
*/
typedef struct {
uint16_t scl_low; /*!< I2C scl low period */
uint16_t scl_high; /*!< I2C scl hight period */
uint16_t scl_wait_high; /*!< I2C scl wait_high period */
uint16_t sda_hold; /*!< I2C scl low period */
uint16_t sda_sample; /*!< I2C sda sample time */
uint16_t setup; /*!< I2C start and stop condition setup period */
uint16_t hold; /*!< I2C start and stop condition hold period */
uint16_t tout; /*!< I2C bus timeout period */
} i2c_clk_cal_t;
// Get the I2C hardware instance
#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == 0) ? &I2C0 : &I2C1)
// Get the I2C hardware FIFO address
@ -62,6 +76,58 @@ typedef enum {
#define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M)
/**
* @brief Calculate I2C bus frequency
*
* @param source_clk I2C source clock
* @param bus_freq I2C bus frequency
* @param clk_cal Pointer to accept the clock configuration
*
* @return None
*/
static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2c_clk_cal_t *clk_cal)
{
uint32_t half_cycle = source_clk / bus_freq / 2;
//SCL
clk_cal->scl_low = half_cycle;
// default, scl_wait_high < scl_high
clk_cal->scl_high = half_cycle / 2 + 2;
clk_cal->scl_wait_high = half_cycle - clk_cal->scl_high;
clk_cal->sda_hold = half_cycle / 2;
// scl_wait_high < sda_sample <= scl_high
clk_cal->sda_sample = half_cycle / 2 - 1;
clk_cal->setup = half_cycle;
clk_cal->hold = half_cycle;
//default we set the timeout value to 10 bus cycles
clk_cal->tout = half_cycle * 20;
}
/**
* @brief Configure the I2C bus timing related register.
*
* @param hw Beginning address of the peripheral registers
* @param bus_cfg Pointer to the data structure holding the register configuration.
*
* @return None
*/
static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg)
{
//scl period
hw->scl_low_period.period = bus_cfg->scl_low - 1;
hw->scl_high_period.period = bus_cfg->scl_high;
hw->scl_high_period.scl_wait_high_period = bus_cfg->scl_wait_high;
//sda sample
hw->sda_hold.time = bus_cfg->sda_hold;
hw->sda_sample.time = bus_cfg->sda_sample;
//setup
hw->scl_rstart_setup.time = bus_cfg->setup;
hw->scl_stop_setup.time = bus_cfg->setup;
//hold
hw->scl_start_hold.time = bus_cfg->hold - 1;
hw->scl_stop_hold.time = bus_cfg->hold;
hw->timeout.tout = bus_cfg->tout;
}
/**
* @brief Reset I2C txFIFO
*
@ -92,16 +158,16 @@ static inline void i2c_ll_rxfifo_rst(i2c_dev_t *hw)
* @brief Configure I2C SCL timing
*
* @param hw Beginning address of the peripheral registers
* @param hight_period The I2C SCL hight period (in APB cycle)
* @param low_period The I2C SCL low period (in APB cycle)
* @param hight_period The I2C SCL hight period (in APB cycle, hight_period > 2)
* @param low_period The I2C SCL low period (in APB cycle, low_period > 1)
*
* @return None.
*/
static inline void i2c_ll_set_scl_timing(i2c_dev_t *hw, int hight_period, int low_period)
{
hw->scl_low_period.period = low_period;
hw->scl_high_period.period = hight_period;
hw->scl_high_period.scl_wait_high_period = 0;
hw->scl_low_period.period = low_period-1;
hw->scl_high_period.period = hight_period/2+2;
hw->scl_high_period.scl_wait_high_period = hight_period - hw->scl_high_period.period;
}
/**
@ -222,7 +288,7 @@ static inline void i2c_ll_write_cmd_reg(i2c_dev_t *hw, i2c_hw_cmd_t cmd, int cmd
static inline void i2c_ll_set_start_timing(i2c_dev_t *hw, int start_setup, int start_hold)
{
hw->scl_rstart_setup.time = start_setup;
hw->scl_start_hold.time = start_hold;
hw->scl_start_hold.time = start_hold-1;
}
/**
@ -422,7 +488,7 @@ static inline void i2c_ll_trans_start(i2c_dev_t *hw)
static inline void i2c_ll_get_start_timing(i2c_dev_t *hw, int *setup_time, int *hold_time)
{
*setup_time = hw->scl_rstart_setup.time;
*hold_time = hw->scl_start_hold.time;
*hold_time = hw->scl_start_hold.time+1;
}
/**
@ -451,8 +517,8 @@ static inline void i2c_ll_get_stop_timing(i2c_dev_t *hw, int *setup_time, int *h
*/
static inline void i2c_ll_get_scl_timing(i2c_dev_t *hw, int *high_period, int *low_period)
{
*high_period = hw->scl_high_period.period;
*low_period = hw->scl_low_period.period;
*high_period = hw->scl_high_period.period + hw->scl_high_period.scl_wait_high_period;
*low_period = hw->scl_low_period.period + 1;
}
/**
@ -797,4 +863,4 @@ static inline void i2c_ll_slave_init(i2c_dev_t *hw)
ctrl_reg.ref_always_on = 1;
hw->ctr.val = ctrl_reg.val;
hw->fifo_conf.fifo_addr_cfg_en = 0;
}
}

View file

@ -111,7 +111,7 @@ typedef struct {
#define i2c_hal_slave_clr_rx_it(hal) i2c_ll_slave_clr_rx_it((hal)->dev)
/**
* @brief Get the I2C hardware instance and init the I2C master. Note that this function should be called before other hal layer function is called.
* @brief Init the I2C master.
*
* @param hal Context of the HAL layer
* @param i2c_num I2C port number
@ -121,7 +121,7 @@ typedef struct {
void i2c_hal_master_init(i2c_hal_context_t *hal, i2c_port_t i2c_num);
/**
* @brief Get the I2C hardware instance and init the I2C slave. Note that this function should be called before other hal layer function is called.
* @brief Init the I2C slave.
*
* @param hal Context of the HAL layer
* @param i2c_num I2C port number

View file

@ -177,21 +177,13 @@ void i2c_hal_disable_slave_rx_it(i2c_hal_context_t *hal)
void i2c_hal_set_bus_timing(i2c_hal_context_t *hal, uint32_t scl_freq, i2c_sclk_t src_clk)
{
uint32_t sclk = (src_clk == I2C_SCLK_REF_TICK) ? 1000000 : 80000000;
uint32_t cycle = sclk / scl_freq;
i2c_ll_set_source_clk(hal->dev, src_clk);
// Set SDA timing
i2c_ll_set_sda_timing(hal->dev, cycle/4, cycle/4);
// Set start timing
i2c_ll_set_start_timing(hal->dev, cycle/2, cycle/2);
i2c_ll_set_scl_timing(hal->dev, cycle/2, cycle/2);
i2c_ll_set_stop_timing(hal->dev, cycle/2, cycle/2);
//Set time out value
i2c_ll_set_tout(hal->dev, cycle * 9);
i2c_clk_cal_t clk_cal = {0};
i2c_ll_cal_bus_clk(sclk, scl_freq, &clk_cal);
i2c_ll_set_bus_timing(hal->dev, &clk_cal);
}
void i2c_hal_slave_init(i2c_hal_context_t *hal, int i2c_num)
{
hal->dev = I2C_LL_GET_HW(i2c_num);
i2c_ll_slave_init(hal->dev);
//Use fifo mode
i2c_ll_set_fifo_mode(hal->dev, true);
@ -214,7 +206,6 @@ void i2c_hal_master_fsm_rst(i2c_hal_context_t *hal)
void i2c_hal_master_init(i2c_hal_context_t *hal, int i2c_num)
{
hal->dev = I2C_LL_GET_HW(i2c_num);
hal->version = i2c_ll_get_hw_version(hal->dev);
i2c_ll_master_init(hal->dev);
//Use fifo mode

View file

@ -151,8 +151,8 @@ static esp_err_t i2c_master_init(void)
conf.scl_io_num = I2C_MASTER_SCL_IO;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
return i2c_param_config(i2c_master_port, &conf);
i2c_param_config(i2c_master_port, &conf);
return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}
/**
@ -169,8 +169,8 @@ static esp_err_t i2c_slave_init(void)
conf_slave.mode = I2C_MODE_SLAVE;
conf_slave.slave.addr_10bit_en = 0;
conf_slave.slave.slave_addr = ESP_SLAVE_ADDR;
i2c_driver_install(i2c_slave_port, conf_slave.mode, I2C_SLAVE_RX_BUF_LEN, I2C_SLAVE_TX_BUF_LEN, 0);
return i2c_param_config(i2c_slave_port, &conf_slave);
i2c_param_config(i2c_slave_port, &conf_slave);
return i2c_driver_install(i2c_slave_port, conf_slave.mode, I2C_SLAVE_RX_BUF_LEN, I2C_SLAVE_TX_BUF_LEN, 0);
}
/**