espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.85k stars 7.32k forks source link

CONFIG_PM_ENABLE without Dynamic Frequency Scaling (IDFGH-12481) #13492

Closed pggh closed 7 months ago

pggh commented 8 months ago

Is your feature request related to a problem?

From what is have read (doc and code) about the Power Management, enabling CONFIG_PM_ENABLE always comes with the cost described in the doc as:

Enabling power management features comes at the cost of increased interrupt latency. Extra latency depends on a number of factors, such as the CPU frequency, single/dual core mode, whether or not frequency switch needs to be done. Minimum extra latency is 0.2 us (when the CPU frequency is 240 MHz and frequency scaling is not enabled). Maximum extra latency is 40 us (when frequency scaling is enabled, and a switch from 40 MHz to 80 MHz is performed on interrupt entry).

However I believe this cost is actually only required when DFS or automatic Light-sleep are used. (hooking idle and interrupt processing to change clock)

It would be nice to have a possibility to change the CPU clock in an application specific way, without having the costs mentioned above.

Describe the solution you'd like.

A configuration option like CONFIG_PM_NO_DFS_AUTO_LIGHT_SLEEP.

Describe alternatives you've considered.

A new API like set_cpu_frequency that is available when CONFIG_PM_ENABLE is not set to allow to change the cpu frequency manually. (alternative to call esp_pm_configure(with min=max=new_freq))

Additional context.

Possible applications are:

while running 99% of the time with a power saving low frequency.

igrr commented 8 months ago

Unfortunately what you are proposing (having an API to set the CPU frequency) is not possible in the general case (i.e. on all chips, with all frequency combinations). For example, on the ESP32, we can't switch between 240 and 160 MHz CPU clock at an arbitrary moment. (The technical reason is that it requires reconfiguring the PLL, which would disrupt Wi-Fi connection if the Wi-Fi modem is active at this point in time.) On most chips, setting the CPU frequency lower than the minimal APB frequency required for Wi-Fi MAC to work isn't possible either (while maintaining Wi-Fi connection).

For this reason, the API is defined the way it is. We may revisit it in the future when newer chips allow the CPU frequency to be changed independently from the peripherals' frequency.

esp-wzh commented 8 months ago

@pggh

Actually, IDF already provide the interface you need. You can use rtc_clk_cpu_freq_mhz_to_config to convert the CPU frequency you expect to configure into a config structure and use API rtc_clk_cpu_freq_set_config_fast or rtc_clk_cpu_freq_set_config to configure it. (all in soc/rtc.h)

However, as ivan said, the CPU frequency of esp32 series chips is somewhat tied to the peripheral APB frequency, and switching the CPU frequency in some scenarios will destroy the peripheral's runtime clock and cause an error. so we strongly do not recommend users to actively configure the CPU frequency in the app.

If you use esp_pm to manage the CPU freq, pm lock will be requested in the IDF peripheral driver to protect the peripheral's running clock, so the user code doesn't need to pay attention to the CPU frequency anymore, and the system will always work in the lowest power mode allowed by all the peripherals.

pggh commented 8 months ago

The info above is a bit surprising to me. After all a call to esp_pm_configure() with min_freq_mhz = max_freq_mhz = 80 or min_freq_mhz = max_freq_mhz = 240 would allow to switch between 80 and 240 MHz. I don't see anything in the doc that this would not be possible or that the frequency would not occur immediately.

Up to 40 us interrupt latency is not acceptable for certain scenarios. So I suggested this change. Is there any chance to implement an API that:

Not all frequency combinations would need to be supported. e. g. only switching between 80 and 240 MHz. (I'm using ESP32-S3 only)

Also a complete list of interrupt latency depending on the min/max frequency would be helpful. If it is sufficiently small for the relevant configuration, the current API could be good enough.

PS: The doc does not mention that WiFi will not work with CPU-Clock < 80MHz, only that APB must be 80 MHz.

igrr commented 8 months ago

The doc does not mention that WiFi will not work with CPU-Clock < 80MHz, only that APB must be 80 MHz.

IDF docs indeed don't state this, but it should be mentioned somewhere in the chip documentation (TRM) that CPU frequency can't be below the APB frequency, at least on the ESP32.

I don't see anything in the doc that this would not be possible or that the frequency would not occur immediately.

Depending on the chip and on the CPU frequency combination, the switch may occur immediately. For example, on the ESP32-S3 the switch between 80 and 240 MHz can occur without reconfiguring the PLL, so it will be done immediately.

Regarding your requirements, I think simply calling esp_pm_configure with min_freq == max_freq == desired_freq should do the trick. Interrupt latency shouldn't increase because the system won't be automatically switching the CPU frequency when waking up from waiti state and entering the ISR.

esp-wzh commented 8 months ago

@pggh I guess I understand the problem you're having, instead of updating the CPU frequency configuration immediately after running esp_pm_configure, it waits until the next interrupt arrives or until pm_lock is acquired, whereas your expectation should be to be able to update the CPU frequency configuration immediately after calling esp_pm_configure. It's a reasonable request, I'll fix it.

pggh commented 8 months ago

@esp-wzh That is good news. However I'm still concerned about the overhead created for interrupt latency. I don't know whether I found all code that is called for every interrupt but it looks big with lot of overhead, nested calls and even spinlocks. Looks scary to me. It might be worth to eliminate all this overhead in case min_freq_mhz = max_freq_mhz, without light_sleep and put a boolean-check right in xtensa_vectors.S to skip over esp_pm_impl_isr_hook in this case. For applications where fast interrupt processing in needed, this could help.

esp-wzh commented 8 months ago

It might be worth to eliminate all this overhead in case min_freq_mhz = max_freq_mhz, without light_sleep and put a boolean-check right in xtensa_vectors.S to skip over esp_pm_impl_isr_hook in this case. For applications where fast interrupt processing in needed, this could help.

Sorry, I don't think it's worth it, and if you must do it, I'd rather suggest that you turn off ESP_PM_ENABLED and then use the rtc_clk_cpu_freq_set_config API to manage the CPU frequency manually, which also means you need to carefully evaluate the CPU frequency required for each phase of the application.