Merge branch 'power_management/i2s+i2c-v3.3' into 'release/v3.3'
Power management/i2s+i2 (Backport v3.3) See merge request espressif/esp-idf!6002
This commit is contained in:
commit
d190c53ec8
3 changed files with 75 additions and 7 deletions
|
@ -29,6 +29,7 @@
|
||||||
#include "driver/i2c.h"
|
#include "driver/i2c.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "driver/periph_ctrl.h"
|
#include "driver/periph_ctrl.h"
|
||||||
|
#include "esp_pm.h"
|
||||||
|
|
||||||
static const char* I2C_TAG = "i2c";
|
static const char* I2C_TAG = "i2c";
|
||||||
#define I2C_CHECK(a, str, ret) if(!(a)) { \
|
#define I2C_CHECK(a, str, ret) if(!(a)) { \
|
||||||
|
@ -67,6 +68,7 @@ static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 };
|
||||||
#define I2C_ACK_TYPE_ERR_STR "i2c ack type error"
|
#define I2C_ACK_TYPE_ERR_STR "i2c ack type error"
|
||||||
#define I2C_DATA_LEN_ERR_STR "i2c data read length 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_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_FULL_THRESH_VAL (28)
|
||||||
#define I2C_FIFO_EMPTY_THRESH_VAL (5)
|
#define I2C_FIFO_EMPTY_THRESH_VAL (5)
|
||||||
#define I2C_IO_INIT_LEVEL (1)
|
#define I2C_IO_INIT_LEVEL (1)
|
||||||
|
@ -134,6 +136,9 @@ typedef struct {
|
||||||
StaticQueue_t evt_queue_buffer; /*!< The buffer that will hold the queue structure*/
|
StaticQueue_t evt_queue_buffer; /*!< The buffer that will hold the queue structure*/
|
||||||
#endif
|
#endif
|
||||||
xSemaphoreHandle cmd_mux; /*!< semaphore to lock command process */
|
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 tx_fifo_remain; /*!< tx fifo remain length, for master mode */
|
||||||
size_t rx_fifo_remain; /*!< rx fifo remain length, for master mode */
|
size_t rx_fifo_remain; /*!< rx fifo remain length, for master mode */
|
||||||
|
|
||||||
|
@ -226,6 +231,12 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
|
||||||
} else {
|
} else {
|
||||||
//semaphore to sync sending process, because we only have 32 bytes for hardware fifo.
|
//semaphore to sync sending process, because we only have 32 bytes for hardware fifo.
|
||||||
p_i2c->cmd_mux = xSemaphoreCreateMutex();
|
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
|
#if !CONFIG_SPIRAM_USE_MALLOC
|
||||||
p_i2c->cmd_evt_queue = xQueueCreate(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t));
|
p_i2c->cmd_evt_queue = xQueueCreate(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t));
|
||||||
#else
|
#else
|
||||||
|
@ -297,6 +308,12 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
|
||||||
if (p_i2c_obj[i2c_num]->slv_tx_mux) {
|
if (p_i2c_obj[i2c_num]->slv_tx_mux) {
|
||||||
vSemaphoreDelete(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 CONFIG_SPIRAM_USE_MALLOC
|
||||||
if (p_i2c_obj[i2c_num]->evt_queue_storage) {
|
if (p_i2c_obj[i2c_num]->evt_queue_storage) {
|
||||||
free(p_i2c_obj[i2c_num]->evt_queue_storage);
|
free(p_i2c_obj[i2c_num]->evt_queue_storage);
|
||||||
|
@ -365,6 +382,12 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num)
|
||||||
p_i2c->tx_ring_buf = NULL;
|
p_i2c->tx_ring_buf = NULL;
|
||||||
p_i2c->tx_buf_length = 0;
|
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 CONFIG_SPIRAM_USE_MALLOC
|
||||||
if (p_i2c_obj[i2c_num]->evt_queue_storage) {
|
if (p_i2c_obj[i2c_num]->evt_queue_storage) {
|
||||||
free(p_i2c_obj[i2c_num]->evt_queue_storage);
|
free(p_i2c_obj[i2c_num]->evt_queue_storage);
|
||||||
|
@ -1261,6 +1284,9 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
|
||||||
i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
|
i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
|
||||||
portTickType ticks_start = xTaskGetTickCount();
|
portTickType ticks_start = xTaskGetTickCount();
|
||||||
portBASE_TYPE res = xSemaphoreTake(p_i2c->cmd_mux, ticks_to_wait);
|
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) {
|
if (res == pdFALSE) {
|
||||||
return ESP_ERR_TIMEOUT;
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
@ -1338,6 +1364,9 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p_i2c->status = I2C_STATUS_DONE;
|
p_i2c->status = I2C_STATUS_DONE;
|
||||||
|
#ifdef CONFIG_PM_ENABLE
|
||||||
|
esp_pm_lock_release(p_i2c->pm_lock);
|
||||||
|
#endif
|
||||||
xSemaphoreGive(p_i2c->cmd_mux);
|
xSemaphoreGive(p_i2c->cmd_mux);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,10 @@
|
||||||
#include "esp_intr.h"
|
#include "esp_intr.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_pm.h"
|
||||||
|
|
||||||
static const char* I2S_TAG = "I2S";
|
static const char* I2S_TAG = "I2S";
|
||||||
|
|
||||||
#define I2S_CHECK(a, str, ret) if (!(a)) { \
|
#define I2S_CHECK(a, str, ret) if (!(a)) { \
|
||||||
ESP_LOGE(I2S_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
ESP_LOGE(I2S_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||||
return (ret); \
|
return (ret); \
|
||||||
|
@ -91,6 +93,9 @@ typedef struct {
|
||||||
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor on underflow */
|
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor on underflow */
|
||||||
int fixed_mclk; /*!< I2S fixed MLCK clock */
|
int fixed_mclk; /*!< I2S fixed MLCK clock */
|
||||||
double real_rate;
|
double real_rate;
|
||||||
|
#ifdef CONFIG_PM_ENABLE
|
||||||
|
esp_pm_lock_handle_t pm_lock;
|
||||||
|
#endif
|
||||||
} i2s_obj_t;
|
} i2s_obj_t;
|
||||||
|
|
||||||
static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0};
|
static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0};
|
||||||
|
@ -543,7 +548,6 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg)
|
||||||
}
|
}
|
||||||
xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &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) {
|
if (i2s_reg->int_st.in_suc_eof && p_i2s->rx) {
|
||||||
|
@ -1082,6 +1086,20 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
|
||||||
p_i2s_obj[i2s_num]->bytes_per_sample = 0; // Not initialized yet
|
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;
|
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.
|
//To make sure hardware is enabled before any hardware register operations.
|
||||||
if (i2s_num == I2S_NUM_1) {
|
if (i2s_num == I2S_NUM_1) {
|
||||||
periph_module_enable(PERIPH_I2S1_MODULE);
|
periph_module_enable(PERIPH_I2S1_MODULE);
|
||||||
|
@ -1092,6 +1110,11 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
|
||||||
//initial interrupt
|
//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);
|
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) {
|
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]);
|
free(p_i2s_obj[i2s_num]);
|
||||||
p_i2s_obj[i2s_num] = NULL;
|
p_i2s_obj[i2s_num] = NULL;
|
||||||
ESP_LOGE(I2S_TAG, "Register I2S Interrupt error");
|
ESP_LOGE(I2S_TAG, "Register I2S Interrupt error");
|
||||||
|
@ -1147,6 +1170,11 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
|
||||||
if(p_i2s_obj[i2s_num]->use_apll) {
|
if(p_i2s_obj[i2s_num]->use_apll) {
|
||||||
rtc_clk_apll_enable(0, 0, 0, 0, 0);
|
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]);
|
free(p_i2s_obj[i2s_num]);
|
||||||
p_i2s_obj[i2s_num] = NULL;
|
p_i2s_obj[i2s_num] = NULL;
|
||||||
|
@ -1180,6 +1208,9 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by
|
||||||
I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", 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);
|
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);
|
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;
|
src_byte = (char *)src;
|
||||||
while (size > 0) {
|
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 (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) {
|
||||||
|
@ -1201,6 +1232,10 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by
|
||||||
p_i2s_obj[i2s_num]->tx->rw_pos += bytes_can_write;
|
p_i2s_obj[i2s_num]->tx->rw_pos += bytes_can_write;
|
||||||
(*bytes_written) += 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);
|
xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
@ -1311,6 +1346,9 @@ esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_re
|
||||||
I2S_CHECK((size < I2S_MAX_BUFFER_SIZE), "size is too large", 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);
|
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);
|
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) {
|
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 (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) {
|
if (xQueueReceive(p_i2s_obj[i2s_num]->rx->queue, &p_i2s_obj[i2s_num]->rx->curr_ptr, ticks_to_wait) == pdFALSE) {
|
||||||
|
@ -1330,6 +1368,9 @@ esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_re
|
||||||
p_i2s_obj[i2s_num]->rx->rw_pos += bytes_can_read;
|
p_i2s_obj[i2s_num]->rx->rw_pos += bytes_can_read;
|
||||||
(*bytes_read) += 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);
|
xSemaphoreGive(p_i2s_obj[i2s_num]->rx->mux);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
@ -1359,5 +1400,3 @@ int i2s_pop_sample(i2s_port_t i2s_num, void *sample, TickType_t ticks_to_wait)
|
||||||
return bytes_pop;
|
return bytes_pop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,10 @@ Currently, the following peripheral drivers are aware of DFS and will use ``ESP_
|
||||||
|
|
||||||
- SPI master
|
- SPI master
|
||||||
|
|
||||||
|
- I2C
|
||||||
|
|
||||||
|
- I2S (If APLL clock is used then it will use ``ESP_PM_NO_LIGHT_SLEEP`` lock)
|
||||||
|
|
||||||
- SDMMC
|
- SDMMC
|
||||||
|
|
||||||
The following drivers will hold ``ESP_PM_APB_FREQ_MAX`` lock while the driver is enabled:
|
The following drivers will hold ``ESP_PM_APB_FREQ_MAX`` lock while the driver is enabled:
|
||||||
|
@ -124,10 +128,6 @@ The following drivers will hold ``ESP_PM_APB_FREQ_MAX`` lock while the driver is
|
||||||
|
|
||||||
The following peripheral drivers are not aware of DFS yet. Applications need to acquire/release locks when necessary:
|
The following peripheral drivers are not aware of DFS yet. Applications need to acquire/release locks when necessary:
|
||||||
|
|
||||||
- I2C
|
|
||||||
|
|
||||||
- I2S
|
|
||||||
|
|
||||||
- MCPWM
|
- MCPWM
|
||||||
|
|
||||||
- PCNT
|
- PCNT
|
||||||
|
|
Loading…
Reference in a new issue