diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index 9d43f98551..a6f049db78 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -108,6 +108,9 @@ if(CONFIG_SOC_I2C_SUPPORTED) "i2c/i2c_master.c" "i2c/i2c_common.c" ) + if(CONFIG_SOC_I2C_SUPPORT_SLAVE) + list(APPEND srcs "i2c/i2c_slave.c") + endif() list(APPEND ldfragments "i2c/linker.lf") endif() diff --git a/components/driver/i2c/i2c_common.c b/components/driver/i2c/i2c_common.c index 5f90a695df..f9cb44da59 100644 --- a/components/driver/i2c/i2c_common.c +++ b/components/driver/i2c/i2c_common.c @@ -37,7 +37,7 @@ typedef struct i2c_platform_t { static i2c_platform_t s_i2c_platform = {}; // singleton platform -esp_err_t i2c_acquire_bus_handle(i2c_port_num_t port_num, i2c_bus_handle_t *i2c_new_bus, i2c_bus_mode_t mode) +static esp_err_t s_i2c_bus_handle_aquire(i2c_port_num_t port_num, i2c_bus_handle_t *i2c_new_bus, i2c_bus_mode_t mode) { #if CONFIG_I2C_ENABLE_DEBUG_LOG esp_log_level_set(TAG, ESP_LOG_DEBUG); @@ -76,15 +76,41 @@ esp_err_t i2c_acquire_bus_handle(i2c_port_num_t port_num, i2c_bus_handle_t *i2c_ return ret; } -bool i2c_bus_occupied(i2c_port_num_t port_num) +static bool i2c_bus_occupied(i2c_port_num_t port_num) +{ + return s_i2c_platform.buses[port_num] != NULL; +} + +esp_err_t i2c_acquire_bus_handle(i2c_port_num_t port_num, i2c_bus_handle_t *i2c_new_bus, i2c_bus_mode_t mode) { bool bus_occupied = false; + bool bus_found = false; + esp_err_t ret = ESP_OK; _lock_acquire(&s_i2c_platform.mutex); - if (s_i2c_platform.buses[port_num]) { - bus_occupied = true; + if (port_num == -1) { + for (int i = 0; i < SOC_I2C_NUM; i++) { + bus_occupied = i2c_bus_occupied(i); + if (bus_occupied == false) { + ret = s_i2c_bus_handle_aquire(i, i2c_new_bus, mode); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "acquire bus failed"); + _lock_release(&s_i2c_platform.mutex); + return ret; + } + bus_found = true; + port_num = i; + break; + } + } + ESP_RETURN_ON_FALSE((bus_found == true), ESP_ERR_NOT_FOUND, TAG, "acquire bus failed, no free bus"); + } else { + ret = s_i2c_bus_handle_aquire(port_num, i2c_new_bus, mode); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "acquire bus failed"); + } } _lock_release(&s_i2c_platform.mutex); - return bus_occupied; + return ret; } esp_err_t i2c_release_bus_handle(i2c_bus_handle_t i2c_bus) @@ -205,12 +231,8 @@ esp_err_t i2c_common_set_pins(i2c_bus_handle_t handle) .pull_up_en = handle->pull_up_enable ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE, .pin_bit_mask = 1ULL << handle->sda_num, }; -#if CONFIG_IDF_TARGET_ESP32 - // on esp32, must enable internal pull-up - sda_conf.pull_up_en = GPIO_PULLUP_ENABLE; -#endif - ESP_RETURN_ON_ERROR(gpio_config(&sda_conf), TAG, "config GPIO failed"); ESP_RETURN_ON_ERROR(gpio_set_level(handle->sda_num, 1), TAG, "i2c sda pin set level failed"); + ESP_RETURN_ON_ERROR(gpio_config(&sda_conf), TAG, "config GPIO failed"); gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[handle->sda_num], PIN_FUNC_GPIO); esp_rom_gpio_connect_out_signal(handle->sda_num, i2c_periph_signal[port_id].sda_out_sig, 0, 0); esp_rom_gpio_connect_in_signal(handle->sda_num, i2c_periph_signal[port_id].sda_in_sig, 0); @@ -224,12 +246,8 @@ esp_err_t i2c_common_set_pins(i2c_bus_handle_t handle) .pull_up_en = handle->pull_up_enable ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE, .pin_bit_mask = 1ULL << handle->scl_num, }; -#if CONFIG_IDF_TARGET_ESP32 - // on esp32, must enable internal pull-up - scl_conf.pull_up_en = GPIO_PULLUP_ENABLE; -#endif - ESP_RETURN_ON_ERROR(gpio_config(&scl_conf), TAG, "config GPIO failed"); ESP_RETURN_ON_ERROR(gpio_set_level(handle->scl_num, 1), TAG, "i2c scl pin set level failed"); + ESP_RETURN_ON_ERROR(gpio_config(&scl_conf), TAG, "config GPIO failed"); gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[handle->scl_num], PIN_FUNC_GPIO); esp_rom_gpio_connect_out_signal(handle->scl_num, i2c_periph_signal[port_id].scl_out_sig, 0, 0); esp_rom_gpio_connect_in_signal(handle->scl_num, i2c_periph_signal[port_id].scl_in_sig, 0); diff --git a/components/driver/i2c/i2c_master.c b/components/driver/i2c/i2c_master.c index 929c7b45d9..2fa24a020a 100644 --- a/components/driver/i2c/i2c_master.c +++ b/components/driver/i2c/i2c_master.c @@ -35,7 +35,6 @@ #include "freertos/idf_additions.h" static const char *TAG = "i2c.master"; -static _lock_t s_i2c_bus_acquire; #define DIM(array) (sizeof(array)/sizeof(*array)) #define I2C_ADDRESS_TRANS_WRITE(device_address) (((device_address) << 1) | 0) @@ -785,39 +784,13 @@ esp_err_t i2c_new_master_bus(const i2c_master_bus_config_t *bus_config, i2c_mast ESP_RETURN_ON_FALSE(bus_config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE((bus_config->i2c_port < SOC_I2C_NUM || bus_config->i2c_port == -1), ESP_ERR_INVALID_ARG, TAG, "invalid i2c port number"); ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(bus_config->sda_io_num) && GPIO_IS_VALID_GPIO(bus_config->scl_io_num), ESP_ERR_INVALID_ARG, TAG, "invalid SDA/SCL pin number"); - bool bus_occupied = false; - bool bus_found = false; i2c_master = heap_caps_calloc(1, sizeof(i2c_master_bus_t) + 20 * sizeof(i2c_transaction_t), I2C_MEM_ALLOC_CAPS); ESP_RETURN_ON_FALSE(i2c_master, ESP_ERR_NO_MEM, TAG, "no memory for i2c master bus"); - _lock_acquire(&s_i2c_bus_acquire); - if (i2c_port_num == -1) { - for (int i = 0; i < SOC_I2C_NUM; i++) { - bus_occupied = i2c_bus_occupied(i); - if (bus_occupied == false) { - ret = i2c_acquire_bus_handle(i, &i2c_master->base, I2C_BUS_MODE_MASTER); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "acquire bus failed"); - _lock_release(&s_i2c_bus_acquire); - goto err; - } - bus_found = true; - i2c_port_num = i; - break; - } - } - ESP_GOTO_ON_FALSE((bus_found == true), ESP_ERR_NOT_FOUND, err, TAG, "acquire bus failed, no free bus"); - } else { - ret = i2c_acquire_bus_handle(i2c_port_num, &i2c_master->base, I2C_BUS_MODE_MASTER); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "acquire bus failed"); - _lock_release(&s_i2c_bus_acquire); - goto err; - } - } - _lock_release(&s_i2c_bus_acquire); + ESP_GOTO_ON_ERROR(i2c_acquire_bus_handle(i2c_port_num, &i2c_master->base, I2C_BUS_MODE_MASTER), err, TAG, "I2C bus acquire failed"); + i2c_port_num = i2c_master->base->port_num; i2c_hal_context_t *hal = &i2c_master->base->hal; i2c_master->base->scl_num = bus_config->scl_io_num; diff --git a/components/driver/i2c/i2c_private.h b/components/driver/i2c/i2c_private.h index bdf8e09a58..8d4688562d 100644 --- a/components/driver/i2c/i2c_private.h +++ b/components/driver/i2c/i2c_private.h @@ -16,6 +16,7 @@ #include "freertos/semphr.h" #include "freertos/task.h" #include "freertos/ringbuf.h" +#include "driver/i2c_slave.h" #include "esp_pm.h" #ifdef __cplusplus @@ -52,6 +53,7 @@ typedef struct i2c_bus_t i2c_bus_t; typedef struct i2c_master_bus_t i2c_master_bus_t; typedef struct i2c_bus_t *i2c_bus_handle_t; typedef struct i2c_master_dev_t i2c_master_dev_t; +typedef struct i2c_slave_dev_t i2c_slave_dev_t; typedef enum { I2C_BUS_MODE_MASTER = 0, @@ -153,6 +155,34 @@ struct i2c_master_dev_t { void *user_ctx; // Callback user context }; +typedef struct { + bool trans_complete; // Event of transaction complete + bool slave_stretch; // Event of slave stretch happens + bool addr_unmatch; // Event of address unmatched +} i2c_slave_evt_t; + +typedef struct { + uint8_t *buffer; // Pointer to the buffer need to be received in ISR + uint32_t rcv_fifo_cnt; // receive fifo count. +} i2c_slave_receive_t; + +struct i2c_slave_dev_t { + i2c_bus_t *base; // bus base class + SemaphoreHandle_t slv_rx_mux; // Mutex for slave rx direction + SemaphoreHandle_t slv_tx_mux; // Mutex for slave tx direction + RingbufHandle_t rx_ring_buf; // Handle for rx ringbuffer + RingbufHandle_t tx_ring_buf; // Handle for tx ringbuffer + uint8_t data_buf[SOC_I2C_FIFO_LEN]; // Data buffer for slave + uint32_t trans_data_length; // Send data length + i2c_slave_event_callbacks_t callbacks; // I2C slave callbacks + void *user_ctx; // Callback user context + i2c_slave_fifo_mode_t fifo_mode; // Slave fifo mode. + QueueHandle_t slv_evt_queue; // Event Queue used in slave nonfifo mode. + i2c_slave_evt_t slave_evt; // Slave event structure. + i2c_slave_receive_t receive_desc; // Slave receive descriptor + uint32_t already_receive_len; // Data length already received in ISR. +}; + /** * @brief Acquire I2C bus handle * @@ -198,14 +228,6 @@ esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, i2c_clock_source_t cl */ esp_err_t i2c_common_set_pins(i2c_bus_handle_t handle); -/** - * @brief Check whether I2C bus is occupied - * - * @param port_num I2C port number. - * @return true: occupied, otherwise, false. - */ -bool i2c_bus_occupied(i2c_port_num_t port_num); - #ifdef __cplusplus } #endif diff --git a/components/driver/i2c/i2c_slave.c b/components/driver/i2c/i2c_slave.c new file mode 100644 index 0000000000..e3bae30bc4 --- /dev/null +++ b/components/driver/i2c/i2c_slave.c @@ -0,0 +1,424 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_types.h" +#include "esp_intr_alloc.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/task.h" +#include "freertos/ringbuf.h" +#include "freertos/queue.h" +#include "hal/i2c_hal.h" +#include "soc/i2c_periph.h" +#include "esp_rom_gpio.h" +#include "driver/gpio.h" +#include "hal/gpio_ll.h" +#include "clk_ctrl_os.h" +#include "esp_private/esp_clk.h" +#include "driver/i2c_slave.h" +#include "i2c_private.h" +#include "esp_memory_utils.h" +#include "freertos/idf_additions.h" + +#if CONFIG_I2C_ENABLE_DEBUG_LOG +// The local log level must be defined before including esp_log.h +// Set the maximum log level for this source file +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#endif +#include "esp_log.h" +#include "esp_check.h" + +#define I2C_SLAVE_TIMEOUT_DEFAULT (32000) /* I2C slave timeout value, APB clock cycle number */ +#define I2C_FIFO_EMPTY_THRESH_VAL_DEFAULT (SOC_I2C_FIFO_LEN/2) +#define I2C_FIFO_FULL_THRESH_VAL_DEFAULT (SOC_I2C_FIFO_LEN/2) + +static const char *TAG = "i2c.slave"; + +static esp_err_t i2c_slave_bus_destroy(i2c_slave_dev_handle_t i2c_slave); + +#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE +static IRAM_ATTR void s_i2c_handle_clock_stretch(i2c_slave_dev_handle_t i2c_slave) +{ + i2c_hal_context_t *hal = &i2c_slave->base->hal; + if (i2c_slave->callbacks.on_stretch_occur) { + i2c_slave_stretch_event_data_t evt = { 0 }; + i2c_hal_context_t *hal = &i2c_slave->base->hal; + i2c_ll_slave_get_stretch_cause(hal->dev, &evt.stretch_cause); + i2c_slave->callbacks.on_stretch_occur(i2c_slave, &evt, i2c_slave->user_ctx); + } + i2c_ll_slave_clear_stretch(hal->dev); +} +#endif + +static IRAM_ATTR void s_i2c_handle_rx_fifo_wm(i2c_slave_dev_handle_t i2c_slave, i2c_slave_receive_t *t) +{ + i2c_hal_context_t *hal = &i2c_slave->base->hal; + uint32_t rx_fifo_cnt; + i2c_ll_get_rxfifo_cnt(hal->dev, &rx_fifo_cnt); + i2c_ll_read_rxfifo(hal->dev, i2c_slave->data_buf, rx_fifo_cnt); + memcpy(t->buffer + i2c_slave->already_receive_len, i2c_slave->data_buf, rx_fifo_cnt); + i2c_slave->already_receive_len += rx_fifo_cnt; + t->rcv_fifo_cnt -= rx_fifo_cnt; +} + +static IRAM_ATTR void s_i2c_handle_complete(i2c_slave_dev_handle_t i2c_slave, i2c_slave_receive_t *t, BaseType_t *do_yield) +{ + i2c_hal_context_t *hal = &i2c_slave->base->hal; + uint32_t rx_fifo_cnt; + i2c_ll_get_rxfifo_cnt(hal->dev, &rx_fifo_cnt); + if (rx_fifo_cnt != 0) { + i2c_ll_read_rxfifo(hal->dev, i2c_slave->data_buf, t->rcv_fifo_cnt); + memcpy(t->buffer + i2c_slave->already_receive_len, i2c_slave->data_buf, t->rcv_fifo_cnt); + i2c_slave->already_receive_len += t->rcv_fifo_cnt; + t->rcv_fifo_cnt -= t->rcv_fifo_cnt; + } + if (i2c_slave->callbacks.on_recv_done) { + + i2c_slave_rx_done_event_data_t edata = { + .buffer = t->buffer, + }; + i2c_slave->callbacks.on_recv_done(i2c_slave, &edata, i2c_slave->user_ctx); + xSemaphoreGiveFromISR(i2c_slave->slv_rx_mux, do_yield); + i2c_ll_disable_intr_mask(hal->dev, I2C_LL_SLAVE_RX_EVENT_INTR); + } +} + +static IRAM_ATTR void s_i2c_handle_tx_fifo_wm(i2c_slave_dev_handle_t i2c_slave, BaseType_t *do_yield) +{ + i2c_hal_context_t *hal = &i2c_slave->base->hal; + uint32_t tx_fifo_rem; + i2c_ll_get_txfifo_len(hal->dev, &tx_fifo_rem); + size_t size = 0; + uint8_t *data = (uint8_t *) xRingbufferReceiveUpToFromISR(i2c_slave->tx_ring_buf, &size, tx_fifo_rem); + if (data) { + i2c_ll_write_txfifo(hal->dev, data, size); + vRingbufferReturnItemFromISR(i2c_slave->tx_ring_buf, data, do_yield); + } + if (size <= i2c_slave->trans_data_length) { + portENTER_CRITICAL_ISR(&i2c_slave->base->spinlock); + i2c_slave->trans_data_length -= size; + portEXIT_CRITICAL_ISR(&i2c_slave->base->spinlock); + if (i2c_slave->trans_data_length == 0) { + i2c_ll_slave_disable_tx_it(hal->dev); + } + } else { + ESP_DRAM_LOGE(TAG, "I2C TX BUFFER SIZE ERROR"); + } +} + +static IRAM_ATTR void s_slave_fifo_isr_handler(uint32_t int_mask, void *arg, BaseType_t *do_yield) +{ + i2c_slave_dev_handle_t i2c_slave = (i2c_slave_dev_handle_t) arg; +#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE + if (int_mask & I2C_INTR_STRETCH) { + s_i2c_handle_clock_stretch(i2c_slave); + } +#endif + i2c_slave_receive_t *t = &i2c_slave->receive_desc; + if (int_mask & I2C_INTR_SLV_RXFIFO_WM) { + s_i2c_handle_rx_fifo_wm(i2c_slave, t); + } + if (int_mask & I2C_INTR_SLV_COMPLETE) { + s_i2c_handle_complete(i2c_slave, t, do_yield); + } + if (int_mask & I2C_INTR_SLV_TXFIFO_WM) { + s_i2c_handle_tx_fifo_wm(i2c_slave, do_yield); + } +} + +static IRAM_ATTR void s_slave_nonfifo_isr_handler(uint32_t int_mask, void *arg, BaseType_t *do_yield) +{ + i2c_slave_dev_handle_t i2c_slave = (i2c_slave_dev_handle_t) arg; + i2c_hal_context_t *hal = &i2c_slave->base->hal; + if (int_mask & I2C_INTR_STRETCH) { + i2c_slave->slave_evt.slave_stretch = 1; + i2c_ll_slave_clear_stretch(hal->dev); + } + + if (int_mask & I2C_INTR_SLV_COMPLETE) { + i2c_slave->slave_evt.trans_complete = 1; + } + xQueueSendFromISR(i2c_slave->slv_evt_queue, &i2c_slave->slave_evt, do_yield); +} + +static IRAM_ATTR void s_slave_isr_handle_default(void *arg) +{ + i2c_slave_dev_handle_t i2c_slave = (i2c_slave_dev_handle_t) arg; + i2c_hal_context_t *hal = &i2c_slave->base->hal; + portBASE_TYPE HPTaskAwoken = pdFALSE; + uint32_t int_mask = 0; + + i2c_ll_get_intr_mask(hal->dev, &int_mask); + i2c_ll_clear_intr_mask(hal->dev, int_mask); + if (int_mask == 0) { + return; + } +#if SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH + if (int_mask & I2C_INTR_UNMATCH) { + i2c_slave->slave_evt.addr_unmatch = 1; + ESP_DRAM_LOGE(TAG, "I2C address not match, trans failed"); + } +#endif + + if (i2c_slave->fifo_mode == I2C_SLAVE_NONFIFO) { + s_slave_nonfifo_isr_handler(int_mask, i2c_slave, &HPTaskAwoken); + } else { + s_slave_fifo_isr_handler(int_mask, i2c_slave, &HPTaskAwoken); + } + + //We only need to check here if there is a high-priority task needs to be switched. + if (HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR(); + } + +} + +esp_err_t i2c_new_slave_device(const i2c_slave_config_t *slave_config, i2c_slave_dev_handle_t *ret_handle) +{ +#if CONFIG_I2C_ENABLE_DEBUG_LOG + esp_log_level_set(TAG, ESP_LOG_DEBUG); +#endif + esp_err_t ret = ESP_OK; + i2c_slave_dev_t *i2c_slave = NULL; + ESP_RETURN_ON_FALSE(slave_config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(slave_config->sda_io_num) && GPIO_IS_VALID_GPIO(slave_config->scl_io_num), ESP_ERR_INVALID_ARG, TAG, "invalid SDA/SCL pin number"); + ESP_RETURN_ON_FALSE(slave_config->i2c_port < SOC_I2C_NUM || slave_config->i2c_port == -1, ESP_ERR_INVALID_ARG, TAG, "invalid i2c port number"); + ESP_RETURN_ON_FALSE((slave_config->send_buf_depth > 0), ESP_ERR_INVALID_ARG, TAG, "invalid SCL speed"); +#if SOC_I2C_SLAVE_SUPPORT_BROADCAST + ESP_GOTO_ON_FALSE(((slave_config->addr_bit_len != I2C_ADDR_BIT_LEN_10) || (!slave_config->flags.broadcast_en)), ESP_ERR_INVALID_STATE, err, TAG, "10bits address cannot used together with broadcast"); +#endif + + int i2c_port_num = slave_config->i2c_port; + i2c_slave = heap_caps_calloc(1, sizeof(i2c_slave_dev_t), I2C_MEM_ALLOC_CAPS); + ESP_RETURN_ON_FALSE(i2c_slave, ESP_ERR_NO_MEM, TAG, "no memory for i2c slave bus"); + + ESP_GOTO_ON_ERROR(i2c_acquire_bus_handle(i2c_port_num, &i2c_slave->base, I2C_BUS_MODE_SLAVE), err, TAG, "I2C bus acquire failed"); + + i2c_hal_context_t *hal = &i2c_slave->base->hal; + i2c_slave->base->scl_num = slave_config->scl_io_num; + i2c_slave->base->sda_num = slave_config->sda_io_num; +#if SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS + i2c_slave->fifo_mode = (slave_config->flags.access_ram_en == true) ? I2C_SLAVE_NONFIFO : I2C_SLAVE_FIFO; +#endif + +#if SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH + if (slave_config->flags.slave_unmatch_en) { + i2c_ll_enable_intr_mask(hal->dev, I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M); + } +#endif + + ESP_GOTO_ON_ERROR(i2c_common_set_pins(i2c_slave->base), err, TAG, "i2c slave set pins failed"); + + i2c_slave->tx_ring_buf = xRingbufferCreateWithCaps(slave_config->send_buf_depth, RINGBUF_TYPE_BYTEBUF, I2C_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(i2c_slave->tx_ring_buf != NULL, ESP_ERR_INVALID_STATE, err, TAG, "ringbuffer create failed"); + + i2c_slave->slv_rx_mux = xSemaphoreCreateBinaryWithCaps(I2C_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(i2c_slave->slv_rx_mux, ESP_ERR_NO_MEM, err, TAG, "No memory for binary semaphore"); + i2c_slave->slv_tx_mux = xSemaphoreCreateBinaryWithCaps(I2C_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(i2c_slave->slv_tx_mux, ESP_ERR_NO_MEM, err, TAG, "No memory for binary semaphore"); + i2c_slave->slv_evt_queue = xQueueCreateWithCaps(1, sizeof(i2c_slave_evt_t), I2C_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE((i2c_slave->slv_evt_queue != NULL), ESP_ERR_INVALID_STATE, err, TAG, "queue create failed"); + + int isr_flags = I2C_INTR_ALLOC_FLAG; + if (slave_config->intr_priority) { + isr_flags |= 1 << (slave_config->intr_priority); + } + ret = esp_intr_alloc_intrstatus(i2c_periph_signal[i2c_port_num].irq, I2C_INTR_ALLOC_FLAG, (uint32_t)i2c_ll_get_interrupt_status_reg(hal->dev), I2C_LL_SLAVE_EVENT_INTR, s_slave_isr_handle_default, i2c_slave, &i2c_slave->base->intr_handle); + ESP_GOTO_ON_ERROR(ret, err, TAG, "install i2c slave interrupt failed"); + + portENTER_CRITICAL(&i2c_slave->base->spinlock); + i2c_ll_clear_intr_mask(hal->dev, I2C_LL_SLAVE_EVENT_INTR); + i2c_hal_slave_init(hal); + +#if SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS + if (i2c_slave->fifo_mode == I2C_SLAVE_NONFIFO) { + i2c_ll_slave_set_fifo_mode(hal->dev, false); + i2c_ll_enable_mem_access_nonfifo(hal->dev, true); + } else { + i2c_ll_slave_set_fifo_mode(hal->dev, true); + i2c_ll_enable_mem_access_nonfifo(hal->dev, false); + } +#endif + + //Default, we enable hardware filter + i2c_ll_set_source_clk(hal->dev, slave_config->clk_source); + bool addr_10bit_en = slave_config->addr_bit_len != I2C_ADDR_BIT_LEN_7; + i2c_ll_set_slave_addr(hal->dev, slave_config->slave_addr, addr_10bit_en); +#if SOC_I2C_SLAVE_SUPPORT_BROADCAST + i2c_ll_slave_broadcast_enable(hal->dev, slave_config->flags.broadcast_en); +#endif + i2c_ll_set_txfifo_empty_thr(hal->dev, I2C_FIFO_EMPTY_THRESH_VAL_DEFAULT); + i2c_ll_set_rxfifo_full_thr(hal->dev, I2C_FIFO_FULL_THRESH_VAL_DEFAULT); + // set timing for data + i2c_ll_set_sda_timing(hal->dev, 10, 10); + i2c_ll_set_tout(hal->dev, I2C_SLAVE_TIMEOUT_DEFAULT); + +#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE + i2c_ll_slave_enable_scl_stretch(hal->dev, slave_config->flags.stretch_en); +#endif + i2c_ll_slave_tx_auto_start_en(hal->dev, true); + + i2c_ll_update(hal->dev); + portEXIT_CRITICAL(&i2c_slave->base->spinlock); + + xSemaphoreGive(i2c_slave->slv_rx_mux); + xSemaphoreGive(i2c_slave->slv_tx_mux); + *ret_handle = i2c_slave; + return ESP_OK; + +err: + if (i2c_slave) { + i2c_slave_bus_destroy(i2c_slave); + } + return ret; +} + +static esp_err_t i2c_slave_bus_destroy(i2c_slave_dev_handle_t i2c_slave) +{ + if (i2c_slave) { + if (i2c_slave->slv_rx_mux) { + vSemaphoreDeleteWithCaps(i2c_slave->slv_rx_mux); + i2c_slave->slv_rx_mux = NULL; + } + if (i2c_slave->slv_tx_mux) { + vSemaphoreDeleteWithCaps(i2c_slave->slv_tx_mux); + i2c_slave->slv_tx_mux = NULL; + } + if (i2c_slave->tx_ring_buf) { + vRingbufferDeleteWithCaps(i2c_slave->tx_ring_buf); + i2c_slave->tx_ring_buf = NULL; + } + if (i2c_slave->slv_evt_queue) { + vQueueDeleteWithCaps(i2c_slave->slv_evt_queue); + } + i2c_release_bus_handle(i2c_slave->base); + } + + free(i2c_slave); + return ESP_OK; +} + +esp_err_t i2c_del_slave_device(i2c_slave_dev_handle_t i2c_slave) +{ + ESP_RETURN_ON_FALSE(i2c_slave, ESP_ERR_INVALID_ARG, TAG, "i2c slave not initialized"); + int port_id = i2c_slave->base->port_num; + ESP_LOGD(TAG, "del i2c bus(%d)", port_id); + ESP_RETURN_ON_ERROR(i2c_slave_bus_destroy(i2c_slave), TAG, "destroy i2c bus failed"); + return ESP_OK; +} + +esp_err_t i2c_slave_transmit(i2c_slave_dev_handle_t i2c_slave, const uint8_t *data, int size, int xfer_timeout_ms) +{ + ESP_RETURN_ON_FALSE(i2c_slave, ESP_ERR_INVALID_ARG, TAG, "i2c slave not initialized"); + ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "invalid data buffer"); + ESP_RETURN_ON_FALSE((i2c_slave->fifo_mode == I2C_SLAVE_FIFO), ESP_ERR_NOT_SUPPORTED, TAG, "non-fifo mode is not suppored in this API, please set access_ram_en to false"); + esp_err_t ret = ESP_OK; + i2c_hal_context_t *hal = &i2c_slave->base->hal; + TickType_t wait_ticks = (xfer_timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(xfer_timeout_ms); + + ESP_RETURN_ON_FALSE(xSemaphoreTake(i2c_slave->slv_tx_mux, wait_ticks) == pdTRUE, ESP_ERR_TIMEOUT, TAG, "transmit timeout"); + ESP_GOTO_ON_FALSE(xRingbufferSend(i2c_slave->tx_ring_buf, data, size, wait_ticks) == pdTRUE, ESP_ERR_INVALID_STATE, err, TAG, "no space in ringbuffer"); + portENTER_CRITICAL(&i2c_slave->base->spinlock); + i2c_slave->trans_data_length += size; + i2c_ll_enable_intr_mask(hal->dev, I2C_LL_SLAVE_TX_EVENT_INTR); + portEXIT_CRITICAL(&i2c_slave->base->spinlock); +err: + xSemaphoreGive(i2c_slave->slv_tx_mux); + return ret; +} + +esp_err_t i2c_slave_receive(i2c_slave_dev_handle_t i2c_slave, uint8_t *data, size_t receive_size) +{ + ESP_RETURN_ON_FALSE(i2c_slave, ESP_ERR_INVALID_ARG, TAG, "i2c slave not initialized"); + ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "invalid data buffer"); + ESP_RETURN_ON_FALSE((i2c_slave->fifo_mode == I2C_SLAVE_FIFO), ESP_ERR_NOT_SUPPORTED, TAG, "non-fifo mode is not suppored in this API, please set access_ram_en to false"); +#if CONFIG_I2C_ISR_IRAM_SAFE + ESP_RETURN_ON_FALSE(esp_ptr_internal(data), ESP_ERR_INVALID_ARG, TAG, "buffer must locate in internal RAM if IRAM_SAFE is enabled"); +#endif + i2c_hal_context_t *hal = &i2c_slave->base->hal; + + xSemaphoreTake(i2c_slave->slv_rx_mux, portMAX_DELAY); + i2c_slave_receive_t *t = &i2c_slave->receive_desc; + t->buffer = data; + t->rcv_fifo_cnt = receive_size; + i2c_slave->already_receive_len = 0; + // Clear all interrupt raw bits before enable, avoid previous bus data affects interrupt. + i2c_ll_clear_intr_mask(hal->dev, I2C_LL_SLAVE_RX_EVENT_INTR); + i2c_ll_enable_intr_mask(hal->dev, I2C_LL_SLAVE_RX_EVENT_INTR); + + return ESP_OK; +} + +#if SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS + +esp_err_t i2c_slave_read_ram(i2c_slave_dev_handle_t i2c_slave, uint8_t ram_offset, uint8_t *data, size_t receive_size) +{ + ESP_RETURN_ON_FALSE(i2c_slave, ESP_ERR_INVALID_ARG, TAG, "i2c slave not initialized"); + ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "invalid data buffer"); + ESP_RETURN_ON_FALSE((ram_offset + receive_size <= SOC_I2C_FIFO_LEN), ESP_ERR_INVALID_SIZE, TAG, "don't read data cross fifo boundary, see `SOC_I2C_FIFO_LEN`"); + ESP_RETURN_ON_FALSE((i2c_slave->fifo_mode == I2C_SLAVE_NONFIFO), ESP_ERR_NOT_SUPPORTED, TAG, "fifo mode is not suppored in this API, please set access_ram_en to true"); + i2c_hal_context_t *hal = &i2c_slave->base->hal; + + uint32_t fifo_size = 0; + portENTER_CRITICAL(&i2c_slave->base->spinlock); + i2c_ll_get_rxfifo_cnt(hal->dev, &fifo_size); + if (receive_size > fifo_size) { + ESP_LOGE(TAG, "receive size is so large that fifo has not so much data to get"); + portEXIT_CRITICAL(&i2c_slave->base->spinlock); + return ESP_ERR_INVALID_SIZE; + } + i2c_ll_read_by_nonfifo(hal->dev, ram_offset, data, fifo_size); + portEXIT_CRITICAL(&i2c_slave->base->spinlock); + + return ESP_OK; +} + +esp_err_t i2c_slave_write_ram(i2c_slave_dev_handle_t i2c_slave, uint8_t ram_offset, const uint8_t *data, size_t size) +{ + ESP_RETURN_ON_FALSE(i2c_slave, ESP_ERR_INVALID_ARG, TAG, "i2c slave not initialized"); + ESP_RETURN_ON_FALSE(data, ESP_ERR_INVALID_ARG, TAG, "invalid data buffer"); + ESP_RETURN_ON_FALSE((i2c_slave->fifo_mode == I2C_SLAVE_NONFIFO), ESP_ERR_NOT_SUPPORTED, TAG, "fifo mode is not suppored in this API, please set access_ram_en to true"); + + i2c_hal_context_t *hal = &i2c_slave->base->hal; + ESP_RETURN_ON_FALSE(xSemaphoreTake(i2c_slave->slv_tx_mux, portMAX_DELAY) == pdTRUE, ESP_ERR_TIMEOUT, TAG, "write to ram lock timeout"); + uint32_t fifo_size = 0; + i2c_ll_txfifo_rst(hal->dev); + i2c_ll_get_txfifo_len(hal->dev, &fifo_size); + if (ram_offset + fifo_size < size) { + ESP_EARLY_LOGE(TAG, "No extra fifo to fill your buffer, please split your buffer"); + return ESP_ERR_INVALID_SIZE; + } + i2c_ll_write_by_nonfifo(hal->dev, ram_offset, data, size); + xSemaphoreGive(i2c_slave->slv_tx_mux); + return ESP_OK; +} + +#endif + +esp_err_t i2c_slave_register_event_callbacks(i2c_slave_dev_handle_t i2c_slave, const i2c_slave_event_callbacks_t *cbs, void *user_data) +{ + ESP_RETURN_ON_FALSE(i2c_slave != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c slave handle not initialized"); + ESP_RETURN_ON_FALSE(cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + +#if CONFIG_I2C_ISR_IRAM_SAFE +#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE + if (cbs->on_stretch_occur) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_stretch_occur), ESP_ERR_INVALID_ARG, TAG, "i2c stretch occur callback not in IRAM"); + } +#endif // SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE + if (cbs->on_recv_done) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_recv_done), ESP_ERR_INVALID_ARG, TAG, "i2c receive done callback not in IRAM"); + } + if (user_data) { + ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM"); + } +#endif // CONFIG_I2C_ISR_IRAM_SAFE + + memcpy(&(i2c_slave->callbacks), cbs, sizeof(i2c_slave_event_callbacks_t)); + i2c_slave->user_ctx = user_data; + return ESP_OK; +} diff --git a/components/driver/i2c/include/driver/i2c_master.h b/components/driver/i2c/include/driver/i2c_master.h index 48471ddd67..94f3f78834 100644 --- a/components/driver/i2c/include/driver/i2c_master.h +++ b/components/driver/i2c/include/driver/i2c_master.h @@ -109,7 +109,7 @@ esp_err_t i2c_master_bus_rm_device(i2c_master_dev_handle_t handle); * @param[in] xfer_timeout_ms Wait timeout, in ms. Note: -1 means wait forever. * @return * - ESP_OK: I2C master transmit success - * - ESP_ERR_INVALID_ARG: I2c master transmit parameter invalid. + * - ESP_ERR_INVALID_ARG: I2C master transmit parameter invalid. * - ESP_ERR_TIMEOUT: Operation timeout(larger than xfer_timeout_ms) because the bus is busy or hardware crash. */ esp_err_t i2c_master_transmit(i2c_master_dev_handle_t i2c_dev, const uint8_t *write_buffer, size_t write_size, int xfer_timeout_ms); @@ -130,7 +130,7 @@ esp_err_t i2c_master_transmit(i2c_master_dev_handle_t i2c_dev, const uint8_t *wr * @param[in] xfer_timeout_ms Wait timeout, in ms. Note: -1 means wait forever. * @return * - ESP_OK: I2C master transmit-receive success - * - ESP_ERR_INVALID_ARG: I2c master transmit parameter invalid. + * - ESP_ERR_INVALID_ARG: I2C master transmit parameter invalid. * - ESP_ERR_TIMEOUT: Operation timeout(larger than xfer_timeout_ms) because the bus is busy or hardware crash. */ esp_err_t i2c_master_transmit_receive(i2c_master_dev_handle_t i2c_dev, const uint8_t *write_buffer, size_t write_size, uint8_t *read_buffer, size_t read_size, int xfer_timeout_ms); @@ -149,7 +149,7 @@ esp_err_t i2c_master_transmit_receive(i2c_master_dev_handle_t i2c_dev, const uin * @param[in] xfer_timeout_ms Wait timeout, in ms. Note: -1 means wait forever. * @return * - ESP_OK: I2C master receive success - * - ESP_ERR_INVALID_ARG: I2c master receive parameter invalid. + * - ESP_ERR_INVALID_ARG: I2C master receive parameter invalid. * - ESP_ERR_TIMEOUT: Operation timeout(larger than xfer_timeout_ms) because the bus is busy or hardware crash. */ esp_err_t i2c_master_receive(i2c_master_dev_handle_t i2c_dev, uint8_t *read_buffer, size_t read_size, int xfer_timeout_ms); diff --git a/components/driver/i2c/include/driver/i2c_slave.h b/components/driver/i2c/include/driver/i2c_slave.h new file mode 100644 index 0000000000..70ba813ce6 --- /dev/null +++ b/components/driver/i2c/include/driver/i2c_slave.h @@ -0,0 +1,166 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "driver/i2c_types.h" +#include "hal/gpio_types.h" +#include "soc/soc_caps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief I2C slave specific configurations + */ +typedef struct { + i2c_port_num_t i2c_port; /*!< I2C port number, `-1` for auto selecting */ + gpio_num_t sda_io_num; /*!< SDA IO number used by I2C bus */ + gpio_num_t scl_io_num; /*!< SCL IO number used by I2C bus */ + i2c_clock_source_t clk_source; /*!< Clock source of I2C bus. */ + uint32_t send_buf_depth; /*!< Depth of internal transfer ringbuffer, increase this value can support more transfers pending in the background */ + uint16_t slave_addr; /*!< I2C slave address */ + i2c_addr_bit_len_t addr_bit_len; /*!< I2C slave address in bit length */ + int intr_priority; /*!< I2C interrupt priority, if set to 0, driver will select the default priority (1,2,3). */ + struct { +#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE + uint32_t stretch_en:1; /*!< Enable slave stretch */ +#endif +#if SOC_I2C_SLAVE_SUPPORT_BROADCAST + uint32_t broadcast_en:1; /*!< I2C slave enable broadcast */ +#endif +#if SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS + uint32_t access_ram_en:1; /*!< Can get access to I2C RAM directly */ +#endif +#if SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH + uint32_t slave_unmatch_en:1; /*!< Can trigger unmatch interrupt when slave address does not match what master sends*/ +#endif + } flags; +} i2c_slave_config_t; + +/** + * @brief Group of I2C slave callbacks (e.g. get i2c slave stretch cause). But take care of potential concurrency issues. + * @note The callbacks are all running under ISR context + * @note When CONFIG_I2C_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. + * The variables used in the function should be in the SRAM as well. + */ +typedef struct { +#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE + i2c_slave_stretch_callback_t on_stretch_occur; /*!< I2C slave stretched callback */ +#endif + i2c_slave_received_callback_t on_recv_done; /*!< I2C slave receive done callback */ +} i2c_slave_event_callbacks_t; + +/** + * @brief Initialize an I2C slave device + * + * @param[in] slave_config I2C slave device configurations + * @param[out] ret_handle Return a generic I2C device handle + * @return + * - ESP_OK: I2C slave device initialized successfully + * - ESP_ERR_INVALID_ARG: I2C device initialization failed because of invalid argument. + * - ESP_ERR_NO_MEM: Create I2C device failed because of out of memory. + */ +esp_err_t i2c_new_slave_device(const i2c_slave_config_t *slave_config, i2c_slave_dev_handle_t *ret_handle); + +/** + * @brief Deinitialize the I2C slave device + * + * @param[in] i2c_slave I2C slave device handle that created by `i2c_new_slave_device`. + * @return + * - ESP_OK: Delete I2C device successfully. + * - ESP_ERR_INVALID_ARG: I2C device initialization failed because of invalid argument. + */ +esp_err_t i2c_del_slave_device(i2c_slave_dev_handle_t i2c_slave); + +/** + * @brief Read bytes from I2C internal buffer. Start a job to receive I2C data. + * + * @note This function is non-blocking, it initiates a new receive job and then returns. + * User should check the received data from the `on_recv_done` callback that registered by `i2c_slave_register_event_callbacks()`. + * + * @param[in] i2c_slave I2C slave device handle that created by `i2c_new_slave_device`. + * @param[out] data Buffer to store data from I2C fifo. Should be valid until `on_recv_done` is triggered. + * @param[in] buffer_size Buffer size of data that provided by users. + * @return + * - ESP_OK: I2C slave receive success. + * - ESP_ERR_INVALID_ARG: I2C slave receive parameter invalid. + * - ESP_ERR_NOT_SUPPORTED: This function should be work in fifo mode, but I2C_SLAVE_NONFIFO mode is configured + */ +esp_err_t i2c_slave_receive(i2c_slave_dev_handle_t i2c_slave, uint8_t *data, size_t buffer_size); + +/** + * @brief Write bytes to internal ringbuffer of the I2C slave data. When the TX fifo empty, the ISR will + * fill the hardware FIFO with the internal ringbuffer's data. + * + * @note If you connect this slave device to some master device, the data transaction direction is from slave + * device to master device. + * + * @param[in] i2c_slave I2C slave device handle that created by `i2c_new_slave_device`. + * @param[in] data Buffer to write to slave fifo, can pickup by master. Can be freed after this function returns. Equal or larger than `size`. + * @param[in] size In bytes, of `data` buffer. + * @param[in] xfer_timeout_ms Wait timeout, in ms. Note: -1 means wait forever. + * @return + * - ESP_OK: I2C slave transmit success. + * - ESP_ERR_INVALID_ARG: I2C slave transmit parameter invalid. + * - ESP_ERR_TIMEOUT: Operation timeout(larger than xfer_timeout_ms) because the device is busy or hardware crash. + * - ESP_ERR_NOT_SUPPORTED: This function should be work in fifo mode, but I2C_SLAVE_NONFIFO mode is configured + */ +esp_err_t i2c_slave_transmit(i2c_slave_dev_handle_t i2c_slave, const uint8_t *data, int size, int xfer_timeout_ms); + +/** + * @brief Set I2C slave event callbacks for I2C slave channel. + * + * @note User can deregister a previously registered callback by calling this function and setting the callback member in the `cbs` structure to NULL. + * @note When CONFIG_I2C_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. + * The variables used in the function should be in the SRAM as well. The `user_data` should also reside in SRAM. + * + * @param[in] i2c_slave I2C slave device handle that created by `i2c_new_slave_device`. + * @param[in] cbs Group of callback functions + * @param[in] user_data User data, which will be passed to callback functions directly + * @return + * - ESP_OK: Set I2C transaction callbacks successfully + * - ESP_ERR_INVALID_ARG: Set I2C transaction callbacks failed because of invalid argument + * - ESP_FAIL: Set I2C transaction callbacks failed because of other error + */ +esp_err_t i2c_slave_register_event_callbacks(i2c_slave_dev_handle_t i2c_slave, const i2c_slave_event_callbacks_t *cbs, void *user_data); + +#if SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS +/** + * @brief Read bytes from I2C internal ram. This can be only used when `access_ram_en` in configuration structure set to true. + * + * @param[in] i2c_slave I2C slave device handle that created by `i2c_new_slave_device`. + * @param[in] ram_address The offset of RAM (Cannot larger than I2C RAM memory) + * @param[out] data Buffer to store data read from I2C ram. + * @param[in] receive_size Received size from RAM. + * @return + * - ESP_OK: I2C slave transmit success. + * - ESP_ERR_INVALID_ARG: I2C slave transmit parameter invalid. + * - ESP_ERR_NOT_SUPPORTED: This function should be work in non-fifo mode, but I2C_SLAVE_FIFO mode is configured + */ +esp_err_t i2c_slave_read_ram(i2c_slave_dev_handle_t i2c_slave, uint8_t ram_address, uint8_t *data, size_t receive_size); + +/** + * @brief Write bytes to I2C internal ram. This can be only used when `access_ram_en` in configuration structure set to true. + * + * @param[in] i2c_slave I2C slave device handle that created by `i2c_new_slave_device`. + * @param[in] ram_address The offset of RAM (Cannot larger than I2C RAM memory) + * @param[in] data Buffer to fill. + * @param[in] size Received size from RAM. + * @return + * - ESP_OK: I2C slave transmit success. + * - ESP_ERR_INVALID_ARG: I2C slave transmit parameter invalid. + * - ESP_ERR_INVALID_SIZE: Write size is larger than + * - ESP_ERR_NOT_SUPPORTED: This function should be work in non-fifo mode, but I2C_SLAVE_FIFO mode is configured + */ +esp_err_t i2c_slave_write_ram(i2c_slave_dev_handle_t i2c_slave, uint8_t ram_address, const uint8_t *data, size_t size); + +#endif +#ifdef __cplusplus +} +#endif diff --git a/components/driver/i2c/include/driver/i2c_types.h b/components/driver/i2c/include/driver/i2c_types.h index dd1683852b..6e11cf8c2e 100644 --- a/components/driver/i2c/include/driver/i2c_types.h +++ b/components/driver/i2c/include/driver/i2c_types.h @@ -51,6 +51,11 @@ typedef struct i2c_master_bus_t *i2c_master_bus_handle_t; */ typedef struct i2c_master_dev_t *i2c_master_dev_handle_t; +/** + * @brief Type of I2C slave device handle + */ +typedef struct i2c_slave_dev_t *i2c_slave_dev_handle_t; + /** * @brief Data type used in I2C event callback */ @@ -69,6 +74,46 @@ typedef struct { */ typedef bool (*i2c_master_callback_t)(i2c_master_dev_handle_t i2c_dev, const i2c_master_event_data_t *evt_data, void *arg); +/** + * @brief Event structure used in I2C slave + */ +typedef struct { + uint8_t *buffer; +} i2c_slave_rx_done_event_data_t; + +/** + * @brief Callback signature for I2C slave. + * + * @param[in] i2c_slave Handle for I2C slave. + * @param[out] evt_data I2C capture event data, fed by driver + * @param[in] user_ctx User data, set in `i2c_slave_register_event_callbacks()` + * + * @return Whether a high priority task has been waken up by this function + */ +typedef bool (*i2c_slave_received_callback_t)(i2c_slave_dev_handle_t i2c_slave, const i2c_slave_rx_done_event_data_t *evt_data, void *arg); + +#if SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE + +/** + * @brief Stretch cause event structure used in I2C slave + */ +typedef struct { + i2c_slave_stretch_cause_t stretch_cause; +} i2c_slave_stretch_event_data_t; + +/** + * @brief Callback signature for I2C slave stretch. + * + * @param[in] i2c_slave Handle for I2C slave. + * @param[out] evt_cause I2C capture event cause, fed by driver + * @param[in] user_ctx User data, set in `i2c_slave_register_event_callbacks()` + * + * @return Whether a high priority task has been waken up by this function + */ +typedef bool (*i2c_slave_stretch_callback_t)(i2c_slave_dev_handle_t i2c_slave, const i2c_slave_stretch_event_data_t *evt_cause, void *arg); + +#endif + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32/include/hal/i2c_ll.h b/components/hal/esp32/include/hal/i2c_ll.h index 4e327b82ba..9a2e89ebea 100644 --- a/components/hal/esp32/include/hal/i2c_ll.h +++ b/components/hal/esp32/include/hal/i2c_ll.h @@ -45,24 +45,29 @@ typedef union { #define I2C_LL_CMD_END 4 /*!slave_addr.en_10bit = addr_10bit_en; if (addr_10bit_en) { - uint8_t addr_14_7 = (slave_addr & 0xff) << 7; + uint16_t addr_14_7 = (slave_addr & 0xff) << 7; uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) || 0x78; hw->slave_addr.addr = addr_14_7 || addr_6_0; } else { @@ -368,6 +373,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr) */ static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr) { + hw->fifo_conf.nonfifo_rx_thres = full_thr; hw->fifo_conf.rx_fifo_full_thrhd = full_thr; } diff --git a/components/hal/esp32c2/include/hal/i2c_ll.h b/components/hal/esp32c2/include/hal/i2c_ll.h index c2d2010f1d..8958be0d2e 100644 --- a/components/hal/esp32c2/include/hal/i2c_ll.h +++ b/components/hal/esp32c2/include/hal/i2c_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -47,23 +47,17 @@ typedef union { #define I2C_LL_CMD_END 4 /*!ctr.addr_broadcasting_en = broadcast_en; } +/** + * @brief Get the cause of SCL clock stretching in slave mode + * + * @param hw Beginning address of the peripheral registers + * @param stretch_cause Pointer to stretch cause in the slave mode. + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_get_stretch_cause(i2c_dev_t *hw, i2c_slave_stretch_cause_t *stretch_cause) +{ + switch (hw->sr.stretch_cause) + { + case 0: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_ADDRESS_MATCH; + break; + case 1: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_TX_EMPTY; + break; + case 2: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_RX_FULL; + break; + case 3: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_SENDING_ACK; + break; + default: + HAL_ASSERT(false); + break; + } +} + /** * @brief Configure I2C slave address * @@ -400,6 +430,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr) */ static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr) { + hw->fifo_conf.fifo_prt_en = 1; hw->fifo_conf.rx_fifo_wm_thrhd = full_thr; } diff --git a/components/hal/esp32c6/include/hal/i2c_ll.h b/components/hal/esp32c6/include/hal/i2c_ll.h index db301dceec..80e7738b69 100644 --- a/components/hal/esp32c6/include/hal/i2c_ll.h +++ b/components/hal/esp32c6/include/hal/i2c_ll.h @@ -49,31 +49,31 @@ typedef union { #define I2C_LL_CMD_END 4 /*!ctr.addr_broadcasting_en = broadcast_en; } +/** + * @brief Get the cause of SCL clock stretching in slave mode + * + * @param hw Beginning address of the peripheral registers + * @param stretch_cause Pointer to stretch cause in the slave mode. + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_get_stretch_cause(i2c_dev_t *hw, i2c_slave_stretch_cause_t *stretch_cause) +{ + switch (hw->sr.stretch_cause) + { + case 0: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_ADDRESS_MATCH; + break; + case 1: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_TX_EMPTY; + break; + case 2: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_RX_FULL; + break; + case 3: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_SENDING_ACK; + break; + default: + HAL_ASSERT(false); + break; + } +} + /** * @brief Configure I2C slave address * @@ -312,7 +343,7 @@ static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, boo { hw->slave_addr.addr_10bit_en = addr_10bit_en; if (addr_10bit_en) { - uint8_t addr_14_7 = (slave_addr & 0xff) << 7; + uint16_t addr_14_7 = (slave_addr & 0xff) << 7; uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) | 0x78; hw->slave_addr.slave_addr = addr_14_7 | addr_6_0; hw->ctr.addr_10bit_rw_check_en = addr_10bit_en; @@ -404,6 +435,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr) */ static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr) { + hw->fifo_conf.fifo_prt_en = 1; hw->fifo_conf.rxfifo_wm_thrhd = full_thr; } diff --git a/components/hal/esp32h2/include/hal/i2c_ll.h b/components/hal/esp32h2/include/hal/i2c_ll.h index 70214524fe..1ed9ecddc0 100644 --- a/components/hal/esp32h2/include/hal/i2c_ll.h +++ b/components/hal/esp32h2/include/hal/i2c_ll.h @@ -47,32 +47,32 @@ typedef union { #define I2C_LL_CMD_END 4 /*!ctr.addr_broadcasting_en = broadcast_en; } +/** + * @brief Get the cause of SCL clock stretching in slave mode + * + * @param hw Beginning address of the peripheral registers + * @param stretch_cause Pointer to stretch cause in the slave mode. + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_get_stretch_cause(i2c_dev_t *hw, i2c_slave_stretch_cause_t *stretch_cause) +{ + switch (hw->sr.stretch_cause) + { + case 0: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_ADDRESS_MATCH; + break; + case 1: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_TX_EMPTY; + break; + case 2: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_RX_FULL; + break; + case 3: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_SENDING_ACK; + break; + default: + HAL_ASSERT(false); + break; + } +} + /** * @brief Configure I2C slave address * @@ -308,7 +339,7 @@ static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, boo { hw->slave_addr.addr_10bit_en = addr_10bit_en; if (addr_10bit_en) { - uint8_t addr_14_7 = (slave_addr & 0xff) << 7; + uint16_t addr_14_7 = (slave_addr & 0xff) << 7; uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) | 0x78; hw->slave_addr.slave_addr = addr_14_7 | addr_6_0; hw->ctr.addr_10bit_rw_check_en = addr_10bit_en; @@ -400,6 +431,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr) */ static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr) { + hw->fifo_conf.fifo_prt_en = 1; hw->fifo_conf.rxfifo_wm_thrhd = full_thr; } diff --git a/components/hal/esp32p4/include/hal/i2c_ll.h b/components/hal/esp32p4/include/hal/i2c_ll.h index 636f27f4a0..5888db147e 100644 --- a/components/hal/esp32p4/include/hal/i2c_ll.h +++ b/components/hal/esp32p4/include/hal/i2c_ll.h @@ -47,18 +47,24 @@ typedef union { #define I2C_LL_CMD_END 4 /*!slave_addr.addr_10bit_en = addr_10bit_en; if (addr_10bit_en) { - uint8_t addr_14_7 = (slave_addr & 0xff) << 7; + uint16_t addr_14_7 = (slave_addr & 0xff) << 7; uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) | 0x78; hw->slave_addr.slave_addr = addr_14_7 | addr_6_0; hw->ctr.addr_10bit_rw_check_en = addr_10bit_en; @@ -411,6 +417,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr) */ static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr) { + hw->fifo_conf.fifo_prt_en = 1; hw->fifo_conf.rxfifo_wm_thrhd = full_thr; } diff --git a/components/hal/esp32s2/include/hal/i2c_ll.h b/components/hal/esp32s2/include/hal/i2c_ll.h index 07fe5b419d..d45c4cfd05 100644 --- a/components/hal/esp32s2/include/hal/i2c_ll.h +++ b/components/hal/esp32s2/include/hal/i2c_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -44,24 +44,29 @@ typedef union { #define I2C_LL_CMD_END 4 /*!slave_addr.en_10bit = addr_10bit_en; if (addr_10bit_en) { - uint8_t addr_14_7 = (slave_addr & 0xff) << 7; - uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) || 0x78; - hw->slave_addr.addr = addr_14_7 || addr_6_0; + uint16_t addr_14_7 = (slave_addr & 0xff) << 7; + uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) | 0x78; + hw->slave_addr.addr = addr_14_7 | addr_6_0; } else { hw->slave_addr.addr = slave_addr; } @@ -356,6 +375,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr) */ static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr) { + hw->fifo_conf.fifo_prt_en = 1; hw->fifo_conf.rx_fifo_wm_thrhd = full_thr; } diff --git a/components/hal/esp32s3/include/hal/i2c_ll.h b/components/hal/esp32s3/include/hal/i2c_ll.h index 8c1b862bf7..374c8c6e04 100644 --- a/components/hal/esp32s3/include/hal/i2c_ll.h +++ b/components/hal/esp32s3/include/hal/i2c_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -48,18 +48,23 @@ typedef union { #define I2C_LL_CMD_END 4 /*!ctr.addr_broadcasting_en = broadcast_en; } +/** + * @brief Get the cause of SCL clock stretching in slave mode + * + * @param hw Beginning address of the peripheral registers + * @param stretch_cause Pointer to stretch cause in the slave mode. + * + * @return None + */ +__attribute__((always_inline)) +static inline void i2c_ll_slave_get_stretch_cause(i2c_dev_t *hw, i2c_slave_stretch_cause_t *stretch_cause) +{ + switch (hw->sr.stretch_cause) + { + case 0: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_ADDRESS_MATCH; + break; + case 1: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_TX_EMPTY; + break; + case 2: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_RX_FULL; + break; + case 3: + *stretch_cause = I2C_SLAVE_STRETCH_CAUSE_SENDING_ACK; + break; + default: + HAL_ASSERT(false); + break; + } +} + /** * @brief Configure I2C slave address * @@ -301,7 +337,7 @@ static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, boo { hw->slave_addr.addr_10bit_en = addr_10bit_en; if (addr_10bit_en) { - uint8_t addr_14_7 = (slave_addr & 0xff) << 7; + uint16_t addr_14_7 = (slave_addr & 0xff) << 7; uint8_t addr_6_0 = ((slave_addr & 0x300) >> 8) | 0x78; hw->slave_addr.slave_addr = addr_14_7 | addr_6_0; hw->ctr.addr_10bit_rw_check_en = addr_10bit_en; @@ -393,6 +429,7 @@ static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr) */ static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr) { + hw->fifo_conf.fifo_prt_en = 1; hw->fifo_conf.rxfifo_wm_thrhd = full_thr; } diff --git a/components/hal/include/hal/i2c_types.h b/components/hal/include/hal/i2c_types.h index ef66199ce3..fba2ad0bad 100644 --- a/components/hal/include/hal/i2c_types.h +++ b/components/hal/include/hal/i2c_types.h @@ -87,6 +87,16 @@ typedef enum { I2C_MASTER_ACK_MAX, } i2c_ack_type_t; +/** + * @brief Enum for I2C slave stretch causes + */ +typedef enum { + I2C_SLAVE_STRETCH_CAUSE_ADDRESS_MATCH = 0, /*!< Stretching SCL low when the slave is read by the master and the address just matched */ + I2C_SLAVE_STRETCH_CAUSE_TX_EMPTY = 1, /*!< Stretching SCL low when TX FIFO is empty in slave mode */ + I2C_SLAVE_STRETCH_CAUSE_RX_FULL = 2, /*!< Stretching SCL low when RX FIFO is full in slave mode */ + I2C_SLAVE_STRETCH_CAUSE_SENDING_ACK = 3, /*!< Stretching SCL low when slave sending ACK */ +} i2c_slave_stretch_cause_t; + #if SOC_I2C_SUPPORTED /** * @brief I2C group clock source diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index 0e433b9c2b..9a5ea3f9fc 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -419,6 +419,18 @@ config SOC_I2C_SUPPORT_10BIT_ADDR bool default y +config SOC_I2C_SLAVE_SUPPORT_BROADCAST + bool + default y + +config SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE + bool + default y + +config SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS + bool + default y + config SOC_I2S_NUM int default 1 diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 27ac1025f5..63e518f654 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -196,6 +196,9 @@ #define SOC_I2C_SUPPORT_XTAL (1) #define SOC_I2C_SUPPORT_RTC (1) #define SOC_I2C_SUPPORT_10BIT_ADDR (1) +#define SOC_I2C_SLAVE_SUPPORT_BROADCAST (1) +#define SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE (1) +#define SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS (1) /*-------------------------- I2S CAPS ----------------------------------------*/ #define SOC_I2S_NUM (1U) diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index fd64e06298..cb4f3353cd 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -539,6 +539,22 @@ config SOC_I2C_SUPPORT_10BIT_ADDR bool default y +config SOC_I2C_SLAVE_SUPPORT_BROADCAST + bool + default y + +config SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE + bool + default y + +config SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS + bool + default y + +config SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH + bool + default y + config SOC_LP_I2C_NUM int default 1 diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index ed69e78246..74f1670767 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -239,6 +239,10 @@ #define SOC_I2C_SUPPORT_XTAL (1) #define SOC_I2C_SUPPORT_RTC (1) #define SOC_I2C_SUPPORT_10BIT_ADDR (1) +#define SOC_I2C_SLAVE_SUPPORT_BROADCAST (1) +#define SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE (1) +#define SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS (1) +#define SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH (1) /*-------------------------- LP_I2C CAPS -------------------------------------*/ // ESP32-C6 has 1 LP_I2C diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index adc34fbbc8..82c436d287 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -531,6 +531,22 @@ config SOC_I2C_SUPPORT_10BIT_ADDR bool default y +config SOC_I2C_SLAVE_SUPPORT_BROADCAST + bool + default y + +config SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE + bool + default y + +config SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS + bool + default y + +config SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH + bool + default y + config SOC_I2S_NUM int default 1 diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 9a3231707e..6df8be0068 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -242,6 +242,10 @@ #define SOC_I2C_SUPPORT_XTAL (1) #define SOC_I2C_SUPPORT_RTC (1) #define SOC_I2C_SUPPORT_10BIT_ADDR (1) +#define SOC_I2C_SLAVE_SUPPORT_BROADCAST (1) +#define SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE (1) +#define SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS (1) +#define SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH (1) /*-------------------------- I2S CAPS ----------------------------------------*/ #define SOC_I2S_NUM (1U) diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 6d74147ef2..390450dbd7 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -479,6 +479,22 @@ config SOC_I2C_SUPPORT_RTC bool default y +config SOC_I2C_SUPPORT_10BIT_ADDR + bool + default y + +config SOC_I2C_SLAVE_SUPPORT_BROADCAST + bool + default y + +config SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS + bool + default y + +config SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH + bool + default y + config SOC_I2S_NUM int default 3 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 4c405a9046..1695bb2b77 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -246,6 +246,10 @@ #define SOC_I2C_SUPPORT_XTAL (1) #define SOC_I2C_SUPPORT_RTC (1) +#define SOC_I2C_SUPPORT_10BIT_ADDR (1) +#define SOC_I2C_SLAVE_SUPPORT_BROADCAST (1) +#define SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS (1) +#define SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH (1) /*-------------------------- I2S CAPS ----------------------------------------*/ #define SOC_I2S_NUM (3U) diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index 3da46a8c1d..aa9945311d 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -483,6 +483,14 @@ config SOC_I2C_SUPPORT_10BIT_ADDR bool default y +config SOC_I2C_SLAVE_SUPPORT_BROADCAST + bool + default y + +config SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS + bool + default y + config SOC_I2S_NUM int default 2 diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 42aeff02e3..bffb969493 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -201,6 +201,8 @@ #define SOC_I2C_SUPPORT_RTC (1) #define SOC_I2C_SUPPORT_10BIT_ADDR (1) +#define SOC_I2C_SLAVE_SUPPORT_BROADCAST (1) +#define SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS (1) /*-------------------------- I2S CAPS ----------------------------------------*/ #define SOC_I2S_NUM (2U)