diff --git a/components/driver/i2c.c b/components/driver/i2c.c index 264eefa1c..80466ff6c 100644 --- a/components/driver/i2c.c +++ b/components/driver/i2c.c @@ -1,4 +1,4 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,13 +23,13 @@ #include "freertos/xtensa_api.h" #include "freertos/task.h" #include "freertos/ringbuf.h" -#include "soc/i2c_periph.h" -#include "soc/soc_memory_layout.h" -#include "driver/i2c.h" -#include "driver/gpio.h" -#include "driver/periph_ctrl.h" +#include "soc/dport_reg.h" #include "esp_pm.h" -#include "sdkconfig.h" +#include "soc/soc_memory_layout.h" +#include "hal/i2c_hal.h" +#include "soc/i2c_periph.h" +#include "driver/i2c.h" +#include "driver/periph_ctrl.h" static const char* I2C_TAG = "i2c"; #define I2C_CHECK(a, str, ret) if(!(a)) { \ @@ -39,7 +39,6 @@ static const char* I2C_TAG = "i2c"; 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 */ -static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 }; #define I2C_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux) #define I2C_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux) @@ -86,18 +85,12 @@ static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 }; #define I2C_CLR_BUS_HALF_PERIOD_US (5) typedef struct { - uint8_t byte_num; /*!< cmd byte number */ - uint8_t ack_en; /*!< ack check enable */ - uint8_t ack_exp; /*!< expected ack level to get */ - uint8_t ack_val; /*!< ack value to send */ + i2c_hw_cmd_t hw_cmd; uint8_t* data; /*!< data address */ uint8_t byte_cmd; /*!< to save cmd for one byte command mode */ - i2c_opmode_t op_code; /*!< hardware cmd type */ } i2c_cmd_t; -typedef typeof(I2C[0]->command[0]) i2c_hw_cmd_t; - -typedef struct i2c_cmd_link{ +typedef struct i2c_cmd_link { i2c_cmd_t cmd; /*!< command in current cmd link */ struct i2c_cmd_link *next; /*!< next cmd link */ } i2c_cmd_link_t; @@ -122,13 +115,14 @@ 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*/ int cmd_idx; /*!< record current command index, for master mode */ int status; /*!< record current command status, for master mode */ int rx_cnt; /*!< record current read index, for master mode */ - uint8_t data_buf[I2C_FIFO_LEN]; /*!< a buffer to store i2c fifo data */ + uint8_t data_buf[SOC_I2C_FIFO_LEN ]; /*!< a buffer to store i2c fifo data */ i2c_cmd_desc_t cmd_link; /*!< I2C command link */ QueueHandle_t cmd_evt_queue; /*!< I2C command event queue */ @@ -141,8 +135,6 @@ typedef struct { #ifdef CONFIG_PM_ENABLE esp_pm_lock_handle_t pm_lock; #endif - size_t tx_fifo_remain; /*!< tx fifo remain length, for master mode */ - size_t rx_fifo_remain; /*!< rx fifo remain length, for master mode */ xSemaphoreHandle slv_rx_mux; /*!< slave rx buffer mux */ xSemaphoreHandle slv_tx_mux; /*!< slave tx buffer mux */ @@ -150,6 +142,8 @@ 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; static i2c_obj_t *p_i2c_obj[I2C_NUM_MAX] = {0}; @@ -157,6 +151,16 @@ static void i2c_isr_handler_default(void* arg); static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num); 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); +} + +static void i2c_hw_enable(i2c_port_t i2c_num) +{ + periph_module_enable(i2c_periph_signal[i2c_num].module); +} + /* For i2c master mode, we don't need to use a buffer for the data, the APIs will execute the master commands and return after all of the commands have been sent out or when error occurs. So when we send master commands, @@ -170,9 +174,12 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_ I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); I2C_CHECK(mode == I2C_MODE_MASTER || ( slv_rx_buf_len > 100 || slv_tx_buf_len > 100 ), I2C_SLAVE_BUFFER_LEN_ERR_STR, ESP_ERR_INVALID_ARG); - uint32_t intr_mask = 0; 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 @@ -196,8 +203,6 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_ #if CONFIG_SPIRAM_USE_MALLOC p_i2c->intr_alloc_flags = intr_alloc_flags; #endif - p_i2c->rx_fifo_remain = I2C_FIFO_LEN; - p_i2c->tx_fifo_remain = I2C_FIFO_LEN; if (mode == I2C_MODE_SLAVE) { //we only use ringbuffer for slave mode. @@ -229,7 +234,7 @@ 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; } - intr_mask |= ( I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M); + 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(); @@ -267,21 +272,16 @@ 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; - intr_mask |= I2C_ARBITRATION_LOST_INT_ENA_M | I2C_TIME_OUT_INT_ST_M; + i2c_hal_master_init(&(p_i2c->i2c_hal), i2c_num); } } else { ESP_LOGE(I2C_TAG, I2C_DRIVER_ERR_STR); return ESP_FAIL; } + //Disable I2C interrupt. + i2c_hal_disable_intr_mask(&(p_i2c_obj[i2c_num]->i2c_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); - intr_mask |= ( I2C_TRANS_COMPLETE_INT_ENA_M | - I2C_TRANS_START_INT_ENA_M | - I2C_ACK_ERR_INT_ENA_M | - I2C_RXFIFO_OVF_INT_ENA_M | - I2C_SLAVE_TRAN_COMP_INT_ENA_M); - I2C[i2c_num]->int_clr.val = intr_mask; - I2C[i2c_num]->int_ena.val = intr_mask; return ESP_OK; err: @@ -328,34 +328,13 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_ return ESP_FAIL; } -static esp_err_t i2c_hw_enable(i2c_port_t i2c_num) -{ - if (i2c_num == I2C_NUM_0) { - periph_module_enable(PERIPH_I2C0_MODULE); - } else if (i2c_num == I2C_NUM_1) { - periph_module_enable(PERIPH_I2C1_MODULE); - } - return ESP_OK; -} - -static esp_err_t i2c_hw_disable(i2c_port_t i2c_num) -{ - if (i2c_num == I2C_NUM_0) { - periph_module_disable(PERIPH_I2C0_MODULE); - } else if (i2c_num == I2C_NUM_1) { - periph_module_disable(PERIPH_I2C1_MODULE); - } - return ESP_OK; -} - esp_err_t i2c_driver_delete(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_obj_t* p_i2c = p_i2c_obj[i2c_num]; - - I2C[i2c_num]->int_ena.val = 0; + i2c_hal_disable_intr_mask(&(p_i2c->i2c_hal), I2C_INTR_MASK); esp_intr_free(p_i2c->intr_handle); p_i2c->intr_handle = NULL; @@ -407,9 +386,9 @@ 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[i2c_num]->fifo_conf.tx_fifo_rst = 1; - I2C[i2c_num]->fifo_conf.tx_fifo_rst = 0; + i2c_hal_txfifo_rst(&(p_i2c_obj[i2c_num]->i2c_hal)); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); return ESP_OK; } @@ -417,113 +396,69 @@ esp_err_t i2c_reset_tx_fifo(i2c_port_t i2c_num) 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[i2c_num]->fifo_conf.rx_fifo_rst = 1; - I2C[i2c_num]->fifo_conf.rx_fifo_rst = 0; + i2c_hal_rxfifo_rst(&(p_i2c_obj[i2c_num]->i2c_hal)); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); return ESP_OK; } -static void IRAM_ATTR i2c_isr_handler_default(void* arg) +static void IRAM_ATTR i2c_isr_handler_default(void *arg) { i2c_obj_t* p_i2c = (i2c_obj_t*) arg; int i2c_num = p_i2c->i2c_num; - uint32_t status = I2C[i2c_num]->int_status.val; - int idx = 0; - + i2c_intr_event_t evt_type = I2C_INTR_EVENT_ERR; portBASE_TYPE HPTaskAwoken = pdFALSE; - while (status != 0) { - status = I2C[i2c_num]->int_status.val; - if (status & I2C_TX_SEND_EMPTY_INT_ST_M) { - I2C[i2c_num]->int_clr.tx_send_empty = 1; - } else if (status & I2C_RX_REC_FULL_INT_ST_M) { - I2C[i2c_num]->int_clr.rx_rec_full = 1; - } else if (status & I2C_ACK_ERR_INT_ST_M) { - I2C[i2c_num]->int_ena.ack_err = 0; - I2C[i2c_num]->int_clr.ack_err = 1; - if (p_i2c->mode == I2C_MODE_MASTER) { - p_i2c_obj[i2c_num]->status = I2C_STATUS_ACK_ERROR; - I2C[i2c_num]->int_clr.ack_err = 1; - //get error ack value from slave device, stop the commands + 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); + } else if (p_i2c->status == I2C_STATUS_READ) { + i2c_hal_master_handle_rx_event(&(p_i2c->i2c_hal), &evt_type); + } + if (evt_type == I2C_INTR_EVENT_NACK) { + p_i2c_obj[i2c_num]->status = I2C_STATUS_ACK_ERROR; + i2c_master_cmd_begin_static(i2c_num); + } else if(evt_type == I2C_INTR_EVENT_TOUT) { + p_i2c_obj[i2c_num]->status = I2C_STATUS_TIMEOUT; + i2c_master_cmd_begin_static(i2c_num); + } else if (evt_type == I2C_INTR_EVENT_ARBIT_LOST) { + p_i2c_obj[i2c_num]->status = I2C_STATUS_TIMEOUT; + i2c_master_cmd_begin_static(i2c_num); + } else if (evt_type == I2C_INTR_EVENT_END_DET) { + i2c_master_cmd_begin_static(i2c_num); + } else if (evt_type == I2C_INTR_EVENT_TRANS_DONE) { + if (p_i2c->status != I2C_STATUS_ACK_ERROR && p_i2c->status != I2C_STATUS_IDLE) { i2c_master_cmd_begin_static(i2c_num); } - } else if (status & I2C_TRANS_START_INT_ST_M) { - I2C[i2c_num]->int_clr.trans_start = 1; - } else if (status & I2C_TIME_OUT_INT_ST_M) { - I2C[i2c_num]->int_ena.time_out = 0; - I2C[i2c_num]->int_clr.time_out = 1; - p_i2c_obj[i2c_num]->status = I2C_STATUS_TIMEOUT; - i2c_master_cmd_begin_static(i2c_num); - } else if (status & I2C_TRANS_COMPLETE_INT_ST_M) { - I2C[i2c_num]->int_clr.trans_complete = 1; - if (p_i2c->mode == I2C_MODE_SLAVE) { - int rx_fifo_cnt = I2C[i2c_num]->status_reg.rx_fifo_cnt; - for (idx = 0; idx < rx_fifo_cnt; idx++) { - #if CONFIG_IDF_TARGET_ESP32 - p_i2c->data_buf[idx] = I2C[i2c_num]->fifo_data.data; - #elif CONFIG_IDF_TARGET_ESP32S2BETA - p_i2c->data_buf[idx] = READ_PERI_REG(I2C_DATA_APB_REG(i2c_num)); - #endif - } - xRingbufferSendFromISR(p_i2c->rx_ring_buf, p_i2c->data_buf, rx_fifo_cnt, &HPTaskAwoken); - I2C[i2c_num]->int_clr.rx_fifo_full = 1; - } else { - // add check for unexcepted situations caused by noise. - if (p_i2c->status != I2C_STATUS_ACK_ERROR && p_i2c->status != I2C_STATUS_IDLE) { - i2c_master_cmd_begin_static(i2c_num); - } - } - } else if (status & I2C_MASTER_TRAN_COMP_INT_ST_M) { - I2C[i2c_num]->int_clr.master_tran_comp = 1; - } else if (status & I2C_ARBITRATION_LOST_INT_ST_M) { - I2C[i2c_num]->int_clr.arbitration_lost = 1; - p_i2c_obj[i2c_num]->status = I2C_STATUS_TIMEOUT; - i2c_master_cmd_begin_static(i2c_num); - } else if (status & I2C_SLAVE_TRAN_COMP_INT_ST_M) { - I2C[i2c_num]->int_clr.slave_tran_comp = 1; - } else if (status & I2C_END_DETECT_INT_ST_M) { - I2C[i2c_num]->int_ena.end_detect = 0; - I2C[i2c_num]->int_clr.end_detect = 1; - i2c_master_cmd_begin_static(i2c_num); - } else if (status & I2C_RXFIFO_OVF_INT_ST_M) { - I2C[i2c_num]->int_clr.rx_fifo_ovf = 1; - } else if (status & I2C_TXFIFO_EMPTY_INT_ST_M) { - int tx_fifo_rem = I2C_FIFO_LEN - I2C[i2c_num]->status_reg.tx_fifo_cnt; + } + i2c_cmd_evt_t evt = { + .type = I2C_CMD_EVT_ALIVE + }; + xQueueSendFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken); + } else { + i2c_hal_slave_handle_event(&(p_i2c->i2c_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); + xRingbufferSendFromISR(p_i2c->rx_ring_buf, p_i2c->data_buf, rx_fifo_cnt, &HPTaskAwoken); + i2c_hal_slave_clr_rx_it(&(p_i2c->i2c_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); size_t size = 0; uint8_t *data = (uint8_t*) xRingbufferReceiveUpToFromISR(p_i2c->tx_ring_buf, &size, tx_fifo_rem); if (data) { - for (idx = 0; idx < size; idx++) { - WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), data[idx]); - } + i2c_hal_write_txfifo(&(p_i2c->i2c_hal), data, size); vRingbufferReturnItemFromISR(p_i2c->tx_ring_buf, data, &HPTaskAwoken); - I2C[i2c_num]->int_ena.tx_fifo_empty = 1; - I2C[i2c_num]->int_clr.tx_fifo_empty = 1; } else { - I2C[i2c_num]->int_ena.tx_fifo_empty = 0; - I2C[i2c_num]->int_clr.tx_fifo_empty = 1; + i2c_hal_disable_slave_tx_it(&(p_i2c->i2c_hal)); } - } else if (status & I2C_RXFIFO_FULL_INT_ST_M) { - int rx_fifo_cnt = I2C[i2c_num]->status_reg.rx_fifo_cnt; - for (idx = 0; idx < rx_fifo_cnt; idx++) { - #if CONFIG_IDF_TARGET_ESP32 - p_i2c->data_buf[idx] = I2C[i2c_num]->fifo_data.data; - #elif CONFIG_IDF_TARGET_ESP32S2BETA - p_i2c->data_buf[idx] = READ_PERI_REG(I2C_DATA_APB_REG(i2c_num)); - #endif - } - xRingbufferSendFromISR(p_i2c->rx_ring_buf, p_i2c->data_buf, rx_fifo_cnt, &HPTaskAwoken); - I2C[i2c_num]->int_clr.rx_fifo_full = 1; - } else { - I2C[i2c_num]->int_clr.val = status; + i2c_hal_slave_clr_tx_it(&(p_i2c->i2c_hal)); } } - if (p_i2c->mode == I2C_MODE_MASTER) { - i2c_cmd_evt_t evt; - evt.type = I2C_CMD_EVT_ALIVE; - xQueueSendFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken); - } //We only need to check here if there is a high-priority task needs to be switched. - if(HPTaskAwoken == pdTRUE) { + if (HPTaskAwoken == pdTRUE) { portYIELD_FROM_ISR(); } } @@ -531,11 +466,11 @@ 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[i2c_num]->ctr.rx_lsb_first = rx_trans_mode; //set rx data msb first - I2C[i2c_num]->ctr.tx_lsb_first = tx_trans_mode; //set tx data msb first + 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]); return ESP_OK; } @@ -543,12 +478,8 @@ 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) { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - if (tx_trans_mode) { - *tx_trans_mode = I2C[i2c_num]->ctr.tx_lsb_first; - } - if (rx_trans_mode) { - *rx_trans_mode = I2C[i2c_num]->ctr.rx_lsb_first; - } + 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); return ESP_OK; } @@ -559,22 +490,11 @@ esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode, **/ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num) { - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); -#if CONFIG_IDF_TARGET_ESP32 +#if !I2C_SUPPORT_HW_CLR_BUS const int scl_half_period = I2C_CLR_BUS_HALF_PERIOD_US; // use standard 100kHz data rate - int sda_in_sig = 0, scl_in_sig = 0; int i = 0; - if (i2c_num == I2C_NUM_0) { - sda_in_sig = I2CEXT0_SDA_IN_IDX; - scl_in_sig = I2CEXT0_SCL_IN_IDX; - } else if (i2c_num == I2C_NUM_1) { - sda_in_sig = I2CEXT1_SDA_IN_IDX; - scl_in_sig = I2CEXT1_SCL_IN_IDX; - } - int scl_io = GPIO.func_in_sel_cfg[scl_in_sig].func_sel; - int sda_io = GPIO.func_in_sel_cfg[sda_in_sig].func_sel; - I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(scl_io)), I2C_SCL_IO_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(sda_io)), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG); + int scl_io = p_i2c_obj[i2c_num]->scl_io_num; + int sda_io = p_i2c_obj[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. @@ -585,7 +505,7 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num) gpio_set_level(scl_io, 0); gpio_set_level(sda_io, 1); ets_delay_us(scl_half_period); - while(!gpio_get_level(sda_io) && (i++ < I2C_CLR_BUS_SCL_NUM)) { + while (!gpio_get_level(sda_io) && (i++ < I2C_CLR_BUS_SCL_NUM)) { gpio_set_level(scl_io, 1); ets_delay_us(scl_half_period); gpio_set_level(scl_io, 0); @@ -596,9 +516,8 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num) ets_delay_us(scl_half_period); 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); -#elif CONFIG_IDF_TARGET_ESP32S2BETA - I2C[i2c_num]->scl_sp_conf.scl_rst_slv_num = 9; - I2C[i2c_num]->scl_sp_conf.scl_rst_slv_en = 1; +#else + i2c_hal_master_clr_bus(&(p_i2c_obj[i2c_num]->i2c_hal)); #endif return ESP_OK; } @@ -609,71 +528,46 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num) **/ static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num) { - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); -#if CONFIG_IDF_TARGET_ESP32 - uint32_t ctr = I2C[i2c_num]->ctr.val; - uint32_t fifo_conf = I2C[i2c_num]->fifo_conf.val; - uint32_t scl_low_period = I2C[i2c_num]->scl_low_period.val; - uint32_t scl_high_period = I2C[i2c_num]->scl_high_period.val; - uint32_t scl_start_hold = I2C[i2c_num]->scl_start_hold.val; - uint32_t scl_rstart_setup = I2C[i2c_num]->scl_rstart_setup.val; - uint32_t scl_stop_hold = I2C[i2c_num]->scl_stop_hold.val; - uint32_t scl_stop_setup = I2C[i2c_num]->scl_stop_setup.val; - uint32_t sda_hold = I2C[i2c_num]->sda_hold.val; - uint32_t sda_sample = I2C[i2c_num]->sda_sample.val; - uint32_t timeout = I2C[i2c_num]->timeout.val; - uint32_t scl_filter_cfg = I2C[i2c_num]->scl_filter_cfg.val; - uint32_t sda_filter_cfg = I2C[i2c_num]->sda_filter_cfg.val; - uint32_t slave_addr = I2C[i2c_num]->slave_addr.val; +#if !I2C_SUPPORT_HW_FSM_RST + int scl_low_period, scl_high_period; + int scl_start_hold, scl_rstart_setup; + int scl_stop_hold, scl_stop_setup; + int sda_hold, sda_sample; + 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); //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[i2c_num]->ctr.val = ctr & (~I2C_TRANS_START_M); - I2C[i2c_num]->fifo_conf.val = fifo_conf; - I2C[i2c_num]->scl_low_period.val = scl_low_period; - I2C[i2c_num]->scl_high_period.val = scl_high_period; - I2C[i2c_num]->scl_start_hold.val = scl_start_hold; - I2C[i2c_num]->scl_rstart_setup.val = scl_rstart_setup; - I2C[i2c_num]->scl_stop_hold.val = scl_stop_hold; - I2C[i2c_num]->scl_stop_setup.val = scl_stop_setup; - I2C[i2c_num]->sda_hold.val = sda_hold; - I2C[i2c_num]->sda_sample.val = sda_sample; - I2C[i2c_num]->timeout.val = timeout; - I2C[i2c_num]->scl_filter_cfg.val = scl_filter_cfg; - I2C[i2c_num]->sda_filter_cfg.val = sda_filter_cfg; - I2C[i2c_num]->slave_addr.val = slave_addr; -#elif CONFIG_IDF_TARGET_ESP32S2BETA + 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); +#else + i2c_hal_master_fsm_rst(&(p_i2c_obj[i2c_num]->i2c_hal)); i2c_master_clear_bus(i2c_num); - - I2C[i2c_num]->ctr.fsm_rst = 1; - I2C[i2c_num]->ctr.fsm_rst = 0; - I2C[i2c_num]->fifo_conf.rx_fifo_rst = 1; - I2C[i2c_num]->fifo_conf.rx_fifo_rst = 0; - I2C[i2c_num]->fifo_conf.tx_fifo_rst = 1; - I2C[i2c_num]->fifo_conf.tx_fifo_rst = 0; #endif - - I2C[i2c_num]->int_ena.val = 0; - uint32_t intr_mask = I2C_TRANS_COMPLETE_INT_ENA_M - | I2C_TRANS_START_INT_ENA_M - | I2C_ACK_ERR_INT_ENA_M - | I2C_RXFIFO_OVF_INT_ENA_M - | I2C_SLAVE_TRAN_COMP_INT_ENA_M - | I2C_TIME_OUT_INT_ENA_M - | I2C_RXFIFO_FULL_INT_ENA_M - | I2C_ARBITRATION_LOST_INT_ENA_M; - - I2C[i2c_num]->int_clr.val = intr_mask; - I2C[i2c_num]->int_ena.val = intr_mask; return ESP_OK; } 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); @@ -682,68 +576,24 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf) if (ret != ESP_OK) { return ret; } - - // Reset the I2C hardware in case there is a soft reboot. - i2c_hw_disable(i2c_num); - i2c_hw_enable(i2c_num); + p_i2c_obj[i2c_num]->mode = i2c_conf->mode; I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->ctr.rx_lsb_first = I2C_DATA_MODE_MSB_FIRST; //set rx data msb first - I2C[i2c_num]->ctr.tx_lsb_first = I2C_DATA_MODE_MSB_FIRST; //set tx data msb first - I2C[i2c_num]->ctr.ms_mode = i2c_conf->mode; //mode for master or slave - I2C[i2c_num]->ctr.sda_force_out = 1; // set open-drain output mode - I2C[i2c_num]->ctr.scl_force_out = 1; // set open-drain output mode - I2C[i2c_num]->ctr.sample_scl_level = 0; //sample at high level of clock - -#if CONFIG_IDF_TARGET_ESP32S2BETA - I2C[i2c_num]->ctr.ref_always_on = 1; - I2C[i2c_num]->sda_filter_cfg.val = 0; - I2C[i2c_num]->scl_filter_cfg.val = 0; -#endif - + 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); if (i2c_conf->mode == I2C_MODE_SLAVE) { //slave mode - I2C[i2c_num]->slave_addr.addr = i2c_conf->slave.slave_addr; - I2C[i2c_num]->slave_addr.en_10bit = i2c_conf->slave.addr_10bit_en; - I2C[i2c_num]->fifo_conf.nonfifo_en = 0; - I2C[i2c_num]->fifo_conf.fifo_addr_cfg_en = 0; - I2C[i2c_num]->fifo_conf.rx_fifo_full_thrhd = I2C_FIFO_FULL_THRESH_VAL; - I2C[i2c_num]->fifo_conf.tx_fifo_empty_thrhd = I2C_FIFO_EMPTY_THRESH_VAL; - I2C[i2c_num]->ctr.trans_start = 0; - I2C[i2c_num]->timeout.tout = I2C_SLAVE_TIMEOUT_DEFAULT; + 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); //set timing for data - I2C[i2c_num]->sda_hold.time = I2C_SLAVE_SDA_HOLD_DEFAULT; - I2C[i2c_num]->sda_sample.time = I2C_SLAVE_SDA_SAMPLE_DEFAULT; + 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)); } else { - I2C[i2c_num]->fifo_conf.nonfifo_en = 0; - int cycle = (I2C_APB_CLK_FREQ / i2c_conf->master.clk_speed); - int half_cycle = cycle / 2; - I2C[i2c_num]->timeout.tout = cycle * I2C_MASTER_TOUT_CNUM_DEFAULT; - //set timing for data - I2C[i2c_num]->sda_hold.time = half_cycle / 2; - -#if CONFIG_IDF_TARGET_ESP32 - I2C[i2c_num]->sda_sample.time = half_cycle / 2; - I2C[i2c_num]->scl_low_period.period = half_cycle; - I2C[i2c_num]->scl_high_period.period = half_cycle; -#elif CONFIG_IDF_TARGET_ESP32S2BETA - int low_period = half_cycle; - int wait_high = 0; - int high_period = cycle - low_period - wait_high; - I2C[i2c_num]->sda_sample.time = high_period / 2; - I2C[i2c_num]->scl_low_period.period = low_period; - I2C[i2c_num]->scl_high_period.period = high_period; - I2C[i2c_num]->scl_high_period.scl_wait_high_period = wait_high; -#endif - - //set timing for start signal - I2C[i2c_num]->scl_start_hold.time = half_cycle; - I2C[i2c_num]->scl_rstart_setup.time = half_cycle; - //set timing for stop signal - I2C[i2c_num]->scl_stop_hold.time = half_cycle; - I2C[i2c_num]->scl_stop_setup.time = half_cycle; //Default, we enable hardware filter - i2c_filter_enable(i2c_num, I2C_FILTER_CYC_NUM_DEF); + 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_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); return ESP_OK; } @@ -751,26 +601,22 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf) 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[i2c_num]->scl_high_period.period = high_period; - I2C[i2c_num]->scl_low_period.period = low_period; + i2c_hal_set_scl_timing(&(p_i2c_obj[i2c_num]->i2c_hal), high_period, low_period); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); 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, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); + 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]); - if (high_period) { - *high_period = I2C[i2c_num]->scl_high_period.period; - } - if (low_period) { - *low_period = I2C[i2c_num]->scl_low_period.period; - } + i2c_hal_get_scl_timing(&(p_i2c_obj[i2c_num]->i2c_hal), high_period, low_period); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); return ESP_OK; } @@ -778,11 +624,9 @@ esp_err_t i2c_get_period(i2c_port_t i2c_num, int* high_period, int* low_period) 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[i2c_num]->scl_filter_cfg.thres = cyc_num; - I2C[i2c_num]->sda_filter_cfg.thres = cyc_num; - I2C[i2c_num]->scl_filter_cfg.en = 1; - I2C[i2c_num]->sda_filter_cfg.en = 1; + i2c_hal_set_filter(&(p_i2c_obj[i2c_num]->i2c_hal), cyc_num); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); return ESP_OK; } @@ -790,9 +634,9 @@ esp_err_t i2c_filter_enable(i2c_port_t i2c_num, uint8_t cyc_num) 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[i2c_num]->scl_filter_cfg.en = 0; - I2C[i2c_num]->sda_filter_cfg.en = 0; + i2c_hal_set_filter(&(p_i2c_obj[i2c_num]->i2c_hal), 0); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); return ESP_OK; } @@ -800,26 +644,22 @@ esp_err_t i2c_filter_disable(i2c_port_t i2c_num) 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[i2c_num]->scl_start_hold.time = hold_time; - I2C[i2c_num]->scl_rstart_setup.time = setup_time; + i2c_hal_set_start_timing(&(p_i2c_obj[i2c_num]->i2c_hal), setup_time, hold_time); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); 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, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); + 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]); - if (hold_time) { - *hold_time = I2C[i2c_num]->scl_start_hold.time; - } - if (setup_time) { - *setup_time = I2C[i2c_num]->scl_rstart_setup.time; - } + i2c_hal_get_start_timing(&(p_i2c_obj[i2c_num]->i2c_hal), setup_time, hold_time); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); return ESP_OK; } @@ -827,26 +667,22 @@ esp_err_t i2c_get_start_timing(i2c_port_t i2c_num, int* setup_time, int* hold_ti 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[i2c_num]->scl_stop_hold.time = hold_time; - I2C[i2c_num]->scl_stop_setup.time = setup_time; + i2c_hal_set_stop_timing(&(p_i2c_obj[i2c_num]->i2c_hal), setup_time, hold_time); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); 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, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); + 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]); - if (setup_time) { - *setup_time = I2C[i2c_num]->scl_stop_setup.time; - } - if (hold_time) { - *hold_time = I2C[i2c_num]->scl_stop_hold.time; - } + i2c_hal_get_stop_timing(&(p_i2c_obj[i2c_num]->i2c_hal), setup_time, hold_time); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); return ESP_OK; } @@ -854,26 +690,22 @@ esp_err_t i2c_get_stop_timing(i2c_port_t i2c_num, int* setup_time, int* hold_tim 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[i2c_num]->sda_hold.time = hold_time; - I2C[i2c_num]->sda_sample.time = sample_time; + i2c_hal_set_sda_timing(&(p_i2c_obj[i2c_num]->i2c_hal), sample_time, hold_time); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); 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, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); + 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]); - if (sample_time) { - *sample_time = I2C[i2c_num]->sda_sample.time; - } - if (hold_time) { - *hold_time = I2C[i2c_num]->sda_hold.time; - } + i2c_hal_get_sda_timing(&(p_i2c_obj[i2c_num]->i2c_hal), sample_time, hold_time); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); return ESP_OK; } @@ -881,20 +713,20 @@ esp_err_t i2c_get_data_timing(i2c_port_t i2c_num, int* sample_time, int* hold_ti 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[i2c_num]->timeout.tout = timeout; + i2c_hal_set_tout(&(p_i2c_obj[i2c_num]->i2c_hal), timeout); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); return ESP_OK; } esp_err_t i2c_get_timeout(i2c_port_t i2c_num, int* timeout) { - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - if (timeout) { - *timeout = I2C[i2c_num]->timeout.tout; - } + 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); return ESP_OK; } @@ -902,16 +734,7 @@ esp_err_t i2c_isr_register(i2c_port_t i2c_num, void (*fn)(void*), void * arg, in { I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); I2C_CHECK(fn != NULL, I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); - esp_err_t ret; - switch (i2c_num) { - case I2C_NUM_1: - ret = esp_intr_alloc(ETS_I2C_EXT1_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); - break; - case I2C_NUM_0: - default: - ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); - break; - } + esp_err_t ret = esp_intr_alloc(i2c_periph_signal[i2c_num].irq, intr_alloc_flags, fn, arg, handle); return ret; } @@ -920,7 +743,7 @@ esp_err_t i2c_isr_free(intr_handle_t handle) return esp_intr_free(handle); } -esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, gpio_pullup_t sda_pullup_en, gpio_pullup_t scl_pullup_en, i2c_mode_t mode) +esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, bool sda_pullup_en, bool scl_pullup_en, i2c_mode_t mode) { I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); I2C_CHECK(((sda_io_num < 0) || ((GPIO_IS_VALID_OUTPUT_GPIO(sda_io_num)))), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG); @@ -937,21 +760,10 @@ esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, gpio_p scl_pullup_en == GPIO_PULLUP_DISABLE, I2C_GPIO_PULLUP_ERR_STR, ESP_ERR_INVALID_ARG); int sda_in_sig, sda_out_sig, scl_in_sig, scl_out_sig; - switch (i2c_num) { - case I2C_NUM_1: - sda_out_sig = I2CEXT1_SDA_OUT_IDX; - sda_in_sig = I2CEXT1_SDA_IN_IDX; - scl_out_sig = I2CEXT1_SCL_OUT_IDX; - scl_in_sig = I2CEXT1_SCL_IN_IDX; - break; - case I2C_NUM_0: - default: - sda_out_sig = I2CEXT0_SDA_OUT_IDX; - sda_in_sig = I2CEXT0_SDA_IN_IDX; - scl_out_sig = I2CEXT0_SCL_OUT_IDX; - scl_in_sig = I2CEXT0_SCL_IN_IDX; - break; - } + sda_out_sig = i2c_periph_signal[i2c_num].sda_out_sig; + sda_in_sig = i2c_periph_signal[i2c_num].sda_in_sig; + scl_out_sig = i2c_periph_signal[i2c_num].scl_out_sig; + scl_in_sig = i2c_periph_signal[i2c_num].scl_in_sig; if (sda_io_num >= 0) { gpio_set_level(sda_io_num, I2C_IO_INIT_LEVEL); PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[sda_io_num], PIN_FUNC_GPIO); @@ -982,6 +794,8 @@ esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, gpio_p } 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; return ESP_OK; } @@ -1052,12 +866,12 @@ esp_err_t i2c_master_start(i2c_cmd_handle_t cmd_handle) { I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG); i2c_cmd_t cmd; - cmd.ack_en = 0; - cmd.ack_exp = 0; - cmd.ack_val = 0; - cmd.byte_num = 0; + cmd.hw_cmd.ack_en = 0; + cmd.hw_cmd.ack_exp = 0; + cmd.hw_cmd.ack_val = 0; + cmd.hw_cmd.op_code = I2C_CMD_RESTART; + cmd.hw_cmd.byte_num = 0; cmd.data = NULL; - cmd.op_code = I2C_CMD_RESTART; return i2c_cmd_link_append(cmd_handle, &cmd); } @@ -1065,12 +879,12 @@ esp_err_t i2c_master_stop(i2c_cmd_handle_t cmd_handle) { I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG); i2c_cmd_t cmd; - cmd.ack_en = 0; - cmd.ack_exp = 0; - cmd.ack_val = 0; - cmd.byte_num = 0; + cmd.hw_cmd.ack_en = 0; + cmd.hw_cmd.ack_exp = 0; + cmd.hw_cmd.ack_val = 0; + cmd.hw_cmd.op_code = I2C_CMD_STOP; + cmd.hw_cmd.byte_num = 0; cmd.data = NULL; - cmd.op_code = I2C_CMD_STOP; return i2c_cmd_link_append(cmd_handle, &cmd); } @@ -1086,11 +900,11 @@ esp_err_t i2c_master_write(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t da len_tmp = data_len > 0xff ? 0xff : data_len; data_len -= len_tmp; i2c_cmd_t cmd; - cmd.ack_en = ack_en; - cmd.ack_exp = 0; - cmd.ack_val = 0; - cmd.byte_num = len_tmp; - cmd.op_code = I2C_CMD_WRITE; + cmd.hw_cmd.ack_en = ack_en; + cmd.hw_cmd.ack_exp = 0; + cmd.hw_cmd.ack_val = 0; + cmd.hw_cmd.op_code = I2C_CMD_WRITE; + cmd.hw_cmd.byte_num = len_tmp; cmd.data = data + data_offset; ret = i2c_cmd_link_append(cmd_handle, &cmd); data_offset += len_tmp; @@ -1105,11 +919,11 @@ esp_err_t i2c_master_write_byte(i2c_cmd_handle_t cmd_handle, uint8_t data, bool { I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG); i2c_cmd_t cmd; - cmd.ack_en = ack_en; - cmd.ack_exp = 0; - cmd.ack_val = 0; - cmd.byte_num = 1; - cmd.op_code = I2C_CMD_WRITE; + cmd.hw_cmd.ack_en = ack_en; + cmd.hw_cmd.ack_exp = 0; + cmd.hw_cmd.ack_val = 0; + cmd.hw_cmd.op_code = I2C_CMD_WRITE; + cmd.hw_cmd.byte_num = 1; cmd.data = NULL; cmd.byte_cmd = data; return i2c_cmd_link_append(cmd_handle, &cmd); @@ -1124,11 +938,11 @@ static esp_err_t i2c_master_read_static(i2c_cmd_handle_t cmd_handle, uint8_t* da len_tmp = data_len > 0xff ? 0xff : data_len; data_len -= len_tmp; i2c_cmd_t cmd; - cmd.ack_en = 0; - cmd.ack_exp = 0; - cmd.ack_val = ack & 0x1; - cmd.byte_num = len_tmp; - cmd.op_code = I2C_CMD_READ; + cmd.hw_cmd.ack_en = 0; + cmd.hw_cmd.ack_exp = 0; + cmd.hw_cmd.ack_val = ack & 0x1; + cmd.hw_cmd.byte_num = len_tmp; + cmd.hw_cmd.op_code = I2C_CMD_READ; cmd.data = data + data_offset; ret = i2c_cmd_link_append(cmd_handle, &cmd); data_offset += len_tmp; @@ -1146,11 +960,11 @@ esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t* data, i2c_a I2C_CHECK(ack < I2C_MASTER_ACK_MAX, I2C_ACK_TYPE_ERR_STR, ESP_ERR_INVALID_ARG); i2c_cmd_t cmd; - cmd.ack_en = 0; - cmd.ack_exp = 0; - cmd.ack_val = ((ack == I2C_MASTER_LAST_NACK) ? I2C_MASTER_NACK : (ack & 0x1)); - cmd.byte_num = 1; - cmd.op_code = I2C_CMD_READ; + cmd.hw_cmd.ack_en = 0; + cmd.hw_cmd.ack_exp = 0; + cmd.hw_cmd.ack_val = ((ack == I2C_MASTER_LAST_NACK) ? I2C_MASTER_NACK : (ack & 0x1)); + cmd.hw_cmd.byte_num = 1; + cmd.hw_cmd.op_code = I2C_CMD_READ; cmd.data = data; return i2c_cmd_link_append(cmd_handle, &cmd); } @@ -1162,14 +976,14 @@ esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t dat I2C_CHECK(ack < I2C_MASTER_ACK_MAX, I2C_ACK_TYPE_ERR_STR, ESP_ERR_INVALID_ARG); I2C_CHECK(data_len > 0, I2C_DATA_LEN_ERR_STR, ESP_ERR_INVALID_ARG); - if(ack != I2C_MASTER_LAST_NACK) { + if (ack != I2C_MASTER_LAST_NACK) { return i2c_master_read_static(cmd_handle, data, data_len, ack); } else { - if(data_len == 1) { + if (data_len == 1) { return i2c_master_read_byte(cmd_handle, data, I2C_MASTER_NACK); } else { esp_err_t ret; - if((ret = i2c_master_read_static(cmd_handle, data, data_len - 1, I2C_MASTER_ACK)) != ESP_OK) { + if ((ret = i2c_master_read_static(cmd_handle, data, data_len - 1, I2C_MASTER_ACK)) != ESP_OK) { return ret; } return i2c_master_read_byte(cmd_handle, data + data_len - 1, I2C_MASTER_NACK); @@ -1182,114 +996,84 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num) i2c_obj_t* p_i2c = p_i2c_obj[i2c_num]; portBASE_TYPE HPTaskAwoken = pdFALSE; i2c_cmd_evt_t evt; - //This should never happen - if (p_i2c->mode == I2C_MODE_SLAVE) { - return; - } - if (p_i2c->status == I2C_STATUS_DONE) { - return; - } else if ((p_i2c->status == I2C_STATUS_ACK_ERROR) - || (p_i2c->status == I2C_STATUS_TIMEOUT)) { - I2C[i2c_num]->int_ena.end_detect = 0; - I2C[i2c_num]->int_clr.end_detect = 1; - if(p_i2c->status == I2C_STATUS_TIMEOUT) { - I2C[i2c_num]->int_clr.time_out = 1; - I2C[i2c_num]->int_ena.val = 0; - } - evt.type = I2C_CMD_EVT_DONE; - xQueueOverwriteFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken); - if (HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } - return; - } else if (p_i2c->cmd_link.head != NULL && p_i2c->status == I2C_STATUS_READ) { + if (p_i2c->cmd_link.head != NULL && p_i2c->status == I2C_STATUS_READ) { i2c_cmd_t *cmd = &p_i2c->cmd_link.head->cmd; - while (p_i2c->rx_cnt-- > 0) { - *cmd->data++ = READ_PERI_REG(I2C_DATA_APB_REG(i2c_num)); - } - if (cmd->byte_num > 0) { - p_i2c->rx_fifo_remain = I2C_FIFO_LEN; + i2c_hal_read_rxfifo(&(p_i2c->i2c_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; } else { p_i2c->cmd_link.head = p_i2c->cmd_link.head->next; } - } + } else if ((p_i2c->status == I2C_STATUS_ACK_ERROR) + || (p_i2c->status == I2C_STATUS_TIMEOUT)) { + evt.type = I2C_CMD_EVT_DONE; + xQueueOverwriteFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken); + return; + } else if (p_i2c->status == I2C_STATUS_DONE) { + return; + } + if (p_i2c->cmd_link.head == NULL) { p_i2c->cmd_link.cur = NULL; evt.type = I2C_CMD_EVT_DONE; xQueueOverwriteFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken); - if (HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } // Return to the IDLE status after cmd_eve_done signal were send out. p_i2c->status = I2C_STATUS_IDLE; return; } + const i2c_hw_cmd_t hw_end_cmd = { + .op_code = I2C_CMD_END + }; while (p_i2c->cmd_link.head) { i2c_cmd_t *cmd = &p_i2c->cmd_link.head->cmd; - i2c_hw_cmd_t * const p_cur_hw_cmd = &I2C[i2c_num]->command[p_i2c->cmd_idx]; - i2c_hw_cmd_t hw_cmd = { - .ack_en = cmd->ack_en, - .ack_exp = cmd->ack_exp, - .ack_val = cmd->ack_val, - .byte_num = cmd->byte_num, - .op_code = cmd->op_code - }; - const i2c_hw_cmd_t hw_end_cmd = { - .op_code = I2C_CMD_END - }; - if (cmd->op_code == I2C_CMD_WRITE) { - uint32_t wr_filled = 0; + i2c_hw_cmd_t hw_cmd = cmd->hw_cmd; + if (cmd->hw_cmd.op_code == I2C_CMD_WRITE) { + uint8_t wr_filled = 0; + uint8_t *write_pr = NULL; //TODO: to reduce interrupt number if (cmd->data) { - while (p_i2c->tx_fifo_remain > 0 && cmd->byte_num > 0) { - WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), *cmd->data++); - p_i2c->tx_fifo_remain--; - cmd->byte_num--; - wr_filled++; - } + wr_filled = (cmd->hw_cmd.byte_num > SOC_I2C_FIFO_LEN) ? SOC_I2C_FIFO_LEN : cmd->hw_cmd.byte_num; + write_pr = cmd->data; + cmd->data += wr_filled; + cmd->hw_cmd.byte_num -= wr_filled; } else { - WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), cmd->byte_cmd); - p_i2c->tx_fifo_remain--; - cmd->byte_num--; - wr_filled ++; + wr_filled = 1; + write_pr = &(cmd->byte_cmd); + cmd->hw_cmd.byte_num--; } hw_cmd.byte_num = wr_filled; - *p_cur_hw_cmd = hw_cmd; - *(p_cur_hw_cmd + 1) = hw_end_cmd; - p_i2c->tx_fifo_remain = I2C_FIFO_LEN; + 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)); p_i2c->cmd_idx = 0; - if (cmd->byte_num > 0) { - } else { + if (cmd->hw_cmd.byte_num == 0) { p_i2c->cmd_link.head = p_i2c->cmd_link.head->next; } p_i2c->status = I2C_STATUS_WRITE; break; - } else if(cmd->op_code == I2C_CMD_READ) { + } else if (cmd->hw_cmd.op_code == I2C_CMD_READ) { //TODO: to reduce interrupt number - p_i2c->rx_cnt = cmd->byte_num > p_i2c->rx_fifo_remain ? p_i2c->rx_fifo_remain : cmd->byte_num; - cmd->byte_num -= p_i2c->rx_cnt; + 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; - hw_cmd.ack_val = cmd->ack_val; - *p_cur_hw_cmd = hw_cmd; - *(p_cur_hw_cmd + 1) = hw_end_cmd; + 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)); p_i2c->status = I2C_STATUS_READ; break; } else { - *p_cur_hw_cmd = hw_cmd; + i2c_hal_write_cmd_reg(&(p_i2c->i2c_hal), hw_cmd, p_i2c->cmd_idx); } p_i2c->cmd_idx++; p_i2c->cmd_link.head = p_i2c->cmd_link.head->next; if (p_i2c->cmd_link.head == NULL || p_i2c->cmd_idx >= 15) { - p_i2c->tx_fifo_remain = I2C_FIFO_LEN; p_i2c->cmd_idx = 0; break; } } - I2C[i2c_num]->int_clr.end_detect = 1; - I2C[i2c_num]->int_ena.end_detect = 1; - I2C[i2c_num]->ctr.trans_start = 0; - I2C[i2c_num]->ctr.trans_start = 1; + i2c_hal_trans_start(&(p_i2c->i2c_hal)); return; } @@ -1298,9 +1082,9 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num) static bool is_cmd_link_buffer_internal(i2c_cmd_link_t *link) { i2c_cmd_link_t* cmd_link = link; - while(cmd_link != NULL) { - if (cmd_link->cmd.op_code == I2C_CMD_WRITE || cmd_link->cmd.op_code == I2C_CMD_READ) { - if( cmd_link->cmd.data != NULL && !esp_ptr_internal(cmd_link->cmd.data)) { + while (cmd_link != NULL) { + if (cmd_link->cmd.hw_cmd.op_code == I2C_CMD_WRITE || cmd_link->cmd.hw_cmd.op_code == I2C_CMD_READ) { + if (cmd_link->cmd.data != NULL && !esp_ptr_internal(cmd_link->cmd.data)) { return false; } } @@ -1320,8 +1104,8 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, #if CONFIG_SPIRAM_USE_MALLOC //If the i2c read or write buffer is not in internal RAM, we will return ESP_FAIL //to avoid the ISR handler function crashing when the cache is disabled. - if( (p_i2c_obj[i2c_num]->intr_alloc_flags & ESP_INTR_FLAG_IRAM) ) { - if( !is_cmd_link_buffer_internal(((i2c_cmd_desc_t*)cmd_handle)->head) ) { + if ((p_i2c_obj[i2c_num]->intr_alloc_flags & ESP_INTR_FLAG_IRAM)) { + if (!is_cmd_link_buffer_internal(((i2c_cmd_desc_t*)cmd_handle)->head) ) { ESP_LOGE(I2C_TAG, I2C_PSRAM_BUFFER_WARN_STR); return ESP_ERR_INVALID_ARG; } @@ -1341,7 +1125,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[i2c_num]->status_reg.bus_busy == 1) { + || i2c_hal_is_bus_busy(&(p_i2c->i2c_hal))) { i2c_hw_fsm_reset(i2c_num); clear_bus_cnt = 0; } @@ -1354,14 +1138,12 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, p_i2c->status = I2C_STATUS_IDLE; p_i2c->cmd_idx = 0; p_i2c->rx_cnt = 0; - p_i2c->tx_fifo_remain = I2C_FIFO_LEN; - p_i2c->rx_fifo_remain = I2C_FIFO_LEN; i2c_reset_tx_fifo(i2c_num); 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[i2c_num]->int_ena.ack_err = 1; - I2C[i2c_num]->int_ena.time_out = 1; + 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); //start send commands, at most 32 bytes one time, isr handler will process the remaining commands. i2c_master_cmd_begin_static(i2c_num); @@ -1391,8 +1173,7 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, ret = ESP_ERR_TIMEOUT; } else if (p_i2c->status == I2C_STATUS_ACK_ERROR) { clear_bus_cnt++; - if(clear_bus_cnt >= I2C_ACKERR_CNT_MAX) { - i2c_master_clear_bus(i2c_num); + if (clear_bus_cnt >= I2C_ACKERR_CNT_MAX) { clear_bus_cnt = 0; } ret = ESP_FAIL; @@ -1423,31 +1204,26 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, TickType_t ticks_to_wait) { I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_FAIL); + I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_FAIL); I2C_CHECK(p_i2c_obj[i2c_num]->mode == I2C_MODE_SLAVE, I2C_MODE_SLAVE_ERR_STR, ESP_FAIL); i2c_obj_t* p_i2c = p_i2c_obj[i2c_num]; portBASE_TYPE res; int cnt = 0; - portTickType ticks_start = xTaskGetTickCount(); + portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait; res = xSemaphoreTake(p_i2c->slv_tx_mux, ticks_to_wait); if (res == pdFALSE) { return 0; } - TickType_t ticks_end = xTaskGetTickCount(); - if (ticks_end - ticks_start > ticks_to_wait) { - ticks_to_wait = 0; - } else { - ticks_to_wait = ticks_to_wait - (ticks_end - ticks_start); - } + ticks_to_wait = ticks_end - xTaskGetTickCount(); res = xRingbufferSend(p_i2c->tx_ring_buf, data, size, ticks_to_wait); if (res == pdFALSE) { cnt = 0; } else { I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->int_clr.tx_fifo_empty = 1; - I2C[i2c_num]->int_ena.tx_fifo_empty = 1; + i2c_hal_enable_slave_tx_it(&(p_i2c->i2c_hal)); I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); cnt = size; } @@ -1455,54 +1231,36 @@ int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, TickType return cnt; } -static int i2c_slave_read(i2c_port_t i2c_num, uint8_t* data, size_t max_size, TickType_t ticks_to_wait) -{ - i2c_obj_t* p_i2c = p_i2c_obj[i2c_num]; - size_t size = 0; - uint8_t* pdata = (uint8_t*) xRingbufferReceiveUpTo(p_i2c->rx_ring_buf, &size, ticks_to_wait, max_size); - if (pdata && size > 0) { - memcpy(data, pdata, size); - vRingbufferReturnItem(p_i2c->rx_ring_buf, pdata); - } - return size; -} - int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, TickType_t ticks_to_wait) { I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_FAIL); + I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_FAIL); I2C_CHECK(p_i2c_obj[i2c_num]->mode == I2C_MODE_SLAVE, I2C_MODE_SLAVE_ERR_STR, ESP_FAIL); + size_t size = 0; + size_t size_rem = max_size; i2c_obj_t* p_i2c = p_i2c_obj[i2c_num]; - portBASE_TYPE res; - portTickType ticks_start = xTaskGetTickCount(); - res = xSemaphoreTake(p_i2c->slv_rx_mux, ticks_to_wait); - if (res == pdFALSE) { + if (xSemaphoreTake(p_i2c->slv_rx_mux, ticks_to_wait) == pdFALSE) { return 0; } - TickType_t ticks_end = xTaskGetTickCount(); - if (ticks_end - ticks_start > ticks_to_wait) { - ticks_to_wait = 0; - } else { - ticks_to_wait = ticks_to_wait - (ticks_end - ticks_start); - } - int cnt = i2c_slave_read(i2c_num, data, max_size, ticks_to_wait); - if (cnt > 0) { - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->int_ena.rx_fifo_full = 1; - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - ticks_end = xTaskGetTickCount(); - if (ticks_end - ticks_start > ticks_to_wait) { - ticks_to_wait = 0; - } else { - ticks_to_wait = ticks_to_wait - (ticks_end - ticks_start); + 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]); + 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) { + memcpy(data, pdata, size); + vRingbufferReturnItem(p_i2c->rx_ring_buf, pdata); + data += size; + size_rem -= size; } - if (cnt < max_size && ticks_to_wait > 0) { - cnt += i2c_slave_read(i2c_num, data + cnt, max_size - cnt, ticks_to_wait); + if (ticks_to_wait != portMAX_DELAY) { + ticks_rem = ticks_end - xTaskGetTickCount(); } - } else { - cnt = 0; } xSemaphoreGive(p_i2c->slv_rx_mux); - return cnt; -} + return max_size - size_rem; +} \ No newline at end of file diff --git a/components/driver/include/driver/i2c.h b/components/driver/include/driver/i2c.h index fafbc7b96..7e7e5d1cf 100644 --- a/components/driver/include/driver/i2c.h +++ b/components/driver/include/driver/i2c.h @@ -1,4 +1,4 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,10 +15,10 @@ #ifndef _DRIVER_I2C_H_ #define _DRIVER_I2C_H_ - #ifdef __cplusplus extern "C" { #endif + #include #include "esp_err.h" #include "esp_intr_alloc.h" @@ -29,74 +29,14 @@ extern "C" { #include "freertos/queue.h" #include "freertos/ringbuf.h" #include "driver/gpio.h" +#include "hal/i2c_types.h" +#include "soc/i2c_caps.h" #define I2C_APB_CLK_FREQ APB_CLK_FREQ /*!< I2C source clock is APB clock, 80MHz */ -#define I2C_FIFO_LEN (32) /*!< I2C hardware fifo length */ -typedef enum{ - I2C_MODE_SLAVE = 0, /*!< I2C slave mode */ - I2C_MODE_MASTER, /*!< I2C master mode */ - I2C_MODE_MAX, -}i2c_mode_t; -typedef enum { - I2C_MASTER_WRITE = 0, /*!< I2C write data */ - I2C_MASTER_READ, /*!< I2C read data */ -} i2c_rw_t; - -typedef enum { - I2C_DATA_MODE_MSB_FIRST = 0, /*!< I2C data msb first */ - I2C_DATA_MODE_LSB_FIRST = 1, /*!< I2C data lsb first */ - I2C_DATA_MODE_MAX -} i2c_trans_mode_t; - -typedef enum{ - I2C_CMD_RESTART = 0, /*!ctr.ms_mode, 1); TEST_ESP_OK(i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0)); + TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master)); + TEST_ASSERT_EQUAL_INT32(I2C[I2C_MASTER_NUM]->ctr.ms_mode, 1); TEST_ESP_OK(i2c_driver_delete(I2C_MASTER_NUM)); } } @@ -113,15 +113,13 @@ TEST_CASE("I2C config test", "[i2c]") i2c_config_t conf_slave = i2c_slave_init(); for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { - conf_master.sda_pullup_en = sda_pull_up_en[i]; - conf_master.scl_pullup_en = scl_pull_up_en[j]; conf_slave.sda_pullup_en = sda_pull_up_en[i]; conf_slave.scl_pullup_en = scl_pull_up_en[j]; - TEST_ESP_OK(i2c_param_config( I2C_SLAVE_NUM, &conf_slave)); - TEST_ASSERT_EQUAL_INT32(I2C[I2C_SLAVE_NUM] -> ctr.ms_mode, 0); TEST_ESP_OK(i2c_driver_install(I2C_SLAVE_NUM, I2C_MODE_SLAVE, I2C_SLAVE_RX_BUF_LEN, I2C_SLAVE_TX_BUF_LEN, 0)); + TEST_ESP_OK(i2c_param_config( I2C_SLAVE_NUM, &conf_slave)); + TEST_ASSERT_EQUAL_INT32(I2C[I2C_SLAVE_NUM] -> ctr.ms_mode, 0); TEST_ESP_OK(i2c_driver_delete(I2C_SLAVE_NUM)); } } @@ -133,10 +131,10 @@ TEST_CASE("I2C set and get period test", "[i2c]") { int high_period, low_period; i2c_config_t conf_master = i2c_master_init(); - TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master)); TEST_ESP_OK(i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0)); + TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master)); TEST_ESP_OK(i2c_set_period(I2C_MASTER_NUM, I2C_SCL_HIGH_PERIOD_V, I2C_SCL_HIGH_PERIOD_V)); TEST_ESP_OK(i2c_get_period(I2C_MASTER_NUM, &high_period, &low_period)); @@ -154,12 +152,18 @@ TEST_CASE("I2C set and get period test", "[i2c]") TEST_CASE("I2C config FIFO test", "[i2c]") { + i2c_config_t conf_slave = i2c_slave_init(); + TEST_ESP_OK(i2c_driver_install(I2C_SLAVE_NUM, I2C_MODE_SLAVE, + I2C_SLAVE_RX_BUF_LEN, + I2C_SLAVE_TX_BUF_LEN, 0)); + TEST_ESP_OK(i2c_param_config( I2C_SLAVE_NUM, &conf_slave)); TEST_ASSERT_BIT_LOW(1, I2C[I2C_SLAVE_NUM]->fifo_conf.tx_fifo_rst); TEST_ESP_OK(i2c_reset_tx_fifo(I2C_SLAVE_NUM)); TEST_ASSERT_BIT_LOW(0, I2C[I2C_SLAVE_NUM]->fifo_conf.tx_fifo_rst); TEST_ESP_OK(i2c_reset_rx_fifo(I2C_SLAVE_NUM)); TEST_ASSERT_BIT_LOW(0, I2C[I2C_SLAVE_NUM]->fifo_conf.rx_fifo_rst); + TEST_ESP_OK(i2c_driver_delete(I2C_SLAVE_NUM)); } TEST_CASE("I2C timing test", "[i2c]") @@ -167,10 +171,10 @@ TEST_CASE("I2C timing test", "[i2c]") int test_setup_time, test_data_time, test_stop_time, test_hold_time; uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH); i2c_config_t conf_master = i2c_master_init(); - TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master)); TEST_ESP_OK(i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0)); + TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master)); TEST_ESP_OK(i2c_set_start_timing(I2C_MASTER_NUM, 50, 60)); TEST_ESP_OK(i2c_set_data_timing(I2C_MASTER_NUM, 80, 60)); @@ -191,28 +195,28 @@ TEST_CASE("I2C timing test", "[i2c]") i2c_driver_delete(I2C_MASTER_NUM); } - TEST_CASE("I2C data mode test", "[i2c]") { uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH); i2c_trans_mode_t test_tx_trans_mode, test_rx_trans_mode; i2c_config_t conf_master = i2c_master_init(); - TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master)); TEST_ESP_OK(i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0)); + TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master)); for (int i = 0; i < DATA_LENGTH; i++) { data_wr[i] = i; } - i2c_master_write_slave(I2C_MASTER_NUM, data_wr, RW_TEST_LENGTH); TEST_ESP_OK(i2c_set_data_mode(I2C_MASTER_NUM, I2C_DATA_MODE_LSB_FIRST, I2C_DATA_MODE_LSB_FIRST)); - i2c_master_write_slave(I2C_MASTER_NUM, data_wr, RW_TEST_LENGTH); - TEST_ASSERT_EQUAL_INT(1, I2C[I2C_MASTER_NUM]->ctr.rx_lsb_first); - TEST_ASSERT_EQUAL_INT(1, I2C[I2C_MASTER_NUM]->ctr.tx_lsb_first); - TEST_ESP_OK(i2c_get_data_mode(I2C_MASTER_NUM, &test_tx_trans_mode, &test_rx_trans_mode)); - TEST_ASSERT_EQUAL_INT(1, test_tx_trans_mode); - TEST_ASSERT_EQUAL_INT(1, test_rx_trans_mode); + TEST_ASSERT_EQUAL_INT(I2C_DATA_MODE_LSB_FIRST, test_tx_trans_mode); + TEST_ASSERT_EQUAL_INT(I2C_DATA_MODE_LSB_FIRST, test_rx_trans_mode); + i2c_master_write_slave(I2C_MASTER_NUM, data_wr, RW_TEST_LENGTH); + TEST_ESP_OK(i2c_set_data_mode(I2C_MASTER_NUM, I2C_DATA_MODE_MSB_FIRST, I2C_DATA_MODE_MSB_FIRST)); + TEST_ESP_OK(i2c_get_data_mode(I2C_MASTER_NUM, &test_tx_trans_mode, &test_rx_trans_mode)); + TEST_ASSERT_EQUAL_INT(I2C_DATA_MODE_MSB_FIRST, test_tx_trans_mode); + TEST_ASSERT_EQUAL_INT(I2C_DATA_MODE_MSB_FIRST, test_rx_trans_mode); + i2c_master_write_slave(I2C_MASTER_NUM, data_wr, RW_TEST_LENGTH); free(data_wr); i2c_driver_delete(I2C_MASTER_NUM); } @@ -221,9 +225,6 @@ TEST_CASE("I2C data mode test", "[i2c]") TEST_CASE("I2C driver memory leaking check", "[i2c]") { esp_err_t ret; - i2c_config_t conf_slave = i2c_slave_init(); - ret = i2c_param_config(I2C_SLAVE_NUM, &conf_slave); - TEST_ASSERT(ret == ESP_OK); int size = esp_get_free_heap_size(); for (uint32_t i = 0; i <= 1000; i++) { @@ -248,16 +249,17 @@ static void test_task(void *pvParameters) uint8_t *data = (uint8_t *) malloc(DATA_LENGTH); i2c_config_t conf_slave = i2c_slave_init(); - TEST_ESP_OK(i2c_param_config( I2C_SLAVE_NUM, &conf_slave)); TEST_ESP_OK(i2c_driver_install(I2C_SLAVE_NUM, I2C_MODE_SLAVE, I2C_SLAVE_RX_BUF_LEN, I2C_SLAVE_TX_BUF_LEN, 0)); + TEST_ESP_OK(i2c_param_config( I2C_SLAVE_NUM, &conf_slave)); while (exit_flag == false) { if (test_read_func) { i2c_slave_read_buffer(I2C_SLAVE_NUM, data, DATA_LENGTH, 0); } else { i2c_slave_write_buffer(I2C_SLAVE_NUM, data, DATA_LENGTH, 0); } + vTaskDelay(10/portTICK_RATE_MS); } free(data); diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 6f13bf733..f9c6c44d6 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -25,6 +25,8 @@ list(APPEND srcs "src/hal/timer_hal.c" "src/hal/ledc_hal.c" "src/hal/ledc_hal_iram.c" + "src/hal/i2c_hal.c" + "src/hal/i2c_hal_iram.c" ) # TODO: SPI Flash HAL for ESP32S2Beta also diff --git a/components/soc/esp32/i2c_periph.c b/components/soc/esp32/i2c_periph.c new file mode 100644 index 000000000..1406cc1fd --- /dev/null +++ b/components/soc/esp32/i2c_periph.c @@ -0,0 +1,38 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "soc/i2c_periph.h" +#include "soc/gpio_sig_map.h" + +/* + Bunch of constants for every I2C peripheral: GPIO signals, irqs, hw addr of registers etc +*/ +const i2c_signal_conn_t i2c_periph_signal[SOC_I2C_NUM] = { + { + .sda_out_sig = I2CEXT0_SDA_OUT_IDX, + .sda_in_sig = I2CEXT0_SDA_IN_IDX, + .scl_out_sig = I2CEXT0_SCL_OUT_IDX, + .scl_in_sig = I2CEXT0_SCL_IN_IDX, + .irq = ETS_I2C_EXT0_INTR_SOURCE, + .module = PERIPH_I2C0_MODULE, + }, + { + .sda_out_sig = I2CEXT1_SDA_OUT_IDX, + .sda_in_sig = I2CEXT1_SDA_IN_IDX, + .scl_out_sig = I2CEXT1_SCL_OUT_IDX, + .scl_in_sig = I2CEXT1_SCL_IN_IDX, + .irq = ETS_I2C_EXT1_INTR_SOURCE, + .module = PERIPH_I2C1_MODULE, + }, +}; \ No newline at end of file diff --git a/components/soc/esp32/include/hal/i2c_ll.h b/components/soc/esp32/include/hal/i2c_ll.h new file mode 100644 index 000000000..e3415d68b --- /dev/null +++ b/components/soc/esp32/include/hal/i2c_ll.h @@ -0,0 +1,791 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The LL layer for I2C register operations + +#pragma once +#include "soc/i2c_periph.h" +#include "hal/i2c_types.h" + +/** + * @brief I2C hardware cmd register filed. + */ +typedef union { + struct { + uint32_t byte_num: 8, + ack_en: 1, + ack_exp: 1, + ack_val: 1, + op_code: 3, + reserved14: 17, + done: 1; + }; + 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; + +// 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 base clock freq 80M +#define I2C_BASE_CLK_FREQ (80000000) + +/** + * @brief Reset I2C txFIFO + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_txfifo_rst(i2c_dev_t *hw) +{ + hw->fifo_conf.tx_fifo_rst = 1; + hw->fifo_conf.tx_fifo_rst = 0; +} + +/** + * @brief Reset I2C rxFIFO + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_rxfifo_rst(i2c_dev_t *hw) +{ + hw->fifo_conf.rx_fifo_rst = 1; + hw->fifo_conf.rx_fifo_rst = 0; +} + +/** + * @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) + * + * @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; +} + +/** + * @brief Clear I2C interrupt status + * + * @param hw Beginning address of the peripheral registers + * @param mask Interrupt mask needs to be cleared + * + * @return None + */ +static inline void i2c_ll_clr_intsts_mask(i2c_dev_t *hw, uint32_t mask) +{ + hw->int_clr.val = mask; +} + +/** + * @brief Enable I2C interrupt + * + * @param hw Beginning address of the peripheral registers + * @param mask Interrupt mask needs to be enabled + * + * @return None + */ +static inline void i2c_ll_enable_intr_mask(i2c_dev_t *hw, uint32_t mask) +{ + hw->int_ena.val |= mask; +} + +/** + * @brief Disable I2C interrupt + * + * @param hw Beginning address of the peripheral registers + * @param mask Interrupt mask needs to be disabled + * + * @return None + */ +static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) +{ + hw->int_ena.val &= (~mask); +} + +/** + * @brief Get I2C interrupt status + * + * @param hw Beginning address of the peripheral registers + * + * @return I2C interrupt status + */ +static inline uint32_t i2c_ll_get_intsts_mask(i2c_dev_t *hw) +{ + return hw->int_status.val; +} + +/** + * @brief Configure I2C memory access mode, FIFO mode or non-FIFO mode + * + * @param hw Beginning address of the peripheral registers + * @param fifo_mode_en Set true to enable FIFO access mode, else, set it false + * + * @return None + */ +static inline void i2c_ll_set_fifo_mode(i2c_dev_t *hw, bool fifo_mode_en) +{ + hw->fifo_conf.nonfifo_en = fifo_mode_en ? 0 : 1; +} + +/** + * @brief Configure I2C timeout + * + * @param hw Beginning address of the peripheral registers + * @param tout_num The I2C timeout value needs to be set (in APB cycle) + * + * @return None + */ +static inline void i2c_ll_set_tout(i2c_dev_t *hw, int tout) +{ + hw->timeout.tout = tout; +} + +/** + * @brief Configure I2C slave address + * + * @param hw Beginning address of the peripheral registers + * @param slave_addr I2C slave address needs to be set + * @param addr_10bit_en Set true to enable 10-bit slave address mode, set false to enable 7-bit address mode + * + * @return None + */ +static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, bool addr_10bit_en) +{ + hw->slave_addr.addr = slave_addr; + hw->slave_addr.en_10bit = addr_10bit_en; +} + +/** + * @brief Write I2C hardware command register + * + * @param hw Beginning address of the peripheral registers + * @param cmd I2C hardware command + * @param cmd_idx The index of the command register, should be less than 16 + * + * @return None + */ +static inline void i2c_ll_write_cmd_reg(i2c_dev_t *hw, i2c_hw_cmd_t cmd, int cmd_idx) +{ + hw->command[cmd_idx].val = cmd.val; +} + +/** + * @brief Configure I2C start timing + * + * @param hw Beginning address of the peripheral registers + * @param start_setup The start condition setup period (in APB cycle) + * @param start_hold The start condition hold period (in APB cycle) + * + * @return None + */ +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; +} + +/** + * @brief Configure I2C stop timing + * + * @param hw Beginning address of the peripheral registers + * @param stop_setup The stop condition setup period (in APB cycle) + * @param stop_hold The stop condition hold period (in APB cycle) + * + * @return None + */ +static inline void i2c_ll_set_stop_timing(i2c_dev_t *hw, int stop_setup, int stop_hold) +{ + hw->scl_stop_setup.time = stop_setup; + hw->scl_stop_hold.time = stop_hold; +} + +/** + * @brief Configure I2C stop timing + * + * @param hw Beginning address of the peripheral registers + * @param sda_sample The SDA sample time (in APB cycle) + * @param sda_hold The SDA hold time (in APB cycle) + * + * @return None + */ +static inline void i2c_ll_set_sda_timing(i2c_dev_t *hw, int sda_sample, int sda_hold) +{ + hw->sda_hold.time = sda_hold; + hw->sda_sample.time = sda_sample; +} + +/** + * @brief Set I2C txFIFO empty threshold + * + * @param hw Beginning address of the peripheral registers + * @param empty_thr The txFIFO empty threshold + * + * @return None + */ +static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr) +{ + hw->fifo_conf.tx_fifo_empty_thrhd = empty_thr; +} + +/** + * @brief Set I2C rxFIFO full threshold + * + * @param hw Beginning address of the peripheral registers + * @param full_thr The rxFIFO full threshold + * + * @return None + */ +static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr) +{ + hw->fifo_conf.rx_fifo_full_thrhd = full_thr; +} + +/** + * @brief Set the I2C data mode, LSB or MSB + * + * @param hw Beginning address of the peripheral registers + * @param tx_mode Tx data bit mode + * @param rx_mode Rx data bit mode + * + * @return None + */ +static inline void i2c_ll_set_data_mode(i2c_dev_t *hw, i2c_trans_mode_t tx_mode, i2c_trans_mode_t rx_mode) +{ + hw->ctr.tx_lsb_first = tx_mode; + hw->ctr.rx_lsb_first = rx_mode; +} + +/** + * @brief Get the I2C data mode + * + * @param hw Beginning address of the peripheral registers + * @param tx_mode Pointer to accept the received bytes mode + * @param rx_mode Pointer to accept the sended bytes mode + * + * @return None + */ +static inline void i2c_ll_get_data_mode(i2c_dev_t *hw, i2c_trans_mode_t *tx_mode, i2c_trans_mode_t *rx_mode) +{ + *tx_mode = hw->ctr.tx_lsb_first; + *rx_mode = hw->ctr.rx_lsb_first; +} + +/** + * @brief Get I2C sda timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param sda_sample Pointer to accept the SDA sample timing configuration + * @param sda_hold Pointer to accept the SDA hold timing configuration + * + * @return None + */ +static inline void i2c_ll_get_sda_timing(i2c_dev_t *hw, int *sda_sample, int *sda_hold) +{ + *sda_hold = hw->sda_hold.time; + *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 + * + * @param hw Beginning address of the peripheral registers + * + * @return True if I2C state machine is busy, else false will be returned + */ +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 + * + * @param hw Beginning address of the peripheral registers + * + * @return RxFIFO readable length + */ +static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) +{ + return hw->status_reg.rx_fifo_cnt; +} + +/** + * @brief Get I2C txFIFO writable length + * + * @param hw Beginning address of the peripheral registers + * + * @return TxFIFO writable length + */ +static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) +{ + return SOC_I2C_FIFO_LEN - hw->status_reg.tx_fifo_cnt; +} + +/** + * @brief Get I2C timeout configuration + * + * @param hw Beginning address of the peripheral registers + * + * @return The I2C timeout value + */ +static inline uint32_t i2c_ll_get_tout(i2c_dev_t *hw) +{ + return hw->timeout.tout; +} + +/** + * @brief Start I2C transfer + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_trans_start(i2c_dev_t *hw) +{ + hw->ctr.trans_start = 1; +} + +/** + * @brief Get I2C start timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param setup_time Pointer to accept the start condition setup period + * @param hold_time Pointer to accept the start condition hold period + * + * @return None + */ +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; +} + +/** + * @brief Get I2C stop timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param setup_time Pointer to accept the stop condition setup period + * @param hold_time Pointer to accept the stop condition hold period + * + * @return None + */ +static inline void i2c_ll_get_stop_timing(i2c_dev_t *hw, int *setup_time, int *hold_time) +{ + *setup_time = hw->scl_stop_setup.time; + *hold_time = hw->scl_stop_hold.time; +} + +/** + * @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_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; +} + +/** + * @brief Write the I2C hardware txFIFO + * + * @param hw Beginning address of the peripheral registers + * @param ptr Pointer to data buffer + * @param len Amount of data needs to be writen + * + * @return None. + */ +static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) +{ + uint32_t fifo_addr = (hw == &I2C0) ? 0x6001301c : 0x6002701c; + for(int i = 0; i < len; i++) { + WRITE_PERI_REG(fifo_addr, ptr[i]); + } +} + +/** + * @brief Read the I2C hardware rxFIFO + * + * @param hw Beginning address of the peripheral registers + * @param ptr Pointer to data buffer + * @param len Amount of data needs read + * + * @return None + */ +static inline void i2c_ll_read_rxfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) +{ + for(int i = 0; i < len; i++) { + ptr[i] = hw->fifo_data.data; + } +} + +/** + * @brief Configure I2C hardware filter + * + * @param hw Beginning address of the peripheral registers + * @param filter_num If the glitch period on the line is less than this value, it can be filtered out + * If `filter_num == 0`, the filter will be disabled + * + * @return None + */ +static inline void i2c_ll_set_filter(i2c_dev_t *hw, uint8_t filter_num) +{ + if(filter_num > 0) { + hw->scl_filter_cfg.thres = filter_num; + hw->sda_filter_cfg.thres = filter_num; + hw->scl_filter_cfg.en = 1; + hw->sda_filter_cfg.en = 1; + } else { + hw->scl_filter_cfg.en = 0; + hw->sda_filter_cfg.en = 0; + } +} + +/** + * @brief Get I2C hardware filter configuration + * + * @param hw Beginning address of the peripheral registers + * + * @return The hardware filter configuration + */ +static inline uint8_t i2c_ll_get_filter(i2c_dev_t *hw) +{ + 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; +} + +/** + * @brief Reste I2C master FSM. When the master FSM is stuck, call this function to reset the FSM + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_fsm_rst(i2c_dev_t *hw) +{ + ;//ESP32 do not support +} + +/** + * @brief Clear I2C bus, when the slave is stuck in a deadlock and keeps pulling the bus low, + * master can controls the SCL bus to generate 9 CLKs. + * + * Note: The master cannot detect if deadlock happens, but when the scl_st_to interrupt is generated, a deadlock may occur. + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw) +{ + ;//ESP32 do not support +} + +/** + * @brief Set I2C source clock + * + * @param hw Beginning address of the peripheral registers + * @param src_clk Source clock of the I2C + * + * @return None + */ +static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_sclk_t src_clk) +{ + ;//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 + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_init(i2c_dev_t *hw) +{ + typeof(hw->ctr) ctrl_reg; + ctrl_reg.val = 0; + ctrl_reg.ms_mode = 1; + ctrl_reg.sda_force_out = 1; + ctrl_reg.scl_force_out = 1; + hw->ctr.val = ctrl_reg.val; +} + +/** + * @brief Init I2C slave + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_init(i2c_dev_t *hw) +{ + typeof(hw->ctr) ctrl_reg; + ctrl_reg.val = 0; + ctrl_reg.sda_force_out = 1; + ctrl_reg.scl_force_out = 1; + hw->ctr.val = ctrl_reg.val; + hw->fifo_conf.fifo_addr_cfg_en = 0; +} \ No newline at end of file diff --git a/components/soc/esp32/include/soc/i2c_caps.h b/components/soc/esp32/include/soc/i2c_caps.h new file mode 100644 index 000000000..d2fec8099 --- /dev/null +++ b/components/soc/esp32/include/soc/i2c_caps.h @@ -0,0 +1,36 @@ +// Copyright 2010-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +// ESP32 have 2 I2C. +#define SOC_I2C_NUM (2) + +#define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */ +#define I2C_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ + +//ESP32 do not support hardware FSM reset +#define I2C_SUPPORT_HW_FSM_RST (0) +//ESP32 do not support hardware clear bus +#define I2C_SUPPORT_HW_CLR_BUS (0) + +#ifdef __cplusplus +} +#endif + + diff --git a/components/soc/esp32/sources.cmake b/components/soc/esp32/sources.cmake index 726389fb7..37d968cbb 100644 --- a/components/soc/esp32/sources.cmake +++ b/components/soc/esp32/sources.cmake @@ -15,7 +15,8 @@ set(SOC_SRCS "cpu_util.c" "soc_memory_layout.c" "spi_periph.c" "ledc_periph.c" - "i2s_periph.c") + "i2s_periph.c" + "i2c_periph.c") if(NOT BOOTLOADER_BUILD AND CONFIG_ETH_USE_ESP32_EMAC) list(APPEND SOC_SRCS "emac_hal.c") diff --git a/components/soc/esp32s2beta/i2c_periph.c b/components/soc/esp32s2beta/i2c_periph.c new file mode 100644 index 000000000..1406cc1fd --- /dev/null +++ b/components/soc/esp32s2beta/i2c_periph.c @@ -0,0 +1,38 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "soc/i2c_periph.h" +#include "soc/gpio_sig_map.h" + +/* + Bunch of constants for every I2C peripheral: GPIO signals, irqs, hw addr of registers etc +*/ +const i2c_signal_conn_t i2c_periph_signal[SOC_I2C_NUM] = { + { + .sda_out_sig = I2CEXT0_SDA_OUT_IDX, + .sda_in_sig = I2CEXT0_SDA_IN_IDX, + .scl_out_sig = I2CEXT0_SCL_OUT_IDX, + .scl_in_sig = I2CEXT0_SCL_IN_IDX, + .irq = ETS_I2C_EXT0_INTR_SOURCE, + .module = PERIPH_I2C0_MODULE, + }, + { + .sda_out_sig = I2CEXT1_SDA_OUT_IDX, + .sda_in_sig = I2CEXT1_SDA_IN_IDX, + .scl_out_sig = I2CEXT1_SCL_OUT_IDX, + .scl_in_sig = I2CEXT1_SCL_IN_IDX, + .irq = ETS_I2C_EXT1_INTR_SOURCE, + .module = PERIPH_I2C1_MODULE, + }, +}; \ No newline at end of file diff --git a/components/soc/esp32s2beta/include/hal/i2c_ll.h b/components/soc/esp32s2beta/include/hal/i2c_ll.h new file mode 100644 index 000000000..11f5d3785 --- /dev/null +++ b/components/soc/esp32s2beta/include/hal/i2c_ll.h @@ -0,0 +1,800 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The LL layer for I2C register operations + +#pragma once +#include "soc/i2c_periph.h" +#include "hal/i2c_types.h" + +/** + * @brief I2C hardware cmd register filed. + */ +typedef union { + struct { + uint32_t byte_num: 8, + ack_en: 1, + ack_exp: 1, + ack_val: 1, + op_code: 3, + reserved14: 17, + done: 1; + }; + 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; + +// 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) + + +/** + * @brief Reset I2C txFIFO + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_txfifo_rst(i2c_dev_t *hw) +{ + hw->fifo_conf.tx_fifo_rst = 1; + hw->fifo_conf.tx_fifo_rst = 0; +} + +/** + * @brief Reset I2C rxFIFO + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_rxfifo_rst(i2c_dev_t *hw) +{ + hw->fifo_conf.rx_fifo_rst = 1; + hw->fifo_conf.rx_fifo_rst = 0; +} + +/** + * @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) + * + * @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*0.6; + hw->scl_high_period.scl_wait_high_period = hight_period*0.4-1; +} + +/** + * @brief Clear I2C interrupt status + * + * @param hw Beginning address of the peripheral registers + * @param mask Interrupt mask needs to be cleared + * + * @return None + */ +static inline void i2c_ll_clr_intsts_mask(i2c_dev_t *hw, uint32_t mask) +{ + hw->int_clr.val = mask; +} + +/** + * @brief Enable I2C interrupt + * + * @param hw Beginning address of the peripheral registers + * @param mask Interrupt mask needs to be enabled + * + * @return None + */ +static inline void i2c_ll_enable_intr_mask(i2c_dev_t *hw, uint32_t mask) +{ + hw->int_ena.val |= mask; +} + +/** + * @brief Disable I2C interrupt + * + * @param hw Beginning address of the peripheral registers + * @param mask Interrupt mask needs to be disabled + * + * @return None + */ +static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask) +{ + hw->int_ena.val &= (~mask); +} + +/** + * @brief Get I2C interrupt status + * + * @param hw Beginning address of the peripheral registers + * + * @return I2C interrupt status + */ +static inline uint32_t i2c_ll_get_intsts_mask(i2c_dev_t *hw) +{ + return hw->int_status.val; +} + +/** + * @brief Configure I2C memory access mode, FIFO mode or non-FIFO mode + * + * @param hw Beginning address of the peripheral registers + * @param fifo_mode_en Set true to enable FIFO access mode, else, set it false + * + * @return None + */ +static inline void i2c_ll_set_fifo_mode(i2c_dev_t *hw, bool fifo_mode_en) +{ + hw->fifo_conf.nonfifo_en = fifo_mode_en ? 0 : 1; +} + +/** + * @brief Configure I2C timeout + * + * @param hw Beginning address of the peripheral registers + * @param tout_num The I2C timeout value needs to be set (in APB cycle) + * + * @return None + */ +static inline void i2c_ll_set_tout(i2c_dev_t *hw, int tout) +{ + hw->timeout.tout = tout; +} + +/** + * @brief Configure I2C slave address + * + * @param hw Beginning address of the peripheral registers + * @param slave_addr I2C slave address needs to be set + * @param addr_10bit_en Set true to enable 10-bit slave address mode, set false to enable 7-bit address mode + * + * @return None + */ +static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, bool addr_10bit_en) +{ + hw->slave_addr.addr = slave_addr; + hw->slave_addr.en_10bit = addr_10bit_en; +} + +/** + * @brief Write I2C hardware command register + * + * @param hw Beginning address of the peripheral registers + * @param cmd I2C hardware command + * @param cmd_idx The index of the command register, should be less than 16 + * + * @return None + */ +static inline void i2c_ll_write_cmd_reg(i2c_dev_t *hw, i2c_hw_cmd_t cmd, int cmd_idx) +{ + hw->command[cmd_idx].val = cmd.val; +} + +/** + * @brief Configure I2C start timing + * + * @param hw Beginning address of the peripheral registers + * @param start_setup The start condition setup period (in APB cycle) + * @param start_hold The start condition hold period (in APB cycle) + * + * @return None + */ +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; +} + +/** + * @brief Configure I2C stop timing + * + * @param hw Beginning address of the peripheral registers + * @param stop_setup The stop condition setup period (in APB cycle) + * @param stop_hold The stop condition hold period (in APB cycle) + * + * @return None + */ +static inline void i2c_ll_set_stop_timing(i2c_dev_t *hw, int stop_setup, int stop_hold) +{ + hw->scl_stop_setup.time = stop_setup; + hw->scl_stop_hold.time = stop_hold; +} + +/** + * @brief Configure I2C stop timing + * + * @param hw Beginning address of the peripheral registers + * @param sda_sample The SDA sample time (in APB cycle) + * @param sda_hold The SDA hold time (in APB cycle) + * + * @return None + */ +static inline void i2c_ll_set_sda_timing(i2c_dev_t *hw, int sda_sample, int sda_hold) +{ + hw->sda_hold.time = sda_hold; + hw->sda_sample.time = sda_sample; +} + +/** + * @brief Set I2C txFIFO empty threshold + * + * @param hw Beginning address of the peripheral registers + * @param empty_thr The txFIFO empty threshold + * + * @return None + */ +static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr) +{ + hw->fifo_conf.tx_fifo_empty_thrhd = empty_thr; +} + +/** + * @brief Set I2C rxFIFO full threshold + * + * @param hw Beginning address of the peripheral registers + * @param full_thr The rxFIFO full threshold + * + * @return None + */ +static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr) +{ + hw->fifo_conf.rx_fifo_full_thrhd = full_thr; +} + +/** + * @brief Set the I2C data mode, LSB or MSB + * + * @param hw Beginning address of the peripheral registers + * @param tx_mode Tx data bit mode + * @param rx_mode Rx data bit mode + * + * @return None + */ +static inline void i2c_ll_set_data_mode(i2c_dev_t *hw, i2c_trans_mode_t tx_mode, i2c_trans_mode_t rx_mode) +{ + hw->ctr.tx_lsb_first = tx_mode; + hw->ctr.rx_lsb_first = rx_mode; +} + +/** + * @brief Get the I2C data mode + * + * @param hw Beginning address of the peripheral registers + * @param tx_mode Pointer to accept the received bytes mode + * @param rx_mode Pointer to accept the sended bytes mode + * + * @return None + */ +static inline void i2c_ll_get_data_mode(i2c_dev_t *hw, i2c_trans_mode_t *tx_mode, i2c_trans_mode_t *rx_mode) +{ + *tx_mode = hw->ctr.tx_lsb_first; + *rx_mode = hw->ctr.rx_lsb_first; +} + +/** + * @brief Get I2C sda timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param sda_sample Pointer to accept the SDA sample timing configuration + * @param sda_hold Pointer to accept the SDA hold timing configuration + * + * @return None + */ +static inline void i2c_ll_get_sda_timing(i2c_dev_t *hw, int *sda_sample, int *sda_hold) +{ + *sda_hold = hw->sda_hold.time; + *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 + * + * @param hw Beginning address of the peripheral registers + * + * @return True if I2C state machine is busy, else false will be returned + */ +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 + * + * @param hw Beginning address of the peripheral registers + * + * @return RxFIFO readable length + */ +static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw) +{ + return hw->status_reg.rx_fifo_cnt; +} + +/** + * @brief Get I2C txFIFO writable length + * + * @param hw Beginning address of the peripheral registers + * + * @return TxFIFO writable length + */ +static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw) +{ + return SOC_I2C_FIFO_LEN - hw->status_reg.tx_fifo_cnt; +} + +/** + * @brief Get I2C timeout configuration + * + * @param hw Beginning address of the peripheral registers + * + * @return The I2C timeout value + */ +static inline uint32_t i2c_ll_get_tout(i2c_dev_t *hw) +{ + return hw->timeout.tout; +} + +/** + * @brief Start I2C transfer + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_trans_start(i2c_dev_t *hw) +{ + hw->ctr.trans_start = 1; +} + +/** + * @brief Get I2C start timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param setup_time Pointer to accept the start condition setup period + * @param hold_time Pointer to accept the start condition hold period + * + * @return None + */ +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; +} + +/** + * @brief Get I2C stop timing configuration + * + * @param hw Beginning address of the peripheral registers + * @param setup_time Pointer to accept the stop condition setup period + * @param hold_time Pointer to accept the stop condition hold period + * + * @return None + */ +static inline void i2c_ll_get_stop_timing(i2c_dev_t *hw, int *setup_time, int *hold_time) +{ + *setup_time = hw->scl_stop_setup.time; + *hold_time = hw->scl_stop_hold.time; +} + +/** + * @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_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; +} + +/** + * @brief Write the I2C hardware txFIFO + * + * @param hw Beginning address of the peripheral registers + * @param ptr Pointer to data buffer + * @param len Amount of data needs to be writen + * + * @return None. + */ +static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len) +{ + uint32_t fifo_addr = (hw == &I2C0) ? 0x6001301c : 0x6002701c; + for(int i = 0; i < len; i++) { + WRITE_PERI_REG(fifo_addr, ptr[i]); + } +} + +/** + * @brief Read the I2C hardware rxFIFO + * + * @param hw Beginning address of the peripheral registers + * @param ptr Pointer to data buffer + * @param len Amount of data needs read + * + * @return None + */ +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; + for(int i = 0; i < len; i++) { + ptr[i] = READ_PERI_REG(fifo_addr); + } +} + +/** + * @brief Configure I2C hardware filter + * + * @param hw Beginning address of the peripheral registers + * @param filter_num If the glitch period on the line is less than this value, it can be filtered out + * If `filter_num == 0`, the filter will be disabled + * + * @return None + */ +static inline void i2c_ll_set_filter(i2c_dev_t *hw, uint8_t filter_num) +{ + if(filter_num > 0) { + hw->scl_filter_cfg.thres = filter_num; + hw->sda_filter_cfg.thres = filter_num; + hw->scl_filter_cfg.en = 1; + hw->sda_filter_cfg.en = 1; + } else { + hw->scl_filter_cfg.en = 0; + hw->sda_filter_cfg.en = 0; + } +} + +/** + * @brief Get I2C hardware filter configuration + * + * @param hw Beginning address of the peripheral registers + * + * @return The hardware filter configuration + */ +static inline uint8_t i2c_ll_get_filter(i2c_dev_t *hw) +{ + 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; +} + +/** + * @brief Reste I2C master FSM. When the master FSM is stuck, call this function to reset the FSM + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_fsm_rst(i2c_dev_t *hw) +{ + hw->ctr.fsm_rst = 1; +} + +/** + * @brief Clear I2C bus, when the slave is stuck in a deadlock and keeps pulling the bus low, + * master can controls the SCL bus to generate 9 CLKs. + * + * Note: The master cannot detect if deadlock happens, but when the scl_st_to interrupt is generated, a deadlock may occur. + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw) +{ + uint32_t reg_val = hw->scl_sp_conf.val; + hw->scl_sp_conf.scl_pd_en = 1; + hw->scl_sp_conf.sda_pd_en = 1; + hw->scl_sp_conf.scl_rst_slv_en = 1; + hw->scl_sp_conf.val = reg_val & 0xfe; +} + +/** + * @brief Set I2C source clock + * + * @param hw Beginning address of the peripheral registers + * @param src_clk Source clock of the I2C + * + * @return None + */ +static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_sclk_t src_clk) +{ + hw->ctr.ref_always_on = src_clk; +} + +/** + * @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 + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_master_init(i2c_dev_t *hw) +{ + typeof(hw->ctr) ctrl_reg; + ctrl_reg.val = 0; + ctrl_reg.ms_mode = 1; + ctrl_reg.sda_force_out = 1; + ctrl_reg.scl_force_out = 1; + //Disable REF tick; + ctrl_reg.ref_always_on = 1; + hw->ctr.val = ctrl_reg.val; +} + +/** + * @brief Init I2C slave + * + * @param hw Beginning address of the peripheral registers + * + * @return None + */ +static inline void i2c_ll_slave_init(i2c_dev_t *hw) +{ + typeof(hw->ctr) ctrl_reg; + ctrl_reg.val = 0; + ctrl_reg.sda_force_out = 1; + ctrl_reg.scl_force_out = 1; + //Disable REF tick; + ctrl_reg.ref_always_on = 1; + hw->ctr.val = ctrl_reg.val; + hw->fifo_conf.fifo_addr_cfg_en = 0; +} \ No newline at end of file diff --git a/components/soc/esp32s2beta/include/soc/i2c_caps.h b/components/soc/esp32s2beta/include/soc/i2c_caps.h new file mode 100644 index 000000000..dddb36eea --- /dev/null +++ b/components/soc/esp32s2beta/include/soc/i2c_caps.h @@ -0,0 +1,36 @@ +// Copyright 2010-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +// ESP32-S2 have 2 I2C. +#define SOC_I2C_NUM (2) + +#define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */ +#define I2C_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ + +//ESP32-S2 support hardware FSM reset +#define I2C_SUPPORT_HW_FSM_RST (1) +//ESP32-S2 support hardware clear bus +#define I2C_SUPPORT_HW_CLR_BUS (1) + +#ifdef __cplusplus +} +#endif + + diff --git a/components/soc/esp32s2beta/sources.cmake b/components/soc/esp32s2beta/sources.cmake index 5c07bfccb..1c63e653b 100644 --- a/components/soc/esp32s2beta/sources.cmake +++ b/components/soc/esp32s2beta/sources.cmake @@ -12,7 +12,8 @@ set(SOC_SRCS "cpu_util.c" "soc_memory_layout.c" "spi_periph.c" "ledc_periph.c" - "i2s_periph.c") + "i2s_periph.c" + "i2c_periph.c") if(NOT CMAKE_BUILD_EARLY_EXPANSION) set_source_files_properties("esp32s2beta/rtc_clk.c" PROPERTIES diff --git a/components/soc/include/hal/i2c_hal.h b/components/soc/include/hal/i2c_hal.h new file mode 100644 index 000000000..a104ad51e --- /dev/null +++ b/components/soc/include/hal/i2c_hal.h @@ -0,0 +1,524 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The HAL layer for I2C + +#pragma once +#include "hal/i2c_ll.h" +#include "hal/i2c_types.h" + +/** + * @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 trasaction + * + * @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) + +/** + * @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 Get the I2C hardware instance and init the I2C master. Note that this function should be called before other hal layer function is called. + * + * @param hal Context of the HAL layer + * @param i2c_num I2C port number + * + * @return None + */ +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. + * + * @param hal Context of the HAL layer + * @param i2c_num I2C port number + * + * @return None + */ +void i2c_hal_slave_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 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 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); + +/** + * @brief Set I2C bus timing with the given frequency + * + * @param hal Context of the HAL layer + * @param scl_freq The scl frequency to be set + * @param src_clk Source clock of I2C + * + * @return None + */ +void i2c_hal_set_bus_timing(i2c_hal_context_t *hal, uint32_t scl_freq, i2c_sclk_t src_clk); + +/** + * @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 + * + * @param hal Context of the HAL layer + * + * @return None + */ +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 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 master handle tx interrupt event + * + * @param hal Context of the HAL layer + * @param event Pointer to accept the interrupt event + * + * @return None + */ +void i2c_hal_master_handle_tx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event); + +/** + * @brief I2C master handle rx interrupt event + * + * @param hal Context of the HAL layer + * @param event Pointer to accept the interrupt event + * + * @return None + */ +void i2c_hal_master_handle_rx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event); + +/** + * @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); \ No newline at end of file diff --git a/components/soc/include/hal/i2c_types.h b/components/soc/include/hal/i2c_types.h new file mode 100644 index 000000000..426515c0d --- /dev/null +++ b/components/soc/include/hal/i2c_types.h @@ -0,0 +1,96 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "soc/i2c_caps.h" + +/** + * @brief I2C port number, can be I2C_NUM_0 ~ (I2C_NUM_MAX-1). + */ +typedef int i2c_port_t; + +typedef enum{ + I2C_MODE_SLAVE = 0, /*!< I2C slave mode */ + I2C_MODE_MASTER, /*!< I2C master mode */ + I2C_MODE_MAX, +} i2c_mode_t; + +typedef enum { + I2C_MASTER_WRITE = 0, /*!< I2C write data */ + I2C_MASTER_READ, /*!< I2C read data */ +} i2c_rw_t; + +typedef enum{ + I2C_CMD_RESTART = 0, /*!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_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_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); +} + +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); +} + +void i2c_hal_enable_slave_tx_it(i2c_hal_context_t *hal) +{ + i2c_ll_slave_enable_tx_it(hal->dev); +} + +void i2c_hal_disable_slave_tx_it(i2c_hal_context_t *hal) +{ + i2c_ll_slave_disable_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_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); +} + +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); + //MSB + i2c_ll_set_data_mode(hal->dev, I2C_DATA_MODE_MSB_FIRST, I2C_DATA_MODE_MSB_FIRST); + //Reset fifo + i2c_ll_txfifo_rst(hal->dev); + i2c_ll_rxfifo_rst(hal->dev); +} + +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, 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 + i2c_ll_set_fifo_mode(hal->dev, true); + //MSB + i2c_ll_set_data_mode(hal->dev, I2C_DATA_MODE_MSB_FIRST, I2C_DATA_MODE_MSB_FIRST); + //Reset fifo + i2c_ll_txfifo_rst(hal->dev); + i2c_ll_rxfifo_rst(hal->dev); +} diff --git a/components/soc/src/hal/i2c_hal_iram.c b/components/soc/src/hal/i2c_hal_iram.c new file mode 100644 index 000000000..80c490009 --- /dev/null +++ b/components/soc/src/hal/i2c_hal_iram.c @@ -0,0 +1,44 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "hal/i2c_hal.h" + +void i2c_hal_master_handle_tx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event) +{ + 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); + } else if (*event == I2C_INTR_EVENT_END_DET) { + i2c_ll_master_clr_tx_it(hal->dev); + } +} + +void i2c_hal_master_handle_rx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event) +{ + 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); + } else if (*event == I2C_INTR_EVENT_END_DET) { + i2c_ll_master_clr_rx_it(hal->dev); + } +} + +void i2c_hal_slave_handle_event(i2c_hal_context_t *hal, i2c_intr_event_t *event) +{ + i2c_ll_slave_get_event(hal->dev, event); +} diff --git a/docs/Doxyfile b/docs/Doxyfile index 70ae701c4..37b13d151 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -111,6 +111,7 @@ INPUT = \ ../../components/soc/include/hal/sigmadelta_types.h \ ../../components/soc/include/hal/timer_types.h \ ../../components/soc/include/hal/ledc_types.h \ + ../../components/soc/include/hal/i2c_types.h \ ../../components/soc/esp32/include/soc/adc_channel.h \ ../../components/soc/esp32/include/soc/dac_channel.h \ ../../components/soc/esp32/include/soc/touch_channel.h \ diff --git a/examples/peripherals/i2c/i2c_self_test/main/i2c_example_main.c b/examples/peripherals/i2c/i2c_self_test/main/i2c_example_main.c index 7fe6e0ffc..e5d8de7a3 100644 --- a/examples/peripherals/i2c/i2c_self_test/main/i2c_example_main.c +++ b/examples/peripherals/i2c/i2c_self_test/main/i2c_example_main.c @@ -151,10 +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_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); + 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); } /** @@ -171,10 +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_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); + 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); } /** diff --git a/examples/peripherals/i2c/i2c_tools/main/cmd_i2ctools.c b/examples/peripherals/i2c/i2c_tools/main/cmd_i2ctools.c index 1030f4387..4adb0b9ea 100644 --- a/examples/peripherals/i2c/i2c_tools/main/cmd_i2ctools.c +++ b/examples/peripherals/i2c/i2c_tools/main/cmd_i2ctools.c @@ -113,8 +113,8 @@ static void register_i2cconfig(void) static int do_i2cdetect_cmd(int argc, char **argv) { - i2c_master_driver_initialize(); i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); + i2c_master_driver_initialize(); uint8_t address; printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n"); for (int i = 0; i < 128; i += 16) { @@ -184,8 +184,8 @@ static int do_i2cget_cmd(int argc, char **argv) } uint8_t *data = malloc(len); - i2c_master_driver_initialize(); i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); + i2c_master_driver_initialize(); i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); if (data_addr != -1) { @@ -262,8 +262,8 @@ static int do_i2cset_cmd(int argc, char **argv) /* Check data: "-d" option */ int len = i2cset_args.data->count; - i2c_master_driver_initialize(); i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); + i2c_master_driver_initialize(); i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, chip_addr << 1 | WRITE_BIT, ACK_CHECK_EN); @@ -328,8 +328,8 @@ static int do_i2cdump_cmd(int argc, char **argv) ESP_LOGE(TAG, "Wrong read size. Only support 1,2,4"); return 1; } - i2c_master_driver_initialize(); i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); + i2c_master_driver_initialize(); uint8_t data_addr; uint8_t data[4]; int32_t block[16];