Code: Select all
#include "Arduino.h"
#include "soc/rtc.h"
#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in seconds) */
RTC_DATA_ATTR int bootCount = 0;
#include "soc/rtc_io_reg.h"
#include "soc/sens_reg.h"
#include "esp_deep_sleep.h"
#include "rom/rtc.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
void debug_xtal_out_dac1() {
SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RDE | RTC_IO_X32P_RUE | RTC_IO_X32N_RUE | RTC_IO_X32N_RDE);
CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
SET_PERI_REG_BITS(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DAC_XTAL_32K, 1, RTC_IO_DAC_XTAL_32K_S);
SET_PERI_REG_BITS(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DRES_XTAL_32K, 3, RTC_IO_DRES_XTAL_32K_S);
SET_PERI_REG_BITS(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DBIAS_XTAL_32K, 0, RTC_IO_DBIAS_XTAL_32K_S);
SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K);
REG_SET_BIT(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_MUX_SEL_M);
REG_CLR_BIT(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_RDE_M | RTC_IO_PDAC1_RUE_M);
REG_SET_FIELD(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_FUN_SEL, 1);
REG_SET_FIELD(SENS_SAR_DAC_CTRL1_REG, SENS_DEBUG_BIT_SEL, 0);
const uint8_t sel = 4; /* sel = 4 : 32k XTAL; sel = 5 : internal 150k RC */
REG_SET_FIELD(RTC_IO_RTC_DEBUG_SEL_REG, RTC_IO_DEBUG_SEL0, sel);
}
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason)
{
case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
}
}
const float factor = (1 << 19) * 1000.0f;
#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)
static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name)
{
const uint32_t cal_count = 1000;
uint32_t cali_val;
printf("%s:\n", name);
for (int i = 0; i < 5; ++i)
{
printf("calibrate (%d): ", i);
cali_val = rtc_clk_cal(cal_clk, cal_count);
printf("%.3f kHz\n", factor / (float)cali_val);
}
return cali_val;
}
void print_slow_clock_source() {
rtc_slow_freq_t slow_clk = rtc_clk_slow_freq_get();
Serial.print("Slow clk source: ");
switch(slow_clk) {
case RTC_SLOW_FREQ_RTC: Serial.println("Internal 150kHz"); break;
case RTC_SLOW_FREQ_32K_XTAL: Serial.println("External 32kHz"); break;
case RTC_SLOW_FREQ_8MD256: Serial.println("Internal 8MHz");
}
}
void print_fast_clk_math() {
const uint32_t cal_count = 1000;
uint32_t cali_val;
uint64_t freq = (uint64_t)rtc_clk_xtal_freq_get();
printf("Fast Clk: %lluMHz\n", freq);
}
float crystal_frequency() {
const uint32_t cal_count = 100;
uint32_t cali_val;
cali_val = rtc_clk_cal(RTC_CAL_32K_XTAL, cal_count);
float freq_32k = factor / (float)cali_val;
return freq_32k;
}
void setExternalCrystalAsRTCSource(){
if (bootCount == 1) {
Serial.println("First boot, bootstrap and enable 32k XTAL");
print_fast_clk_math();
// rtc_clk_32k_bootstrap(10);
rtc_clk_32k_enable(true);
} else {
Serial.println("Wake from deepsleep, not jumping XTAL.");
printf("rtc sleep reg0: %u\n", REG_READ(RTC_CNTL_SLP_TIMER0_REG));
printf("rtc sleep reg1: %u\n", REG_READ(RTC_CNTL_SLP_TIMER1_REG));
}
uint32_t cal_32k = CALIBRATE_ONE(RTC_CAL_32K_XTAL);
debug_xtal_out_dac1();
float freq_32k = factor / (float)cal_32k;
float delta = freq_32k - 32.768;
if (delta < 0) delta = -delta;
uint32_t startCal=millis();
while (delta > 0.002 && millis()-startCal<15000) {
printf("Waiting for 32kHz clock to be stable: %.3f kHz\n", freq_32k);
cal_32k = CALIBRATE_ONE(RTC_CAL_32K_XTAL);
freq_32k = factor / (float)cal_32k;
delta = freq_32k - 32.768;
if (delta < 0) delta = -delta;
}
if(delta < 0.002){
rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
uint32_t rtc_clk_calibration = REG_READ(RTC_SLOW_CLK_CAL_REG);
printf("Slow clock calibration: %u\n", rtc_clk_calibration);
printf("32k calibration: %u\n", cal_32k);
if ((rtc_clk_calibration > (cal_32k + 5)) || (rtc_clk_calibration < (cal_32k - 5))) {
printf("Miscalibrated, setting calibration register to 32k calibration.\n");
REG_WRITE(RTC_SLOW_CLK_CAL_REG, cal_32k);
rtc_clk_calibration = REG_READ(RTC_SLOW_CLK_CAL_REG);
if (rtc_clk_calibration != cal_32k) {
printf("ERROR Calibration write failure.\n");
}
}
if (cal_32k == 0)
{
printf("32K XTAL OSC has not started up");
}
else
{
printf("done\n");
}
if (rtc_clk_32k_enabled())
{
Serial.println("OSC Enabled");
}
}
else{
Serial.println("OSC Not Enabled, using Internal 150KHz RC");
}
print_slow_clock_source();
}
void setup() {
delay(500);
Serial.begin(115200);
//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
//Print the wakeup reason for ESP32
print_wakeup_reason();
print_slow_clock_source();
setExternalCrystalAsRTCSource();
/*
First we configure the wake up source
We set our ESP32 to wake up every 5 seconds
*/
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
" Seconds");
// By default the ESP32 powers down all peripherals which are not needed to wake up again.
// We can change this behaviour with pd_config
// ESP_PD_DOMAIN_RTC_PERIPH
// ESP_PD_DOMAIN_RTC_SLOW_MEM
// ESP_PD_DOMAIN_RTC_FAST_MEM
esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
Serial.println("Configured peripheral power");
delay(50);
uint64_t ticks = rtc_time_get();
Serial.printf("Going to sleep now, rtc ticks: %llu\n", ticks);
Serial.flush();
delay(50);
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop() {
// put your main code here, to run repeatedly:
// Left blank because we are just deepsleeping
}
This code is working fine for rtc external crystal selection, without building esp-idf library for arduino.
Could you please confirm that it is working with your hardware setup, Or any mistake in this.
I am going to test this for longer deepsleep time of 24 hours.