diff --git a/idf-patch/i2c.c b/idf-patch/i2c.c deleted file mode 100644 index aeadfaad..00000000 --- a/idf-patch/i2c.c +++ /dev/null @@ -1,1465 +0,0 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include -#include -#include "esp_types.h" -#include "esp_attr.h" -#include "esp_intr_alloc.h" -#include "esp_log.h" -#include "malloc.h" -#include "freertos/FreeRTOS.h" -#include "freertos/semphr.h" -#include "freertos/xtensa_api.h" -#include "freertos/task.h" -#include "freertos/ringbuf.h" -#include "soc/i2c_periph.h" -#include "driver/i2c.h" -#include "driver/gpio.h" -#include "driver/periph_ctrl.h" -#include "esp_pm.h" -#include "soc/soc_memory_layout.h" - -static const char* I2C_TAG = "i2c"; -#define I2C_CHECK(a, str, ret) if(!(a)) { \ - ESP_LOGE(I2C_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \ - return (ret); \ - } - -static portMUX_TYPE i2c_spinlock[I2C_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED}; -/* DRAM_ATTR is required to avoid I2C array placed in flash, due to accessed from ISR */ -static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 }; - -#define I2C_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux) -#define I2C_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux) -#define I2C_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux) -#define I2C_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux) - -#define I2C_DRIVER_ERR_STR "i2c driver install error" -#define I2C_DRIVER_MALLOC_ERR_STR "i2c driver malloc error" -#define I2C_NUM_ERROR_STR "i2c number error" -#define I2C_TIMEING_VAL_ERR_STR "i2c timing value error" -#define I2C_ADDR_ERROR_STR "i2c null address error" -#define I2C_DRIVER_NOT_INSTALL_ERR_STR "i2c driver not installed" -#define I2C_SLAVE_BUFFER_LEN_ERR_STR "i2c buffer size too small for slave mode" -#define I2C_EVT_QUEUE_ERR_STR "i2c evt queue error" -#define I2C_SEM_ERR_STR "i2c semaphore error" -#define I2C_BUF_ERR_STR "i2c ringbuffer error" -#define I2C_MASTER_MODE_ERR_STR "Only allowed in master mode" -#define I2C_MODE_SLAVE_ERR_STR "Only allowed in slave mode" -#define I2C_CMD_MALLOC_ERR_STR "i2c command link malloc error" -#define I2C_TRANS_MODE_ERR_STR "i2c trans mode error" -#define I2C_MODE_ERR_STR "i2c mode error" -#define I2C_SDA_IO_ERR_STR "sda gpio number error" -#define I2C_SCL_IO_ERR_STR "scl gpio number error" -#define I2C_CMD_LINK_INIT_ERR_STR "i2c command link error" -#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_LOCK_ERR_STR "Power lock creation error" -#define I2C_FIFO_FULL_THRESH_VAL (28) -#define I2C_FIFO_EMPTY_THRESH_VAL (5) -#define I2C_IO_INIT_LEVEL (1) -#define I2C_CMD_ALIVE_INTERVAL_TICK (1000 / portTICK_PERIOD_MS) -#define I2C_CMD_EVT_ALIVE (0) -#define I2C_CMD_EVT_DONE (1) -#define I2C_EVT_QUEUE_LEN (1) -#define I2C_SLAVE_TIMEOUT_DEFAULT (32000) /* I2C slave timeout value, APB clock cycle number */ -#define I2C_SLAVE_SDA_SAMPLE_DEFAULT (10) /* I2C slave sample time after scl positive edge default value */ -#define I2C_SLAVE_SDA_HOLD_DEFAULT (10) /* I2C slave hold time after scl negative edge default value */ -#define I2C_MASTER_TOUT_CNUM_DEFAULT (8) /* I2C master timeout cycle number of I2C clock, after which the timeout interrupt will be triggered */ -#define I2C_ACKERR_CNT_MAX (10) -#define I2C_FILTER_CYC_NUM_DEF (7) /* The number of apb cycles filtered by default*/ -#define I2C_CLR_BUS_SCL_NUM (9) -#define I2C_CLR_BUS_HALF_PERIOD_US (5) - -typedef struct { - uint8_t byte_num; /*!< cmd byte number */ - uint8_t ack_en; /*!< ack check enable */ - uint8_t ack_exp; /*!< expected ack level to get */ - uint8_t ack_val; /*!< ack value to send */ - uint8_t* data; /*!< data address */ - uint8_t byte_cmd; /*!< to save cmd for one byte command mode */ - i2c_opmode_t op_code; /*!< hardware cmd type */ -} i2c_cmd_t; - -typedef typeof(I2C[0]->command[0]) i2c_hw_cmd_t; - -typedef struct i2c_cmd_link{ - i2c_cmd_t cmd; /*!< command in current cmd link */ - struct i2c_cmd_link *next; /*!< next cmd link */ -} i2c_cmd_link_t; - -typedef struct { - i2c_cmd_link_t* head; /*!< head of the command link */ - i2c_cmd_link_t* cur; /*!< last node of the command link */ - i2c_cmd_link_t* free; /*!< the first node to free of the command link */ -} i2c_cmd_desc_t; - -typedef enum { - I2C_STATUS_READ, /*!< read status for current master command */ - I2C_STATUS_WRITE, /*!< write status for current master command */ - I2C_STATUS_IDLE, /*!< idle status for current master command */ - I2C_STATUS_ACK_ERROR, /*!< ack error status for current master command */ - I2C_STATUS_DONE, /*!< I2C command done */ - I2C_STATUS_TIMEOUT, /*!< I2C bus status error, and operation timeout */ -} i2c_status_t; - -typedef struct { - int type; -} i2c_cmd_evt_t; - -typedef struct { - int i2c_num; /*!< I2C port number */ - int mode; /*!< I2C mode, master or slave */ - intr_handle_t intr_handle; /*!< I2C interrupt handle*/ - int cmd_idx; /*!< record current command index, for master mode */ - int status; /*!< record current command status, for master mode */ - int rx_cnt; /*!< record current read index, for master mode */ - uint8_t data_buf[I2C_FIFO_LEN]; /*!< a buffer to store i2c fifo data */ - - 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 */ -#ifdef CONFIG_PM_ENABLE - esp_pm_lock_handle_t pm_lock; -#endif - size_t tx_fifo_remain; /*!< tx fifo remain length, for master mode */ - size_t rx_fifo_remain; /*!< rx fifo remain length, for master mode */ - - xSemaphoreHandle slv_rx_mux; /*!< slave rx buffer mux */ - xSemaphoreHandle slv_tx_mux; /*!< slave tx buffer mux */ - size_t rx_buf_length; /*!< rx buffer length */ - RingbufHandle_t rx_ring_buf; /*!< rx ringbuffer handler of slave mode */ - size_t tx_buf_length; /*!< tx buffer length */ - RingbufHandle_t tx_ring_buf; /*!< tx ringbuffer handler of slave mode */ -} i2c_obj_t; - -static i2c_obj_t *p_i2c_obj[I2C_NUM_MAX] = {0}; -static void i2c_isr_handler_default(void* arg); -static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num); -static esp_err_t IRAM_ATTR i2c_hw_fsm_reset(i2c_port_t i2c_num); - -/* - For i2c master mode, we don't need to use a buffer for the data, the APIs will execute the master commands -and return after all of the commands have been sent out or when error occurs. So when we send master commands, -we should free or modify the source data only after the i2c_master_cmd_begin function returns. - For i2c slave mode, we need a data buffer to stash the sending and receiving data, because the hardware fifo -has only 32 bytes. -*/ -esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_buf_len, size_t slv_tx_buf_len, - int intr_alloc_flags) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(mode == I2C_MODE_MASTER || ( slv_rx_buf_len > 100 || slv_tx_buf_len > 100 ), I2C_SLAVE_BUFFER_LEN_ERR_STR, - ESP_ERR_INVALID_ARG); - uint32_t intr_mask = 0; - if (p_i2c_obj[i2c_num] == NULL) { - -#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; - } - i2c_obj_t* p_i2c = p_i2c_obj[i2c_num]; - p_i2c->i2c_num = i2c_num; - p_i2c->mode = mode; - p_i2c->cmd_idx = 0; - 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; - - if (mode == I2C_MODE_SLAVE) { - //we only use ringbuffer for slave mode. - if (slv_rx_buf_len > 0) { - p_i2c->rx_ring_buf = xRingbufferCreate(slv_rx_buf_len, RINGBUF_TYPE_BYTEBUF); - if (p_i2c->rx_ring_buf == NULL) { - ESP_LOGE(I2C_TAG, I2C_BUF_ERR_STR); - goto err; - } - p_i2c->rx_buf_length = slv_rx_buf_len; - } else { - p_i2c->rx_ring_buf = NULL; - p_i2c->rx_buf_length = 0; - } - if (slv_tx_buf_len > 0) { - p_i2c->tx_ring_buf = xRingbufferCreate(slv_tx_buf_len, RINGBUF_TYPE_BYTEBUF); - if (p_i2c->tx_ring_buf == NULL) { - ESP_LOGE(I2C_TAG, I2C_BUF_ERR_STR); - goto err; - } - p_i2c->tx_buf_length = slv_tx_buf_len; - } else { - p_i2c->tx_ring_buf = NULL; - p_i2c->tx_buf_length = 0; - } - p_i2c->slv_rx_mux = xSemaphoreCreateMutex(); - p_i2c->slv_tx_mux = xSemaphoreCreateMutex(); - if (p_i2c->slv_rx_mux == NULL || p_i2c->slv_tx_mux == NULL) { - ESP_LOGE(I2C_TAG, I2C_SEM_ERR_STR); - goto err; - } - intr_mask |= ( I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M); - } else { - //semaphore to sync sending process, because we only have 32 bytes for hardware fifo. - p_i2c->cmd_mux = xSemaphoreCreateMutex(); -#ifdef CONFIG_PM_ENABLE - if (esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "i2c_driver", &p_i2c->pm_lock) != ESP_OK) { - ESP_LOGE(I2C_TAG, I2C_LOCK_ERR_STR); - goto err; - } -#endif -#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; - } - //command link - p_i2c->cmd_link.cur = NULL; - p_i2c->cmd_link.head = NULL; - p_i2c->cmd_link.free = NULL; - - p_i2c->tx_ring_buf = NULL; - p_i2c->rx_buf_length = 0; - p_i2c->tx_ring_buf = NULL; - p_i2c->tx_buf_length = 0; - intr_mask |= I2C_ARBITRATION_LOST_INT_ENA_M | I2C_TIME_OUT_INT_ST_M; - } - } else { - ESP_LOGE(I2C_TAG, I2C_DRIVER_ERR_STR); - return ESP_FAIL; - } - //hook isr handler - i2c_isr_register(i2c_num, i2c_isr_handler_default, p_i2c_obj[i2c_num], intr_alloc_flags, &p_i2c_obj[i2c_num]->intr_handle); - intr_mask |= ( I2C_TRANS_COMPLETE_INT_ENA_M | - I2C_TRANS_START_INT_ENA_M | - I2C_ACK_ERR_INT_ENA_M | - I2C_RXFIFO_OVF_INT_ENA_M | - I2C_SLAVE_TRAN_COMP_INT_ENA_M); - I2C[i2c_num]->int_clr.val = intr_mask; - I2C[i2c_num]->int_ena.val = intr_mask; - return ESP_OK; - - err: - //Some error has happened. Free/destroy all allocated things and return ESP_FAIL. - if (p_i2c_obj[i2c_num]) { - if (p_i2c_obj[i2c_num]->rx_ring_buf) { - vRingbufferDelete(p_i2c_obj[i2c_num]->rx_ring_buf); - p_i2c_obj[i2c_num]->rx_ring_buf = NULL; - p_i2c_obj[i2c_num]->rx_buf_length = 0; - } - if (p_i2c_obj[i2c_num]->tx_ring_buf) { - vRingbufferDelete(p_i2c_obj[i2c_num]->tx_ring_buf); - p_i2c_obj[i2c_num]->tx_ring_buf = NULL; - p_i2c_obj[i2c_num]->tx_buf_length = 0; - } - if (p_i2c_obj[i2c_num]->cmd_evt_queue) { - vQueueDelete(p_i2c_obj[i2c_num]->cmd_evt_queue); - p_i2c_obj[i2c_num]->cmd_evt_queue = NULL; - } - if (p_i2c_obj[i2c_num]->cmd_mux) { - vSemaphoreDelete(p_i2c_obj[i2c_num]->cmd_mux); - } - if (p_i2c_obj[i2c_num]->slv_rx_mux) { - vSemaphoreDelete(p_i2c_obj[i2c_num]->slv_rx_mux); - } - if (p_i2c_obj[i2c_num]->slv_tx_mux) { - vSemaphoreDelete(p_i2c_obj[i2c_num]->slv_tx_mux); - } -#ifdef CONFIG_PM_ENABLE - if (p_i2c_obj[i2c_num]->pm_lock) { - esp_pm_lock_delete(p_i2c_obj[i2c_num]->pm_lock); - p_i2c_obj[i2c_num]->pm_lock = NULL; - } -#endif -#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; - return ESP_FAIL; -} - -static esp_err_t i2c_hw_enable(i2c_port_t i2c_num) -{ - if (i2c_num == I2C_NUM_0) { - periph_module_enable(PERIPH_I2C0_MODULE); - } else if (i2c_num == I2C_NUM_1) { - periph_module_enable(PERIPH_I2C1_MODULE); - } - return ESP_OK; -} - -static esp_err_t i2c_hw_disable(i2c_port_t i2c_num) -{ - if (i2c_num == I2C_NUM_0) { - periph_module_disable(PERIPH_I2C0_MODULE); - } else if (i2c_num == I2C_NUM_1) { - periph_module_disable(PERIPH_I2C1_MODULE); - } - return ESP_OK; -} - -esp_err_t i2c_driver_delete(i2c_port_t i2c_num) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_ERR_STR, ESP_FAIL); - - i2c_obj_t* p_i2c = p_i2c_obj[i2c_num]; - - I2C[i2c_num]->int_ena.val = 0; - esp_intr_free(p_i2c->intr_handle); - p_i2c->intr_handle = NULL; - - if (p_i2c->cmd_mux) { - xSemaphoreTake(p_i2c->cmd_mux, portMAX_DELAY); - vSemaphoreDelete(p_i2c->cmd_mux); - } - if (p_i2c_obj[i2c_num]->cmd_evt_queue) { - vQueueDelete(p_i2c_obj[i2c_num]->cmd_evt_queue); - p_i2c_obj[i2c_num]->cmd_evt_queue = NULL; - } - if (p_i2c->slv_rx_mux) { - vSemaphoreDelete(p_i2c->slv_rx_mux); - } - if (p_i2c->slv_tx_mux) { - vSemaphoreDelete(p_i2c->slv_tx_mux); - } - - if (p_i2c->rx_ring_buf) { - vRingbufferDelete(p_i2c->rx_ring_buf); - p_i2c->rx_ring_buf = NULL; - p_i2c->rx_buf_length = 0; - } - if (p_i2c->tx_ring_buf) { - vRingbufferDelete(p_i2c->tx_ring_buf); - p_i2c->tx_ring_buf = NULL; - p_i2c->tx_buf_length = 0; - } -#ifdef CONFIG_PM_ENABLE - if (p_i2c->pm_lock) { - esp_pm_lock_delete(p_i2c->pm_lock); - p_i2c->pm_lock = NULL; - } -#endif -#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; - - i2c_hw_disable(i2c_num); - return ESP_OK; -} - -esp_err_t i2c_reset_tx_fifo(i2c_port_t i2c_num) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->fifo_conf.tx_fifo_rst = 1; - I2C[i2c_num]->fifo_conf.tx_fifo_rst = 0; - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_reset_rx_fifo(i2c_port_t i2c_num) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->fifo_conf.rx_fifo_rst = 1; - I2C[i2c_num]->fifo_conf.rx_fifo_rst = 0; - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -static void IRAM_ATTR i2c_isr_handler_default(void* arg) -{ - i2c_obj_t* p_i2c = (i2c_obj_t*) arg; - int i2c_num = p_i2c->i2c_num; - uint32_t status = I2C[i2c_num]->int_status.val; - int idx = 0; - - portBASE_TYPE HPTaskAwoken = pdFALSE; - while (status != 0) { - status = I2C[i2c_num]->int_status.val; - if (status & I2C_TX_SEND_EMPTY_INT_ST_M) { - I2C[i2c_num]->int_clr.tx_send_empty = 1; - } else if (status & I2C_RX_REC_FULL_INT_ST_M) { - I2C[i2c_num]->int_clr.rx_rec_full = 1; - } else if (status & I2C_ACK_ERR_INT_ST_M) { - I2C[i2c_num]->int_ena.ack_err = 0; - I2C[i2c_num]->int_clr.ack_err = 1; - if (p_i2c->mode == I2C_MODE_MASTER) { - p_i2c_obj[i2c_num]->status = I2C_STATUS_ACK_ERROR; - I2C[i2c_num]->int_clr.ack_err = 1; - //get error ack value from slave device, stop the commands - i2c_master_cmd_begin_static(i2c_num); - } - } else if (status & I2C_TRANS_START_INT_ST_M) { - I2C[i2c_num]->int_clr.trans_start = 1; - } else if (status & I2C_TIME_OUT_INT_ST_M) { - I2C[i2c_num]->int_ena.time_out = 0; - I2C[i2c_num]->int_clr.time_out = 1; - p_i2c_obj[i2c_num]->status = I2C_STATUS_TIMEOUT; - i2c_master_cmd_begin_static(i2c_num); - } else if (status & I2C_TRANS_COMPLETE_INT_ST_M) { - I2C[i2c_num]->int_clr.trans_complete = 1; - if (p_i2c->mode == I2C_MODE_SLAVE) { - int rx_fifo_cnt = I2C[i2c_num]->status_reg.rx_fifo_cnt; - for (idx = 0; idx < rx_fifo_cnt; idx++) { - p_i2c->data_buf[idx] = I2C[i2c_num]->fifo_data.data; - } - xRingbufferSendFromISR(p_i2c->rx_ring_buf, p_i2c->data_buf, rx_fifo_cnt, &HPTaskAwoken); - I2C[i2c_num]->int_clr.rx_fifo_full = 1; - } else { - // add check for unexcepted situations caused by noise. - if (p_i2c->status != I2C_STATUS_ACK_ERROR && p_i2c->status != I2C_STATUS_IDLE) { - i2c_master_cmd_begin_static(i2c_num); - } - } - } else if (status & I2C_MASTER_TRAN_COMP_INT_ST_M) { - I2C[i2c_num]->int_clr.master_tran_comp = 1; - } else if (status & I2C_ARBITRATION_LOST_INT_ST_M) { - I2C[i2c_num]->int_clr.arbitration_lost = 1; - p_i2c_obj[i2c_num]->status = I2C_STATUS_TIMEOUT; - i2c_master_cmd_begin_static(i2c_num); - } else if (status & I2C_SLAVE_TRAN_COMP_INT_ST_M) { - I2C[i2c_num]->int_clr.slave_tran_comp = 1; - } else if (status & I2C_END_DETECT_INT_ST_M) { - I2C[i2c_num]->int_ena.end_detect = 0; - I2C[i2c_num]->int_clr.end_detect = 1; - i2c_master_cmd_begin_static(i2c_num); - } else if (status & I2C_RXFIFO_OVF_INT_ST_M) { - I2C[i2c_num]->int_clr.rx_fifo_ovf = 1; - } else if (status & I2C_TXFIFO_EMPTY_INT_ST_M) { - int tx_fifo_rem = I2C_FIFO_LEN - I2C[i2c_num]->status_reg.tx_fifo_cnt; - size_t size = 0; - uint8_t *data = (uint8_t*) xRingbufferReceiveUpToFromISR(p_i2c->tx_ring_buf, &size, tx_fifo_rem); - if (data) { - for (idx = 0; idx < size; idx++) { - WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), data[idx]); - } - vRingbufferReturnItemFromISR(p_i2c->tx_ring_buf, data, &HPTaskAwoken); - I2C[i2c_num]->int_ena.tx_fifo_empty = 1; - I2C[i2c_num]->int_clr.tx_fifo_empty = 1; - } else { - I2C[i2c_num]->int_ena.tx_fifo_empty = 0; - I2C[i2c_num]->int_clr.tx_fifo_empty = 1; - } - } else if (status & I2C_RXFIFO_FULL_INT_ST_M) { - int rx_fifo_cnt = I2C[i2c_num]->status_reg.rx_fifo_cnt; - for (idx = 0; idx < rx_fifo_cnt; idx++) { - p_i2c->data_buf[idx] = I2C[i2c_num]->fifo_data.data; - } - xRingbufferSendFromISR(p_i2c->rx_ring_buf, p_i2c->data_buf, rx_fifo_cnt, &HPTaskAwoken); - I2C[i2c_num]->int_clr.rx_fifo_full = 1; - } else { - I2C[i2c_num]->int_clr.val = status; - } - } - if (p_i2c->mode == I2C_MODE_MASTER) { - i2c_cmd_evt_t evt; - evt.type = I2C_CMD_EVT_ALIVE; - xQueueSendFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken); - } - //We only need to check here if there is a high-priority task needs to be switched. - if(HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } -} - -esp_err_t i2c_set_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t tx_trans_mode, i2c_trans_mode_t rx_trans_mode) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(tx_trans_mode < I2C_DATA_MODE_MAX, I2C_TRANS_MODE_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(rx_trans_mode < I2C_DATA_MODE_MAX, I2C_TRANS_MODE_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->ctr.rx_lsb_first = rx_trans_mode; //set rx data msb first - I2C[i2c_num]->ctr.tx_lsb_first = tx_trans_mode; //set tx data msb first - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode, i2c_trans_mode_t *rx_trans_mode) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - if (tx_trans_mode) { - *tx_trans_mode = I2C[i2c_num]->ctr.tx_lsb_first; - } - if (rx_trans_mode) { - *rx_trans_mode = I2C[i2c_num]->ctr.rx_lsb_first; - } - return ESP_OK; -} - -/* Some slave device will die by accident and keep the SDA in low level, - * in this case, master should send several clock to make the slave release the bus. - * Slave mode of ESP32 might also get in wrong state that held the SDA low, - * in this case, master device could send a stop signal to make esp32 slave release the bus. - **/ -static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - const int scl_half_period = I2C_CLR_BUS_HALF_PERIOD_US; // use standard 100kHz data rate - int sda_in_sig = 0, scl_in_sig = 0; - int i = 0; - if (i2c_num == I2C_NUM_0) { - sda_in_sig = I2CEXT0_SDA_IN_IDX; - scl_in_sig = I2CEXT0_SCL_IN_IDX; - } else if (i2c_num == I2C_NUM_1) { - sda_in_sig = I2CEXT1_SDA_IN_IDX; - scl_in_sig = I2CEXT1_SCL_IN_IDX; - } - int scl_io = GPIO.func_in_sel_cfg[scl_in_sig].func_sel; - int sda_io = GPIO.func_in_sel_cfg[sda_in_sig].func_sel; - I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(scl_io)), I2C_SCL_IO_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(sda_io)), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG); - gpio_set_direction(scl_io, GPIO_MODE_OUTPUT_OD); - gpio_set_direction(sda_io, GPIO_MODE_INPUT_OUTPUT_OD); - // If a SLAVE device was in a read operation when the bus was interrupted, the SLAVE device is controlling SDA. - // The only bit during the 9 clock cycles of a READ byte the MASTER(ESP32) is guaranteed control over is during the ACK bit - // period. If the slave is sending a stream of ZERO bytes, it will only release SDA during the ACK bit period. - // So, this reset code needs to synchronize the bit stream with, Either, the ACK bit, Or a 1 bit to correctly generate - // a STOP condition. - gpio_set_level(scl_io, 0); - gpio_set_level(sda_io, 1); - ets_delay_us(scl_half_period); - while(!gpio_get_level(sda_io) && (i++ < I2C_CLR_BUS_SCL_NUM)) { - gpio_set_level(scl_io, 1); - ets_delay_us(scl_half_period); - gpio_set_level(scl_io, 0); - ets_delay_us(scl_half_period); - } - gpio_set_level(sda_io,0); // setup for STOP - gpio_set_level(scl_io,1); - ets_delay_us(scl_half_period); - gpio_set_level(sda_io, 1); // STOP, SDA low -> high while SCL is HIGH - i2c_set_pin(i2c_num, sda_io, scl_io, 1, 1, I2C_MODE_MASTER); - return ESP_OK; -} - -/**if the power and SDA/SCL wires are in proper condition, everything works find with reading the slave. - * If we remove the power supply for the slave during I2C is reading, or directly connect SDA or SCL to ground, - * this would cause the I2C FSM get stuck in wrong state, all we can do is to reset the I2C hardware in this case. - **/ -static esp_err_t i2c_hw_fsm_reset(i2c_port_t i2c_num) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - uint32_t ctr = I2C[i2c_num]->ctr.val; - uint32_t fifo_conf = I2C[i2c_num]->fifo_conf.val; - uint32_t scl_low_period = I2C[i2c_num]->scl_low_period.val; - uint32_t scl_high_period = I2C[i2c_num]->scl_high_period.val; - uint32_t scl_start_hold = I2C[i2c_num]->scl_start_hold.val; - uint32_t scl_rstart_setup = I2C[i2c_num]->scl_rstart_setup.val; - uint32_t scl_stop_hold = I2C[i2c_num]->scl_stop_hold.val; - uint32_t scl_stop_setup = I2C[i2c_num]->scl_stop_setup.val; - uint32_t sda_hold = I2C[i2c_num]->sda_hold.val; - uint32_t sda_sample = I2C[i2c_num]->sda_sample.val; - uint32_t timeout = I2C[i2c_num]->timeout.val; - uint32_t scl_filter_cfg = I2C[i2c_num]->scl_filter_cfg.val; - uint32_t sda_filter_cfg = I2C[i2c_num]->sda_filter_cfg.val; - uint32_t slave_addr = I2C[i2c_num]->slave_addr.val; - - //to reset the I2C hw module, we need re-enable the hw - i2c_hw_disable(i2c_num); - i2c_master_clear_bus(i2c_num); - i2c_hw_enable(i2c_num); - I2C[i2c_num]->int_ena.val = 0; - I2C[i2c_num]->ctr.val = ctr & (~I2C_TRANS_START_M); - I2C[i2c_num]->fifo_conf.val = fifo_conf; - I2C[i2c_num]->scl_low_period.val = scl_low_period; - I2C[i2c_num]->scl_high_period.val = scl_high_period; - I2C[i2c_num]->scl_start_hold.val = scl_start_hold; - I2C[i2c_num]->scl_rstart_setup.val = scl_rstart_setup; - I2C[i2c_num]->scl_stop_hold.val = scl_stop_hold; - I2C[i2c_num]->scl_stop_setup.val = scl_stop_setup; - I2C[i2c_num]->sda_hold.val = sda_hold; - I2C[i2c_num]->sda_sample.val = sda_sample; - I2C[i2c_num]->timeout.val = timeout; - I2C[i2c_num]->scl_filter_cfg.val = scl_filter_cfg; - I2C[i2c_num]->sda_filter_cfg.val = sda_filter_cfg; - uint32_t intr_mask = ( I2C_TRANS_COMPLETE_INT_ENA_M - | I2C_TRANS_START_INT_ENA_M - | I2C_ACK_ERR_INT_ENA_M - | I2C_RXFIFO_OVF_INT_ENA_M - | I2C_SLAVE_TRAN_COMP_INT_ENA_M - | I2C_TIME_OUT_INT_ENA_M); - if (I2C[i2c_num]->ctr.ms_mode == I2C_MODE_SLAVE) { - I2C[i2c_num]->slave_addr.val = slave_addr; - intr_mask |= ( I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M); - } else { - intr_mask |= I2C_ARBITRATION_LOST_INT_ENA_M; - } - I2C[i2c_num]->int_clr.val = intr_mask; - I2C[i2c_num]->int_ena.val = intr_mask; - return ESP_OK; -} - -esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(i2c_conf != NULL, I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(i2c_conf->mode < I2C_MODE_MAX, I2C_MODE_ERR_STR, ESP_ERR_INVALID_ARG); - - esp_err_t ret = i2c_set_pin(i2c_num, i2c_conf->sda_io_num, i2c_conf->scl_io_num, - i2c_conf->sda_pullup_en, i2c_conf->scl_pullup_en, i2c_conf->mode); - if (ret != ESP_OK) { - return ret; - } - // Reset the I2C hardware in case there is a soft reboot. - i2c_hw_disable(i2c_num); - i2c_hw_enable(i2c_num); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->ctr.rx_lsb_first = I2C_DATA_MODE_MSB_FIRST; //set rx data msb first - I2C[i2c_num]->ctr.tx_lsb_first = I2C_DATA_MODE_MSB_FIRST; //set tx data msb first - I2C[i2c_num]->ctr.ms_mode = i2c_conf->mode; //mode for master or slave - I2C[i2c_num]->ctr.sda_force_out = 1; // set open-drain output mode - I2C[i2c_num]->ctr.scl_force_out = 1; // set open-drain output mode - I2C[i2c_num]->ctr.sample_scl_level = 0; //sample at high level of clock - - if (i2c_conf->mode == I2C_MODE_SLAVE) { //slave mode - I2C[i2c_num]->slave_addr.addr = i2c_conf->slave.slave_addr; - I2C[i2c_num]->slave_addr.en_10bit = i2c_conf->slave.addr_10bit_en; - I2C[i2c_num]->fifo_conf.nonfifo_en = 0; - I2C[i2c_num]->fifo_conf.fifo_addr_cfg_en = 0; - I2C[i2c_num]->fifo_conf.rx_fifo_full_thrhd = I2C_FIFO_FULL_THRESH_VAL; - I2C[i2c_num]->fifo_conf.tx_fifo_empty_thrhd = I2C_FIFO_EMPTY_THRESH_VAL; - I2C[i2c_num]->ctr.trans_start = 0; - I2C[i2c_num]->timeout.tout = I2C_SLAVE_TIMEOUT_DEFAULT; - //set timing for data - I2C[i2c_num]->sda_hold.time = I2C_SLAVE_SDA_HOLD_DEFAULT; - I2C[i2c_num]->sda_sample.time = I2C_SLAVE_SDA_SAMPLE_DEFAULT; - } else { - I2C[i2c_num]->fifo_conf.nonfifo_en = 0; - int cycle = (I2C_APB_CLK_FREQ / i2c_conf->master.clk_speed); - int half_cycle = cycle / 2; - I2C[i2c_num]->timeout.tout = cycle * I2C_MASTER_TOUT_CNUM_DEFAULT; - //set timing for data - I2C[i2c_num]->sda_hold.time = half_cycle / 2; - I2C[i2c_num]->sda_sample.time = half_cycle / 2; - - I2C[i2c_num]->scl_low_period.period = half_cycle; - I2C[i2c_num]->scl_high_period.period = half_cycle; - //set timing for start signal - I2C[i2c_num]->scl_start_hold.time = half_cycle; - I2C[i2c_num]->scl_rstart_setup.time = half_cycle; - //set timing for stop signal - I2C[i2c_num]->scl_stop_hold.time = half_cycle; - I2C[i2c_num]->scl_stop_setup.time = half_cycle; - //Default, we enable hardware filter - i2c_filter_enable(i2c_num, I2C_FILTER_CYC_NUM_DEF); - } - - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK((high_period <= I2C_SCL_HIGH_PERIOD_V) && (high_period > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK((low_period <= I2C_SCL_LOW_PERIOD_V) && (low_period > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->scl_high_period.period = high_period; - I2C[i2c_num]->scl_low_period.period = low_period; - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_get_period(i2c_port_t i2c_num, int* high_period, int* low_period) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - if (high_period) { - *high_period = I2C[i2c_num]->scl_high_period.period; - } - if (low_period) { - *low_period = I2C[i2c_num]->scl_low_period.period; - } - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_filter_enable(i2c_port_t i2c_num, uint8_t cyc_num) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->scl_filter_cfg.thres = cyc_num; - I2C[i2c_num]->sda_filter_cfg.thres = cyc_num; - I2C[i2c_num]->scl_filter_cfg.en = 1; - I2C[i2c_num]->sda_filter_cfg.en = 1; - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_filter_disable(i2c_port_t i2c_num) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->scl_filter_cfg.en = 0; - I2C[i2c_num]->sda_filter_cfg.en = 0; - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK((hold_time <= I2C_SCL_START_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK((setup_time <= I2C_SCL_RSTART_SETUP_TIME_V) && (setup_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->scl_start_hold.time = hold_time; - I2C[i2c_num]->scl_rstart_setup.time = setup_time; - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_get_start_timing(i2c_port_t i2c_num, int* setup_time, int* hold_time) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - if (hold_time) { - *hold_time = I2C[i2c_num]->scl_start_hold.time; - } - if (setup_time) { - *setup_time = I2C[i2c_num]->scl_rstart_setup.time; - } - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_set_stop_timing(i2c_port_t i2c_num, int setup_time, int hold_time) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK((setup_time <= I2C_SCL_STOP_SETUP_TIME_V) && (setup_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK((hold_time <= I2C_SCL_STOP_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->scl_stop_hold.time = hold_time; - I2C[i2c_num]->scl_stop_setup.time = setup_time; - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_get_stop_timing(i2c_port_t i2c_num, int* setup_time, int* hold_time) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - if (setup_time) { - *setup_time = I2C[i2c_num]->scl_stop_setup.time; - } - if (hold_time) { - *hold_time = I2C[i2c_num]->scl_stop_hold.time; - } - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK((sample_time <= I2C_SDA_SAMPLE_TIME_V) && (sample_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK((hold_time <= I2C_SDA_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->sda_hold.time = hold_time; - I2C[i2c_num]->sda_sample.time = sample_time; - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_get_data_timing(i2c_port_t i2c_num, int* sample_time, int* hold_time) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - if (sample_time) { - *sample_time = I2C[i2c_num]->sda_sample.time; - } - if (hold_time) { - *hold_time = I2C[i2c_num]->sda_hold.time; - } - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_set_timeout(i2c_port_t i2c_num, int timeout) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK((timeout <= I2C_TIME_OUT_REG_V) && (timeout > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG); - - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->timeout.tout = timeout; - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - return ESP_OK; -} - -esp_err_t i2c_get_timeout(i2c_port_t i2c_num, int* timeout) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - if (timeout) { - *timeout = I2C[i2c_num]->timeout.tout; - } - return ESP_OK; -} - -esp_err_t i2c_isr_register(i2c_port_t i2c_num, void (*fn)(void*), void * arg, int intr_alloc_flags, intr_handle_t *handle) -{ - I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(fn != NULL, I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); - esp_err_t ret; - switch (i2c_num) { - case I2C_NUM_1: - ret = esp_intr_alloc(ETS_I2C_EXT1_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); - break; - case I2C_NUM_0: - default: - ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); - break; - } - return ret; -} - -esp_err_t i2c_isr_free(intr_handle_t handle) -{ - return esp_intr_free(handle); -} - -esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, gpio_pullup_t sda_pullup_en, gpio_pullup_t scl_pullup_en, i2c_mode_t mode) -{ - I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(((sda_io_num < 0) || ((GPIO_IS_VALID_OUTPUT_GPIO(sda_io_num)))), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(scl_io_num < 0 || - (GPIO_IS_VALID_OUTPUT_GPIO(scl_io_num)) || - (GPIO_IS_VALID_GPIO(scl_io_num) && mode == I2C_MODE_SLAVE), - I2C_SCL_IO_ERR_STR, - ESP_ERR_INVALID_ARG); - I2C_CHECK(sda_io_num < 0 || - (sda_pullup_en == GPIO_PULLUP_ENABLE && GPIO_IS_VALID_OUTPUT_GPIO(sda_io_num)) || - sda_pullup_en == GPIO_PULLUP_DISABLE, I2C_GPIO_PULLUP_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(scl_io_num < 0 || - (scl_pullup_en == GPIO_PULLUP_ENABLE && GPIO_IS_VALID_OUTPUT_GPIO(scl_io_num)) || - scl_pullup_en == GPIO_PULLUP_DISABLE, I2C_GPIO_PULLUP_ERR_STR, ESP_ERR_INVALID_ARG); - - int sda_in_sig, sda_out_sig, scl_in_sig, scl_out_sig; - switch (i2c_num) { - case I2C_NUM_1: - sda_out_sig = I2CEXT1_SDA_OUT_IDX; - sda_in_sig = I2CEXT1_SDA_IN_IDX; - scl_out_sig = I2CEXT1_SCL_OUT_IDX; - scl_in_sig = I2CEXT1_SCL_IN_IDX; - break; - case I2C_NUM_0: - default: - sda_out_sig = I2CEXT0_SDA_OUT_IDX; - sda_in_sig = I2CEXT0_SDA_IN_IDX; - scl_out_sig = I2CEXT0_SCL_OUT_IDX; - scl_in_sig = I2CEXT0_SCL_IN_IDX; - break; - } - if (sda_io_num >= 0) { - gpio_set_level(sda_io_num, I2C_IO_INIT_LEVEL); - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[sda_io_num], PIN_FUNC_GPIO); - gpio_set_direction(sda_io_num, GPIO_MODE_INPUT_OUTPUT_OD); - - if (sda_pullup_en == GPIO_PULLUP_ENABLE) { - gpio_set_pull_mode(sda_io_num, GPIO_PULLUP_ONLY); - } else { - gpio_set_pull_mode(sda_io_num, GPIO_FLOATING); - } - gpio_matrix_out(sda_io_num, sda_out_sig, 0, 0); - gpio_matrix_in(sda_io_num, sda_in_sig, 0); - } - - if (scl_io_num >= 0) { - gpio_set_level(scl_io_num, I2C_IO_INIT_LEVEL); - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[scl_io_num], PIN_FUNC_GPIO); - if (mode == I2C_MODE_MASTER) { - gpio_set_direction(scl_io_num, GPIO_MODE_INPUT_OUTPUT_OD); - gpio_matrix_out(scl_io_num, scl_out_sig, 0, 0); - } else { - gpio_set_direction(scl_io_num, GPIO_MODE_INPUT); - } - if (scl_pullup_en == GPIO_PULLUP_ENABLE) { - gpio_set_pull_mode(scl_io_num, GPIO_PULLUP_ONLY); - } else { - gpio_set_pull_mode(scl_io_num, GPIO_FLOATING); - } - gpio_matrix_in(scl_io_num, scl_in_sig, 0); - } - return ESP_OK; -} - -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; -} - -void i2c_cmd_link_delete(i2c_cmd_handle_t cmd_handle) -{ - if (cmd_handle == NULL) { - return; - } - i2c_cmd_desc_t* cmd = (i2c_cmd_desc_t*) cmd_handle; - while (cmd->free) { - i2c_cmd_link_t* ptmp = cmd->free; - cmd->free = cmd->free->next; - free(ptmp); - } - cmd->cur = NULL; - cmd->free = NULL; - cmd->head = NULL; - free(cmd_handle); - return; -} - -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) { -#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; - } - cmd_desc->cur = cmd_desc->head; - cmd_desc->free = cmd_desc->head; - } else { -#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; - } - cmd_desc->cur = cmd_desc->cur->next; - } - memcpy((uint8_t*) &cmd_desc->cur->cmd, (uint8_t*) cmd, sizeof(i2c_cmd_t)); - cmd_desc->cur->next = NULL; - return ESP_OK; - - err: - return ESP_FAIL; -} - -esp_err_t i2c_master_start(i2c_cmd_handle_t cmd_handle) -{ - I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG); - i2c_cmd_t cmd; - cmd.ack_en = 0; - cmd.ack_exp = 0; - cmd.ack_val = 0; - cmd.byte_num = 0; - cmd.data = NULL; - cmd.op_code = I2C_CMD_RESTART; - return i2c_cmd_link_append(cmd_handle, &cmd); -} - -esp_err_t i2c_master_stop(i2c_cmd_handle_t cmd_handle) -{ - I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG); - i2c_cmd_t cmd; - cmd.ack_en = 0; - cmd.ack_exp = 0; - cmd.ack_val = 0; - cmd.byte_num = 0; - cmd.data = NULL; - cmd.op_code = I2C_CMD_STOP; - return i2c_cmd_link_append(cmd_handle, &cmd); -} - -esp_err_t i2c_master_write(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, bool ack_en) -{ - I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG); - - uint8_t len_tmp; - int data_offset = 0; - esp_err_t ret; - while (data_len > 0) { - len_tmp = data_len > 0xff ? 0xff : data_len; - data_len -= len_tmp; - i2c_cmd_t cmd; - cmd.ack_en = ack_en; - cmd.ack_exp = 0; - cmd.ack_val = 0; - cmd.byte_num = len_tmp; - cmd.op_code = I2C_CMD_WRITE; - cmd.data = data + data_offset; - ret = i2c_cmd_link_append(cmd_handle, &cmd); - data_offset += len_tmp; - if (ret != ESP_OK) { - return ret; - } - } - return ESP_OK; -} - -esp_err_t i2c_master_write_byte(i2c_cmd_handle_t cmd_handle, uint8_t data, bool ack_en) -{ - I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG); - i2c_cmd_t cmd; - cmd.ack_en = ack_en; - cmd.ack_exp = 0; - cmd.ack_val = 0; - cmd.byte_num = 1; - cmd.op_code = I2C_CMD_WRITE; - cmd.data = NULL; - cmd.byte_cmd = data; - return i2c_cmd_link_append(cmd_handle, &cmd); -} - -static esp_err_t i2c_master_read_static(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, i2c_ack_type_t ack) -{ - int len_tmp; - int data_offset = 0; - esp_err_t ret; - while (data_len > 0) { - len_tmp = data_len > 0xff ? 0xff : data_len; - data_len -= len_tmp; - i2c_cmd_t cmd; - cmd.ack_en = 0; - cmd.ack_exp = 0; - cmd.ack_val = ack & 0x1; - cmd.byte_num = len_tmp; - cmd.op_code = I2C_CMD_READ; - cmd.data = data + data_offset; - ret = i2c_cmd_link_append(cmd_handle, &cmd); - data_offset += len_tmp; - if (ret != ESP_OK) { - return ret; - } - } - return ESP_OK; -} - -esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t* data, i2c_ack_type_t ack) -{ - I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(ack < I2C_MASTER_ACK_MAX, I2C_ACK_TYPE_ERR_STR, ESP_ERR_INVALID_ARG); - - i2c_cmd_t cmd; - cmd.ack_en = 0; - cmd.ack_exp = 0; - cmd.ack_val = ((ack == I2C_MASTER_LAST_NACK) ? I2C_MASTER_NACK : (ack & 0x1)); - cmd.byte_num = 1; - cmd.op_code = I2C_CMD_READ; - cmd.data = data; - return i2c_cmd_link_append(cmd_handle, &cmd); -} - -esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, i2c_ack_type_t ack) -{ - I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(ack < I2C_MASTER_ACK_MAX, I2C_ACK_TYPE_ERR_STR, ESP_ERR_INVALID_ARG); - I2C_CHECK(data_len > 0, I2C_DATA_LEN_ERR_STR, ESP_ERR_INVALID_ARG); - - if(ack != I2C_MASTER_LAST_NACK) { - return i2c_master_read_static(cmd_handle, data, data_len, ack); - } else { - if(data_len == 1) { - return i2c_master_read_byte(cmd_handle, data, I2C_MASTER_NACK); - } else { - esp_err_t ret; - if((ret = i2c_master_read_static(cmd_handle, data, data_len - 1, I2C_MASTER_ACK)) != ESP_OK) { - return ret; - } - return i2c_master_read_byte(cmd_handle, data + data_len - 1, I2C_MASTER_NACK); - } - } -} - -static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num) -{ - i2c_obj_t* p_i2c = p_i2c_obj[i2c_num]; - portBASE_TYPE HPTaskAwoken = pdFALSE; - i2c_cmd_evt_t evt; - //This should never happen - if (p_i2c->mode == I2C_MODE_SLAVE) { - return; - } - if (p_i2c->status == I2C_STATUS_DONE) { - return; - } else if ((p_i2c->status == I2C_STATUS_ACK_ERROR) - || (p_i2c->status == I2C_STATUS_TIMEOUT)) { - I2C[i2c_num]->int_ena.end_detect = 0; - I2C[i2c_num]->int_clr.end_detect = 1; - if(p_i2c->status == I2C_STATUS_TIMEOUT) { - I2C[i2c_num]->int_clr.time_out = 1; - I2C[i2c_num]->int_ena.val = 0; - } - evt.type = I2C_CMD_EVT_DONE; - xQueueOverwriteFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken); - if (HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } - return; - } else if (p_i2c->cmd_link.head != NULL && p_i2c->status == I2C_STATUS_READ) { - i2c_cmd_t *cmd = &p_i2c->cmd_link.head->cmd; - while (p_i2c->rx_cnt-- > 0) { - *cmd->data++ = READ_PERI_REG(I2C_DATA_APB_REG(i2c_num)); - } - if (cmd->byte_num > 0) { - p_i2c->rx_fifo_remain = I2C_FIFO_LEN; - p_i2c->cmd_idx = 0; - } else { - p_i2c->cmd_link.head = p_i2c->cmd_link.head->next; - } - } - if (p_i2c->cmd_link.head == NULL) { - p_i2c->cmd_link.cur = NULL; - evt.type = I2C_CMD_EVT_DONE; - xQueueOverwriteFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken); - if (HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } - // Return to the IDLE status after cmd_eve_done signal were send out. - p_i2c->status = I2C_STATUS_IDLE; - return; - } - while (p_i2c->cmd_link.head) { - i2c_cmd_t *cmd = &p_i2c->cmd_link.head->cmd; - i2c_hw_cmd_t * const p_cur_hw_cmd = &I2C[i2c_num]->command[p_i2c->cmd_idx]; - i2c_hw_cmd_t hw_cmd = { - .ack_en = cmd->ack_en, - .ack_exp = cmd->ack_exp, - .ack_val = cmd->ack_val, - .byte_num = cmd->byte_num, - .op_code = cmd->op_code - }; - const i2c_hw_cmd_t hw_end_cmd = { - .op_code = I2C_CMD_END - }; - if (cmd->op_code == I2C_CMD_WRITE) { - uint32_t wr_filled = 0; - //TODO: to reduce interrupt number - if (cmd->data) { - while (p_i2c->tx_fifo_remain > 0 && cmd->byte_num > 0) { - WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), *cmd->data++); - p_i2c->tx_fifo_remain--; - cmd->byte_num--; - wr_filled++; - } - } else { - WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), cmd->byte_cmd); - p_i2c->tx_fifo_remain--; - cmd->byte_num--; - wr_filled ++; - } - hw_cmd.byte_num = wr_filled; - *p_cur_hw_cmd = hw_cmd; - *(p_cur_hw_cmd + 1) = hw_end_cmd; - p_i2c->tx_fifo_remain = I2C_FIFO_LEN; - p_i2c->cmd_idx = 0; - if (cmd->byte_num > 0) { - } else { - p_i2c->cmd_link.head = p_i2c->cmd_link.head->next; - } - p_i2c->status = I2C_STATUS_WRITE; - break; - } else if(cmd->op_code == I2C_CMD_READ) { - //TODO: to reduce interrupt number - p_i2c->rx_cnt = cmd->byte_num > p_i2c->rx_fifo_remain ? p_i2c->rx_fifo_remain : cmd->byte_num; - cmd->byte_num -= p_i2c->rx_cnt; - hw_cmd.byte_num = p_i2c->rx_cnt; - hw_cmd.ack_val = cmd->ack_val; - *p_cur_hw_cmd = hw_cmd; - *(p_cur_hw_cmd + 1) = hw_end_cmd; - p_i2c->status = I2C_STATUS_READ; - break; - } else { - *p_cur_hw_cmd = hw_cmd; - } - p_i2c->cmd_idx++; - p_i2c->cmd_link.head = p_i2c->cmd_link.head->next; - if (p_i2c->cmd_link.head == NULL || p_i2c->cmd_idx >= 15) { - p_i2c->tx_fifo_remain = I2C_FIFO_LEN; - p_i2c->cmd_idx = 0; - break; - } - } - I2C[i2c_num]->int_clr.end_detect = 1; - I2C[i2c_num]->int_ena.end_detect = 1; - I2C[i2c_num]->ctr.trans_start = 0; - I2C[i2c_num]->ctr.trans_start = 1; - 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); - I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_NOT_INSTALL_ERR_STR, ESP_ERR_INVALID_STATE); - 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; - i2c_obj_t* p_i2c = p_i2c_obj[i2c_num]; - portTickType ticks_start = xTaskGetTickCount(); - portBASE_TYPE res = xSemaphoreTake(p_i2c->cmd_mux, ticks_to_wait); -#ifdef CONFIG_PM_ENABLE - esp_pm_lock_acquire(p_i2c->pm_lock); -#endif - if (res == pdFALSE) { - return ESP_ERR_TIMEOUT; - } - xQueueReset(p_i2c->cmd_evt_queue); - if (p_i2c->status == I2C_STATUS_TIMEOUT - || I2C[i2c_num]->status_reg.bus_busy == 1) { - i2c_hw_fsm_reset(i2c_num); - clear_bus_cnt = 0; - } - i2c_reset_tx_fifo(i2c_num); - i2c_reset_rx_fifo(i2c_num); - i2c_cmd_desc_t* cmd = (i2c_cmd_desc_t*) cmd_handle; - p_i2c->cmd_link.free = cmd->free; - p_i2c->cmd_link.cur = cmd->cur; - p_i2c->cmd_link.head = cmd->head; - p_i2c->status = I2C_STATUS_IDLE; - p_i2c->cmd_idx = 0; - p_i2c->rx_cnt = 0; - p_i2c->tx_fifo_remain = I2C_FIFO_LEN; - p_i2c->rx_fifo_remain = I2C_FIFO_LEN; - i2c_reset_tx_fifo(i2c_num); - i2c_reset_rx_fifo(i2c_num); - // These two interrupts some times can not be cleared when the FSM gets stuck. - // so we disable them when these two interrupt occurs and re-enable them here. - I2C[i2c_num]->int_ena.ack_err = 1; - I2C[i2c_num]->int_ena.time_out = 1; - //start send commands, at most 32 bytes one time, isr handler will process the remaining commands. - i2c_master_cmd_begin_static(i2c_num); - - // Wait event bits - i2c_cmd_evt_t evt; - while (1) { - TickType_t wait_time = xTaskGetTickCount(); - if (wait_time - ticks_start > ticks_to_wait) { // out of time - wait_time = I2C_CMD_ALIVE_INTERVAL_TICK; - } else { - wait_time = ticks_to_wait - (wait_time - ticks_start); - if (wait_time < I2C_CMD_ALIVE_INTERVAL_TICK) { - wait_time = I2C_CMD_ALIVE_INTERVAL_TICK; - } - } - // In master mode, since we don't have an interrupt to detective bus error or FSM state, what we do here is to make - // sure the interrupt mechanism for master mode is still working. - // If the command sending is not finished and there is no interrupt any more, the bus is probably dead caused by external noise. - portBASE_TYPE evt_res = xQueueReceive(p_i2c->cmd_evt_queue, &evt, wait_time); - if (evt_res == pdTRUE) { - if (evt.type == I2C_CMD_EVT_DONE) { - if (p_i2c->status == I2C_STATUS_TIMEOUT) { - // If the I2C slave are powered off or the SDA/SCL are connected to ground, for example, - // I2C hw FSM would get stuck in wrong state, we have to reset the I2C module in this case. - i2c_hw_fsm_reset(i2c_num); - clear_bus_cnt = 0; - ret = ESP_ERR_TIMEOUT; - } else if (p_i2c->status == I2C_STATUS_ACK_ERROR) { - clear_bus_cnt++; - if(clear_bus_cnt >= I2C_ACKERR_CNT_MAX) { - i2c_master_clear_bus(i2c_num); - clear_bus_cnt = 0; - } - ret = ESP_FAIL; - } else { - ret = ESP_OK; - } - break; - } - if (evt.type == I2C_CMD_EVT_ALIVE) { - } - } else { - ret = ESP_ERR_TIMEOUT; - // If the I2C slave are powered off or the SDA/SCL are connected to ground, for example, - // I2C hw FSM would get stuck in wrong state, we have to reset the I2C module in this case. - i2c_hw_fsm_reset(i2c_num); - clear_bus_cnt = 0; - break; - } - } - p_i2c->status = I2C_STATUS_DONE; -#ifdef CONFIG_PM_ENABLE - esp_pm_lock_release(p_i2c->pm_lock); -#endif - xSemaphoreGive(p_i2c->cmd_mux); - return ret; -} - -int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t* data, int size, TickType_t ticks_to_wait) -{ - I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_FAIL); - I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_FAIL); - I2C_CHECK(p_i2c_obj[i2c_num]->mode == I2C_MODE_SLAVE, I2C_MODE_SLAVE_ERR_STR, ESP_FAIL); - i2c_obj_t* p_i2c = p_i2c_obj[i2c_num]; - - portBASE_TYPE res; - int cnt = 0; - portTickType ticks_start = xTaskGetTickCount(); - - res = xSemaphoreTake(p_i2c->slv_tx_mux, ticks_to_wait); - if (res == pdFALSE) { - return 0; - } - TickType_t ticks_end = xTaskGetTickCount(); - if (ticks_end - ticks_start > ticks_to_wait) { - ticks_to_wait = 0; - } else { - ticks_to_wait = ticks_to_wait - (ticks_end - ticks_start); - } - res = xRingbufferSend(p_i2c->tx_ring_buf, data, size, ticks_to_wait); - if (res == pdFALSE) { - cnt = 0; - } else { - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->int_clr.tx_fifo_empty = 1; - I2C[i2c_num]->int_ena.tx_fifo_empty = 1; - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - cnt = size; - } - xSemaphoreGive(p_i2c->slv_tx_mux); - return cnt; -} - -static int i2c_slave_read(i2c_port_t i2c_num, uint8_t* data, size_t max_size, TickType_t ticks_to_wait) -{ - i2c_obj_t* p_i2c = p_i2c_obj[i2c_num]; - size_t size = 0; - uint8_t* pdata = (uint8_t*) xRingbufferReceiveUpTo(p_i2c->rx_ring_buf, &size, ticks_to_wait, max_size); - if (pdata && size > 0) { - memcpy(data, pdata, size); - vRingbufferReturnItem(p_i2c->rx_ring_buf, pdata); - } - return size; -} - -int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, TickType_t ticks_to_wait) -{ - I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_FAIL); - I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_FAIL); - I2C_CHECK(p_i2c_obj[i2c_num]->mode == I2C_MODE_SLAVE, I2C_MODE_SLAVE_ERR_STR, ESP_FAIL); - - i2c_obj_t* p_i2c = p_i2c_obj[i2c_num]; - portBASE_TYPE res; - portTickType ticks_start = xTaskGetTickCount(); - res = xSemaphoreTake(p_i2c->slv_rx_mux, ticks_to_wait); - if (res == pdFALSE) { - return 0; - } - TickType_t ticks_end = xTaskGetTickCount(); - if (ticks_end - ticks_start > ticks_to_wait) { - ticks_to_wait = 0; - } else { - ticks_to_wait = ticks_to_wait - (ticks_end - ticks_start); - } - int cnt = i2c_slave_read(i2c_num, data, max_size, ticks_to_wait); - if (cnt > 0) { - I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]); - I2C[i2c_num]->int_ena.rx_fifo_full = 1; - I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]); - ticks_end = xTaskGetTickCount(); - if (ticks_end - ticks_start > ticks_to_wait) { - ticks_to_wait = 0; - } else { - ticks_to_wait = ticks_to_wait - (ticks_end - ticks_start); - } - if (cnt < max_size && ticks_to_wait > 0) { - cnt += i2c_slave_read(i2c_num, data + cnt, max_size - cnt, ticks_to_wait); - } - } else { - cnt = 0; - } - xSemaphoreGive(p_i2c->slv_rx_mux); - return cnt; -} diff --git a/idf-patch/i2s.c b/idf-patch/i2s.c new file mode 100644 index 00000000..2b9ecf5a --- /dev/null +++ b/idf-patch/i2s.c @@ -0,0 +1,1456 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/xtensa_api.h" + +#include "soc/rtc_periph.h" +#include "soc/rtc.h" +#include "soc/efuse_periph.h" +#include "esp32/rom/lldesc.h" + +#include "driver/gpio.h" +#include "driver/i2s.h" +#include "driver/rtc_io.h" +#include "driver/dac.h" +#include "adc1_i2s_private.h" + +#include "esp_intr_alloc.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_pm.h" + +static const char* I2S_TAG = "I2S"; + +#define I2S_CHECK(a, str, ret) if (!(a)) { \ + ESP_LOGE(I2S_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \ + return (ret); \ + } +#define I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated +#define I2S_BASE_CLK (2*APB_CLK_FREQ) +#define I2S_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_spinlock[i2s_num]) +#define I2S_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_spinlock[i2s_num]) +#define I2S_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_spinlock[i2s_num]) +#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num]) +#define I2S_FULL_DUPLEX_SLAVE_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_SLAVE) +#define I2S_FULL_DUPLEX_MASTER_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_MASTER) +#define APLL_MIN_FREQ (250000000) +#define APLL_MAX_FREQ (500000000) +#define APLL_I2S_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware +#define I2S_AD_BCK_FACTOR (2) +#define I2S_PDM_BCK_FACTOR (64) +/** + * @brief DMA buffer object + * + */ +typedef struct { + char **buf; + int buf_size; + int rw_pos; + void *curr_ptr; + SemaphoreHandle_t mux; + xQueueHandle queue; + lldesc_t **desc; +} i2s_dma_t; + +/** + * @brief I2S object instance + * + */ +typedef struct { + i2s_port_t i2s_num; /*!< I2S port number*/ + int queue_size; /*!< I2S event queue size*/ + QueueHandle_t i2s_queue; /*!< I2S queue handler*/ + int dma_buf_count; /*!< DMA buffer count, number of buffer*/ + int dma_buf_len; /*!< DMA buffer length, length of each buffer*/ + i2s_dma_t *rx; /*!< DMA Tx buffer*/ + i2s_dma_t *tx; /*!< DMA Rx buffer*/ + i2s_isr_handle_t i2s_isr_handle; /*!< I2S Interrupt handle*/ + int channel_num; /*!< Number of channels*/ + int bytes_per_sample; /*!< Bytes per sample*/ + int bits_per_sample; /*!< Bits per sample*/ + i2s_mode_t mode; /*!< I2S Working mode*/ + uint32_t sample_rate; /*!< I2S sample rate */ + bool use_apll; /*!< I2S use APLL clock */ + bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor on underflow */ + int fixed_mclk; /*!< I2S fixed MLCK clock */ + double real_rate; +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_handle_t pm_lock; +#endif +} i2s_obj_t; + +static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0}; +static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1}; +static portMUX_TYPE i2s_spinlock[I2S_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED}; +static int _i2s_adc_unit = -1; +static int _i2s_adc_channel = -1; + +static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, int dma_buf_len); +static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma); +static esp_err_t i2s_reset_fifo(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_ENTER_CRITICAL(); + I2S[i2s_num]->conf.rx_fifo_reset = 1; + I2S[i2s_num]->conf.rx_fifo_reset = 0; + I2S[i2s_num]->conf.tx_fifo_reset = 1; + I2S[i2s_num]->conf.tx_fifo_reset = 0; + I2S_EXIT_CRITICAL(); + return ESP_OK; +} + +inline static void gpio_matrix_out_check(uint32_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv) +{ + //if pin = -1, do not need to configure + if (gpio != -1) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); + gpio_set_direction(gpio, GPIO_MODE_DEF_OUTPUT); + gpio_matrix_out(gpio, signal_idx, out_inv, oen_inv); + } +} +inline static void gpio_matrix_in_check(uint32_t gpio, uint32_t signal_idx, bool inv) +{ + if (gpio != -1) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); + //Set direction, for some GPIOs, the input function are not enabled as default. + gpio_set_direction(gpio, GPIO_MODE_DEF_INPUT); + gpio_matrix_in(gpio, signal_idx, inv); + } +} + + +esp_err_t i2s_clear_intr_status(i2s_port_t i2s_num, uint32_t clr_mask) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S[i2s_num]->int_clr.val = clr_mask; + return ESP_OK; +} + +esp_err_t i2s_enable_rx_intr(i2s_port_t i2s_num) +{ + + I2S_ENTER_CRITICAL(); + I2S[i2s_num]->int_ena.in_suc_eof = 1; + I2S[i2s_num]->int_ena.in_dscr_err = 1; + I2S_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t i2s_disable_rx_intr(i2s_port_t i2s_num) +{ + I2S_ENTER_CRITICAL(); + I2S[i2s_num]->int_ena.in_suc_eof = 0; + I2S[i2s_num]->int_ena.in_dscr_err = 0; + I2S_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t i2s_disable_tx_intr(i2s_port_t i2s_num) +{ + I2S_ENTER_CRITICAL(); + I2S[i2s_num]->int_ena.out_eof = 0; + I2S[i2s_num]->int_ena.out_dscr_err = 0; + I2S_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t i2s_enable_tx_intr(i2s_port_t i2s_num) +{ + I2S_ENTER_CRITICAL(); + I2S[i2s_num]->int_ena.out_eof = 1; + I2S[i2s_num]->int_ena.out_dscr_err = 1; + I2S_EXIT_CRITICAL(); + return ESP_OK; +} + +float i2s_get_clk(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + return p_i2s_obj[i2s_num]->real_rate; +} + +static esp_err_t i2s_isr_register(i2s_port_t i2s_num, int intr_alloc_flags, void (*fn)(void*), void * arg, i2s_isr_handle_t *handle) +{ + return esp_intr_alloc(ETS_I2S0_INTR_SOURCE + i2s_num, intr_alloc_flags, fn, arg, handle); +} + + +static float i2s_apll_get_fi2s(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir) +{ + int f_xtal = (int)rtc_clk_xtal_freq_get() * 1000000; + uint32_t is_rev0 = (GET_PERI_REG_BITS2(EFUSE_BLK0_RDATA3_REG, 1, 15) == 0); + if (is_rev0) { + sdm0 = 0; + sdm1 = 0; + } + float fout = f_xtal * (sdm2 + sdm1 / 256.0f + sdm0 / 65536.0f + 4); + if (fout < APLL_MIN_FREQ || fout > APLL_MAX_FREQ) { + return APLL_MAX_FREQ; + } + float fpll = fout / (2 * (odir+2)); //== fi2s (N=1, b=0, a=1) + return fpll/2; +} + +/** + * @brief APLL calculate function, was described by following: + * APLL Output frequency is given by the formula: + * + * apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) + * apll_freq = fout / ((o_div + 2) * 2) + * + * The dividend in this expression should be in the range of 240 - 600 MHz. + * In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0. + * * sdm0 frequency adjustment parameter, 0..255 + * * sdm1 frequency adjustment parameter, 0..255 + * * sdm2 frequency adjustment parameter, 0..63 + * * o_div frequency divider, 0..31 + * + * The most accurate way to find the sdm0..2 and odir parameters is to loop through them all, + * then apply the above formula, finding the closest frequency to the desired one. + * But 256*256*64*32 = 134.217.728 loops are too slow with ESP32 + * 1. We will choose the parameters with the highest level of change, + * With 350MHz 8) _sdm2_max = 8; + + // explore up to 5 sdm2 values + for (; _sdm2 < _sdm2_max; _sdm2++) { + _odir = r * (_sdm2 + 4) - 2; + if (_odir < 0) _odir = 0; + else if (_odir > 31) _odir = 31; + + for (o = 0; o < 2 && _odir + o < 32; o++) { + _sdm1 = 256*((_odir + o + 2) / r - (_sdm2 + 4)); + if (_sdm1 < 0) _sdm1 = 0; + else if (_sdm1 > 255) _sdm1 = 255; + + for (s1 = 0; s1 < 2 && _sdm1 + s1 < 256; s1++) { + _sdm0 = 65536*((_odir + o + 2) / r - (_sdm2 + (float) (_sdm1 + s1)/256 + 4)); + if (_sdm0 < 0) _sdm1 = 0; + else if (_sdm0 > 255) _sdm0 = 255; + + for (s0 = 0; s0 < 2 && _sdm2 + s0 < 256; s0++) { + int _fi2s = i2s_apll_get_fi2s(bits_per_sample, _sdm0 + s0, _sdm1 + s1, _sdm2, _odir + o); + if (abs(_fi2s - rate) < prec) { + prec = abs(_fi2s - rate); + *sdm0 = _sdm0 + s0; + *sdm1 = _sdm1 + s1; + *sdm2 = _sdm2; + *odir = _odir + o; + } + } + } + } + } + + if (*sdm2 + *sdm0 + *sdm0 + *odir) return ESP_OK; + else return ESP_ERR_INVALID_ARG; + } + +#if 0 +static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm0, int *sdm1, int *sdm2, int *odir) +{ + int _odir, _sdm0, _sdm1, _sdm2; + float avg; + float min_rate, max_rate, min_diff; + if (rate/bits_per_sample/2/8 < APLL_I2S_MIN_RATE) { + return ESP_ERR_INVALID_ARG; + } + + *sdm0 = 0; + *sdm1 = 0; + *sdm2 = 0; + *odir = 0; + min_diff = APLL_MAX_FREQ; + + for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) { + max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, 0); + min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, 31); + avg = (max_rate + min_rate)/2; + if (abs(avg - rate) < min_diff) { + min_diff = abs(avg - rate); + *sdm2 = _sdm2; + } + } + min_diff = APLL_MAX_FREQ; + for (_odir = 0; _odir < 32; _odir ++) { + max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, *sdm2, _odir); + min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, *sdm2, _odir); + avg = (max_rate + min_rate)/2; + if (abs(avg - rate) < min_diff) { + min_diff = abs(avg - rate); + *odir = _odir; + } + } + min_diff = APLL_MAX_FREQ; + for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) { + max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, *odir); + min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, *odir); + avg = (max_rate + min_rate)/2; + if (abs(avg - rate) < min_diff) { + min_diff = abs(avg - rate); + *sdm2 = _sdm2; + } + } + + min_diff = APLL_MAX_FREQ; + for (_sdm1 = 0; _sdm1 < 256; _sdm1 ++) { + max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, _sdm1, *sdm2, *odir); + min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, _sdm1, *sdm2, *odir); + avg = (max_rate + min_rate)/2; + if (abs(avg - rate) < min_diff) { + min_diff = abs(avg - rate); + *sdm1 = _sdm1; + } + } + + min_diff = APLL_MAX_FREQ; + for (_sdm0 = 0; _sdm0 < 256; _sdm0 ++) { + avg = i2s_apll_get_fi2s(bits_per_sample, _sdm0, *sdm1, *sdm2, *odir); + if (abs(avg - rate) < min_diff) { + min_diff = abs(avg - rate); + *sdm0 = _sdm0; + } + } + + return ESP_OK; +} +#endif +esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch) +{ + int factor = (256%bits)? 384 : 256; // According to hardware codec requirement(supported 256fs or 384fs) + int clkmInteger, clkmDecimals, bck = 0; + double denom = (double)1 / 64; + int channel = 2; + i2s_dma_t *save_tx = NULL, *save_rx = NULL; + + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + + if (bits % 8 != 0 || bits > I2S_BITS_PER_SAMPLE_32BIT || bits < I2S_BITS_PER_SAMPLE_16BIT) { + ESP_LOGE(I2S_TAG, "Invalid bits per sample"); + return ESP_ERR_INVALID_ARG; + } + + if (p_i2s_obj[i2s_num] == NULL) { + ESP_LOGE(I2S_TAG, "Not initialized yet"); + return ESP_ERR_INVALID_ARG; + } + p_i2s_obj[i2s_num]->sample_rate = rate; + double clkmdiv = (double)I2S_BASE_CLK / (rate * factor); + + if (clkmdiv > 256) { + ESP_LOGE(I2S_TAG, "clkmdiv is too large\r\n"); + return ESP_ERR_INVALID_ARG; + } + + // wait all on-going writing finish + if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) && p_i2s_obj[i2s_num]->tx) { + xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); + } + if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && p_i2s_obj[i2s_num]->rx) { + xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); + } + + i2s_stop(i2s_num); + + + uint32_t cur_mode = 0; + if (p_i2s_obj[i2s_num]->channel_num != ch) { + p_i2s_obj[i2s_num]->channel_num = (ch == 2) ? 2 : 1; + cur_mode = I2S[i2s_num]->fifo_conf.tx_fifo_mod; + I2S[i2s_num]->fifo_conf.tx_fifo_mod = (ch == 2) ? cur_mode - 1 : cur_mode + 1; + cur_mode = I2S[i2s_num]->fifo_conf.rx_fifo_mod; + I2S[i2s_num]->fifo_conf.rx_fifo_mod = (ch == 2) ? cur_mode -1 : cur_mode + 1; + I2S[i2s_num]->conf_chan.tx_chan_mod = (ch == 2) ? 0 : 1; + I2S[i2s_num]->conf_chan.rx_chan_mod = (ch == 2) ? 0 : 1; + } + + if (bits != p_i2s_obj[i2s_num]->bits_per_sample) { + + //change fifo mode + if (p_i2s_obj[i2s_num]->bits_per_sample <= 16 && bits > 16) { + I2S[i2s_num]->fifo_conf.tx_fifo_mod += 2; + I2S[i2s_num]->fifo_conf.rx_fifo_mod += 2; + } else if (p_i2s_obj[i2s_num]->bits_per_sample > 16 && bits <= 16) { + I2S[i2s_num]->fifo_conf.tx_fifo_mod -= 2; + I2S[i2s_num]->fifo_conf.rx_fifo_mod -= 2; + } + + p_i2s_obj[i2s_num]->bits_per_sample = bits; + p_i2s_obj[i2s_num]->bytes_per_sample = p_i2s_obj[i2s_num]->bits_per_sample / 8; + + // Round bytes_per_sample up to next multiple of 16 bits + int halfwords_per_sample = (p_i2s_obj[i2s_num]->bits_per_sample + 15) / 16; + p_i2s_obj[i2s_num]->bytes_per_sample = halfwords_per_sample * 2; + + // Because limited of DMA buffer is 4092 bytes + if (p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num > 4092) { + p_i2s_obj[i2s_num]->dma_buf_len = 4092 / p_i2s_obj[i2s_num]->bytes_per_sample / p_i2s_obj[i2s_num]->channel_num; + } + // Re-create TX DMA buffer + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + + save_tx = p_i2s_obj[i2s_num]->tx; + + p_i2s_obj[i2s_num]->tx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len); + if (p_i2s_obj[i2s_num]->tx == NULL) { + ESP_LOGE(I2S_TAG, "Failed to create tx dma buffer"); + i2s_driver_uninstall(i2s_num); + return ESP_ERR_NO_MEM; + } + I2S[i2s_num]->out_link.addr = (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0]; + + //destroy old tx dma if exist + if (save_tx) { + i2s_destroy_dma_queue(i2s_num, save_tx); + } + } + // Re-create RX DMA buffer + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + + save_rx = p_i2s_obj[i2s_num]->rx; + + p_i2s_obj[i2s_num]->rx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len); + if (p_i2s_obj[i2s_num]->rx == NULL){ + ESP_LOGE(I2S_TAG, "Failed to create rx dma buffer"); + i2s_driver_uninstall(i2s_num); + return ESP_ERR_NO_MEM; + } + I2S[i2s_num]->rx_eof_num = (p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->channel_num * p_i2s_obj[i2s_num]->bytes_per_sample)/4; + I2S[i2s_num]->in_link.addr = (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0]; + + //destroy old rx dma if exist + if (save_rx) { + i2s_destroy_dma_queue(i2s_num, save_rx); + } + } + + } + + double mclk; + int sdm0, sdm1, sdm2, odir, m_scale = 8; + int fi2s_clk = rate*channel*bits*m_scale; + if (p_i2s_obj[i2s_num]->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { + //DAC uses bclk as sample clock, not WS. WS can be something arbitrary. + //Rate as given to this function is the intended sample rate; + //According to the TRM, WS clk equals to the sample rate, and bclk is double the speed of WS + uint32_t b_clk = rate * I2S_AD_BCK_FACTOR; + fi2s_clk /= I2S_AD_BCK_FACTOR; + int factor2 = 60; + mclk = b_clk * factor2; + clkmdiv = ((double) I2S_BASE_CLK) / mclk; + clkmInteger = clkmdiv; + clkmDecimals = (clkmdiv - clkmInteger) / denom; + bck = mclk / b_clk; + } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_PDM) { + uint32_t b_clk = 0; + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + int fp = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fp; + int fs = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fs; + b_clk = rate * I2S_PDM_BCK_FACTOR * (fp / fs); + fi2s_clk /= (I2S_PDM_BCK_FACTOR * (fp / fs)); + } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + b_clk = rate * I2S_PDM_BCK_FACTOR * (I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en + 1); + fi2s_clk /= (I2S_PDM_BCK_FACTOR * (I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en + 1)); + } + int factor2 = 5 ; + mclk = b_clk * factor2; + clkmdiv = ((double) I2S_BASE_CLK) / mclk; + clkmInteger = clkmdiv; + clkmDecimals = (clkmdiv - clkmInteger) / denom; + bck = mclk / b_clk; + } else { + clkmInteger = clkmdiv; + clkmDecimals = (clkmdiv - clkmInteger) / denom; + mclk = clkmInteger + denom * clkmDecimals; + bck = factor/(bits * channel); + } + + if(p_i2s_obj[i2s_num]->use_apll && p_i2s_obj[i2s_num]->fixed_mclk) { + fi2s_clk = p_i2s_obj[i2s_num]->fixed_mclk; + m_scale = fi2s_clk/bits/rate/channel; + } + if(p_i2s_obj[i2s_num]->use_apll && i2s_apll_calculate_fi2s(fi2s_clk, bits, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) { + ESP_LOGD(I2S_TAG, "sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir); + rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, odir); + I2S[i2s_num]->clkm_conf.clkm_div_num = 1; + I2S[i2s_num]->clkm_conf.clkm_div_b = 0; + I2S[i2s_num]->clkm_conf.clkm_div_a = 1; + I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = m_scale; + I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = m_scale; + I2S[i2s_num]->clkm_conf.clka_en = 1; + double fi2s_rate = i2s_apll_get_fi2s(bits, sdm0, sdm1, sdm2, odir); + p_i2s_obj[i2s_num]->real_rate = fi2s_rate/bits/channel/m_scale; + ESP_LOGI(I2S_TAG, "APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK_M: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d", + rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/8, 1, 0); + } else { + I2S[i2s_num]->clkm_conf.clka_en = 0; + I2S[i2s_num]->clkm_conf.clkm_div_a = 63; + I2S[i2s_num]->clkm_conf.clkm_div_b = clkmDecimals; + I2S[i2s_num]->clkm_conf.clkm_div_num = clkmInteger; + I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = bck; + I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = bck; + double real_rate = (double) (I2S_BASE_CLK / (bck * bits * clkmInteger) / 2); + p_i2s_obj[i2s_num]->real_rate = real_rate; + ESP_LOGI(I2S_TAG, "PLL_D2: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d", + rate, real_rate, bits, clkmInteger, bck, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 64, clkmDecimals); + } + + I2S[i2s_num]->sample_rate_conf.tx_bits_mod = bits; + I2S[i2s_num]->sample_rate_conf.rx_bits_mod = bits; + + // wait all writing on-going finish + if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) && p_i2s_obj[i2s_num]->tx) { + xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux); + } + if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && p_i2s_obj[i2s_num]->rx) { + xSemaphoreGive(p_i2s_obj[i2s_num]->rx->mux); + } + i2s_start(i2s_num); + return ESP_OK; +} + +static void IRAM_ATTR i2s_intr_handler_default(void *arg) +{ + i2s_obj_t *p_i2s = (i2s_obj_t*) arg; + uint8_t i2s_num = p_i2s->i2s_num; + i2s_dev_t* i2s_reg = I2S[i2s_num]; + i2s_event_t i2s_event; + int dummy; + + portBASE_TYPE high_priority_task_awoken = 0; + + lldesc_t *finish_desc; + + if (i2s_reg->int_st.out_dscr_err || i2s_reg->int_st.in_dscr_err) { + ESP_EARLY_LOGE(I2S_TAG, "dma error, interrupt status: 0x%08x", i2s_reg->int_st.val); + if (p_i2s->i2s_queue) { + i2s_event.type = I2S_EVENT_DMA_ERROR; + if (xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) { + xQueueReceiveFromISR(p_i2s->i2s_queue, &dummy, &high_priority_task_awoken); + } + xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken); + } + } + + if (i2s_reg->int_st.out_eof && p_i2s->tx) { + finish_desc = (lldesc_t*) i2s_reg->out_eof_des_addr; + // All buffers are empty. This means we have an underflow on our hands. + if (xQueueIsQueueFullFromISR(p_i2s->tx->queue)) { + xQueueReceiveFromISR(p_i2s->tx->queue, &dummy, &high_priority_task_awoken); + // See if tx descriptor needs to be auto cleared: + // This will avoid any kind of noise that may get introduced due to transmission + // of previous data from tx descriptor on I2S line. + if (p_i2s->tx_desc_auto_clear == true) { + memset((void *) dummy, 0, p_i2s->tx->buf_size); + } + } + xQueueSendFromISR(p_i2s->tx->queue, (void*)(&finish_desc->buf), &high_priority_task_awoken); + if (p_i2s->i2s_queue) { + i2s_event.type = I2S_EVENT_TX_DONE; + if (xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) { + xQueueReceiveFromISR(p_i2s->i2s_queue, &dummy, &high_priority_task_awoken); + } + xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken); + } + } + + if (i2s_reg->int_st.in_suc_eof && p_i2s->rx) { + // All buffers are full. This means we have an overflow. + finish_desc = (lldesc_t*) i2s_reg->in_eof_des_addr; + if (xQueueIsQueueFullFromISR(p_i2s->rx->queue)) { + xQueueReceiveFromISR(p_i2s->rx->queue, &dummy, &high_priority_task_awoken); + } + xQueueSendFromISR(p_i2s->rx->queue, (void*)(&finish_desc->buf), &high_priority_task_awoken); + if (p_i2s->i2s_queue) { + i2s_event.type = I2S_EVENT_RX_DONE; + if (p_i2s->i2s_queue && xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) { + xQueueReceiveFromISR(p_i2s->i2s_queue, &dummy, &high_priority_task_awoken); + } + xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken); + } + } + if (high_priority_task_awoken == pdTRUE) { + portYIELD_FROM_ISR(); + } + + i2s_reg->int_clr.val = I2S[i2s_num]->int_st.val; +} + +static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma) +{ + int bux_idx; + if (p_i2s_obj[i2s_num] == NULL) { + ESP_LOGE(I2S_TAG, "Not initialized yet"); + return ESP_ERR_INVALID_ARG; + } + if (dma == NULL) { + ESP_LOGE(I2S_TAG, "dma is NULL"); + return ESP_ERR_INVALID_ARG; + } + for (bux_idx = 0; bux_idx < p_i2s_obj[i2s_num]->dma_buf_count; bux_idx++) { + if (dma->desc && dma->desc[bux_idx]) { + free(dma->desc[bux_idx]); + } + if (dma->buf && dma->buf[bux_idx]) { + free(dma->buf[bux_idx]); + } + } + if (dma->buf) { + free(dma->buf); + } + if (dma->desc) { + free(dma->desc); + } + vQueueDelete(dma->queue); + vSemaphoreDelete(dma->mux); + free(dma); + return ESP_OK; +} + +static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, int dma_buf_len) +{ + int bux_idx; + int sample_size = p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num; + i2s_dma_t *dma = (i2s_dma_t*) malloc(sizeof(i2s_dma_t)); + if (dma == NULL) { + ESP_LOGE(I2S_TAG, "Error malloc i2s_dma_t"); + return NULL; + } + memset(dma, 0, sizeof(i2s_dma_t)); + + dma->buf = (char **)malloc(sizeof(char*) * dma_buf_count); + if (dma->buf == NULL) { + ESP_LOGE(I2S_TAG, "Error malloc dma buffer pointer"); + free(dma); + return NULL; + } + memset(dma->buf, 0, sizeof(char*) * dma_buf_count); + + for (bux_idx = 0; bux_idx < dma_buf_count; bux_idx++) { + dma->buf[bux_idx] = (char*) heap_caps_calloc(1, dma_buf_len * sample_size, MALLOC_CAP_DMA); + if (dma->buf[bux_idx] == NULL) { + ESP_LOGE(I2S_TAG, "Error malloc dma buffer"); + i2s_destroy_dma_queue(i2s_num, dma); + return NULL; + } + ESP_LOGD(I2S_TAG, "Addr[%d] = %d", bux_idx, (int)dma->buf[bux_idx]); + } + + dma->desc = (lldesc_t**) malloc(sizeof(lldesc_t*) * dma_buf_count); + if (dma->desc == NULL) { + ESP_LOGE(I2S_TAG, "Error malloc dma description"); + i2s_destroy_dma_queue(i2s_num, dma); + return NULL; + } + for (bux_idx = 0; bux_idx < dma_buf_count; bux_idx++) { + dma->desc[bux_idx] = (lldesc_t*) heap_caps_malloc(sizeof(lldesc_t), MALLOC_CAP_DMA); + if (dma->desc[bux_idx] == NULL) { + ESP_LOGE(I2S_TAG, "Error malloc dma description entry"); + i2s_destroy_dma_queue(i2s_num, dma); + return NULL; + } + } + + for (bux_idx = 0; bux_idx < dma_buf_count; bux_idx++) { + dma->desc[bux_idx]->owner = 1; + dma->desc[bux_idx]->eof = 1; + dma->desc[bux_idx]->sosf = 0; + dma->desc[bux_idx]->length = dma_buf_len * sample_size; + dma->desc[bux_idx]->size = dma_buf_len * sample_size; + dma->desc[bux_idx]->buf = (uint8_t *) dma->buf[bux_idx]; + dma->desc[bux_idx]->offset = 0; + dma->desc[bux_idx]->empty = (uint32_t)((bux_idx < (dma_buf_count - 1)) ? (dma->desc[bux_idx + 1]) : dma->desc[0]); + } + dma->queue = xQueueCreate(dma_buf_count - 1, sizeof(char*)); + dma->mux = xSemaphoreCreateMutex(); + dma->rw_pos = 0; + dma->buf_size = dma_buf_len * sample_size; + dma->curr_ptr = NULL; + ESP_LOGI(I2S_TAG, "DMA Malloc info, datalen=blocksize=%d, dma_buf_count=%d", dma_buf_len * sample_size, dma_buf_count); + return dma; +} + + +esp_err_t i2s_start(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + //start DMA link + I2S_ENTER_CRITICAL(); + i2s_reset_fifo(i2s_num); + //reset dma + I2S[i2s_num]->lc_conf.in_rst = 1; + I2S[i2s_num]->lc_conf.in_rst = 0; + I2S[i2s_num]->lc_conf.out_rst = 1; + I2S[i2s_num]->lc_conf.out_rst = 0; + + I2S[i2s_num]->conf.tx_reset = 1; + I2S[i2s_num]->conf.tx_reset = 0; + I2S[i2s_num]->conf.rx_reset = 1; + I2S[i2s_num]->conf.rx_reset = 0; + + esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle); + I2S[i2s_num]->int_clr.val = 0xFFFFFFFF; + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + i2s_enable_tx_intr(i2s_num); + I2S[i2s_num]->out_link.start = 1; + I2S[i2s_num]->conf.tx_start = 1; + } + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + i2s_enable_rx_intr(i2s_num); + I2S[i2s_num]->in_link.start = 1; + I2S[i2s_num]->conf.rx_start = 1; + } + esp_intr_enable(p_i2s_obj[i2s_num]->i2s_isr_handle); + I2S_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t i2s_stop(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_ENTER_CRITICAL(); + esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle); + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + I2S[i2s_num]->out_link.stop = 1; + I2S[i2s_num]->conf.tx_start = 0; + i2s_disable_tx_intr(i2s_num); + } + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + I2S[i2s_num]->in_link.stop = 1; + I2S[i2s_num]->conf.rx_start = 0; + i2s_disable_rx_intr(i2s_num); + } + I2S[i2s_num]->int_clr.val = I2S[i2s_num]->int_st.val; //clear pending interrupt + I2S_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode) +{ + I2S_CHECK((dac_mode < I2S_DAC_CHANNEL_MAX), "i2s dac mode error", ESP_ERR_INVALID_ARG); + if (dac_mode == I2S_DAC_CHANNEL_DISABLE) { + dac_output_disable(DAC_CHANNEL_1); + dac_output_disable(DAC_CHANNEL_2); + dac_i2s_disable(); + } else { + dac_i2s_enable(); + } + + if (dac_mode & I2S_DAC_CHANNEL_RIGHT_EN) { + //DAC1, right channel, GPIO25 + dac_output_enable(DAC_CHANNEL_1); + } + if (dac_mode & I2S_DAC_CHANNEL_LEFT_EN) { + //DAC2, left channel, GPIO26 + dac_output_enable(DAC_CHANNEL_2); + } + return ESP_OK; +} + +static esp_err_t _i2s_adc_mode_recover(void) +{ + I2S_CHECK(((_i2s_adc_unit != -1) && (_i2s_adc_channel != -1)), "i2s ADC recover error, not initialized...", ESP_ERR_INVALID_ARG); + return adc_i2s_mode_init(_i2s_adc_unit, _i2s_adc_channel); +} + +esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel) +{ + I2S_CHECK((adc_unit < ADC_UNIT_2), "i2s ADC unit error, only support ADC1 for now", ESP_ERR_INVALID_ARG); + // For now, we only support SAR ADC1. + _i2s_adc_unit = adc_unit; + _i2s_adc_channel = adc_channel; + return adc_i2s_mode_init(adc_unit, adc_channel); +} + +esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + if (pin == NULL) { + return i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); + } + if (pin->bck_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->bck_io_num)) { + ESP_LOGE(I2S_TAG, "bck_io_num error"); + return ESP_FAIL; + } + if (pin->ws_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->ws_io_num)) { + ESP_LOGE(I2S_TAG, "ws_io_num error"); + return ESP_FAIL; + } + if (pin->data_out_num != -1 && !GPIO_IS_VALID_OUTPUT_GPIO(pin->data_out_num)) { + ESP_LOGE(I2S_TAG, "data_out_num error"); + return ESP_FAIL; + } + if (pin->data_in_num != -1 && !GPIO_IS_VALID_GPIO(pin->data_in_num)) { + ESP_LOGE(I2S_TAG, "data_in_num error"); + return ESP_FAIL; + } + + int bck_sig = -1, ws_sig = -1, data_out_sig = -1, data_in_sig = -1; + //Each IIS hw module has a RX and TX unit. + //For TX unit, the output signal index should be I2SnO_xxx_OUT_IDX + //For TX unit, the input signal index should be I2SnO_xxx_IN_IDX + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { + if (i2s_num == I2S_NUM_0) { + bck_sig = I2S0O_BCK_OUT_IDX; + ws_sig = I2S0O_WS_OUT_IDX; + data_out_sig = I2S0O_DATA_OUT23_IDX; + } else { + bck_sig = I2S1O_BCK_OUT_IDX; + ws_sig = I2S1O_WS_OUT_IDX; + data_out_sig = I2S1O_DATA_OUT23_IDX; + } + } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { + if (i2s_num == I2S_NUM_0) { + bck_sig = I2S0O_BCK_IN_IDX; + ws_sig = I2S0O_WS_IN_IDX; + data_out_sig = I2S0O_DATA_OUT23_IDX; + } else { + bck_sig = I2S1O_BCK_IN_IDX; + ws_sig = I2S1O_WS_IN_IDX; + data_out_sig = I2S1O_DATA_OUT23_IDX; + } + } + } + //For RX unit, the output signal index should be I2SnI_xxx_OUT_IDX + //For RX unit, the input signal index shuld be I2SnI_xxx_IN_IDX + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { + if (i2s_num == I2S_NUM_0) { + bck_sig = I2S0I_BCK_OUT_IDX; + ws_sig = I2S0I_WS_OUT_IDX; + data_in_sig = I2S0I_DATA_IN15_IDX; + } else { + bck_sig = I2S1I_BCK_OUT_IDX; + ws_sig = I2S1I_WS_OUT_IDX; + data_in_sig = I2S1I_DATA_IN15_IDX; + } + } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { + if (i2s_num == I2S_NUM_0) { + bck_sig = I2S0I_BCK_IN_IDX; + ws_sig = I2S0I_WS_IN_IDX; + data_in_sig = I2S0I_DATA_IN15_IDX; + } else { + bck_sig = I2S1I_BCK_IN_IDX; + ws_sig = I2S1I_WS_IN_IDX; + data_in_sig = I2S1I_DATA_IN15_IDX; + } + } + } + //For "full-duplex + slave" mode, we should select RX signal index for ws and bck. + //For "full-duplex + master" mode, we should select TX signal index for ws and bck. + if ((p_i2s_obj[i2s_num]->mode & I2S_FULL_DUPLEX_SLAVE_MODE_MASK) == I2S_FULL_DUPLEX_SLAVE_MODE_MASK) { + if (i2s_num == I2S_NUM_0) { + bck_sig = I2S0I_BCK_IN_IDX; + ws_sig = I2S0I_WS_IN_IDX; + } else { + bck_sig = I2S1I_BCK_IN_IDX; + ws_sig = I2S1I_WS_IN_IDX; + } + } else if ((p_i2s_obj[i2s_num]->mode & I2S_FULL_DUPLEX_MASTER_MODE_MASK) == I2S_FULL_DUPLEX_MASTER_MODE_MASK) { + if (i2s_num == I2S_NUM_0) { + bck_sig = I2S0O_BCK_OUT_IDX; + ws_sig = I2S0O_WS_OUT_IDX; + } else { + bck_sig = I2S1O_BCK_OUT_IDX; + ws_sig = I2S1O_WS_OUT_IDX; + } + } + + gpio_matrix_out_check(pin->data_out_num, data_out_sig, 0, 0); + gpio_matrix_in_check(pin->data_in_num, data_in_sig, 0); + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { + gpio_matrix_out_check(pin->ws_io_num, ws_sig, 0, 0); + gpio_matrix_out_check(pin->bck_io_num, bck_sig, 0, 0); + } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { + gpio_matrix_in_check(pin->ws_io_num, ws_sig, 0); + gpio_matrix_in_check(pin->bck_io_num, bck_sig, 0); + } + ESP_LOGD(I2S_TAG, "data: out %d, in: %d, ws: %d, bck: %d", data_out_sig, data_in_sig, ws_sig, bck_sig); + + return ESP_OK; +} + +esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num]->bytes_per_sample > 0), "bits_per_sample not set", ESP_ERR_INVALID_ARG); + return i2s_set_clk(i2s_num, rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); +} + +esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en = dsr; + return i2s_set_clk(i2s_num, p_i2s_obj[i2s_num]->sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); +} + +static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_config) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((i2s_config), "param null", ESP_ERR_INVALID_ARG); + I2S_CHECK(!((i2s_config->mode & I2S_MODE_ADC_BUILT_IN) && (i2s_num != I2S_NUM_0)), "I2S ADC built-in only support on I2S0", ESP_ERR_INVALID_ARG); + I2S_CHECK(!((i2s_config->mode & I2S_MODE_DAC_BUILT_IN) && (i2s_num != I2S_NUM_0)), "I2S DAC built-in only support on I2S0", ESP_ERR_INVALID_ARG); + I2S_CHECK(!((i2s_config->mode & I2S_MODE_PDM) && (i2s_num != I2S_NUM_0)), "I2S DAC PDM only support on I2S0", ESP_ERR_INVALID_ARG); + + if (i2s_num == I2S_NUM_1) { + periph_module_enable(PERIPH_I2S1_MODULE); + } else { + periph_module_enable(PERIPH_I2S0_MODULE); + } + + if(i2s_config->mode & I2S_MODE_ADC_BUILT_IN) { + //in ADC built-in mode, we need to call i2s_set_adc_mode to + //initialize the specific ADC channel. + //in the current stage, we only support ADC1 and single channel mode. + //In default data mode, the ADC data is in 12-bit resolution mode. + adc_power_always_on(); + } + // configure I2S data port interface. + i2s_reset_fifo(i2s_num); + //reset i2s + I2S[i2s_num]->conf.tx_reset = 1; + I2S[i2s_num]->conf.tx_reset = 0; + I2S[i2s_num]->conf.rx_reset = 1; + I2S[i2s_num]->conf.rx_reset = 0; + + //reset dma + I2S[i2s_num]->lc_conf.in_rst = 1; + I2S[i2s_num]->lc_conf.in_rst = 0; + I2S[i2s_num]->lc_conf.out_rst = 1; + I2S[i2s_num]->lc_conf.out_rst = 0; + + //Enable and configure DMA + I2S[i2s_num]->lc_conf.check_owner = 0; + I2S[i2s_num]->lc_conf.out_loop_test = 0; + I2S[i2s_num]->lc_conf.out_auto_wrback = 0; + I2S[i2s_num]->lc_conf.out_data_burst_en = 0; + I2S[i2s_num]->lc_conf.outdscr_burst_en = 0; + I2S[i2s_num]->lc_conf.out_no_restart_clr = 0; + I2S[i2s_num]->lc_conf.indscr_burst_en = 0; + I2S[i2s_num]->lc_conf.out_eof_mode = 1; + + I2S[i2s_num]->conf2.lcd_en = 0; + I2S[i2s_num]->conf2.camera_en = 0; + I2S[i2s_num]->pdm_conf.pcm2pdm_conv_en = 0; + I2S[i2s_num]->pdm_conf.pdm2pcm_conv_en = 0; + + I2S[i2s_num]->fifo_conf.dscr_en = 0; + + I2S[i2s_num]->conf_chan.tx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left + I2S[i2s_num]->fifo_conf.tx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel + I2S[i2s_num]->conf.tx_mono = 0; + + I2S[i2s_num]->conf_chan.rx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left + I2S[i2s_num]->fifo_conf.rx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel + I2S[i2s_num]->conf.rx_mono = 0; + + I2S[i2s_num]->fifo_conf.dscr_en = 1;//connect dma to fifo + + I2S[i2s_num]->conf.tx_start = 0; + I2S[i2s_num]->conf.rx_start = 0; + + if (i2s_config->mode & I2S_MODE_TX) { + I2S[i2s_num]->conf.tx_msb_right = 1; + I2S[i2s_num]->conf.tx_right_first = 0; + + I2S[i2s_num]->conf.tx_slave_mod = 0; // Master + I2S[i2s_num]->fifo_conf.tx_fifo_mod_force_en = 1; + + if (i2s_config->mode & I2S_MODE_SLAVE) { + I2S[i2s_num]->conf.tx_slave_mod = 1;//TX Slave + } + } + + if (i2s_config->mode & I2S_MODE_RX) { + I2S[i2s_num]->conf.rx_msb_right = 1; + I2S[i2s_num]->conf.rx_right_first = 0; + I2S[i2s_num]->conf.rx_slave_mod = 0; // Master + I2S[i2s_num]->fifo_conf.rx_fifo_mod_force_en = 1; + + if (i2s_config->mode & I2S_MODE_SLAVE) { + I2S[i2s_num]->conf.rx_slave_mod = 1;//RX Slave + } + } + + if (i2s_config->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { + I2S[i2s_num]->conf2.lcd_en = 1; + I2S[i2s_num]->conf.tx_right_first = 1; + I2S[i2s_num]->conf2.camera_en = 0; + } + + if (i2s_config->mode & I2S_MODE_PDM) { + I2S[i2s_num]->fifo_conf.rx_fifo_mod_force_en = 1; + I2S[i2s_num]->fifo_conf.tx_fifo_mod_force_en = 1; + + I2S[i2s_num]->pdm_freq_conf.tx_pdm_fp = 960; + I2S[i2s_num]->pdm_freq_conf.tx_pdm_fs = i2s_config->sample_rate / 1000 * 10; + I2S[i2s_num]->pdm_conf.tx_sinc_osr2 = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fp / I2S[i2s_num]->pdm_freq_conf.tx_pdm_fs; + + I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en = 0; + I2S[i2s_num]->pdm_conf.rx_pdm_en = 1; + I2S[i2s_num]->pdm_conf.tx_pdm_en = 1; + + I2S[i2s_num]->pdm_conf.pcm2pdm_conv_en = 1; + I2S[i2s_num]->pdm_conf.pdm2pcm_conv_en = 1; + } else { + I2S[i2s_num]->pdm_conf.rx_pdm_en = 0; + I2S[i2s_num]->pdm_conf.tx_pdm_en = 0; + } + if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S) { + I2S[i2s_num]->conf.tx_short_sync = 0; + I2S[i2s_num]->conf.rx_short_sync = 0; + I2S[i2s_num]->conf.tx_msb_shift = 1; + I2S[i2s_num]->conf.rx_msb_shift = 1; + if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S_LSB) { + if (i2s_config->mode & I2S_MODE_TX) { + I2S[i2s_num]->conf.tx_msb_shift = 0; + } + if (i2s_config->mode & I2S_MODE_RX) { + I2S[i2s_num]->conf.rx_msb_shift = 0; + } + } + } + + if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM) { + I2S[i2s_num]->conf.tx_msb_shift = 0; + I2S[i2s_num]->conf.rx_msb_shift = 0; + I2S[i2s_num]->conf.tx_short_sync = 0; + I2S[i2s_num]->conf.rx_short_sync = 0; + if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM_SHORT) { + if (i2s_config->mode & I2S_MODE_TX) { + I2S[i2s_num]->conf.tx_short_sync = 1; + } + if (i2s_config->mode & I2S_MODE_RX) { + I2S[i2s_num]->conf.rx_short_sync = 1; + } + } + } + if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX)) { + I2S[i2s_num]->conf.sig_loopback = 1; + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { + I2S[i2s_num]->conf.tx_slave_mod = 0; //MASTER Slave + I2S[i2s_num]->conf.rx_slave_mod = 1; //RX Slave + } else { + I2S[i2s_num]->conf.tx_slave_mod = 1; //RX Slave + I2S[i2s_num]->conf.rx_slave_mod = 1; //RX Slave + } + } + + p_i2s_obj[i2s_num]->use_apll = i2s_config->use_apll; + p_i2s_obj[i2s_num]->tx_desc_auto_clear = i2s_config->tx_desc_auto_clear; + p_i2s_obj[i2s_num]->fixed_mclk = i2s_config->fixed_mclk; + return ESP_OK; +} + +esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + if (p_i2s_obj[i2s_num]->rx && p_i2s_obj[i2s_num]->rx->buf != NULL && p_i2s_obj[i2s_num]->rx->buf_size != 0) { + for (int i = 0; i < p_i2s_obj[i2s_num]->dma_buf_count; i++) { + memset(p_i2s_obj[i2s_num]->rx->buf[i], 0, p_i2s_obj[i2s_num]->rx->buf_size); + } + } + if (p_i2s_obj[i2s_num]->tx && p_i2s_obj[i2s_num]->tx->buf != NULL && p_i2s_obj[i2s_num]->tx->buf_size != 0) { + int bytes_left = 0; + bytes_left = (p_i2s_obj[i2s_num]->tx->buf_size - p_i2s_obj[i2s_num]->tx->rw_pos) % 4; + if (bytes_left) { + size_t zero_bytes = 0, bytes_written; + i2s_write(i2s_num, (void *)&zero_bytes, bytes_left, &bytes_written, portMAX_DELAY); + } + for (int i = 0; i < p_i2s_obj[i2s_num]->dma_buf_count; i++) { + memset(p_i2s_obj[i2s_num]->tx->buf[i], 0, p_i2s_obj[i2s_num]->tx->buf_size); + } + } + return ESP_OK; +} + +esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue) +{ + esp_err_t err; + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((i2s_config != NULL), "I2S configuration must not NULL", ESP_ERR_INVALID_ARG); + I2S_CHECK((i2s_config->dma_buf_count >= 2 && i2s_config->dma_buf_count <= 128), "I2S buffer count less than 128 and more than 2", ESP_ERR_INVALID_ARG); + I2S_CHECK((i2s_config->dma_buf_len >= 8 && i2s_config->dma_buf_len <= 1024), "I2S buffer length at most 1024 and more than 8", ESP_ERR_INVALID_ARG); + if (p_i2s_obj[i2s_num] == NULL) { + p_i2s_obj[i2s_num] = (i2s_obj_t*) malloc(sizeof(i2s_obj_t)); + if (p_i2s_obj[i2s_num] == NULL) { + ESP_LOGE(I2S_TAG, "Malloc I2S driver error"); + return ESP_ERR_NO_MEM; + } + memset(p_i2s_obj[i2s_num], 0, sizeof(i2s_obj_t)); + + p_i2s_obj[i2s_num]->i2s_num = i2s_num; + p_i2s_obj[i2s_num]->dma_buf_count = i2s_config->dma_buf_count; + p_i2s_obj[i2s_num]->dma_buf_len = i2s_config->dma_buf_len; + p_i2s_obj[i2s_num]->i2s_queue = i2s_queue; + p_i2s_obj[i2s_num]->mode = i2s_config->mode; + + p_i2s_obj[i2s_num]->bits_per_sample = 0; + p_i2s_obj[i2s_num]->bytes_per_sample = 0; // Not initialized yet + p_i2s_obj[i2s_num]->channel_num = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1; + +#ifdef CONFIG_PM_ENABLE + if (i2s_config->use_apll) { + err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "i2s_driver", &p_i2s_obj[i2s_num]->pm_lock); + } else { + err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "i2s_driver", &p_i2s_obj[i2s_num]->pm_lock); + } + if (err != ESP_OK) { + free(p_i2s_obj[i2s_num]); + p_i2s_obj[i2s_num] = NULL; + ESP_LOGE(I2S_TAG, "I2S pm lock error"); + return err; + } +#endif //CONFIG_PM_ENABLE + + //To make sure hardware is enabled before any hardware register operations. + if (i2s_num == I2S_NUM_1) { + periph_module_enable(PERIPH_I2S1_MODULE); + } else { + periph_module_enable(PERIPH_I2S0_MODULE); + } + + //initial interrupt + err = i2s_isr_register(i2s_num, i2s_config->intr_alloc_flags, i2s_intr_handler_default, p_i2s_obj[i2s_num], &p_i2s_obj[i2s_num]->i2s_isr_handle); + if (err != ESP_OK) { +#ifdef CONFIG_PM_ENABLE + if (p_i2s_obj[i2s_num]->pm_lock) { + esp_pm_lock_delete(p_i2s_obj[i2s_num]->pm_lock); + } +#endif + free(p_i2s_obj[i2s_num]); + p_i2s_obj[i2s_num] = NULL; + ESP_LOGE(I2S_TAG, "Register I2S Interrupt error"); + return err; + } + i2s_stop(i2s_num); + err = i2s_param_config(i2s_num, i2s_config); + if (err != ESP_OK) { + i2s_driver_uninstall(i2s_num); + ESP_LOGE(I2S_TAG, "I2S param configure error"); + return err; + } + + if (i2s_queue) { + p_i2s_obj[i2s_num]->i2s_queue = xQueueCreate(queue_size, sizeof(i2s_event_t)); + *((QueueHandle_t*) i2s_queue) = p_i2s_obj[i2s_num]->i2s_queue; + ESP_LOGI(I2S_TAG, "queue free spaces: %d", uxQueueSpacesAvailable(p_i2s_obj[i2s_num]->i2s_queue)); + } else { + p_i2s_obj[i2s_num]->i2s_queue = NULL; + } + //set clock and start + return i2s_set_clk(i2s_num, i2s_config->sample_rate, i2s_config->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); + } + + ESP_LOGW(I2S_TAG, "I2S driver already installed"); + return ESP_OK; +} + +esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + if (p_i2s_obj[i2s_num] == NULL) { + ESP_LOGI(I2S_TAG, "already uninstalled"); + return ESP_OK; + } + i2s_stop(i2s_num); + esp_intr_free(p_i2s_obj[i2s_num]->i2s_isr_handle); + + if (p_i2s_obj[i2s_num]->tx != NULL && p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { + i2s_destroy_dma_queue(i2s_num, p_i2s_obj[i2s_num]->tx); + p_i2s_obj[i2s_num]->tx = NULL; + } + if (p_i2s_obj[i2s_num]->rx != NULL && p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + i2s_destroy_dma_queue(i2s_num, p_i2s_obj[i2s_num]->rx); + p_i2s_obj[i2s_num]->rx = NULL; + } + + if (p_i2s_obj[i2s_num]->i2s_queue) { + vQueueDelete(p_i2s_obj[i2s_num]->i2s_queue); + p_i2s_obj[i2s_num]->i2s_queue = NULL; + } + + if(p_i2s_obj[i2s_num]->use_apll) { + rtc_clk_apll_enable(0, 0, 0, 0, 0); + } +#ifdef CONFIG_PM_ENABLE + if (p_i2s_obj[i2s_num]->pm_lock) { + esp_pm_lock_delete(p_i2s_obj[i2s_num]->pm_lock); + } +#endif + + free(p_i2s_obj[i2s_num]); + p_i2s_obj[i2s_num] = NULL; + + if (i2s_num == I2S_NUM_0) { + periph_module_disable(PERIPH_I2S0_MODULE); + } else if (i2s_num == I2S_NUM_1) { + periph_module_disable(PERIPH_I2S1_MODULE); + } + return ESP_OK; +} + +int i2s_write_bytes(i2s_port_t i2s_num, const void *src, size_t size, TickType_t ticks_to_wait) +{ + size_t bytes_written = 0; + int res = 0; + res = i2s_write(i2s_num, src, size, &bytes_written, ticks_to_wait); + if (res != ESP_OK) { + return ESP_FAIL; + } else { + return bytes_written; + } +} + +esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *bytes_written, TickType_t ticks_to_wait) +{ + char *data_ptr, *src_byte; + int bytes_can_write; + *bytes_written = 0; + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_ERR_INVALID_ARG); + xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_acquire(p_i2s_obj[i2s_num]->pm_lock); +#endif + src_byte = (char *)src; + while (size > 0) { + if (p_i2s_obj[i2s_num]->tx->rw_pos == p_i2s_obj[i2s_num]->tx->buf_size || p_i2s_obj[i2s_num]->tx->curr_ptr == NULL) { + if (xQueueReceive(p_i2s_obj[i2s_num]->tx->queue, &p_i2s_obj[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) { + break; + } + p_i2s_obj[i2s_num]->tx->rw_pos = 0; + } + ESP_LOGD(I2S_TAG, "size: %d, rw_pos: %d, buf_size: %d, curr_ptr: %d", size, p_i2s_obj[i2s_num]->tx->rw_pos, p_i2s_obj[i2s_num]->tx->buf_size, (int)p_i2s_obj[i2s_num]->tx->curr_ptr); + data_ptr = (char*)p_i2s_obj[i2s_num]->tx->curr_ptr; + data_ptr += p_i2s_obj[i2s_num]->tx->rw_pos; + bytes_can_write = p_i2s_obj[i2s_num]->tx->buf_size - p_i2s_obj[i2s_num]->tx->rw_pos; + if (bytes_can_write > size) { + bytes_can_write = size; + } + memcpy(data_ptr, src_byte, bytes_can_write); + size -= bytes_can_write; + src_byte += bytes_can_write; + p_i2s_obj[i2s_num]->tx->rw_pos += bytes_can_write; + (*bytes_written) += bytes_can_write; + } +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_release(p_i2s_obj[i2s_num]->pm_lock); +#endif + + xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux); + return ESP_OK; +} + +esp_err_t i2s_adc_enable(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); + I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); + + adc1_i2s_mode_acquire(); + _i2s_adc_mode_recover(); + return i2s_set_clk(i2s_num, p_i2s_obj[i2s_num]->sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); +} + +esp_err_t i2s_adc_disable(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); + I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); + + adc1_lock_release(); + return ESP_OK; +} + +esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, size_t src_bits, size_t aim_bits, size_t *bytes_written, TickType_t ticks_to_wait) +{ + char *data_ptr; + int bytes_can_write, tail; + int src_bytes, aim_bytes, zero_bytes; + *bytes_written = 0; + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((size > 0), "size must greater than zero", ESP_ERR_INVALID_ARG); + I2S_CHECK((aim_bits * size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); + I2S_CHECK((aim_bits >= src_bits), "aim_bits musn't less than src_bits", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num]->tx), "tx NULL", ESP_ERR_INVALID_ARG); + if (src_bits < I2S_BITS_PER_SAMPLE_8BIT || aim_bits < I2S_BITS_PER_SAMPLE_8BIT) { + ESP_LOGE(I2S_TAG,"bits musn't be less than 8, src_bits %d aim_bits %d", src_bits, aim_bits); + return ESP_ERR_INVALID_ARG; + } + if (src_bits > I2S_BITS_PER_SAMPLE_32BIT || aim_bits > I2S_BITS_PER_SAMPLE_32BIT) { + ESP_LOGE(I2S_TAG,"bits musn't be greater than 32, src_bits %d aim_bits %d", src_bits, aim_bits); + return ESP_ERR_INVALID_ARG; + } + if ((src_bits == I2S_BITS_PER_SAMPLE_16BIT || src_bits == I2S_BITS_PER_SAMPLE_32BIT) && (size % 2 != 0)) { + ESP_LOGE(I2S_TAG,"size must be a even number while src_bits is even, src_bits %d size %d", src_bits, size); + return ESP_ERR_INVALID_ARG; + } + if (src_bits == I2S_BITS_PER_SAMPLE_24BIT && (size % 3 != 0)) { + ESP_LOGE(I2S_TAG,"size must be a multiple of 3 while src_bits is 24, size %d", size); + return ESP_ERR_INVALID_ARG; + } + + src_bytes = src_bits / 8; + aim_bytes = aim_bits / 8; + zero_bytes = aim_bytes - src_bytes; + xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); + size = size * aim_bytes / src_bytes; + ESP_LOGD(I2S_TAG,"aim_bytes %d src_bytes %d size %d", aim_bytes, src_bytes, size); + while (size > 0) { + if (p_i2s_obj[i2s_num]->tx->rw_pos == p_i2s_obj[i2s_num]->tx->buf_size || p_i2s_obj[i2s_num]->tx->curr_ptr == NULL) { + if (xQueueReceive(p_i2s_obj[i2s_num]->tx->queue, &p_i2s_obj[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) { + break; + } + p_i2s_obj[i2s_num]->tx->rw_pos = 0; + } + data_ptr = (char*)p_i2s_obj[i2s_num]->tx->curr_ptr; + data_ptr += p_i2s_obj[i2s_num]->tx->rw_pos; + bytes_can_write = p_i2s_obj[i2s_num]->tx->buf_size - p_i2s_obj[i2s_num]->tx->rw_pos; + if (bytes_can_write > size) { + bytes_can_write = size; + } + tail = bytes_can_write % aim_bytes; + bytes_can_write = bytes_can_write - tail; + + memset(data_ptr, 0, bytes_can_write); + for (int j = 0; j < bytes_can_write; j += (aim_bytes - zero_bytes)) { + j += zero_bytes; + memcpy(&data_ptr[j], (const char *)(src + *bytes_written), aim_bytes - zero_bytes); + (*bytes_written) += (aim_bytes - zero_bytes); + } + size -= bytes_can_write; + p_i2s_obj[i2s_num]->tx->rw_pos += bytes_can_write; + } + xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux); + return ESP_OK; +} + +int i2s_read_bytes(i2s_port_t i2s_num, void *dest, size_t size, TickType_t ticks_to_wait) +{ + size_t bytes_read = 0; + int res = 0; + res = i2s_read(i2s_num, dest, size, &bytes_read, ticks_to_wait); + if (res != ESP_OK) { + return ESP_FAIL; + } else { + return bytes_read; + } +} + +esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_read, TickType_t ticks_to_wait) +{ + char *data_ptr, *dest_byte; + int bytes_can_read; + *bytes_read = 0; + dest_byte = (char *)dest; + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num]->rx), "rx NULL", ESP_ERR_INVALID_ARG); + xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_acquire(p_i2s_obj[i2s_num]->pm_lock); +#endif + while (size > 0) { + if (p_i2s_obj[i2s_num]->rx->rw_pos == p_i2s_obj[i2s_num]->rx->buf_size || p_i2s_obj[i2s_num]->rx->curr_ptr == NULL) { + if (xQueueReceive(p_i2s_obj[i2s_num]->rx->queue, &p_i2s_obj[i2s_num]->rx->curr_ptr, ticks_to_wait) == pdFALSE) { + break; + } + p_i2s_obj[i2s_num]->rx->rw_pos = 0; + } + data_ptr = (char*)p_i2s_obj[i2s_num]->rx->curr_ptr; + data_ptr += p_i2s_obj[i2s_num]->rx->rw_pos; + bytes_can_read = p_i2s_obj[i2s_num]->rx->buf_size - p_i2s_obj[i2s_num]->rx->rw_pos; + if (bytes_can_read > size) { + bytes_can_read = size; + } + memcpy(dest_byte, data_ptr, bytes_can_read); + size -= bytes_can_read; + dest_byte += bytes_can_read; + p_i2s_obj[i2s_num]->rx->rw_pos += bytes_can_read; + (*bytes_read) += bytes_can_read; + } +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_release(p_i2s_obj[i2s_num]->pm_lock); +#endif + xSemaphoreGive(p_i2s_obj[i2s_num]->rx->mux); + return ESP_OK; +} + +int i2s_push_sample(i2s_port_t i2s_num, const void *sample, TickType_t ticks_to_wait) +{ + size_t bytes_push = 0; + int res = 0; + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL); + res = i2s_write(i2s_num, sample, p_i2s_obj[i2s_num]->bytes_per_sample, &bytes_push, ticks_to_wait); + if (res != ESP_OK) { + return ESP_FAIL; + } else { + return bytes_push; + } +} + +int i2s_pop_sample(i2s_port_t i2s_num, void *sample, TickType_t ticks_to_wait) +{ + size_t bytes_pop = 0; + int res = 0; + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL); + res = i2s_read(i2s_num, sample, p_i2s_obj[i2s_num]->bytes_per_sample, &bytes_pop, ticks_to_wait); + if (res != ESP_OK) { + return ESP_FAIL; + } else { + return bytes_pop; + } +}