mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-29 18:27:20 +02:00
Merge branch 'feature/i2c_slave_new_driver' into 'master'
feat(i2c_slave): Add new APIs for I2C-slave, and add multi-board tests with I2C-master Closes IDF-8111 See merge request espressif/esp-idf!25403
This commit is contained in:
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
424
components/driver/i2c/i2c_slave.c
Normal file
424
components/driver/i2c/i2c_slave.c
Normal file
@ -0,0 +1,424 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
@ -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);
|
||||
|
166
components/driver/i2c/include/driver/i2c_slave.h
Normal file
166
components/driver/i2c/include/driver/i2c_slave.h
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#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
|
@ -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
|
||||
|
@ -1,7 +1,26 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_i2c.c"
|
||||
"test_i2c_common.c"
|
||||
)
|
||||
|
||||
if(CONFIG_SOC_I2C_SUPPORT_SLAVE)
|
||||
list(APPEND srcs "test_i2c_multi.c")
|
||||
if(CONFIG_I2C_ISR_IRAM_SAFE)
|
||||
list(APPEND srcs "test_i2c_iram.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_I2C_SLAVE_SUPPORT_BROADCAST)
|
||||
list(APPEND srcs "test_i2c_broadcast.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS)
|
||||
list(APPEND srcs "test_i2c_ram.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR AND CONFIG_SOC_I2C_SUPPORT_SLAVE)
|
||||
list(APPEND srcs "test_i2c_10bit.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
PRIV_REQUIRES unity driver test_utils
|
||||
WHOLE_ARCHIVE)
|
||||
|
42
components/driver/test_apps/i2c_test_apps/main/test_board.h
Normal file
42
components/driver/test_apps/i2c_test_apps/main/test_board.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define I2C_SLAVE_SCL_IO 18 /*!<gpio number for i2c slave clock */
|
||||
#define I2C_SLAVE_SDA_IO 19 /*!<gpio number for i2c slave data */
|
||||
|
||||
#define I2C_MASTER_SCL_IO 18 /*!< gpio number for I2C master clock */
|
||||
#define I2C_MASTER_SDA_IO 19 /*!< gpio number for I2C master data */
|
||||
#else
|
||||
#define I2C_SLAVE_SCL_IO 4 /*!<gpio number for i2c slave clock */
|
||||
#define I2C_SLAVE_SDA_IO 2 /*!<gpio number for i2c slave data */
|
||||
|
||||
#define I2C_MASTER_SCL_IO 4 /*!< gpio number for I2C master clock */
|
||||
#define I2C_MASTER_SDA_IO 2 /*!< gpio number for I2C master data */
|
||||
#endif
|
||||
|
||||
#define ESP_SLAVE_ADDR 0x28 /*!< ESP_I2C slave address, you can set any 7bit value */
|
||||
#define TEST_I2C_PORT 0
|
||||
#define DATA_LENGTH 100
|
||||
|
||||
/**
|
||||
* @brief Display buffer
|
||||
*
|
||||
* @param buf Pointer to the buffer
|
||||
* @param len buffer length
|
||||
*/
|
||||
void disp_buf(uint8_t *buf, int len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
196
components/driver/test_apps/i2c_test_apps/main/test_i2c_10bit.c
Normal file
196
components/driver/test_apps/i2c_test_apps/main/test_i2c_10bit.c
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_err.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "hal/uart_ll.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/i2c_slave.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "test_utils.h"
|
||||
#include "test_board.h"
|
||||
|
||||
static QueueHandle_t s_receive_queue;
|
||||
|
||||
static IRAM_ATTR bool example_i2c_rx_done_callback(i2c_slave_dev_handle_t channel, const i2c_slave_rx_done_event_data_t *edata, void *user_data)
|
||||
{
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
QueueHandle_t receive_queue = (QueueHandle_t)user_data;
|
||||
xQueueSendFromISR(receive_queue, edata, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
static void i2c_master_write_test_10bit(void)
|
||||
{
|
||||
uint8_t data_wr[DATA_LENGTH] = { 0 };
|
||||
int i;
|
||||
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
|
||||
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
||||
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_10,
|
||||
.device_address = 0x134,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
unity_send_signal("master write");
|
||||
for (i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
|
||||
disp_buf(data_wr, i);
|
||||
TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1));
|
||||
unity_wait_for_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
|
||||
|
||||
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
|
||||
}
|
||||
|
||||
static void i2c_slave_read_test_10bit(void)
|
||||
{
|
||||
uint8_t data_rd[DATA_LENGTH] = {0};
|
||||
|
||||
i2c_slave_config_t i2c_slv_config = {
|
||||
.addr_bit_len = I2C_ADDR_BIT_LEN_10,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.send_buf_depth = 256,
|
||||
.scl_io_num = I2C_SLAVE_SCL_IO,
|
||||
.sda_io_num = I2C_SLAVE_SDA_IO,
|
||||
.slave_addr = 0x134,
|
||||
};
|
||||
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
|
||||
s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t));
|
||||
i2c_slave_event_callbacks_t cbs = {
|
||||
.on_recv_done = example_i2c_rx_done_callback,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue));
|
||||
|
||||
i2c_slave_rx_done_event_data_t rx_data;
|
||||
TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH));
|
||||
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
unity_wait_for_signal("master write");
|
||||
xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(1000));
|
||||
|
||||
disp_buf(data_rd, DATA_LENGTH);
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
TEST_ASSERT(data_rd[i] == i);
|
||||
}
|
||||
vQueueDelete(s_receive_queue);
|
||||
unity_send_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_del_slave_device(slave_handle));
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test 10 bit", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_test_10bit, i2c_slave_read_test_10bit);
|
||||
|
||||
|
||||
static void master_read_slave_test_10bit(void)
|
||||
{
|
||||
uint8_t data_rd[DATA_LENGTH] = {0};
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
||||
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_10,
|
||||
.device_address = 0x134,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
printf("Slave please write data to buffer\n");
|
||||
|
||||
unity_send_signal("slave write");
|
||||
unity_wait_for_signal("master read");
|
||||
|
||||
TEST_ESP_OK(i2c_master_receive(dev_handle, data_rd, DATA_LENGTH, -1));
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
printf("%d\n", data_rd[i]);
|
||||
TEST_ASSERT(data_rd[i]==i);
|
||||
}
|
||||
unity_send_signal("ready to delete 10bit");
|
||||
|
||||
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
|
||||
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
|
||||
}
|
||||
|
||||
static void slave_write_buffer_test_10bit(void)
|
||||
{
|
||||
uint8_t data_wr[DATA_LENGTH] = {0};
|
||||
|
||||
i2c_slave_config_t i2c_slv_config = {
|
||||
.addr_bit_len = I2C_ADDR_BIT_LEN_10,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.send_buf_depth = 256,
|
||||
.scl_io_num = I2C_SLAVE_SCL_IO,
|
||||
.sda_io_num = I2C_SLAVE_SDA_IO,
|
||||
.slave_addr = 0x134,
|
||||
};
|
||||
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
unity_wait_for_signal("slave write");
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
|
||||
TEST_ESP_OK(i2c_slave_transmit(slave_handle, data_wr, DATA_LENGTH, -1));
|
||||
disp_buf(data_wr, DATA_LENGTH);
|
||||
unity_send_signal("master read");
|
||||
unity_wait_for_signal("ready to delete 10bit");
|
||||
TEST_ESP_OK(i2c_del_slave_device(slave_handle));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C master read slave test 10 bit", "[i2c][test_env=generic_multi_device][timeout=150]", master_read_slave_test_10bit, slave_write_buffer_test_10bit);
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_err.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "hal/uart_ll.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/i2c_slave.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "test_utils.h"
|
||||
#include "test_board.h"
|
||||
|
||||
static QueueHandle_t s_receive_queue;
|
||||
|
||||
static IRAM_ATTR bool example_i2c_rx_done_callback(i2c_slave_dev_handle_t channel, const i2c_slave_rx_done_event_data_t *edata, void *user_data)
|
||||
{
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
QueueHandle_t receive_queue = (QueueHandle_t)user_data;
|
||||
xQueueSendFromISR(receive_queue, edata, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
static void i2c_master_write_test_broadcast(void)
|
||||
{
|
||||
uint8_t data_wr[DATA_LENGTH] = { 0 };
|
||||
int i;
|
||||
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
|
||||
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
||||
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = 0x00,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
unity_send_signal("master write");
|
||||
for (i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
|
||||
disp_buf(data_wr, i);
|
||||
TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1));
|
||||
unity_wait_for_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
|
||||
|
||||
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
|
||||
}
|
||||
|
||||
static void i2c_slave_read_test_broadcast(void)
|
||||
{
|
||||
uint8_t data_rd[DATA_LENGTH] = {0};
|
||||
|
||||
i2c_slave_config_t i2c_slv_config = {
|
||||
.addr_bit_len = I2C_ADDR_BIT_LEN_7,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.send_buf_depth = 256,
|
||||
.scl_io_num = I2C_SLAVE_SCL_IO,
|
||||
.sda_io_num = I2C_SLAVE_SDA_IO,
|
||||
.slave_addr = 0x53,
|
||||
.flags.broadcast_en = true,
|
||||
};
|
||||
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
|
||||
s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t));
|
||||
i2c_slave_event_callbacks_t cbs = {
|
||||
.on_recv_done = example_i2c_rx_done_callback,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue));
|
||||
|
||||
i2c_slave_rx_done_event_data_t rx_data;
|
||||
TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH));
|
||||
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
unity_wait_for_signal("master write");
|
||||
|
||||
xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(1000));
|
||||
disp_buf(data_rd, DATA_LENGTH);
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
TEST_ASSERT(data_rd[i] == i);
|
||||
}
|
||||
vQueueDelete(s_receive_queue);
|
||||
unity_send_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_del_slave_device(slave_handle));
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test broadcast", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_test_broadcast, i2c_slave_read_test_broadcast);
|
@ -22,23 +22,18 @@
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "test_utils.h"
|
||||
#include "test_board.h"
|
||||
|
||||
static const char TAG[] = "test-i2c";
|
||||
|
||||
#define TEST_I2C_SCL_PIN 2
|
||||
#define TEST_I2C_SDA_PIN 4
|
||||
#define TEST_I2C_SCL_FREQ (100 * 1000)
|
||||
#define TEST_I2C_PORT 0
|
||||
#define SLAVE_ADDR 0x58
|
||||
|
||||
|
||||
TEST_CASE("I2C bus install-uninstall test", "[i2c]")
|
||||
{
|
||||
i2c_master_bus_config_t i2c_mst_config_1 = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = TEST_I2C_SCL_PIN,
|
||||
.sda_io_num = TEST_I2C_SDA_PIN,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t i2c_mst_handle1;
|
||||
|
||||
@ -46,8 +41,9 @@ TEST_CASE("I2C bus install-uninstall test", "[i2c]")
|
||||
i2c_master_bus_config_t i2c_mst_config_2 = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = 1,
|
||||
.scl_io_num = TEST_I2C_SCL_PIN,
|
||||
.sda_io_num = TEST_I2C_SDA_PIN,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t i2c_mst_handle2;
|
||||
#endif
|
||||
@ -75,8 +71,9 @@ TEST_CASE("I2C driver memory leaking check", "[i2c]")
|
||||
i2c_master_bus_config_t i2c_mst_config_1 = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = TEST_I2C_SCL_PIN,
|
||||
.sda_io_num = TEST_I2C_SDA_PIN,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
|
||||
@ -95,8 +92,9 @@ TEST_CASE("I2C device add & remove check", "[i2c]")
|
||||
i2c_master_bus_config_t i2c_mst_config_1 = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = TEST_I2C_SCL_PIN,
|
||||
.sda_io_num = TEST_I2C_SDA_PIN,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
|
||||
@ -137,8 +135,8 @@ TEST_CASE("I2C master probe device test", "[i2c]")
|
||||
i2c_master_bus_config_t i2c_mst_config_1 = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = TEST_I2C_SCL_PIN,
|
||||
.sda_io_num = TEST_I2C_SDA_PIN,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
141
components/driver/test_apps/i2c_test_apps/main/test_i2c_iram.c
Normal file
141
components/driver/test_apps/i2c_test_apps/main/test_i2c_iram.c
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_err.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "hal/uart_ll.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/i2c_slave.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "test_utils.h"
|
||||
#include "test_board.h"
|
||||
#include "unity_test_utils_cache.h"
|
||||
|
||||
static QueueHandle_t s_send_queue;
|
||||
static QueueHandle_t s_receive_queue;
|
||||
|
||||
static IRAM_ATTR bool test_master_tx_done_callback(i2c_master_dev_handle_t i2c_dev, const i2c_master_event_data_t *evt_data, void *arg)
|
||||
{
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
QueueHandle_t s_send_queue = (QueueHandle_t)arg;
|
||||
xQueueSendFromISR(s_send_queue, evt_data, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
static IRAM_ATTR bool test_i2c_rx_done_callback(i2c_slave_dev_handle_t channel, const i2c_slave_rx_done_event_data_t *edata, void *user_data)
|
||||
{
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
QueueHandle_t receive_queue = (QueueHandle_t)user_data;
|
||||
xQueueSendFromISR(receive_queue, edata, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR test_delay_post_cache_disable(void *args)
|
||||
{
|
||||
esp_rom_delay_us(10000);
|
||||
}
|
||||
|
||||
static void i2c_master_write_test_iram_safe(void)
|
||||
{
|
||||
uint8_t data_wr[DATA_LENGTH] = { 0 };
|
||||
int i;
|
||||
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
.trans_queue_depth = 200,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
|
||||
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
||||
s_send_queue = xQueueCreate(1, sizeof(i2c_master_event_data_t));
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = 0x58,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
i2c_master_event_callbacks_t cbs = {
|
||||
.on_trans_done = test_master_tx_done_callback,
|
||||
};
|
||||
i2c_master_event_data_t evt_data;
|
||||
i2c_master_register_event_callbacks(dev_handle, &cbs, s_send_queue);
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
unity_send_signal("master write");
|
||||
for (i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
|
||||
disp_buf(data_wr, i);
|
||||
TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1));
|
||||
unity_utils_run_cache_disable_stub(test_delay_post_cache_disable, NULL);
|
||||
xQueueReceive(s_send_queue, &evt_data, pdMS_TO_TICKS(10000));
|
||||
unity_wait_for_signal("ready to delete");
|
||||
vQueueDelete(s_send_queue);
|
||||
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
|
||||
|
||||
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
|
||||
}
|
||||
|
||||
static void i2c_slave_read_test_iram_safe(void)
|
||||
{
|
||||
uint8_t data_rd[DATA_LENGTH] = {0};
|
||||
|
||||
i2c_slave_config_t i2c_slv_config = {
|
||||
.addr_bit_len = I2C_ADDR_BIT_LEN_7,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.send_buf_depth = 256,
|
||||
.scl_io_num = I2C_SLAVE_SCL_IO,
|
||||
.sda_io_num = I2C_SLAVE_SDA_IO,
|
||||
.slave_addr = 0x58,
|
||||
};
|
||||
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
|
||||
s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t));
|
||||
i2c_slave_event_callbacks_t cbs = {
|
||||
.on_recv_done = test_i2c_rx_done_callback,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue));
|
||||
|
||||
i2c_slave_rx_done_event_data_t rx_data;
|
||||
TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH));
|
||||
unity_utils_run_cache_disable_stub(test_delay_post_cache_disable, NULL);
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
unity_wait_for_signal("master write");
|
||||
xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(10000));
|
||||
disp_buf(data_rd, DATA_LENGTH);
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
TEST_ASSERT(data_rd[i] == i);
|
||||
}
|
||||
vQueueDelete(s_receive_queue);
|
||||
unity_send_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_del_slave_device(slave_handle));
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test iram safe", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_test_iram_safe, i2c_slave_read_test_iram_safe);
|
487
components/driver/test_apps/i2c_test_apps/main/test_i2c_multi.c
Normal file
487
components/driver/test_apps/i2c_test_apps/main/test_i2c_multi.c
Normal file
@ -0,0 +1,487 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_err.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "hal/uart_ll.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/i2c_slave.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "test_utils.h"
|
||||
#include "test_board.h"
|
||||
|
||||
void disp_buf(uint8_t *buf, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
printf("%02x ", buf[i]);
|
||||
if (( i + 1 ) % 16 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#define DATA_LENGTH 100
|
||||
|
||||
static QueueHandle_t s_receive_queue;
|
||||
|
||||
static IRAM_ATTR bool test_i2c_rx_done_callback(i2c_slave_dev_handle_t channel, const i2c_slave_rx_done_event_data_t *edata, void *user_data)
|
||||
{
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
QueueHandle_t receive_queue = (QueueHandle_t)user_data;
|
||||
xQueueSendFromISR(receive_queue, edata, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
static void i2c_master_write_test(void)
|
||||
{
|
||||
uint8_t data_wr[DATA_LENGTH] = { 0 };
|
||||
int i;
|
||||
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
|
||||
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
||||
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = 0x58,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
unity_send_signal("master write");
|
||||
for (i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
|
||||
disp_buf(data_wr, i);
|
||||
TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1));
|
||||
unity_wait_for_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
|
||||
|
||||
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
|
||||
}
|
||||
|
||||
static void i2c_slave_read_test(void)
|
||||
{
|
||||
uint8_t data_rd[DATA_LENGTH] = {0};
|
||||
|
||||
i2c_slave_config_t i2c_slv_config = {
|
||||
.addr_bit_len = I2C_ADDR_BIT_LEN_7,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.send_buf_depth = 256,
|
||||
.scl_io_num = I2C_SLAVE_SCL_IO,
|
||||
.sda_io_num = I2C_SLAVE_SDA_IO,
|
||||
.slave_addr = 0x58,
|
||||
};
|
||||
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
|
||||
s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t));
|
||||
i2c_slave_event_callbacks_t cbs = {
|
||||
.on_recv_done = test_i2c_rx_done_callback,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue));
|
||||
|
||||
i2c_slave_rx_done_event_data_t rx_data;
|
||||
TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH));
|
||||
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
unity_wait_for_signal("master write");
|
||||
xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(10000));
|
||||
disp_buf(data_rd, DATA_LENGTH);
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
TEST_ASSERT(data_rd[i] == i);
|
||||
}
|
||||
vQueueDelete(s_receive_queue);
|
||||
unity_send_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_del_slave_device(slave_handle));
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_test, i2c_slave_read_test);
|
||||
|
||||
|
||||
static void master_read_slave_test(void)
|
||||
{
|
||||
uint8_t data_rd[DATA_LENGTH] = {0};
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
||||
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = 0x58,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
printf("Slave please write data to buffer\n");
|
||||
|
||||
unity_send_signal("slave write");
|
||||
unity_wait_for_signal("master read");
|
||||
|
||||
TEST_ESP_OK(i2c_master_receive(dev_handle, data_rd, DATA_LENGTH, -1));
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
printf("%d\n", data_rd[i]);
|
||||
TEST_ASSERT(data_rd[i]==i);
|
||||
}
|
||||
unity_send_signal("ready to delete master read test");
|
||||
|
||||
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
|
||||
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
|
||||
}
|
||||
|
||||
static void slave_write_buffer_test(void)
|
||||
{
|
||||
uint8_t data_wr[DATA_LENGTH] = {0};
|
||||
|
||||
i2c_slave_config_t i2c_slv_config = {
|
||||
.addr_bit_len = I2C_ADDR_BIT_LEN_7,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.send_buf_depth = 256,
|
||||
.scl_io_num = I2C_SLAVE_SCL_IO,
|
||||
.sda_io_num = I2C_SLAVE_SDA_IO,
|
||||
.slave_addr = 0x58,
|
||||
};
|
||||
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
unity_wait_for_signal("slave write");
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
|
||||
TEST_ESP_OK(i2c_slave_transmit(slave_handle, data_wr, DATA_LENGTH, -1));
|
||||
disp_buf(data_wr, DATA_LENGTH);
|
||||
unity_send_signal("master read");
|
||||
unity_wait_for_signal("ready to delete master read test");
|
||||
TEST_ESP_OK(i2c_del_slave_device(slave_handle));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C master read slave test", "[i2c][test_env=generic_multi_device][timeout=150]", master_read_slave_test, slave_write_buffer_test);
|
||||
|
||||
static void i2c_master_write_read_test(void)
|
||||
{
|
||||
uint8_t data_rd[DATA_LENGTH] = {0};
|
||||
uint8_t data_wr[DATA_LENGTH] = {0};
|
||||
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
|
||||
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
||||
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = 0x58,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
printf("master read buffer\n");
|
||||
|
||||
unity_send_signal("slave write");
|
||||
unity_wait_for_signal("master read and write");
|
||||
|
||||
TEST_ESP_OK(i2c_master_receive(dev_handle, data_rd, DATA_LENGTH, -1));
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
disp_buf(data_rd, DATA_LENGTH);
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
TEST_ASSERT(data_rd[i] == i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
unity_send_signal("slave read");
|
||||
unity_wait_for_signal("ready to read");
|
||||
TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1));
|
||||
unity_send_signal("sent done");
|
||||
unity_wait_for_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
|
||||
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
|
||||
}
|
||||
|
||||
static void i2c_slave_read_write_test(void)
|
||||
{
|
||||
uint8_t data_rd[DATA_LENGTH] = {0};
|
||||
uint8_t data_wr[DATA_LENGTH] = {0};
|
||||
|
||||
i2c_slave_config_t i2c_slv_config = {
|
||||
.addr_bit_len = I2C_ADDR_BIT_LEN_7,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.send_buf_depth = 256,
|
||||
.scl_io_num = I2C_SLAVE_SCL_IO,
|
||||
.sda_io_num = I2C_SLAVE_SDA_IO,
|
||||
.slave_addr = 0x58,
|
||||
};
|
||||
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
|
||||
s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t));
|
||||
i2c_slave_event_callbacks_t cbs = {
|
||||
.on_recv_done = test_i2c_rx_done_callback,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue));
|
||||
|
||||
unity_send_signal("i2c slave init finish");
|
||||
unity_wait_for_signal("slave write");
|
||||
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
TEST_ESP_OK(i2c_slave_transmit(slave_handle, data_wr, DATA_LENGTH, -1));
|
||||
disp_buf(data_wr, DATA_LENGTH);
|
||||
unity_send_signal("master read and write");
|
||||
unity_wait_for_signal("slave read");
|
||||
TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH));
|
||||
unity_send_signal("ready to read");
|
||||
unity_wait_for_signal("sent done");
|
||||
i2c_slave_rx_done_event_data_t rx_data;
|
||||
xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(1000));
|
||||
|
||||
printf("slave read data is:\n");
|
||||
disp_buf(data_rd, DATA_LENGTH);
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
TEST_ASSERT(data_rd[i] == i);
|
||||
}
|
||||
unity_send_signal("ready to delete");
|
||||
vQueueDelete(s_receive_queue);
|
||||
TEST_ESP_OK(i2c_del_slave_device(slave_handle));
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C read and write test", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_read_test, i2c_slave_read_write_test);
|
||||
|
||||
|
||||
static void i2c_master_repeat_write(void)
|
||||
{
|
||||
uint8_t data_wr[DATA_LENGTH] = {0};
|
||||
int times = 3;
|
||||
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
||||
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = 0x58,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
for (int j = 0; j < times; j++) {
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = j + i;
|
||||
}
|
||||
TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1));
|
||||
disp_buf(data_wr, DATA_LENGTH);
|
||||
}
|
||||
unity_wait_for_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
|
||||
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
|
||||
}
|
||||
|
||||
static void i2c_slave_repeat_read(void)
|
||||
{
|
||||
uint32_t size = 0;
|
||||
int times = 3;
|
||||
uint8_t data_rd[DATA_LENGTH * 3] = {0};
|
||||
|
||||
i2c_slave_config_t i2c_slv_config = {
|
||||
.addr_bit_len = I2C_ADDR_BIT_LEN_7,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.send_buf_depth = 256,
|
||||
.scl_io_num = I2C_SLAVE_SCL_IO,
|
||||
.sda_io_num = I2C_SLAVE_SDA_IO,
|
||||
.slave_addr = 0x58,
|
||||
};
|
||||
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
|
||||
s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t));
|
||||
i2c_slave_event_callbacks_t cbs = {
|
||||
.on_recv_done = test_i2c_rx_done_callback,
|
||||
};
|
||||
TEST_ESP_OK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue));
|
||||
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
while (times > 0) {
|
||||
i2c_slave_rx_done_event_data_t rx_data;
|
||||
TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd + size, DATA_LENGTH));
|
||||
xQueueReceive(s_receive_queue, &rx_data, (TickType_t)portMAX_DELAY);
|
||||
|
||||
size += DATA_LENGTH;
|
||||
times--;
|
||||
}
|
||||
|
||||
disp_buf(data_rd, size);
|
||||
for (int j = 0; j < times; j++) {
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
TEST_ASSERT(data_rd[i + DATA_LENGTH * j] == (i + j));
|
||||
}
|
||||
}
|
||||
unity_send_signal("ready to delete");
|
||||
vQueueDelete(s_receive_queue);
|
||||
TEST_ESP_OK(i2c_del_slave_device(slave_handle));
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C repeat write test", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_repeat_write, i2c_slave_repeat_read);
|
||||
|
||||
#if SOC_I2C_NUM > 1
|
||||
// Now chips with mutiple I2C controllers are up to 2, can change this to interation when we have more I2C controllers.
|
||||
static void i2c_master_write_test_more_port(void)
|
||||
{
|
||||
uint8_t data_wr[DATA_LENGTH] = { 0 };
|
||||
int i;
|
||||
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = 1,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
|
||||
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
||||
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = 0x58,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
unity_send_signal("master write");
|
||||
for (i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
|
||||
disp_buf(data_wr, i);
|
||||
TEST_ESP_OK(i2c_master_transmit(dev_handle, data_wr, DATA_LENGTH, -1));
|
||||
unity_wait_for_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
|
||||
|
||||
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
|
||||
}
|
||||
|
||||
static void i2c_slave_read_test_more_port(void)
|
||||
{
|
||||
uint8_t data_rd[DATA_LENGTH] = {0};
|
||||
|
||||
i2c_slave_config_t i2c_slv_config = {
|
||||
.addr_bit_len = I2C_ADDR_BIT_LEN_7,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = 1,
|
||||
.send_buf_depth = 256,
|
||||
.scl_io_num = I2C_SLAVE_SCL_IO,
|
||||
.sda_io_num = I2C_SLAVE_SDA_IO,
|
||||
.slave_addr = 0x58,
|
||||
};
|
||||
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
|
||||
s_receive_queue = xQueueCreate(1, sizeof(i2c_slave_rx_done_event_data_t));
|
||||
i2c_slave_event_callbacks_t cbs = {
|
||||
.on_recv_done = test_i2c_rx_done_callback,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_slave_register_event_callbacks(slave_handle, &cbs, s_receive_queue));
|
||||
|
||||
i2c_slave_rx_done_event_data_t rx_data;
|
||||
TEST_ESP_OK(i2c_slave_receive(slave_handle, data_rd, DATA_LENGTH));
|
||||
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
unity_wait_for_signal("master write");
|
||||
xQueueReceive(s_receive_queue, &rx_data, pdMS_TO_TICKS(10000));
|
||||
disp_buf(data_rd, DATA_LENGTH);
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
TEST_ASSERT(data_rd[i] == i);
|
||||
}
|
||||
vQueueDelete(s_receive_queue);
|
||||
unity_send_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_del_slave_device(slave_handle));
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test, more ports", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_test_more_port, i2c_slave_read_test_more_port);
|
||||
#endif
|
215
components/driver/test_apps/i2c_test_apps/main/test_i2c_ram.c
Normal file
215
components/driver/test_apps/i2c_test_apps/main/test_i2c_ram.c
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_err.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/clk_tree_defs.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "hal/uart_ll.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
#include "driver/i2c_slave.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "test_utils.h"
|
||||
#include "test_board.h"
|
||||
|
||||
static esp_err_t i2c_master_write_to_addr(i2c_master_dev_handle_t device_handle, uint8_t address, const uint8_t *data, uint32_t size, int xfer_timeout_ms)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t *buffer = (uint8_t*)calloc(1, size + 1);
|
||||
buffer[0] = address;
|
||||
memcpy(buffer + 1, data, size);
|
||||
ret = i2c_master_transmit(device_handle, buffer, 1 + size, xfer_timeout_ms);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define DATA_LENGTH_RAM 6
|
||||
|
||||
static void i2c_master_write_to_ram_test(void)
|
||||
{
|
||||
uint8_t data_wr[DATA_LENGTH_RAM] = { 0 };
|
||||
int i;
|
||||
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
|
||||
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
||||
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = 0x58,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
unity_send_signal("master write");
|
||||
for (i = 0; i < DATA_LENGTH_RAM; i++) {
|
||||
data_wr[i] = i + 1;
|
||||
}
|
||||
disp_buf(data_wr, i);
|
||||
// Write slave ram address is 0x5.
|
||||
i2c_master_write_to_addr(dev_handle, 0x5, data_wr, DATA_LENGTH_RAM, -1);
|
||||
|
||||
unity_wait_for_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
|
||||
|
||||
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
|
||||
}
|
||||
|
||||
static void i2c_slave_read_from_ram_test(void)
|
||||
{
|
||||
uint8_t data_rd[DATA_LENGTH_RAM] = {0};
|
||||
|
||||
i2c_slave_config_t i2c_slv_config = {
|
||||
.addr_bit_len = I2C_ADDR_BIT_LEN_7,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.send_buf_depth = 256,
|
||||
.scl_io_num = I2C_SLAVE_SCL_IO,
|
||||
.sda_io_num = I2C_SLAVE_SDA_IO,
|
||||
.slave_addr = 0x58,
|
||||
.flags.access_ram_en = true,
|
||||
};
|
||||
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
|
||||
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
unity_wait_for_signal("master write");
|
||||
|
||||
TEST_ESP_OK(i2c_slave_read_ram(slave_handle, 0x5, data_rd, DATA_LENGTH_RAM));
|
||||
|
||||
disp_buf(data_rd, DATA_LENGTH_RAM);
|
||||
for (int i = 0; i < DATA_LENGTH_RAM; i++) {
|
||||
TEST_ASSERT(data_rd[i] == (i + 1));
|
||||
}
|
||||
unity_send_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_del_slave_device(slave_handle));
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test - slave directly read from ram", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_to_ram_test, i2c_slave_read_from_ram_test);
|
||||
|
||||
|
||||
static void master_read_slave_from_ram_test(void)
|
||||
{
|
||||
uint8_t data_rd[DATA_LENGTH_RAM] = {0};
|
||||
i2c_master_bus_config_t i2c_mst_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
i2c_master_bus_handle_t bus_handle;
|
||||
TEST_ESP_OK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
|
||||
|
||||
i2c_device_config_t dev_cfg = {
|
||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||
.device_address = 0x58,
|
||||
.scl_speed_hz = 100000,
|
||||
};
|
||||
|
||||
i2c_master_dev_handle_t dev_handle;
|
||||
TEST_ESP_OK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
|
||||
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
printf("Slave please write data to buffer\n");
|
||||
|
||||
unity_send_signal("slave write");
|
||||
unity_wait_for_signal("master read");
|
||||
|
||||
uint8_t *buffer = (uint8_t*)malloc(sizeof(uint8_t));
|
||||
buffer[0] = 0x2; // Means write offset 2 in I2C ram.
|
||||
TEST_ESP_OK(i2c_master_transmit_receive(dev_handle, buffer, 1, data_rd, DATA_LENGTH_RAM, -1));
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
for (int i = 0; i < DATA_LENGTH_RAM; i++) {
|
||||
printf("%d\n", data_rd[i]);
|
||||
TEST_ASSERT(data_rd[i]==i);
|
||||
}
|
||||
unity_send_signal("ready to delete ram test");
|
||||
|
||||
TEST_ESP_OK(i2c_master_bus_rm_device(dev_handle));
|
||||
TEST_ESP_OK(i2c_del_master_bus(bus_handle));
|
||||
}
|
||||
|
||||
static void slave_write_buffer_to_ram_test(void)
|
||||
{
|
||||
uint8_t data_wr[DATA_LENGTH_RAM] = {0};
|
||||
|
||||
i2c_slave_config_t i2c_slv_config = {
|
||||
.addr_bit_len = I2C_ADDR_BIT_LEN_7,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.send_buf_depth = 256,
|
||||
.scl_io_num = I2C_SLAVE_SCL_IO,
|
||||
.sda_io_num = I2C_SLAVE_SDA_IO,
|
||||
.slave_addr = 0x58,
|
||||
.flags.access_ram_en = true,
|
||||
};
|
||||
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
unity_wait_for_signal("slave write");
|
||||
for (int i = 0; i < DATA_LENGTH_RAM; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
|
||||
TEST_ESP_OK(i2c_slave_write_ram(slave_handle, 0x2, data_wr, DATA_LENGTH_RAM));
|
||||
disp_buf(data_wr, DATA_LENGTH_RAM);
|
||||
unity_send_signal("master read");
|
||||
unity_wait_for_signal("ready to delete ram test");
|
||||
TEST_ESP_OK(i2c_del_slave_device(slave_handle));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C master read slave ram test", "[i2c][test_env=generic_multi_device][timeout=150]", master_read_slave_from_ram_test, slave_write_buffer_to_ram_test);
|
||||
|
||||
TEST_CASE("I2C slave init as ram but read by fifo", "[i2c]")
|
||||
{
|
||||
uint8_t data_rd[10] = {0};
|
||||
i2c_slave_config_t i2c_slv_config = {
|
||||
.addr_bit_len = I2C_ADDR_BIT_LEN_7,
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TEST_I2C_PORT,
|
||||
.send_buf_depth = 256,
|
||||
.scl_io_num = I2C_SLAVE_SCL_IO,
|
||||
.sda_io_num = I2C_SLAVE_SDA_IO,
|
||||
.slave_addr = 0x58,
|
||||
.flags.access_ram_en = true,
|
||||
};
|
||||
i2c_slave_dev_handle_t slave_handle;
|
||||
TEST_ESP_OK(i2c_new_slave_device(&i2c_slv_config, &slave_handle));
|
||||
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, i2c_slave_receive(slave_handle, data_rd, 10));
|
||||
TEST_ESP_OK(i2c_del_slave_device(slave_handle));
|
||||
}
|
@ -17,3 +17,23 @@ from pytest_embedded import Dut
|
||||
)
|
||||
def test_i2c(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.esp32c6
|
||||
@pytest.mark.esp32h2
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.generic_multi_device
|
||||
@pytest.mark.parametrize(
|
||||
'count, config',
|
||||
[
|
||||
(2, 'defaults',),
|
||||
],
|
||||
indirect=True
|
||||
)
|
||||
def test_i2c_multi_device(case_tester) -> None: # type: ignore
|
||||
for case in case_tester.test_menu:
|
||||
if case.attributes.get('test_env', 'generic_multi_device') == 'generic_multi_device':
|
||||
case_tester.run_multi_dev_case(case=case, reset=True)
|
||||
|
@ -508,6 +508,66 @@ static void i2c_slave_repeat_read(void)
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C repeat write test", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_repeat_write, i2c_slave_repeat_read);
|
||||
|
||||
#if SOC_I2C_NUM > 1
|
||||
|
||||
static void i2c_master_write_test_more_ports(void)
|
||||
{
|
||||
uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH);
|
||||
int i;
|
||||
|
||||
i2c_config_t conf_master = i2c_master_init();
|
||||
TEST_ESP_OK(i2c_param_config(I2C_NUM_1, &conf_master));
|
||||
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_NUM_1, I2C_MODE_MASTER,
|
||||
I2C_MASTER_RX_BUF_DISABLE,
|
||||
I2C_MASTER_TX_BUF_DISABLE, 0));
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
unity_send_signal("master write");
|
||||
for (i = 0; i < DATA_LENGTH / 2; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
i2c_master_write_slave(I2C_NUM_1, data_wr, DATA_LENGTH / 2);
|
||||
disp_buf(data_wr, i);
|
||||
free(data_wr);
|
||||
unity_wait_for_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_driver_delete(I2C_NUM_1));
|
||||
}
|
||||
|
||||
static void i2c_slave_read_test_more_ports(void)
|
||||
{
|
||||
uint8_t *data_rd = (uint8_t *) malloc(DATA_LENGTH);
|
||||
int size_rd = 0;
|
||||
int len = 0;
|
||||
|
||||
i2c_config_t conf_slave = i2c_slave_init();
|
||||
TEST_ESP_OK(i2c_param_config( I2C_NUM_1, &conf_slave));
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_NUM_1, I2C_MODE_SLAVE,
|
||||
I2C_SLAVE_RX_BUF_LEN,
|
||||
I2C_SLAVE_TX_BUF_LEN, 0));
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
unity_wait_for_signal("master write");
|
||||
while (1) {
|
||||
len = i2c_slave_read_buffer( I2C_NUM_1, data_rd + size_rd, DATA_LENGTH, 10000 / portTICK_PERIOD_MS);
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
size_rd += len;
|
||||
}
|
||||
disp_buf(data_rd, size_rd);
|
||||
for (int i = 0; i < size_rd; i++) {
|
||||
TEST_ASSERT(data_rd[i] == i);
|
||||
}
|
||||
free(data_rd);
|
||||
unity_send_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_driver_delete(I2C_NUM_1));
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test, more ports", "[i2c][test_env=generic_multi_device][timeout=150]", i2c_master_write_test_more_ports, i2c_slave_read_test_more_ports);
|
||||
|
||||
#endif
|
||||
|
||||
static volatile bool exit_flag;
|
||||
static bool test_read_func;
|
||||
|
||||
|
@ -45,24 +45,29 @@ typedef union {
|
||||
#define I2C_LL_CMD_END 4 /*!<I2C end command */
|
||||
|
||||
typedef enum {
|
||||
I2C_LL_INTR_TXFIFO_WM = (1 << 1),
|
||||
I2C_LL_INTR_RXFIFO_WM = (1 << 0),
|
||||
I2C_INTR_MST_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_MST_RXFIFO_WM = (1 << 11),
|
||||
I2C_LL_INTR_NACK = (1 << 10),
|
||||
I2C_LL_INTR_TIMEOUT = (1 << 8),
|
||||
I2C_LL_INTR_MST_COMPLETE = (1 << 7),
|
||||
I2C_LL_INTR_ARBITRATION = (1 << 5),
|
||||
I2C_LL_INTR_END_DETECT = (1 << 3),
|
||||
I2C_LL_INTR_ST_TO = (1 << 13),
|
||||
I2C_LL_INTR_START = (1 << 15),
|
||||
I2C_LL_INTR_STRETCH = (1 << 16),
|
||||
I2C_LL_INTR_UNMATCH = (1 << 18),
|
||||
} i2c_ll_intr_t;
|
||||
} i2c_ll_master_intr_t;
|
||||
|
||||
typedef enum {
|
||||
I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_SLV_RXFIFO_WM = (1 << 11),
|
||||
I2C_INTR_SLV_COMPLETE = (1 << 7),
|
||||
I2C_INTR_START = (1 << 15),
|
||||
I2C_INTR_STRETCH = (1 << 16),
|
||||
} i2c_ll_slave_intr_t;
|
||||
|
||||
// Get the I2C hardware instance
|
||||
#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == 0) ? &I2C0 : &I2C1)
|
||||
#define I2C_LL_MASTER_EVENT_INTR (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)
|
||||
#define I2C_LL_SLAVE_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_EMPTY_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_RXFIFO_FULL_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_EMPTY_INT_ENA_M|I2C_RX_REC_FULL_INT_ST_M)
|
||||
#define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_RX_REC_FULL_INT_ST_M)
|
||||
#define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_EMPTY_INT_ENA_M)
|
||||
|
||||
/**
|
||||
@ -277,7 +282,7 @@ static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, boo
|
||||
{
|
||||
hw->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;
|
||||
}
|
||||
|
||||
|
@ -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 /*!<I2C end command */
|
||||
|
||||
typedef enum {
|
||||
I2C_LL_INTR_TXFIFO_WM = (1 << 1),
|
||||
I2C_LL_INTR_RXFIFO_WM = (1 << 0),
|
||||
I2C_LL_INTR_NACK = (1 << 10),
|
||||
I2C_LL_INTR_TIMEOUT = (1 << 8),
|
||||
I2C_LL_INTR_MST_COMPLETE = (1 << 7),
|
||||
I2C_LL_INTR_ARBITRATION = (1 << 5),
|
||||
I2C_LL_INTR_END_DETECT = (1 << 3),
|
||||
I2C_LL_INTR_ST_TO = (1 << 13),
|
||||
I2C_LL_INTR_START = (1 << 15),
|
||||
I2C_LL_INTR_STRETCH = (1 << 16),
|
||||
I2C_LL_INTR_UNMATCH = (1 << 18),
|
||||
} i2c_ll_intr_t;
|
||||
} i2c_ll_master_intr_t;
|
||||
|
||||
// Get the I2C hardware instance
|
||||
#define I2C_LL_GET_HW(i2c_num) (&I2C0)
|
||||
#define I2C_LL_MASTER_EVENT_INTR (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_EVENT_INTR 0
|
||||
#define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9)
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
*/
|
||||
@ -49,24 +49,23 @@ typedef union {
|
||||
#define I2C_LL_CMD_END 4 /*!<I2C end command */
|
||||
|
||||
typedef enum {
|
||||
I2C_LL_INTR_TXFIFO_WM = (1 << 1),
|
||||
I2C_LL_INTR_RXFIFO_WM = (1 << 0),
|
||||
I2C_INTR_MST_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_MST_RXFIFO_WM = (1 << 0),
|
||||
I2C_LL_INTR_NACK = (1 << 10),
|
||||
I2C_LL_INTR_TIMEOUT = (1 << 8),
|
||||
I2C_LL_INTR_MST_COMPLETE = (1 << 7),
|
||||
I2C_LL_INTR_ARBITRATION = (1 << 5),
|
||||
I2C_LL_INTR_END_DETECT = (1 << 3),
|
||||
I2C_LL_INTR_ST_TO = (1 << 13),
|
||||
I2C_LL_INTR_START = (1 << 15),
|
||||
I2C_LL_INTR_STRETCH = (1 << 16),
|
||||
I2C_LL_INTR_UNMATCH = (1 << 18),
|
||||
} i2c_ll_intr_t;
|
||||
} i2c_ll_master_intr_t;
|
||||
|
||||
typedef enum {
|
||||
I2C_LL_STRETCH_REASON_MASTER_START = 0,
|
||||
I2C_LL_STRETCH_REASON_TX_EMPTY = 1,
|
||||
I2C_LL_STRETCH_REASON_RX_FULL = 2,
|
||||
} i2c_ll_stretch_cause_t;
|
||||
I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_SLV_RXFIFO_WM = (1 << 0),
|
||||
I2C_INTR_SLV_COMPLETE = (1 << 7),
|
||||
I2C_INTR_START = (1 << 15),
|
||||
I2C_INTR_STRETCH = (1 << 16),
|
||||
} i2c_ll_slave_intr_t;
|
||||
|
||||
// Get the I2C hardware instance
|
||||
#define I2C_LL_GET_HW(i2c_num) (&I2C0)
|
||||
@ -295,6 +294,37 @@ static inline void i2c_ll_slave_broadcast_enable(i2c_dev_t *hw, bool broadcast_e
|
||||
hw->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;
|
||||
}
|
||||
|
||||
|
@ -49,31 +49,31 @@ typedef union {
|
||||
#define I2C_LL_CMD_END 4 /*!<I2C end command */
|
||||
|
||||
typedef enum {
|
||||
I2C_LL_INTR_TXFIFO_WM = (1 << 1),
|
||||
I2C_LL_INTR_RXFIFO_WM = (1 << 0),
|
||||
I2C_INTR_MST_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_MST_RXFIFO_WM = (1 << 0),
|
||||
I2C_LL_INTR_NACK = (1 << 10),
|
||||
I2C_LL_INTR_TIMEOUT = (1 << 8),
|
||||
I2C_LL_INTR_MST_COMPLETE = (1 << 7),
|
||||
I2C_LL_INTR_ARBITRATION = (1 << 5),
|
||||
I2C_LL_INTR_END_DETECT = (1 << 3),
|
||||
I2C_LL_INTR_ST_TO = (1 << 13),
|
||||
I2C_LL_INTR_START = (1 << 15),
|
||||
I2C_LL_INTR_STRETCH = (1 << 16),
|
||||
I2C_LL_INTR_UNMATCH = (1 << 18),
|
||||
} i2c_ll_intr_t;
|
||||
} i2c_ll_master_intr_t;
|
||||
|
||||
typedef enum {
|
||||
I2C_LL_STRETCH_REASON_MASTER_START = 0,
|
||||
I2C_LL_STRETCH_REASON_TX_EMPTY = 1,
|
||||
I2C_LL_STRETCH_REASON_RX_FULL = 2,
|
||||
} i2c_ll_stretch_cause_t;
|
||||
I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_SLV_RXFIFO_WM = (1 << 0),
|
||||
I2C_INTR_SLV_COMPLETE = (1 << 7),
|
||||
I2C_INTR_START = (1 << 15),
|
||||
I2C_INTR_STRETCH = (1 << 16),
|
||||
I2C_INTR_UNMATCH = (1 << 18),
|
||||
} i2c_ll_slave_intr_t;
|
||||
|
||||
// Get the I2C hardware instance
|
||||
#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == I2C_NUM_0) ? (&I2C0) : (&LP_I2C))
|
||||
#define I2C_LL_MASTER_EVENT_INTR (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_WM_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_WM_INT_ENA_M)
|
||||
#define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9)
|
||||
|
||||
/**
|
||||
@ -299,6 +299,37 @@ static inline void i2c_ll_slave_broadcast_enable(i2c_dev_t *hw, bool broadcast_e
|
||||
hw->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;
|
||||
}
|
||||
|
||||
|
@ -47,32 +47,32 @@ typedef union {
|
||||
#define I2C_LL_CMD_END 4 /*!<I2C end command */
|
||||
|
||||
typedef enum {
|
||||
I2C_LL_INTR_TXFIFO_WM = (1 << 1),
|
||||
I2C_LL_INTR_RXFIFO_WM = (1 << 0),
|
||||
I2C_INTR_MST_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_MST_RXFIFO_WM = (1 << 0),
|
||||
I2C_LL_INTR_NACK = (1 << 10),
|
||||
I2C_LL_INTR_TIMEOUT = (1 << 8),
|
||||
I2C_LL_INTR_MST_COMPLETE = (1 << 7),
|
||||
I2C_LL_INTR_ARBITRATION = (1 << 5),
|
||||
I2C_LL_INTR_END_DETECT = (1 << 3),
|
||||
I2C_LL_INTR_ST_TO = (1 << 13),
|
||||
I2C_LL_INTR_START = (1 << 15),
|
||||
I2C_LL_INTR_STRETCH = (1 << 16),
|
||||
I2C_LL_INTR_UNMATCH = (1 << 18),
|
||||
} i2c_ll_intr_t;
|
||||
} i2c_ll_master_intr_t;
|
||||
|
||||
typedef enum {
|
||||
I2C_LL_STRETCH_REASON_MASTER_START = 0,
|
||||
I2C_LL_STRETCH_REASON_TX_EMPTY = 1,
|
||||
I2C_LL_STRETCH_REASON_RX_FULL = 2,
|
||||
} i2c_ll_stretch_cause_t;
|
||||
I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_SLV_RXFIFO_WM = (1 << 0),
|
||||
I2C_INTR_SLV_COMPLETE = (1 << 7),
|
||||
I2C_INTR_START = (1 << 15),
|
||||
I2C_INTR_STRETCH = (1 << 16),
|
||||
I2C_INTR_UNMATCH = (1 << 18),
|
||||
} i2c_ll_slave_intr_t;
|
||||
|
||||
// Get the I2C hardware instance
|
||||
#define I2C_LL_GET_HW(i2c_num) (i2c_num == 0 ? (&I2C0) : (&I2C1))
|
||||
#define I2C_LL_GET_NUM(hw) (hw == &I2C0 ? 0 : 1)
|
||||
#define I2C_LL_MASTER_EVENT_INTR (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_WM_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_WM_INT_ENA_M)
|
||||
#define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9)
|
||||
|
||||
/**
|
||||
@ -295,6 +295,37 @@ static inline void i2c_ll_slave_broadcast_enable(i2c_dev_t *hw, bool broadcast_e
|
||||
hw->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;
|
||||
}
|
||||
|
||||
|
@ -47,18 +47,24 @@ typedef union {
|
||||
#define I2C_LL_CMD_END 4 /*!<I2C end command */
|
||||
|
||||
typedef enum {
|
||||
I2C_LL_INTR_TXFIFO_WM = (1 << 1),
|
||||
I2C_LL_INTR_RXFIFO_WM = (1 << 0),
|
||||
I2C_INTR_MST_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_MST_RXFIFO_WM = (1 << 0),
|
||||
I2C_LL_INTR_NACK = (1 << 10),
|
||||
I2C_LL_INTR_TIMEOUT = (1 << 8),
|
||||
I2C_LL_INTR_MST_COMPLETE = (1 << 7),
|
||||
I2C_LL_INTR_ARBITRATION = (1 << 5),
|
||||
I2C_LL_INTR_END_DETECT = (1 << 3),
|
||||
I2C_LL_INTR_ST_TO = (1 << 13),
|
||||
I2C_LL_INTR_START = (1 << 15),
|
||||
I2C_LL_INTR_STRETCH = (1 << 16),
|
||||
I2C_LL_INTR_UNMATCH = (1 << 18),
|
||||
} i2c_ll_intr_t;
|
||||
} i2c_ll_master_intr_t;
|
||||
|
||||
typedef enum {
|
||||
I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_SLV_RXFIFO_WM = (1 << 0),
|
||||
I2C_INTR_SLV_COMPLETE = (1 << 7),
|
||||
I2C_INTR_START = (1 << 15),
|
||||
I2C_INTR_STRETCH = (1 << 16),
|
||||
I2C_INTR_UNMATCH = (1 << 18),
|
||||
} i2c_ll_slave_intr_t;
|
||||
|
||||
typedef enum {
|
||||
I2C_LL_STRETCH_REASON_MASTER_START = 0,
|
||||
@ -69,9 +75,9 @@ typedef enum {
|
||||
// Get the I2C hardware instance
|
||||
#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == I2C_NUM_0) ? (&I2C0) : (((i2c_num) == I2C_NUM_1) ? (&I2C1) : (&LP_I2C)))
|
||||
#define I2C_LL_MASTER_EVENT_INTR (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_WM_INT_ENA_M | I2C_SLAVE_ADDR_UNMATCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_WM_INT_ENA_M)
|
||||
#define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9)
|
||||
|
||||
/**
|
||||
@ -319,7 +325,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;
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 /*!<I2C end command */
|
||||
|
||||
typedef enum {
|
||||
I2C_LL_INTR_TXFIFO_WM = (1 << 1),
|
||||
I2C_LL_INTR_RXFIFO_WM = (1 << 0),
|
||||
I2C_INTR_MST_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_MST_RXFIFO_WM = (1 << 0),
|
||||
I2C_LL_INTR_NACK = (1 << 10),
|
||||
I2C_LL_INTR_TIMEOUT = (1 << 8),
|
||||
I2C_LL_INTR_MST_COMPLETE = (1 << 7),
|
||||
I2C_LL_INTR_ARBITRATION = (1 << 5),
|
||||
I2C_LL_INTR_END_DETECT = (1 << 3),
|
||||
I2C_LL_INTR_ST_TO = (1 << 13),
|
||||
I2C_LL_INTR_START = (1 << 15),
|
||||
I2C_LL_INTR_STRETCH = (1 << 16),
|
||||
I2C_LL_INTR_UNMATCH = (1 << 18),
|
||||
} i2c_ll_intr_t;
|
||||
} i2c_ll_master_intr_t;
|
||||
|
||||
typedef enum {
|
||||
I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_SLV_RXFIFO_WM = (1 << 0),
|
||||
I2C_INTR_SLV_COMPLETE = (1 << 7),
|
||||
I2C_INTR_START = (1 << 15),
|
||||
I2C_INTR_STRETCH = (1 << 16),
|
||||
} i2c_ll_slave_intr_t;
|
||||
|
||||
// Get the I2C hardware instance
|
||||
#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == 0) ? &I2C0 : &I2C1)
|
||||
#define I2C_LL_MASTER_EVENT_INTR (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_SLAVE_STRETCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
|
||||
#define I2C_LL_SLAVE_TX_EVENT_INTR (I2C_TXFIFO_WM_INT_ENA_M)
|
||||
#define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9)
|
||||
|
||||
@ -252,6 +257,20 @@ static inline void i2c_ll_slave_broadcast_enable(i2c_dev_t *hw, bool broadcast_e
|
||||
// Not supported on esp32s2
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
// Not supported on esp32s2
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2C slave address
|
||||
*
|
||||
@ -265,9 +284,9 @@ static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, boo
|
||||
{
|
||||
hw->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;
|
||||
}
|
||||
|
||||
|
@ -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 /*!<I2C end command */
|
||||
|
||||
typedef enum {
|
||||
I2C_LL_INTR_TXFIFO_WM = (1 << 1),
|
||||
I2C_LL_INTR_RXFIFO_WM = (1 << 0),
|
||||
I2C_INTR_MST_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_MST_RXFIFO_WM = (1 << 0),
|
||||
I2C_LL_INTR_NACK = (1 << 10),
|
||||
I2C_LL_INTR_TIMEOUT = (1 << 8),
|
||||
I2C_LL_INTR_MST_COMPLETE = (1 << 7),
|
||||
I2C_LL_INTR_ARBITRATION = (1 << 5),
|
||||
I2C_LL_INTR_END_DETECT = (1 << 3),
|
||||
I2C_LL_INTR_ST_TO = (1 << 13),
|
||||
I2C_LL_INTR_START = (1 << 15),
|
||||
I2C_LL_INTR_STRETCH = (1 << 16),
|
||||
I2C_LL_INTR_UNMATCH = (1 << 18),
|
||||
} i2c_ll_intr_t;
|
||||
} i2c_ll_master_intr_t;
|
||||
|
||||
typedef enum {
|
||||
I2C_INTR_SLV_TXFIFO_WM = (1 << 1),
|
||||
I2C_INTR_SLV_RXFIFO_WM = (1 << 0),
|
||||
I2C_INTR_SLV_COMPLETE = (1 << 7),
|
||||
I2C_INTR_START = (1 << 15),
|
||||
I2C_INTR_STRETCH = (1 << 16),
|
||||
} i2c_ll_slave_intr_t;
|
||||
|
||||
// Get the I2C hardware instance
|
||||
#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == 0) ? &I2C0 : &I2C1)
|
||||
@ -288,6 +293,37 @@ static inline void i2c_ll_slave_broadcast_enable(i2c_dev_t *hw, bool broadcast_e
|
||||
hw->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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Reference in New Issue
Block a user