Merge branch 'bugfix/rmt_memory_power_up_v5.2' into 'release/v5.2'

fix(rmt): power up memory block (v5.2)

See merge request espressif/esp-idf!32172
This commit is contained in:
morris 2024-07-19 09:47:19 +08:00
commit 9757709b2e
10 changed files with 209 additions and 76 deletions

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -152,10 +152,10 @@ esp_err_t rmt_set_tx_carrier(rmt_channel_t channel, bool carrier_en, uint16_t hi
esp_err_t rmt_set_mem_pd(rmt_channel_t channel, bool pd_en); esp_err_t rmt_set_mem_pd(rmt_channel_t channel, bool pd_en);
/** /**
* @brief Get RMT memory low power mode. * @brief Check if the RMT memory is force powered down
* *
* @param channel RMT channel * @param channel RMT channel (actually this function is configured for all channels)
* @param pd_en Pointer to accept RMT memory low power mode. * @param pd_en Pointer to accept the result
* *
* @return * @return
* - ESP_ERR_INVALID_ARG Parameter error * - ESP_ERR_INVALID_ARG Parameter error

View File

@ -141,6 +141,7 @@ static void rmt_module_enable(void)
rmt_ll_enable_bus_clock(0, true); rmt_ll_enable_bus_clock(0, true);
rmt_ll_reset_register(0); rmt_ll_reset_register(0);
} }
rmt_ll_mem_power_by_pmu(rmt_contex.hal.regs);
rmt_contex.rmt_module_enabled = true; rmt_contex.rmt_module_enabled = true;
} }
RMT_EXIT_CRITICAL(); RMT_EXIT_CRITICAL();
@ -151,6 +152,7 @@ static void rmt_module_disable(void)
{ {
RMT_ENTER_CRITICAL(); RMT_ENTER_CRITICAL();
if (rmt_contex.rmt_module_enabled == true) { if (rmt_contex.rmt_module_enabled == true) {
rmt_ll_mem_force_power_off(rmt_contex.hal.regs);
RMT_RCC_ATOMIC() { RMT_RCC_ATOMIC() {
rmt_ll_enable_bus_clock(0, false); rmt_ll_enable_bus_clock(0, false);
} }
@ -250,7 +252,11 @@ esp_err_t rmt_set_mem_pd(rmt_channel_t channel, bool pd_en)
{ {
ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR);
RMT_ENTER_CRITICAL(); RMT_ENTER_CRITICAL();
rmt_ll_power_down_mem(rmt_contex.hal.regs, pd_en); if (pd_en) {
rmt_ll_mem_force_power_off(rmt_contex.hal.regs);
} else {
rmt_ll_mem_power_by_pmu(rmt_contex.hal.regs);
}
RMT_EXIT_CRITICAL(); RMT_EXIT_CRITICAL();
return ESP_OK; return ESP_OK;
} }
@ -259,7 +265,7 @@ esp_err_t rmt_get_mem_pd(rmt_channel_t channel, bool *pd_en)
{ {
ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR);
RMT_ENTER_CRITICAL(); RMT_ENTER_CRITICAL();
*pd_en = rmt_ll_is_mem_powered_down(rmt_contex.hal.regs); *pd_en = rmt_ll_is_mem_force_powered_down(rmt_contex.hal.regs);
RMT_EXIT_CRITICAL(); RMT_EXIT_CRITICAL();
return ESP_OK; return ESP_OK;
} }

View File

@ -88,14 +88,33 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable)
} }
/** /**
* @brief Power down memory * @brief Force power on the RMT memory block, regardless of the outside PMU logic
* *
* @param dev Peripheral instance address * @param dev Peripheral instance address
* @param enable True to power down, False to power up
*/ */
static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev)
{ {
dev->conf_ch[0].conf0.mem_pd = enable; // Only conf0 register of channel0 has `mem_pd` (void)dev;
}
/**
* @brief Force power off the RMT memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev)
{
dev->conf_ch[0].conf0.mem_pd = 1;
}
/**
* @brief Power control the RMT memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev)
{
dev->conf_ch[0].conf0.mem_pd = 0;
} }
/** /**
@ -120,7 +139,7 @@ static inline void rmt_ll_enable_mem_access_nonfifo(rmt_dev_t *dev, bool enable)
* @param divider_numerator Numerator part of the divider * @param divider_numerator Numerator part of the divider
*/ */
static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src, static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src,
uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator)
{ {
(void)divider_integral; (void)divider_integral;
(void)divider_denominator; (void)divider_denominator;
@ -631,7 +650,7 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel
return dev->conf_ch[channel].conf1.idle_out_lv; return dev->conf_ch[channel].conf1.idle_out_lv;
} }
static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev)
{ {
// Only conf0 register of channel0 has `mem_pd` // Only conf0 register of channel0 has `mem_pd`
return dev->conf_ch[0].conf0.mem_pd; return dev->conf_ch[0].conf0.mem_pd;

View File

@ -87,15 +87,36 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable)
} }
/** /**
* @brief Power down memory * @brief Force power on the RMT memory block, regardless of the outside PMU logic
* *
* @param dev Peripheral instance address * @param dev Peripheral instance address
* @param enable True to power down, False to power up
*/ */
static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev)
{ {
dev->sys_conf.mem_force_pu = !enable; dev->sys_conf.mem_force_pu = 1;
dev->sys_conf.mem_force_pd = enable; dev->sys_conf.mem_force_pd = 0;
}
/**
* @brief Force power off the RMT memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev)
{
dev->sys_conf.mem_force_pd = 1;
dev->sys_conf.mem_force_pu = 0;
}
/**
* @brief Power control the RMT memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev)
{
dev->sys_conf.mem_force_pd = 0;
dev->sys_conf.mem_force_pu = 0;
} }
/** /**
@ -812,12 +833,9 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel
return dev->tx_conf[channel].idle_out_lv; return dev->tx_conf[channel].idle_out_lv;
} }
static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev)
{ {
// the RTC domain can also power down RMT memory return dev->sys_conf.mem_force_pd;
// so it's probably not enough to detect whether it's powered down or not
// mem_force_pd has higher priority than mem_force_pu
return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu);
} }
__attribute__((always_inline)) __attribute__((always_inline))

View File

@ -79,15 +79,36 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable)
} }
/** /**
* @brief Power down memory * @brief Force power on the RMT memory block, regardless of the outside PMU logic
* *
* @param dev Peripheral instance address * @param dev Peripheral instance address
* @param enable True to power down, False to power up
*/ */
static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev)
{ {
dev->sys_conf.mem_force_pu = !enable; dev->sys_conf.mem_force_pu = 1;
dev->sys_conf.mem_force_pd = enable; dev->sys_conf.mem_force_pd = 0;
}
/**
* @brief Force power off the RMT memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev)
{
dev->sys_conf.mem_force_pd = 1;
dev->sys_conf.mem_force_pu = 0;
}
/**
* @brief Power control the RMT memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev)
{
dev->sys_conf.mem_force_pd = 0;
dev->sys_conf.mem_force_pu = 0;
} }
/** /**
@ -818,12 +839,9 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel
return dev->chnconf0[channel].idle_out_lv_chn; return dev->chnconf0[channel].idle_out_lv_chn;
} }
static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev)
{ {
// the RTC domain can also power down RMT memory return dev->sys_conf.mem_force_pd;
// so it's probably not enough to detect whether it's powered down or not
// mem_force_pd has higher priority than mem_force_pu
return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu);
} }
__attribute__((always_inline)) __attribute__((always_inline))

View File

@ -79,15 +79,36 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable)
} }
/** /**
* @brief Power down memory * @brief Force power on the RMT memory block, regardless of the outside PMU logic
* *
* @param dev Peripheral instance address * @param dev Peripheral instance address
* @param enable True to power down, False to power up
*/ */
static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev)
{ {
dev->sys_conf.mem_force_pu = !enable; dev->sys_conf.mem_force_pu = 1;
dev->sys_conf.mem_force_pd = enable; dev->sys_conf.mem_force_pd = 0;
}
/**
* @brief Force power off the RMT memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev)
{
dev->sys_conf.mem_force_pd = 1;
dev->sys_conf.mem_force_pu = 0;
}
/**
* @brief Power control the RMT memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev)
{
dev->sys_conf.mem_force_pd = 0;
dev->sys_conf.mem_force_pu = 0;
} }
/** /**
@ -812,12 +833,9 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel
return dev->chnconf0[channel].idle_out_lv_chn; return dev->chnconf0[channel].idle_out_lv_chn;
} }
static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev)
{ {
// the RTC domain can also power down RMT memory return dev->sys_conf.mem_force_pd;
// so it's probably not enough to detect whether it's powered down or not
// mem_force_pd has higher priority than mem_force_pu
return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu);
} }
__attribute__((always_inline)) __attribute__((always_inline))

View File

@ -85,7 +85,7 @@ static inline void rmt_ll_reset_register(int group_id)
* @param divider_numerator Numerator part of the divider * @param divider_numerator Numerator part of the divider
*/ */
static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src, static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src,
uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator)
{ {
(void)dev; (void)dev;
// Formula: rmt_sclk = module_clock_src / (1 + div_num + div_a / div_b) // Formula: rmt_sclk = module_clock_src / (1 + div_num + div_a / div_b)
@ -143,15 +143,36 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable)
} }
/** /**
* @brief Power down memory * @brief Force power on the RMT memory block, regardless of the outside PMU logic
* *
* @param dev Peripheral instance address * @param dev Peripheral instance address
* @param enable True to power down, False to power up
*/ */
static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev)
{ {
dev->sys_conf.mem_force_pu = !enable; dev->sys_conf.mem_force_pu = 1;
dev->sys_conf.mem_force_pd = enable; dev->sys_conf.mem_force_pd = 0;
}
/**
* @brief Force power off the RMT memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev)
{
dev->sys_conf.mem_force_pd = 1;
dev->sys_conf.mem_force_pu = 0;
}
/**
* @brief Power control the RMT memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev)
{
dev->sys_conf.mem_force_pd = 0;
dev->sys_conf.mem_force_pu = 0;
} }
/** /**
@ -860,12 +881,9 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel
return dev->chnconf0[channel].idle_out_lv_chn; return dev->chnconf0[channel].idle_out_lv_chn;
} }
static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev)
{ {
// the RTC domain can also power down RMT memory return dev->sys_conf.mem_force_pd;
// so it's probably not enough to detect whether it's powered down or not
// mem_force_pd has higher priority than mem_force_pu
return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu);
} }
__attribute__((always_inline)) __attribute__((always_inline))

View File

@ -90,15 +90,36 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable)
} }
/** /**
* @brief Power down memory * @brief Force power on the RMT memory block, regardless of the outside PMU logic
* *
* @param dev Peripheral instance address * @param dev Peripheral instance address
* @param enable True to power down, False to power up
*/ */
static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev)
{ {
dev->apb_conf.mem_force_pu = !enable; dev->apb_conf.mem_force_pu = 1;
dev->apb_conf.mem_force_pd = enable; dev->apb_conf.mem_force_pd = 0;
}
/**
* @brief Force power off the RMT memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev)
{
dev->apb_conf.mem_force_pd = 1;
dev->apb_conf.mem_force_pu = 0;
}
/**
* @brief Power control the RMT memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev)
{
dev->apb_conf.mem_force_pd = 0;
dev->apb_conf.mem_force_pu = 0;
} }
/** /**
@ -774,12 +795,9 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel
return dev->conf_ch[channel].conf1.idle_out_lv_chn; return dev->conf_ch[channel].conf1.idle_out_lv_chn;
} }
static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev)
{ {
// the RTC domain can also power down RMT memory return dev->apb_conf.mem_force_pd;
// so it's probably not enough to detect whether it's powered down or not
// mem_force_pd has higher priority than mem_force_pu
return (dev->apb_conf.mem_force_pd) || !(dev->apb_conf.mem_force_pu);
} }
__attribute__((always_inline)) __attribute__((always_inline))

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -87,15 +87,36 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable)
} }
/** /**
* @brief Power down memory * @brief Force power on the RMT memory block, regardless of the outside PMU logic
* *
* @param dev Peripheral instance address * @param dev Peripheral instance address
* @param enable True to power down, False to power up
*/ */
static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev)
{ {
dev->sys_conf.mem_force_pu = !enable; dev->sys_conf.mem_force_pu = 1;
dev->sys_conf.mem_force_pd = enable; dev->sys_conf.mem_force_pd = 0;
}
/**
* @brief Force power off the RMT memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev)
{
dev->sys_conf.mem_force_pd = 1;
dev->sys_conf.mem_force_pu = 0;
}
/**
* @brief Power control the RMT memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev)
{
dev->sys_conf.mem_force_pd = 0;
dev->sys_conf.mem_force_pu = 0;
} }
/** /**
@ -850,12 +871,9 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel
return dev->chnconf0[channel].idle_out_lv_chn; return dev->chnconf0[channel].idle_out_lv_chn;
} }
static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev)
{ {
// the RTC domain can also power down RMT memory return dev->sys_conf.mem_force_pd;
// so it's probably not enough to detect whether it's powered down or not
// mem_force_pd has higher priority than mem_force_pu
return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu);
} }
__attribute__((always_inline)) __attribute__((always_inline))

View File

@ -10,7 +10,7 @@
void rmt_hal_init(rmt_hal_context_t *hal) void rmt_hal_init(rmt_hal_context_t *hal)
{ {
hal->regs = &RMT; hal->regs = &RMT;
rmt_ll_power_down_mem(hal->regs, false); // turn on RMTMEM power domain rmt_ll_mem_power_by_pmu(hal->regs);
rmt_ll_enable_mem_access_nonfifo(hal->regs, true); // APB access the RMTMEM in nonfifo mode rmt_ll_enable_mem_access_nonfifo(hal->regs, true); // APB access the RMTMEM in nonfifo mode
rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interupt events rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interupt events
rmt_ll_clear_interrupt_status(hal->regs, UINT32_MAX); // clear all pending events rmt_ll_clear_interrupt_status(hal->regs, UINT32_MAX); // clear all pending events
@ -23,7 +23,7 @@ void rmt_hal_deinit(rmt_hal_context_t *hal)
{ {
rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interupt events rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interupt events
rmt_ll_clear_interrupt_status(hal->regs, UINT32_MAX); // clear all pending events rmt_ll_clear_interrupt_status(hal->regs, UINT32_MAX); // clear all pending events
rmt_ll_power_down_mem(hal->regs, true); // turn off RMTMEM power domain rmt_ll_mem_force_power_off(hal->regs); // power off RMTMEM power domain forcefully
hal->regs = NULL; hal->regs = NULL;
} }