2222#include "soc/rtc.h"
2323#include "soc/rtc_cntl_reg.h"
2424#include "rom/rtc.h"
25+ #include "soc/apb_ctrl_reg.h"
2526#include "esp32-hal.h"
2627#include "esp32-hal-cpu.h"
2728
@@ -31,16 +32,11 @@ typedef struct apb_change_cb_s {
3132 apb_change_cb_t cb ;
3233} apb_change_t ;
3334
35+ const uint32_t MHZ = 1000000 ;
36+
3437static apb_change_t * apb_change_callbacks = NULL ;
3538static xSemaphoreHandle apb_change_lock = NULL ;
3639
37- static uint32_t calculateApb (rtc_cpu_freq_config_t * conf ){
38- if (conf -> freq_mhz >= 80 ){
39- return 80000000 ;
40- }
41- return (conf -> source_freq_mhz * 1000000 ) / conf -> div ;
42- }
43-
4440static void initApbChangeCallback (){
4541 static volatile bool initialized = false;
4642 if (!initialized ){
@@ -119,31 +115,56 @@ bool removeApbChangeCallback(void * arg, apb_change_cb_t cb){
119115 return true;
120116}
121117
118+ static uint32_t calculateApb (rtc_cpu_freq_config_t * conf ){
119+ if (conf -> freq_mhz >= 80 ){
120+ return 80 * MHZ ;
121+ }
122+ return (conf -> source_freq_mhz * MHZ ) / conf -> div ;
123+ }
124+
122125void esp_timer_impl_update_apb_freq (uint32_t apb_ticks_per_us ); //private in IDF
123126
124127bool setCpuFrequency (uint32_t cpu_freq_mhz ){
125128 rtc_cpu_freq_config_t conf , cconf ;
126129 uint32_t capb , apb ;
130+ //Get current CPU clock configuration
127131 rtc_clk_cpu_freq_get_config (& cconf );
132+ //return if frequency has not changed
128133 if (cconf .freq_mhz == cpu_freq_mhz ){
129134 return true;
130135 }
136+ //Get configuration for the new CPU frequency
131137 if (!rtc_clk_cpu_freq_mhz_to_config (cpu_freq_mhz , & conf )){
132138 log_e ("CPU clock could not be set to %u MHz" , cpu_freq_mhz );
133139 return false;
134140 }
141+ //Current APB
135142 capb = calculateApb (& cconf );
143+ //New APB
136144 apb = calculateApb (& conf );
137- log_i ("%s: %u / %u = %u Mhz" , (conf .source == RTC_CPU_FREQ_SRC_PLL )?"PLL" :((conf .source == RTC_CPU_FREQ_SRC_APLL )?"APLL" :((conf .source == RTC_CPU_FREQ_SRC_XTAL )?"XTAL" :"8M" )), conf .source_freq_mhz , conf .div , conf .freq_mhz );
145+ log_i ("%s: %u / %u = %u Mhz, APB: %u Hz" , (conf .source == RTC_CPU_FREQ_SRC_PLL )?"PLL" :((conf .source == RTC_CPU_FREQ_SRC_APLL )?"APLL" :((conf .source == RTC_CPU_FREQ_SRC_XTAL )?"XTAL" :"8M" )), conf .source_freq_mhz , conf .div , conf .freq_mhz , apb );
146+ //Call peripheral functions before the APB change
138147 if (capb != apb && apb_change_callbacks ){
139148 triggerApbChangeCallback (APB_BEFORE_CHANGE , capb , apb );
140149 }
150+ //Make the frequency change
141151 rtc_clk_cpu_freq_set_config_fast (& conf );
152+ if (capb != apb ){
153+ //Update REF_TICK
154+ uint32_t xtal_mhz = rtc_clk_xtal_freq_get ();
155+ uint32_t tick_freq_mhz = (conf .freq_mhz >= xtal_mhz )?xtal_mhz :conf .freq_mhz ;
156+ uint32_t tick_conf = tick_freq_mhz / (REF_CLK_FREQ / MHZ ) - 1 ;
157+ ESP_REG (APB_CTRL_XTAL_TICK_CONF_REG ) = tick_conf ;
158+ //Update APB Freq REG
159+ rtc_clk_apb_freq_update (apb );
160+ //Update esp_timer divisor
161+ esp_timer_impl_update_apb_freq (apb / MHZ );
162+ }
142163 //Update FreeRTOS Tick Divisor
143- _xt_tick_divisor = cpu_freq_mhz * 1000000 / XT_TICK_PER_SEC ;
164+ uint32_t fcpu = (conf .freq_mhz >= 80 )?(conf .freq_mhz * MHZ ):(apb );
165+ _xt_tick_divisor = fcpu / XT_TICK_PER_SEC ;
166+ //Call peripheral functions after the APB change
144167 if (capb != apb && apb_change_callbacks ){
145- //Update esp_timer divisor
146- esp_timer_impl_update_apb_freq (apb / 1000000 );
147168 triggerApbChangeCallback (APB_AFTER_CHANGE , capb , apb );
148169 }
149170 return true;
0 commit comments