|
|
@@ -66,6 +66,7 @@ static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 };
|
|
|
#define I2C_GPIO_PULLUP_ERR_STR "this i2c pin does not support internal pull-up"
|
|
|
#define I2C_ACK_TYPE_ERR_STR "i2c ack type error"
|
|
|
#define I2C_DATA_LEN_ERR_STR "i2c data read length error"
|
|
|
+#define I2C_PSRAM_BUFFER_WARN_STR "Using buffer allocated from psram"
|
|
|
#define I2C_FIFO_FULL_THRESH_VAL (28)
|
|
|
#define I2C_FIFO_EMPTY_THRESH_VAL (5)
|
|
|
#define I2C_IO_INIT_LEVEL (1)
|
|
|
@@ -124,6 +125,11 @@ typedef struct {
|
|
|
|
|
|
i2c_cmd_desc_t cmd_link; /*!< I2C command link */
|
|
|
QueueHandle_t cmd_evt_queue; /*!< I2C command event queue */
|
|
|
+#if CONFIG_SPIRAM_USE_MALLOC
|
|
|
+ uint8_t* evt_queue_storage; /*!< The buffer that will hold the items in the queue */
|
|
|
+ int intr_alloc_flags; /*!< Used to allocate the interrupt */
|
|
|
+ StaticQueue_t evt_queue_buffer; /*!< The buffer that will hold the queue structure*/
|
|
|
+#endif
|
|
|
xSemaphoreHandle cmd_mux; /*!< semaphore to lock command process */
|
|
|
size_t tx_fifo_remain; /*!< tx fifo remain length, for master mode */
|
|
|
size_t rx_fifo_remain; /*!< rx fifo remain length, for master mode */
|
|
|
@@ -156,7 +162,16 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
|
|
|
ESP_ERR_INVALID_ARG);
|
|
|
uint32_t intr_mask = 0;
|
|
|
if (p_i2c_obj[i2c_num] == NULL) {
|
|
|
+
|
|
|
+#if !CONFIG_SPIRAM_USE_MALLOC
|
|
|
p_i2c_obj[i2c_num] = (i2c_obj_t*) calloc(1, sizeof(i2c_obj_t));
|
|
|
+#else
|
|
|
+ if( !(intr_alloc_flags & ESP_INTR_FLAG_IRAM) ) {
|
|
|
+ p_i2c_obj[i2c_num] = (i2c_obj_t*) calloc(1, sizeof(i2c_obj_t));
|
|
|
+ } else {
|
|
|
+ p_i2c_obj[i2c_num] = (i2c_obj_t*) heap_caps_calloc(1, sizeof(i2c_obj_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
|
|
|
+ }
|
|
|
+#endif
|
|
|
if (p_i2c_obj[i2c_num] == NULL) {
|
|
|
ESP_LOGE(I2C_TAG, I2C_DRIVER_MALLOC_ERR_STR);
|
|
|
return ESP_FAIL;
|
|
|
@@ -168,6 +183,9 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
|
|
|
p_i2c->rx_cnt = 0;
|
|
|
p_i2c->status = I2C_STATUS_IDLE;
|
|
|
|
|
|
+#if CONFIG_SPIRAM_USE_MALLOC
|
|
|
+ p_i2c->intr_alloc_flags = intr_alloc_flags;
|
|
|
+#endif
|
|
|
p_i2c->rx_fifo_remain = I2C_FIFO_LEN;
|
|
|
p_i2c->tx_fifo_remain = I2C_FIFO_LEN;
|
|
|
|
|
|
@@ -205,7 +223,21 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
|
|
|
} else {
|
|
|
//semaphore to sync sending process, because we only have 32 bytes for hardware fifo.
|
|
|
p_i2c->cmd_mux = xSemaphoreCreateMutex();
|
|
|
+#if !CONFIG_SPIRAM_USE_MALLOC
|
|
|
p_i2c->cmd_evt_queue = xQueueCreate(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t));
|
|
|
+#else
|
|
|
+ if( !(intr_alloc_flags & ESP_INTR_FLAG_IRAM) ) {
|
|
|
+ p_i2c->cmd_evt_queue = xQueueCreate(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t));
|
|
|
+ } else {
|
|
|
+ p_i2c->evt_queue_storage = (uint8_t *)heap_caps_calloc(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
|
|
|
+ if( p_i2c->evt_queue_storage == NULL ) {
|
|
|
+ ESP_LOGE(I2C_TAG, I2C_DRIVER_MALLOC_ERR_STR);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+ memset(&p_i2c->evt_queue_buffer, 0, sizeof(StaticQueue_t));
|
|
|
+ p_i2c->cmd_evt_queue = xQueueCreateStatic(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t), p_i2c->evt_queue_storage, &p_i2c->evt_queue_buffer);
|
|
|
+ }
|
|
|
+#endif
|
|
|
if (p_i2c->cmd_mux == NULL || p_i2c->cmd_evt_queue == NULL) {
|
|
|
ESP_LOGE(I2C_TAG, I2C_SEM_ERR_STR);
|
|
|
goto err;
|
|
|
@@ -262,6 +294,12 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
|
|
|
if (p_i2c_obj[i2c_num]->slv_tx_mux) {
|
|
|
vSemaphoreDelete(p_i2c_obj[i2c_num]->slv_tx_mux);
|
|
|
}
|
|
|
+#if CONFIG_SPIRAM_USE_MALLOC
|
|
|
+ if (p_i2c_obj[i2c_num]->evt_queue_storage) {
|
|
|
+ free(p_i2c_obj[i2c_num]->evt_queue_storage);
|
|
|
+ p_i2c_obj[i2c_num]->evt_queue_storage = NULL;
|
|
|
+ }
|
|
|
+#endif
|
|
|
}
|
|
|
free(p_i2c_obj[i2c_num]);
|
|
|
p_i2c_obj[i2c_num] = NULL;
|
|
|
@@ -324,6 +362,12 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num)
|
|
|
p_i2c->tx_ring_buf = NULL;
|
|
|
p_i2c->tx_buf_length = 0;
|
|
|
}
|
|
|
+#if CONFIG_SPIRAM_USE_MALLOC
|
|
|
+ if (p_i2c_obj[i2c_num]->evt_queue_storage) {
|
|
|
+ free(p_i2c_obj[i2c_num]->evt_queue_storage);
|
|
|
+ p_i2c_obj[i2c_num]->evt_queue_storage = NULL;
|
|
|
+ }
|
|
|
+#endif
|
|
|
|
|
|
free(p_i2c_obj[i2c_num]);
|
|
|
p_i2c_obj[i2c_num] = NULL;
|
|
|
@@ -839,7 +883,11 @@ esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, gpio_p
|
|
|
|
|
|
i2c_cmd_handle_t i2c_cmd_link_create()
|
|
|
{
|
|
|
+#if !CONFIG_SPIRAM_USE_MALLOC
|
|
|
i2c_cmd_desc_t* cmd_desc = (i2c_cmd_desc_t*) calloc(1, sizeof(i2c_cmd_desc_t));
|
|
|
+#else
|
|
|
+ i2c_cmd_desc_t* cmd_desc = (i2c_cmd_desc_t*) heap_caps_calloc(1, sizeof(i2c_cmd_desc_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
|
|
|
+#endif
|
|
|
return (i2c_cmd_handle_t) cmd_desc;
|
|
|
}
|
|
|
|
|
|
@@ -865,7 +913,11 @@ static esp_err_t i2c_cmd_link_append(i2c_cmd_handle_t cmd_handle, i2c_cmd_t* cmd
|
|
|
{
|
|
|
i2c_cmd_desc_t* cmd_desc = (i2c_cmd_desc_t*) cmd_handle;
|
|
|
if (cmd_desc->head == NULL) {
|
|
|
- cmd_desc->head = (i2c_cmd_link_t*) malloc(sizeof(i2c_cmd_link_t));
|
|
|
+#if !CONFIG_SPIRAM_USE_MALLOC
|
|
|
+ cmd_desc->head = (i2c_cmd_link_t*) calloc(1, sizeof(i2c_cmd_link_t));
|
|
|
+#else
|
|
|
+ cmd_desc->head = (i2c_cmd_link_t*) heap_caps_calloc(1, sizeof(i2c_cmd_link_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
|
|
|
+#endif
|
|
|
if (cmd_desc->head == NULL) {
|
|
|
ESP_LOGE(I2C_TAG, I2C_CMD_MALLOC_ERR_STR);
|
|
|
goto err;
|
|
|
@@ -873,7 +925,11 @@ static esp_err_t i2c_cmd_link_append(i2c_cmd_handle_t cmd_handle, i2c_cmd_t* cmd
|
|
|
cmd_desc->cur = cmd_desc->head;
|
|
|
cmd_desc->free = cmd_desc->head;
|
|
|
} else {
|
|
|
- cmd_desc->cur->next = (i2c_cmd_link_t*) malloc(sizeof(i2c_cmd_link_t));
|
|
|
+#if !CONFIG_SPIRAM_USE_MALLOC
|
|
|
+ cmd_desc->cur->next = (i2c_cmd_link_t*) calloc(1, sizeof(i2c_cmd_link_t));
|
|
|
+#else
|
|
|
+ cmd_desc->cur->next = (i2c_cmd_link_t*) heap_caps_calloc(1, sizeof(i2c_cmd_link_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
|
|
|
+#endif
|
|
|
if (cmd_desc->cur->next == NULL) {
|
|
|
ESP_LOGE(I2C_TAG, I2C_CMD_MALLOC_ERR_STR);
|
|
|
goto err;
|
|
|
@@ -1128,6 +1184,23 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+#if CONFIG_SPIRAM_USE_MALLOC
|
|
|
+//Check whether read or write buffer in cmd_link is internal.
|
|
|
+static bool is_cmd_link_buffer_internal(i2c_cmd_link_t *link)
|
|
|
+{
|
|
|
+ i2c_cmd_link_t* cmd_link = link;
|
|
|
+ while(cmd_link != NULL) {
|
|
|
+ if (cmd_link->cmd.op_code == I2C_CMD_WRITE || cmd_link->cmd.op_code == I2C_CMD_READ) {
|
|
|
+ if( cmd_link->cmd.data != NULL && !esp_ptr_internal(cmd_link->cmd.data)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ cmd_link = cmd_link->next;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, TickType_t ticks_to_wait)
|
|
|
{
|
|
|
I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
|
|
|
@@ -1135,6 +1208,16 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
|
|
|
I2C_CHECK(p_i2c_obj[i2c_num]->mode == I2C_MODE_MASTER, I2C_MASTER_MODE_ERR_STR, ESP_ERR_INVALID_STATE);
|
|
|
I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
|
|
|
|
|
+#if CONFIG_SPIRAM_USE_MALLOC
|
|
|
+ //If the i2c read or write buffer is not in internal RAM, we will return ESP_FAIL
|
|
|
+ //to avoid the ISR handler function crashing when the cache is disabled.
|
|
|
+ if( (p_i2c_obj[i2c_num]->intr_alloc_flags & ESP_INTR_FLAG_IRAM) ) {
|
|
|
+ if( !is_cmd_link_buffer_internal(((i2c_cmd_desc_t*)cmd_handle)->head) ) {
|
|
|
+ ESP_LOGE(I2C_TAG, I2C_PSRAM_BUFFER_WARN_STR);
|
|
|
+ return ESP_ERR_INVALID_ARG;
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
// Sometimes when the FSM get stuck, the ACK_ERR interrupt will occur endlessly until we reset the FSM and clear bus.
|
|
|
static uint8_t clear_bus_cnt = 0;
|
|
|
esp_err_t ret = ESP_FAIL;
|