2017-04-11 03:44:43 -04:00
# include <stdio.h>
# include "unity.h"
2020-01-07 23:50:03 -05:00
2021-03-12 04:29:59 -05:00
# include "esp_attr.h"
2020-12-22 23:29:57 -05:00
# include "soc/soc_caps.h"
2017-04-11 03:44:43 -04:00
# include "soc/rtc.h"
2019-05-13 06:02:45 -04:00
# include "soc/rtc_periph.h"
2020-12-22 23:29:57 -05:00
# if SOC_ADC_SUPPORT_RTC_CTRL
2019-05-13 06:02:45 -04:00
# include "soc/sens_periph.h"
2020-12-22 23:29:57 -05:00
# endif
2019-05-13 06:02:45 -04:00
# include "soc/gpio_periph.h"
2020-06-19 00:00:58 -04:00
# include "hal/gpio_ll.h"
2017-04-11 03:44:43 -04:00
# include "driver/rtc_io.h"
2017-10-26 06:47:31 -04:00
# include "test_utils.h"
2017-04-11 03:44:43 -04:00
# include "freertos/FreeRTOS.h"
# include "freertos/task.h"
2017-10-26 06:47:31 -04:00
# include "freertos/semphr.h"
2020-06-19 00:00:58 -04:00
# include "esp_rom_gpio.h"
2020-07-21 01:07:34 -04:00
# include "esp_rom_sys.h"
2020-07-13 09:33:23 -04:00
# include "esp_rom_uart.h"
2018-03-19 04:05:32 -04:00
2021-03-12 04:29:59 -05:00
# include "esp_sleep.h"
# include "esp_system.h"
# if CONFIG_IDF_TARGET_ESP32
# include "esp32/rtc.h"
# include "esp32/clk.h"
# include "esp32/rom/rtc.h"
# elif CONFIG_IDF_TARGET_ESP32S2
# include "esp32s2/rtc.h"
# include "esp32s2/clk.h"
# include "esp32s2/rom/rtc.h"
# elif CONFIG_IDF_TARGET_ESP32S3
# include "esp32s3/rtc.h"
# include "esp32s3/clk.h"
# include "esp32s3/rom/rtc.h"
# elif CONFIG_IDF_TARGET_ESP32C3
# include "esp32c3/rtc.h"
# include "esp32c3/clk.h"
# include "esp32c3/rom/rtc.h"
# endif
2020-07-21 01:07:34 -04:00
extern void rtc_clk_select_rtc_slow_clk ( void ) ;
2020-12-29 02:39:52 -05:00
# if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3, ESP32C3)
2020-01-07 23:50:03 -05:00
2017-04-11 03:44:43 -04:00
# 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 ;
const float factor = ( 1 < < 19 ) * 1000.0f ;
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 ;
}
TEST_CASE ( " RTC_SLOW_CLK sources calibration " , " [rtc_clk] " )
{
rtc_clk_32k_enable ( true ) ;
rtc_clk_8m_enable ( true , true ) ;
CALIBRATE_ONE ( RTC_CAL_RTC_MUX ) ;
CALIBRATE_ONE ( RTC_CAL_8MD256 ) ;
uint32_t cal_32k = CALIBRATE_ONE ( RTC_CAL_32K_XTAL ) ;
if ( cal_32k = = 0 ) {
printf ( " 32K XTAL OSC has not started up " ) ;
} else {
printf ( " switching to RTC_SLOW_FREQ_32K_XTAL: " ) ;
rtc_clk_slow_freq_set ( RTC_SLOW_FREQ_32K_XTAL ) ;
printf ( " done \n " ) ;
CALIBRATE_ONE ( RTC_CAL_RTC_MUX ) ;
CALIBRATE_ONE ( RTC_CAL_8MD256 ) ;
CALIBRATE_ONE ( RTC_CAL_32K_XTAL ) ;
}
printf ( " switching to RTC_SLOW_FREQ_8MD256: " ) ;
rtc_clk_slow_freq_set ( RTC_SLOW_FREQ_8MD256 ) ;
printf ( " done \n " ) ;
CALIBRATE_ONE ( RTC_CAL_RTC_MUX ) ;
CALIBRATE_ONE ( RTC_CAL_8MD256 ) ;
CALIBRATE_ONE ( RTC_CAL_32K_XTAL ) ;
}
/* The following two are not unit tests, but are added here to make it easy to
* check the frequency of 150 k / 32 k oscillators . The following two " tests " will
* output either 32 k or 150 k clock to GPIO25 .
*/
static void pull_out_clk ( int sel )
{
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 ) ;
REG_SET_FIELD ( RTC_IO_RTC_DEBUG_SEL_REG , RTC_IO_DEBUG_SEL0 , sel ) ;
}
TEST_CASE ( " Output 150k clock to GPIO25 " , " [rtc_clk][ignore] " )
{
pull_out_clk ( RTC_IO_DEBUG_SEL0_150K_OSC ) ;
}
TEST_CASE ( " Output 32k XTAL clock to GPIO25 " , " [rtc_clk][ignore] " )
{
rtc_clk_32k_enable ( true ) ;
pull_out_clk ( RTC_IO_DEBUG_SEL0_32K_XTAL ) ;
}
2017-04-24 03:29:30 -04:00
TEST_CASE ( " Output 8M XTAL clock to GPIO25 " , " [rtc_clk][ignore] " )
{
rtc_clk_8m_enable ( true , true ) ;
SET_PERI_REG_MASK ( RTC_IO_RTC_DEBUG_SEL_REG , RTC_IO_DEBUG_12M_NO_GATING ) ;
pull_out_clk ( RTC_IO_DEBUG_SEL0_8M ) ;
}
2017-10-26 06:47:31 -04:00
2018-07-29 03:51:19 -04:00
static void test_clock_switching ( void ( * switch_func ) ( const rtc_cpu_freq_config_t * config ) )
2017-10-26 06:47:31 -04:00
{
2020-07-13 09:33:23 -04:00
esp_rom_uart_tx_wait_idle ( CONFIG_ESP_CONSOLE_UART_NUM ) ;
2017-10-26 06:47:31 -04:00
const int test_duration_sec = 10 ;
ref_clock_init ( ) ;
uint64_t t_start = ref_clock_get ( ) ;
2018-07-29 03:51:19 -04:00
rtc_cpu_freq_config_t cur_config ;
rtc_clk_cpu_freq_get_config ( & cur_config ) ;
rtc_cpu_freq_config_t xtal_config ;
rtc_clk_cpu_freq_mhz_to_config ( ( uint32_t ) rtc_clk_xtal_freq_get ( ) , & xtal_config ) ;
2017-10-26 06:47:31 -04:00
int count = 0 ;
while ( ref_clock_get ( ) - t_start < test_duration_sec * 1000000 ) {
2018-07-29 03:51:19 -04:00
switch_func ( & xtal_config ) ;
switch_func ( & cur_config ) ;
2017-10-26 06:47:31 -04:00
+ + count ;
}
uint64_t t_end = ref_clock_get ( ) ;
printf ( " Switch count: %d. Average time to switch PLL -> XTAL -> PLL: %d us \n " , count , ( int ) ( ( t_end - t_start ) / count ) ) ;
ref_clock_deinit ( ) ;
}
2017-12-10 23:11:24 -05:00
TEST_CASE ( " Calculate 8M clock frequency " , " [rtc_clk] " )
{
// calibrate 8M/256 clock against XTAL, get 8M/256 clock period
uint32_t rtc_8md256_period = rtc_clk_cal ( RTC_CAL_8MD256 , 100 ) ;
uint32_t rtc_fast_freq_hz = 1000000ULL * ( 1 < < RTC_CLK_CAL_FRACT ) * 256 / rtc_8md256_period ;
printf ( " RTC_FAST_CLK=%d Hz \n " , rtc_fast_freq_hz ) ;
2021-04-08 06:50:56 -04:00
TEST_ASSERT_INT32_WITHIN ( 650000 , RTC_FAST_CLK_FREQ_APPROX , rtc_fast_freq_hz ) ;
2017-12-10 23:11:24 -05:00
}
2017-10-26 06:47:31 -04:00
TEST_CASE ( " Test switching between PLL and XTAL " , " [rtc_clk] " )
{
2018-07-29 03:51:19 -04:00
test_clock_switching ( rtc_clk_cpu_freq_set_config ) ;
2017-10-26 06:47:31 -04:00
}
TEST_CASE ( " Test fast switching between PLL and XTAL " , " [rtc_clk] " )
{
2018-07-29 03:51:19 -04:00
test_clock_switching ( rtc_clk_cpu_freq_set_config_fast ) ;
2017-10-26 06:47:31 -04:00
}
2018-05-15 02:37:04 -04:00
# define COUNT_TEST 3
2018-03-30 08:14:29 -04:00
# define TIMEOUT_TEST_MS (5 + CONFIG_ESP32_RTC_CLK_CAL_CYCLES / 16)
2018-03-19 04:05:32 -04:00
2019-07-16 05:33:30 -04:00
void stop_rtc_external_quartz ( void ) {
2018-03-19 04:05:32 -04:00
const uint8_t pin_32 = 32 ;
const uint8_t pin_33 = 33 ;
rtc_clk_32k_enable ( false ) ;
2020-06-19 00:00:58 -04:00
esp_rom_gpio_pad_select_gpio ( pin_32 ) ;
esp_rom_gpio_pad_select_gpio ( pin_33 ) ;
gpio_ll_output_enable ( & GPIO , pin_32 ) ;
gpio_ll_output_enable ( & GPIO , pin_33 ) ;
gpio_ll_set_level ( & GPIO , pin_32 , 0 ) ;
gpio_ll_set_level ( & GPIO , pin_33 , 0 ) ;
2020-07-21 01:07:34 -04:00
esp_rom_delay_us ( 500000 ) ;
2020-06-19 00:00:58 -04:00
gpio_ll_output_disable ( & GPIO , pin_32 ) ;
gpio_ll_output_disable ( & GPIO , pin_33 ) ;
2018-03-19 04:05:32 -04:00
}
2017-10-26 06:47:31 -04:00
2018-03-30 08:14:29 -04:00
static void start_freq ( rtc_slow_freq_t required_src_freq , uint32_t start_delay_ms )
{
int i = 0 , fail = 0 ;
uint32_t start_time ;
uint32_t end_time ;
rtc_slow_freq_t selected_src_freq ;
stop_rtc_external_quartz ( ) ;
2019-04-30 06:51:55 -04:00
# ifdef CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS
2020-07-14 08:39:30 -04:00
uint32_t bootstrap_cycles = CONFIG_ESP_SYSTEM_RTC_EXT_XTAL_BOOTSTRAP_CYCLES ;
2018-03-30 08:14:29 -04:00
printf ( " Test is started. Kconfig settings: \n External 32K crystal is selected, \n Oscillation cycles = %d, \n Calibration cycles = %d. \n " ,
bootstrap_cycles ,
CONFIG_ESP32_RTC_CLK_CAL_CYCLES ) ;
# else
uint32_t bootstrap_cycles = 5 ;
printf ( " Test is started. Kconfig settings: \n Internal RC is selected, \n Oscillation cycles = %d, \n Calibration cycles = %d. \n " ,
bootstrap_cycles ,
CONFIG_ESP32_RTC_CLK_CAL_CYCLES ) ;
# endif
if ( start_delay_ms = = 0 & & CONFIG_ESP32_RTC_CLK_CAL_CYCLES < 1500 ) {
start_delay_ms = 50 ;
printf ( " Recommended increase Number of cycles for RTC_SLOW_CLK calibration to 3000! \n " ) ;
}
while ( i < COUNT_TEST ) {
start_time = xTaskGetTickCount ( ) * ( 1000 / configTICK_RATE_HZ ) ;
i + + ;
printf ( " attempt #%d/%d... " , i , COUNT_TEST ) ;
rtc_clk_32k_bootstrap ( bootstrap_cycles ) ;
2020-07-21 01:07:34 -04:00
esp_rom_delay_us ( start_delay_ms * 1000 ) ;
2018-03-30 08:14:29 -04:00
rtc_clk_select_rtc_slow_clk ( ) ;
selected_src_freq = rtc_clk_slow_freq_get ( ) ;
end_time = xTaskGetTickCount ( ) * ( 1000 / configTICK_RATE_HZ ) ;
printf ( " [time=%d] " , ( end_time - start_time ) - start_delay_ms ) ;
if ( selected_src_freq ! = required_src_freq ) {
printf ( " FAIL. Time measurement... " ) ;
fail = 1 ;
} else {
printf ( " PASS. Time measurement... " ) ;
}
uint64_t clk_rtc_time ;
uint32_t fail_measure = 0 ;
for ( int j = 0 ; j < 3 ; + + j ) {
clk_rtc_time = esp_clk_rtc_time ( ) ;
2020-07-21 01:07:34 -04:00
esp_rom_delay_us ( 1000000 ) ;
2018-03-30 08:14:29 -04:00
uint64_t delta = esp_clk_rtc_time ( ) - clk_rtc_time ;
if ( delta < 900000LL | | delta > 1100000 ) {
printf ( " FAIL " ) ;
fail = 1 ;
fail_measure = 1 ;
break ;
}
}
if ( fail_measure = = 0 ) {
printf ( " PASS " ) ;
}
printf ( " [calibration val = %d] \n " , esp_clk_slowclk_cal_get ( ) ) ;
stop_rtc_external_quartz ( ) ;
2020-07-21 01:07:34 -04:00
esp_rom_delay_us ( 500000 ) ;
2018-03-30 08:14:29 -04:00
}
TEST_ASSERT_MESSAGE ( fail = = 0 , " Test failed " ) ;
printf ( " Test passed successfully \n " ) ;
}
2019-10-31 01:22:41 -04:00
TEST_CASE ( " Test starting external RTC quartz " , " [rtc_clk][test_env=UT_T1_32kXTAL] " )
2018-03-19 04:05:32 -04:00
{
int i = 0 , fail = 0 ;
uint32_t start_time ;
uint32_t end_time ;
stop_rtc_external_quartz ( ) ;
2019-04-30 06:51:55 -04:00
# ifdef CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS
2020-07-14 08:39:30 -04:00
uint32_t bootstrap_cycles = CONFIG_ESP_SYSTEM_RTC_EXT_XTAL_BOOTSTRAP_CYCLES ;
2018-03-30 08:14:29 -04:00
printf ( " Test is started. Kconfig settings: \n External 32K crystal is selected, \n Oscillation cycles = %d, \n Calibration cycles = %d. \n " ,
bootstrap_cycles ,
CONFIG_ESP32_RTC_CLK_CAL_CYCLES ) ;
# else
uint32_t bootstrap_cycles = 5 ;
printf ( " Test is started. Kconfig settings: \n Internal RC is selected, \n Oscillation cycles = %d, \n Calibration cycles = %d. \n " ,
bootstrap_cycles ,
CONFIG_ESP32_RTC_CLK_CAL_CYCLES ) ;
# endif
if ( CONFIG_ESP32_RTC_CLK_CAL_CYCLES < 1500 ) {
printf ( " Recommended increase Number of cycles for RTC_SLOW_CLK calibration to 3000! \n " ) ;
}
2018-03-19 04:05:32 -04:00
while ( i < COUNT_TEST ) {
start_time = xTaskGetTickCount ( ) * ( 1000 / configTICK_RATE_HZ ) ;
i + + ;
printf ( " attempt #%d/%d... " , i , COUNT_TEST ) ;
2018-03-30 08:14:29 -04:00
rtc_clk_32k_bootstrap ( bootstrap_cycles ) ;
2018-03-19 04:05:32 -04:00
rtc_clk_select_rtc_slow_clk ( ) ;
end_time = xTaskGetTickCount ( ) * ( 1000 / configTICK_RATE_HZ ) ;
2018-03-30 08:14:29 -04:00
printf ( " [time=%d] " , end_time - start_time ) ;
2018-03-19 04:05:32 -04:00
if ( ( end_time - start_time ) > TIMEOUT_TEST_MS ) {
printf ( " FAIL \n " ) ;
fail = 1 ;
} else {
printf ( " PASS \n " ) ;
}
stop_rtc_external_quartz ( ) ;
2020-07-21 01:07:34 -04:00
esp_rom_delay_us ( 100000 ) ;
2018-03-19 04:05:32 -04:00
}
2018-03-30 08:14:29 -04:00
TEST_ASSERT_MESSAGE ( fail = = 0 , " Test failed " ) ;
printf ( " Test passed successfully \n " ) ;
2018-03-19 04:05:32 -04:00
}
2018-03-30 08:14:29 -04:00
2019-10-31 01:22:41 -04:00
TEST_CASE ( " Test starting 'External 32kHz XTAL' on the board with it. " , " [rtc_clk][test_env=UT_T1_32kXTAL] " )
2018-03-30 08:14:29 -04:00
{
start_freq ( RTC_SLOW_FREQ_32K_XTAL , 200 ) ;
start_freq ( RTC_SLOW_FREQ_32K_XTAL , 0 ) ;
}
2019-10-31 01:22:41 -04:00
TEST_CASE ( " Test starting 'External 32kHz XTAL' on the board without it. " , " [rtc_clk][test_env=UT_T1_no32kXTAL] " )
2018-03-30 08:14:29 -04:00
{
printf ( " Tries to start the 'External 32kHz XTAL' on the board without it. "
" Clock switching to 'Internal 150 kHz RC oscillator'. \n " ) ;
printf ( " This test will be successful for boards without an external crystal or non-working crystal. "
" First, there will be an attempt to start from the external crystal after a failure "
" will switch to the internal RC circuit. If the switch to the internal RC circuit "
" was successful then the test succeeded. \n " ) ;
start_freq ( RTC_SLOW_FREQ_RTC , 200 ) ;
start_freq ( RTC_SLOW_FREQ_RTC , 0 ) ;
}
2020-01-07 23:50:03 -05:00
# endif
2021-03-12 04:29:59 -05:00
static RTC_NOINIT_ATTR int64_t start = 0 ;
TEST_CASE ( " Test rtc clk calibration compensation " , " [rtc_clk] " )
{
int64_t t1 = esp_rtc_get_time_us ( ) ;
// Modify calibration value
esp_clk_slowclk_cal_set ( esp_clk_slowclk_cal_get ( ) / 2 ) ;
// Delay for error accumulation.
vTaskDelay ( pdMS_TO_TICKS ( 1000 ) ) ;
// Internally, the origin point of rtc clk has been adjusted
// so that t2 > t1 remains true
int64_t t2 = esp_rtc_get_time_us ( ) ;
2021-03-25 03:00:17 -04:00
TEST_ASSERT_GREATER_THAN ( t1 , t2 ) ;
2021-03-12 04:29:59 -05:00
// Restore calibration value
esp_clk_slowclk_cal_set ( esp_clk_slowclk_cal_get ( ) * 2 ) ;
// Delay for error accumulation.
vTaskDelay ( pdMS_TO_TICKS ( 1000 ) ) ;
t2 = esp_rtc_get_time_us ( ) ;
2021-03-25 03:00:17 -04:00
TEST_ASSERT_GREATER_THAN ( t1 , t2 ) ;
2021-03-12 04:29:59 -05:00
}
static void trigger_deepsleep ( void )
{
printf ( " Trigger deep sleep. Waiting for 10 sec ... \n " ) ;
// Simulate the dispersion of the calibration coefficients at start-up.
// Corrupt the calibration factor.
esp_clk_slowclk_cal_set ( esp_clk_slowclk_cal_get ( ) / 2 ) ;
// Delay for error accumulation.
vTaskDelay ( pdMS_TO_TICKS ( 1000 ) ) ;
// Save start time. Deep sleep.
start = esp_rtc_get_time_us ( ) ;
esp_sleep_enable_timer_wakeup ( 1000 ) ;
// In function esp_deep_sleep_start() uses function esp_sync_counters_rtc_and_frc()
// to prevent a negative time after wake up.
esp_deep_sleep_start ( ) ;
}
static void check_time_deepsleep_1 ( void )
{
RESET_REASON reason = rtc_get_reset_reason ( 0 ) ;
TEST_ASSERT ( reason = = DEEPSLEEP_RESET ) ;
int64_t end = esp_rtc_get_time_us ( ) ;
2021-03-25 03:00:17 -04:00
TEST_ASSERT_GREATER_THAN ( start , end ) ;
2021-03-12 04:29:59 -05:00
esp_clk_slowclk_cal_set ( esp_clk_slowclk_cal_get ( ) * 2 ) ;
// Delay for error accumulation.
vTaskDelay ( pdMS_TO_TICKS ( 1000 ) ) ;
start = esp_rtc_get_time_us ( ) ;
esp_sleep_enable_timer_wakeup ( 1000 ) ;
// In function esp_deep_sleep_start() uses function esp_sync_counters_rtc_and_frc()
// to prevent a negative time after wake up.
esp_deep_sleep_start ( ) ;
}
static void check_time_deepsleep_2 ( void )
{
RESET_REASON reason = rtc_get_reset_reason ( 0 ) ;
TEST_ASSERT ( reason = = DEEPSLEEP_RESET ) ;
int64_t end = esp_rtc_get_time_us ( ) ;
2021-03-25 03:00:17 -04:00
TEST_ASSERT_GREATER_THAN ( start , end ) ;
2021-03-12 04:29:59 -05:00
}
TEST_CASE_MULTIPLE_STAGES ( " Test rtc clk calibration compensation across deep sleep " , " [rtc_clk][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET] " , trigger_deepsleep , check_time_deepsleep_1 , check_time_deepsleep_2 ) ;