22
22
#include "soc/rtc.h"
23
23
#include "soc/rtc_cntl_reg.h"
24
24
#include "rom/rtc.h"
25
+ #include "soc/apb_ctrl_reg.h"
25
26
#include "esp32-hal.h"
26
27
#include "esp32-hal-cpu.h"
27
28
@@ -31,16 +32,11 @@ typedef struct apb_change_cb_s {
31
32
apb_change_cb_t cb ;
32
33
} apb_change_t ;
33
34
35
+ const uint32_t MHZ = 1000000 ;
36
+
34
37
static apb_change_t * apb_change_callbacks = NULL ;
35
38
static xSemaphoreHandle apb_change_lock = NULL ;
36
39
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
-
44
40
static void initApbChangeCallback (){
45
41
static volatile bool initialized = false;
46
42
if (!initialized ){
@@ -119,31 +115,56 @@ bool removeApbChangeCallback(void * arg, apb_change_cb_t cb){
119
115
return true;
120
116
}
121
117
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
+
122
125
void esp_timer_impl_update_apb_freq (uint32_t apb_ticks_per_us ); //private in IDF
123
126
124
127
bool setCpuFrequency (uint32_t cpu_freq_mhz ){
125
128
rtc_cpu_freq_config_t conf , cconf ;
126
129
uint32_t capb , apb ;
130
+ //Get current CPU clock configuration
127
131
rtc_clk_cpu_freq_get_config (& cconf );
132
+ //return if frequency has not changed
128
133
if (cconf .freq_mhz == cpu_freq_mhz ){
129
134
return true;
130
135
}
136
+ //Get configuration for the new CPU frequency
131
137
if (!rtc_clk_cpu_freq_mhz_to_config (cpu_freq_mhz , & conf )){
132
138
log_e ("CPU clock could not be set to %u MHz" , cpu_freq_mhz );
133
139
return false;
134
140
}
141
+ //Current APB
135
142
capb = calculateApb (& cconf );
143
+ //New APB
136
144
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
138
147
if (capb != apb && apb_change_callbacks ){
139
148
triggerApbChangeCallback (APB_BEFORE_CHANGE , capb , apb );
140
149
}
150
+ //Make the frequency change
141
151
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
+ }
142
163
//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
144
167
if (capb != apb && apb_change_callbacks ){
145
- //Update esp_timer divisor
146
- esp_timer_impl_update_apb_freq (apb / 1000000 );
147
168
triggerApbChangeCallback (APB_AFTER_CHANGE , capb , apb );
148
169
}
149
170
return true;
0 commit comments