Skip to content

Commit abacf8d

Browse files
committed
Merge branch 'bugfix/rtc_and_restart_fixes' into 'master'
rtc_clk and esp_restart fixes See merge request !1458
2 parents 88514f9 + eb5752c commit abacf8d

File tree

7 files changed

+119
-31
lines changed

7 files changed

+119
-31
lines changed

components/esp32/system_api.c

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -266,15 +266,10 @@ void IRAM_ATTR esp_restart(void)
266266
*/
267267
void IRAM_ATTR esp_restart_noos()
268268
{
269-
const uint32_t core_id = xPortGetCoreID();
270-
const uint32_t other_core_id = core_id == 0 ? 1 : 0;
271-
esp_cpu_stall(other_core_id);
272-
273-
// other core is now stalled, can access DPORT registers directly
274-
esp_dport_access_int_pause();
269+
// Disable interrupts
270+
xt_ints_off(0xFFFFFFFF);
275271

276-
// We need to disable TG0/TG1 watchdogs
277-
// First enable RTC watchdog for 1 second
272+
// Enable RTC watchdog for 1 second
278273
REG_WRITE(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
279274
REG_WRITE(RTC_CNTL_WDTCONFIG0_REG,
280275
RTC_CNTL_WDT_FLASHBOOT_MOD_EN_M |
@@ -284,6 +279,18 @@ void IRAM_ATTR esp_restart_noos()
284279
(1 << RTC_CNTL_WDT_CPU_RESET_LENGTH_S) );
285280
REG_WRITE(RTC_CNTL_WDTCONFIG1_REG, rtc_clk_slow_freq_get_hz() * 1);
286281

282+
// Reset and stall the other CPU.
283+
// CPU must be reset before stalling, in case it was running a s32c1i
284+
// instruction. This would cause memory pool to be locked by arbiter
285+
// to the stalled CPU, preventing current CPU from accessing this pool.
286+
const uint32_t core_id = xPortGetCoreID();
287+
const uint32_t other_core_id = (core_id == 0) ? 1 : 0;
288+
esp_cpu_reset(other_core_id);
289+
esp_cpu_stall(other_core_id);
290+
291+
// Other core is now stalled, can access DPORT registers directly
292+
esp_dport_access_int_abort();
293+
287294
// Disable TG0/TG1 watchdogs
288295
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
289296
TIMERG0.wdt_config0.en = 0;
@@ -292,8 +299,10 @@ void IRAM_ATTR esp_restart_noos()
292299
TIMERG1.wdt_config0.en = 0;
293300
TIMERG1.wdt_wprotect=0;
294301

295-
// Disable all interrupts
296-
xt_ints_off(0xFFFFFFFF);
302+
// Flush any data left in UART FIFOs
303+
uart_tx_wait_idle(0);
304+
uart_tx_wait_idle(1);
305+
uart_tx_wait_idle(2);
297306

298307
// Disable cache
299308
Cache_Read_Disable(0);
@@ -310,11 +319,6 @@ void IRAM_ATTR esp_restart_noos()
310319
WRITE_PERI_REG(GPIO_FUNC5_IN_SEL_CFG_REG, 0x30);
311320
#endif
312321

313-
// Flush any data left in UART FIFOs
314-
uart_tx_wait_idle(0);
315-
uart_tx_wait_idle(1);
316-
uart_tx_wait_idle(2);
317-
318322
// Reset wifi/bluetooth/ethernet/sdio (bb/mac)
319323
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG,
320324
DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST |
@@ -337,14 +341,14 @@ void IRAM_ATTR esp_restart_noos()
337341
// Reset CPUs
338342
if (core_id == 0) {
339343
// Running on PRO CPU: APP CPU is stalled. Can reset both CPUs.
340-
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
341-
RTC_CNTL_SW_PROCPU_RST_M | RTC_CNTL_SW_APPCPU_RST_M);
344+
esp_cpu_reset(1);
345+
esp_cpu_reset(0);
342346
} else {
343347
// Running on APP CPU: need to reset PRO CPU and unstall it,
344348
// then reset APP CPU
345-
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_PROCPU_RST_M);
349+
esp_cpu_reset(0);
346350
esp_cpu_unstall(0);
347-
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_APPCPU_RST_M);
351+
esp_cpu_reset(1);
348352
}
349353
while(true) {
350354
;

components/soc/esp32/cpu_util.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ void IRAM_ATTR esp_cpu_unstall(int cpu_id)
4444
}
4545
}
4646

47+
void IRAM_ATTR esp_cpu_reset(int cpu_id)
48+
{
49+
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
50+
cpu_id == 0 ? RTC_CNTL_SW_PROCPU_RST_M : RTC_CNTL_SW_APPCPU_RST_M);
51+
}
52+
4753
bool IRAM_ATTR esp_cpu_in_ocd_debug_mode()
4854
{
4955
#if CONFIG_ESP32_DEBUG_OCDAWARE

components/soc/esp32/include/soc/cpu.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ void esp_cpu_stall(int cpu_id);
8585
*/
8686
void esp_cpu_unstall(int cpu_id);
8787

88+
/**
89+
* @brief Reset CPU using RTC controller
90+
* @param cpu_id ID of the CPU to reset (0 = PRO, 1 = APP)
91+
*/
92+
void esp_cpu_reset(int cpu_id);
93+
94+
8895
/**
8996
* @brief Returns true if a JTAG debugger is attached to CPU
9097
* OCD (on chip debug) port.

components/soc/esp32/include/soc/rtc.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,15 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period);
400400
*/
401401
uint64_t rtc_time_get();
402402

403+
/**
404+
* @brief Busy loop until next RTC_SLOW_CLK cycle
405+
*
406+
* This function returns not earlier than the next RTC_SLOW_CLK clock cycle.
407+
* In some cases (e.g. when RTC_SLOW_CLK cycle is very close), it may return
408+
* one RTC_SLOW_CLK cycle later.
409+
*/
410+
void rtc_clk_wait_for_slow_cycle();
411+
403412
/**
404413
* @brief sleep configuration for rtc_sleep_init function
405414
*/

components/soc/esp32/rtc_clk.c

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,6 @@ static const char* TAG = "rtc_clk";
7272
* All values are in microseconds.
7373
* TODO: some of these are excessive, and should be reduced.
7474
*/
75-
#define DELAY_CPU_FREQ_SWITCH_TO_XTAL_WITH_150K 20
76-
#define DELAY_CPU_FREQ_SWITCH_TO_XTAL_WITH_32K 160
77-
#define DELAY_CPU_FREQ_SWITCH_TO_PLL 20
7875
#define DELAY_PLL_DBIAS_RAISE 3
7976
#define DELAY_PLL_ENABLE_WITH_150K 80
8077
#define DELAY_PLL_ENABLE_WITH_32K 160
@@ -397,9 +394,12 @@ void rtc_clk_cpu_freq_set(rtc_cpu_freq_t cpu_freq)
397394
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, RTC_CNTL_SOC_CLK_SEL_XTL);
398395
REG_SET_FIELD(APB_CTRL_SYSCLK_CONF_REG, APB_CTRL_PRE_DIV_CNT, 0);
399396
ets_update_cpu_frequency(xtal_freq);
400-
uint32_t delay_xtal_switch = (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_RTC) ?
401-
DELAY_CPU_FREQ_SWITCH_TO_XTAL_WITH_150K : DELAY_CPU_FREQ_SWITCH_TO_XTAL_WITH_32K;
402-
ets_delay_us(delay_xtal_switch);
397+
398+
/* Frequency switch is synchronized to SLOW_CLK cycle. Wait until the switch
399+
* is complete before disabling the PLL.
400+
*/
401+
rtc_clk_wait_for_slow_cycle();
402+
403403
DPORT_REG_SET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL, 0);
404404
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
405405
RTC_CNTL_BB_I2C_FORCE_PD | RTC_CNTL_BBPLL_FORCE_PD |
@@ -443,7 +443,7 @@ void rtc_clk_cpu_freq_set(rtc_cpu_freq_t cpu_freq)
443443
s_pll_freq = 480;
444444
}
445445
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, RTC_CNTL_SOC_CLK_SEL_PLL);
446-
ets_delay_us(DELAY_CPU_FREQ_SWITCH_TO_PLL);
446+
rtc_clk_wait_for_slow_cycle();
447447
rtc_clk_apb_freq_update(80 * MHZ);
448448
}
449449
s_cur_freq = cpu_freq;
@@ -558,6 +558,13 @@ void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq)
558558

559559
static rtc_xtal_freq_t rtc_clk_xtal_freq_estimate()
560560
{
561+
/* Enable 8M/256 clock if needed */
562+
const bool clk_8m_enabled = rtc_clk_8m_enabled();
563+
const bool clk_8md256_enabled = rtc_clk_8md256_enabled();
564+
if (!clk_8md256_enabled) {
565+
rtc_clk_8m_enable(true, true);
566+
}
567+
561568
uint64_t cal_val = rtc_clk_cal_ratio(RTC_CAL_8MD256, XTAL_FREQ_EST_CYCLES);
562569
/* cal_val contains period of 8M/256 clock in XTAL clock cycles
563570
* (shifted by RTC_CLK_CAL_FRACT bits).
@@ -581,6 +588,8 @@ static rtc_xtal_freq_t rtc_clk_xtal_freq_estimate()
581588
SOC_LOGW(TAG, "Bogus XTAL frequency: %d MHz", freq_mhz);
582589
return RTC_XTAL_FREQ_AUTO;
583590
}
591+
/* Restore 8M and 8md256 clocks to original state */
592+
rtc_clk_8m_enable(clk_8m_enabled, clk_8md256_enabled);
584593
}
585594

586595
void rtc_clk_apb_freq_update(uint32_t apb_freq)
@@ -634,15 +643,14 @@ void rtc_clk_init(rtc_clk_config_t cfg)
634643
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_APLL_M | I2C_BBPLL_M);
635644

636645
/* Estimate XTAL frequency */
637-
rtc_xtal_freq_t est_xtal_freq = rtc_clk_xtal_freq_estimate();
638646
rtc_xtal_freq_t xtal_freq = cfg.xtal_freq;
639647
if (xtal_freq == RTC_XTAL_FREQ_AUTO) {
640648
if (clk_val_is_valid(READ_PERI_REG(RTC_XTAL_FREQ_REG))) {
641649
/* XTAL frequency has already been set, use existing value */
642650
xtal_freq = rtc_clk_xtal_freq_get();
643651
} else {
644652
/* Not set yet, estimate XTAL frequency based on RTC_FAST_CLK */
645-
xtal_freq = est_xtal_freq;
653+
xtal_freq = rtc_clk_xtal_freq_estimate();
646654
if (xtal_freq == RTC_XTAL_FREQ_AUTO) {
647655
SOC_LOGW(TAG, "Can't estimate XTAL frequency, assuming 26MHz");
648656
xtal_freq = RTC_XTAL_FREQ_26M;
@@ -653,8 +661,11 @@ void rtc_clk_init(rtc_clk_config_t cfg)
653661
* frequency is different. If autodetection failed, worst case we get a
654662
* bit of garbage output.
655663
*/
656-
SOC_LOGW(TAG, "Possibly invalid CONFIG_ESP32_XTAL_FREQ setting (%dMHz). Detected %d MHz.",
657-
xtal_freq, est_xtal_freq);
664+
rtc_xtal_freq_t est_xtal_freq = rtc_clk_xtal_freq_estimate();
665+
if (est_xtal_freq != xtal_freq) {
666+
SOC_LOGW(TAG, "Possibly invalid CONFIG_ESP32_XTAL_FREQ setting (%dMHz). Detected %d MHz.",
667+
xtal_freq, est_xtal_freq);
668+
}
658669
}
659670
uart_tx_wait_idle(0);
660671
rtc_clk_xtal_freq_update(xtal_freq);

components/soc/esp32/rtc_time.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,20 @@ uint64_t rtc_time_get()
135135
t |= ((uint64_t) READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32;
136136
return t;
137137
}
138+
139+
void rtc_clk_wait_for_slow_cycle()
140+
{
141+
REG_CLR_BIT(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START_CYCLING | TIMG_RTC_CALI_START);
142+
REG_CLR_BIT(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY);
143+
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_CLK_SEL, RTC_CAL_RTC_MUX);
144+
/* Request to run calibration for 0 slow clock cycles.
145+
* RDY bit will be set on the nearest slow clock cycle.
146+
*/
147+
REG_SET_FIELD(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_MAX, 0);
148+
REG_SET_BIT(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
149+
ets_delay_us(1); /* RDY needs some time to go low */
150+
while (!GET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_RDY)) {
151+
ets_delay_us(1);
152+
}
153+
}
154+

components/soc/esp32/test/test_rtc_clk.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
#include <stdio.h>
22
#include "unity.h"
33
#include "rom/ets_sys.h"
4+
#include "rom/uart.h"
45
#include "soc/rtc.h"
56
#include "soc/rtc_cntl_reg.h"
67
#include "soc/rtc_io_reg.h"
78
#include "soc/sens_reg.h"
89
#include "soc/io_mux_reg.h"
910
#include "driver/rtc_io.h"
10-
11+
#include "test_utils.h"
1112
#include "freertos/FreeRTOS.h"
1213
#include "freertos/task.h"
14+
#include "freertos/semphr.h"
1315

1416

1517
#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)
@@ -89,3 +91,35 @@ TEST_CASE("Output 8M XTAL clock to GPIO25", "[rtc_clk][ignore]")
8991
SET_PERI_REG_MASK(RTC_IO_RTC_DEBUG_SEL_REG, RTC_IO_DEBUG_12M_NO_GATING);
9092
pull_out_clk(RTC_IO_DEBUG_SEL0_8M);
9193
}
94+
95+
static void test_clock_switching(void (*switch_func)(rtc_cpu_freq_t))
96+
{
97+
uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM);
98+
99+
const int test_duration_sec = 10;
100+
ref_clock_init();
101+
uint64_t t_start = ref_clock_get();
102+
103+
rtc_cpu_freq_t cur_freq = rtc_clk_cpu_freq_get();
104+
int count = 0;
105+
while (ref_clock_get() - t_start < test_duration_sec * 1000000) {
106+
switch_func(RTC_CPU_FREQ_XTAL);
107+
switch_func(cur_freq);
108+
++count;
109+
}
110+
uint64_t t_end = ref_clock_get();
111+
printf("Switch count: %d. Average time to switch PLL -> XTAL -> PLL: %d us\n", count, (int) ((t_end - t_start) / count));
112+
ref_clock_deinit();
113+
}
114+
115+
TEST_CASE("Test switching between PLL and XTAL", "[rtc_clk]")
116+
{
117+
test_clock_switching(rtc_clk_cpu_freq_set);
118+
}
119+
120+
TEST_CASE("Test fast switching between PLL and XTAL", "[rtc_clk]")
121+
{
122+
test_clock_switching(rtc_clk_cpu_freq_set_fast);
123+
}
124+
125+

0 commit comments

Comments
 (0)