From c56f147d484d41d5c8a41ebc33a3d5ae5741c963 Mon Sep 17 00:00:00 2001 From: Sachin Parekh Date: Fri, 22 Feb 2019 17:44:03 +0530 Subject: [PATCH 1/3] I2C: Enable Power Management locks Acquires PM_APB_FREQ_MAX lock when carrying any transaction on I2C if Power Management Framework is enabled. Signed-off-by: Sachin Parekh --- components/driver/i2c.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/components/driver/i2c.c b/components/driver/i2c.c index 279cc81d6..6d9a5c9f2 100644 --- a/components/driver/i2c.c +++ b/components/driver/i2c.c @@ -29,6 +29,7 @@ #include "driver/i2c.h" #include "driver/gpio.h" #include "driver/periph_ctrl.h" +#include "esp_pm.h" static const char* I2C_TAG = "i2c"; #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_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) @@ -134,6 +136,9 @@ typedef struct { 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 */ @@ -226,6 +231,12 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_ } else { //semaphore to sync sending process, because we only have 32 bytes for hardware fifo. p_i2c->cmd_mux = xSemaphoreCreateMutex(); +#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 @@ -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) { 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); @@ -365,6 +382,12 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num) 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); @@ -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]; 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; } @@ -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; +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_release(p_i2c->pm_lock); +#endif xSemaphoreGive(p_i2c->cmd_mux); return ret; } From 4cdf488de8b1ff72585bc3bda183c41d296c3080 Mon Sep 17 00:00:00 2001 From: Sachin Parekh Date: Fri, 22 Feb 2019 17:47:42 +0530 Subject: [PATCH 2/3] I2S: Enable Power Management locks Acquires PM_APB_FREQ_MAX lock when carrying any transaction on I2S if Power Management Framework is enabled. Signed-off-by: Sachin Parekh --- components/driver/i2s.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 0d33a45b9..1d050f824 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -36,8 +36,10 @@ #include "esp_intr.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); \ @@ -88,6 +90,9 @@ typedef struct { 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 */ +#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}; @@ -528,7 +533,6 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) } xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken); } - } if (i2s_reg->int_st.in_suc_eof && p_i2s->rx) { @@ -1060,6 +1064,14 @@ 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]->channel_num = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1; +#ifdef CONFIG_PM_ENABLE + err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "i2s_driver", + &p_i2s_obj[i2s_num]->pm_lock); + if (err != ESP_OK) { + 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); @@ -1070,6 +1082,11 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, //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"); @@ -1125,6 +1142,11 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) 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; @@ -1158,6 +1180,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((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) { @@ -1179,6 +1204,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; (*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; } @@ -1289,6 +1318,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((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) { @@ -1308,6 +1340,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; (*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; } @@ -1337,5 +1372,3 @@ int i2s_pop_sample(i2s_port_t i2s_num, void *sample, TickType_t ticks_to_wait) return bytes_pop; } } - - From eeb9a0359c6327bca4bb2a6e5dad70940ab43f17 Mon Sep 17 00:00:00 2001 From: Sachin Parekh Date: Fri, 22 Feb 2019 19:48:59 +0530 Subject: [PATCH 3/3] PM: I2S and I2C added in the Power Management docs Signed-off-by: Sachin Parekh --- components/driver/i2s.c | 14 ++++++++++---- docs/en/api-reference/system/power_management.rst | 8 ++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 1d050f824..af00148b3 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -1065,13 +1065,19 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, p_i2s_obj[i2s_num]->channel_num = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1; #ifdef CONFIG_PM_ENABLE - err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "i2s_driver", - &p_i2s_obj[i2s_num]->pm_lock); + 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); @@ -1144,7 +1150,7 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) } #ifdef CONFIG_PM_ENABLE if (p_i2s_obj[i2s_num]->pm_lock) { - esp_pm_lock_delete(p_i2s_obj[i2s_num]->pm_lock); + esp_pm_lock_delete(p_i2s_obj[i2s_num]->pm_lock); } #endif diff --git a/docs/en/api-reference/system/power_management.rst b/docs/en/api-reference/system/power_management.rst index 9380a8d88..6c7446a1d 100644 --- a/docs/en/api-reference/system/power_management.rst +++ b/docs/en/api-reference/system/power_management.rst @@ -108,6 +108,10 @@ Currently, the following peripheral drivers are aware of DFS and will use ``ESP_ - SPI master +- I2C + +- I2S (If APLL clock is used then it will use ``ESP_PM_NO_LIGHT_SLEEP`` lock) + - SDMMC 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: -- I2C - -- I2S - - MCPWM - PCNT