2016-12-08 14:22:10 +00:00
# include "unity.h"
2017-04-21 04:32:50 +00:00
# include <sys/time.h>
2018-04-04 07:05:50 +00:00
# include <sys/param.h>
2017-04-21 04:32:50 +00:00
# include "esp_sleep.h"
2018-04-04 07:05:50 +00:00
# include "esp_clk.h"
2016-12-08 14:22:10 +00:00
# include "driver/rtc_io.h"
2018-04-04 07:05:50 +00:00
# include "soc/gpio_reg.h"
# include "soc/rtc.h"
# include "soc/uart_reg.h"
# include "rom/uart.h"
2016-12-08 14:22:10 +00:00
# include "freertos/FreeRTOS.h"
# include "freertos/task.h"
2018-04-04 07:05:50 +00:00
# include "freertos/semphr.h"
2018-03-20 06:43:48 +00:00
# include "soc/rtc.h" // for wakeup trigger defines
2018-03-16 06:57:35 +00:00
# include "soc/rtc_cntl_reg.h" // for read rtc registers directly (cause)
2018-03-20 06:43:48 +00:00
# include "soc/soc.h" // for direct register read macros
2018-06-04 07:39:18 +00:00
# include "rom/rtc.h"
# include "esp_newlib.h"
2018-03-16 06:57:35 +00:00
2018-03-14 05:54:45 +00:00
# define ESP_EXT0_WAKEUP_LEVEL_LOW 0
# define ESP_EXT0_WAKEUP_LEVEL_HIGH 1
2018-03-16 06:57:35 +00:00
static struct timeval tv_start , tv_stop ;
2016-12-08 14:22:10 +00:00
2017-09-20 09:17:51 +00:00
static void deep_sleep_task ( void * arg )
2016-12-08 14:22:10 +00:00
{
esp_deep_sleep_start ( ) ;
}
static void do_deep_sleep_from_app_cpu ( )
{
xTaskCreatePinnedToCore ( & deep_sleep_task , " ds " , 2048 , NULL , 5 , NULL , 1 ) ;
// keep running some non-IRAM code
vTaskSuspendAll ( ) ;
2017-09-20 09:17:51 +00:00
while ( true ) {
2016-12-08 14:22:10 +00:00
;
}
}
2018-04-04 07:05:50 +00:00
TEST_CASE ( " wake up from deep sleep using timer " , " [deepsleep][reset=DEEPSLEEP_RESET] " )
2016-12-08 14:22:10 +00:00
{
2017-04-21 04:32:50 +00:00
esp_sleep_enable_timer_wakeup ( 2000000 ) ;
2016-12-08 14:22:10 +00:00
esp_deep_sleep_start ( ) ;
}
2018-04-04 07:05:50 +00:00
TEST_CASE ( " light sleep followed by deep sleep " , " [deepsleep][reset=DEEPSLEEP_RESET] " )
{
esp_sleep_enable_timer_wakeup ( 1000000 ) ;
esp_light_sleep_start ( ) ;
esp_deep_sleep_start ( ) ;
}
2017-04-21 04:32:50 +00:00
TEST_CASE ( " wake up from light sleep using timer " , " [deepsleep] " )
{
esp_sleep_enable_timer_wakeup ( 2000000 ) ;
struct timeval tv_start , tv_stop ;
gettimeofday ( & tv_start , NULL ) ;
esp_light_sleep_start ( ) ;
gettimeofday ( & tv_stop , NULL ) ;
float dt = ( tv_stop . tv_sec - tv_start . tv_sec ) * 1e3 f +
2017-09-20 09:17:51 +00:00
( tv_stop . tv_usec - tv_start . tv_usec ) * 1e-3 f ;
2017-04-21 04:32:50 +00:00
TEST_ASSERT_INT32_WITHIN ( 500 , 2000 , ( int ) dt ) ;
}
2018-04-04 07:05:50 +00:00
static void test_light_sleep ( void * arg )
{
vTaskDelay ( 2 ) ;
for ( int i = 0 ; i < 1000 ; + + i ) {
printf ( " %d %d \n " , xPortGetCoreID ( ) , i ) ;
fflush ( stdout ) ;
esp_light_sleep_start ( ) ;
}
SemaphoreHandle_t done = ( SemaphoreHandle_t ) arg ;
xSemaphoreGive ( done ) ;
vTaskDelete ( NULL ) ;
}
TEST_CASE ( " light sleep stress test " , " [deepsleep] " )
{
SemaphoreHandle_t done = xSemaphoreCreateCounting ( 2 , 0 ) ;
esp_sleep_enable_timer_wakeup ( 1000 ) ;
xTaskCreatePinnedToCore ( & test_light_sleep , " ls0 " , 4096 , done , UNITY_FREERTOS_PRIORITY + 1 , NULL , 0 ) ;
# if portNUM_PROCESSORS == 2
xTaskCreatePinnedToCore ( & test_light_sleep , " ls1 " , 4096 , done , UNITY_FREERTOS_PRIORITY + 1 , NULL , 1 ) ;
# endif
xSemaphoreTake ( done , portMAX_DELAY ) ;
# if portNUM_PROCESSORS == 2
xSemaphoreTake ( done , portMAX_DELAY ) ;
# endif
vSemaphoreDelete ( done ) ;
}
2018-05-04 04:50:39 +00:00
TEST_CASE ( " light sleep stress test with periodic esp_timer " , " [deepsleep] " )
{
void timer_func ( void * arg )
{
ets_delay_us ( 50 ) ;
}
SemaphoreHandle_t done = xSemaphoreCreateCounting ( 2 , 0 ) ;
esp_sleep_enable_timer_wakeup ( 1000 ) ;
esp_timer_handle_t timer ;
esp_timer_create_args_t config = {
. callback = & timer_func ,
} ;
TEST_ESP_OK ( esp_timer_create ( & config , & timer ) ) ;
esp_timer_start_periodic ( timer , 500 ) ;
xTaskCreatePinnedToCore ( & test_light_sleep , " ls1 " , 4096 , done , UNITY_FREERTOS_PRIORITY + 1 , NULL , 0 ) ;
# if portNUM_PROCESSORS == 2
xTaskCreatePinnedToCore ( & test_light_sleep , " ls1 " , 4096 , done , UNITY_FREERTOS_PRIORITY + 1 , NULL , 1 ) ;
# endif
xSemaphoreTake ( done , portMAX_DELAY ) ;
# if portNUM_PROCESSORS == 2
xSemaphoreTake ( done , portMAX_DELAY ) ;
# endif
vSemaphoreDelete ( done ) ;
esp_timer_stop ( timer ) ;
esp_timer_delete ( timer ) ;
}
2018-04-04 07:05:50 +00:00
# ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
# define MAX_SLEEP_TIME_ERROR_US 200
# else
# define MAX_SLEEP_TIME_ERROR_US 100
# endif
2018-05-11 10:14:13 +00:00
TEST_CASE ( " light sleep duration is correct " , " [deepsleep][ignore] " )
2018-04-04 07:05:50 +00:00
{
// don't power down XTAL — powering it up takes different time on
// different boards
esp_sleep_pd_config ( ESP_PD_DOMAIN_XTAL , ESP_PD_OPTION_ON ) ;
// run one light sleep without checking timing, to warm up the cache
esp_sleep_enable_timer_wakeup ( 1000 ) ;
esp_light_sleep_start ( ) ;
const int sleep_intervals_ms [ ] = {
1 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 10 , 15 ,
20 , 25 , 50 , 100 , 200 , 500 ,
} ;
const int sleep_intervals_count = sizeof ( sleep_intervals_ms ) / sizeof ( sleep_intervals_ms [ 0 ] ) ;
for ( int i = 0 ; i < sleep_intervals_count ; + + i ) {
uint64_t sleep_time = sleep_intervals_ms [ i ] * 1000 ;
esp_sleep_enable_timer_wakeup ( sleep_time ) ;
for ( int repeat = 0 ; repeat < 5 ; + + repeat ) {
uint64_t start = esp_clk_rtc_time ( ) ;
int64_t start_hs = esp_timer_get_time ( ) ;
esp_light_sleep_start ( ) ;
int64_t stop_hs = esp_timer_get_time ( ) ;
uint64_t stop = esp_clk_rtc_time ( ) ;
int diff_us = ( int ) ( stop - start ) ;
int diff_hs_us = ( int ) ( stop_hs - start_hs ) ;
printf ( " %lld %d \n " , sleep_time , ( int ) ( diff_us - sleep_time ) ) ;
int32_t threshold = MAX ( sleep_time / 100 , MAX_SLEEP_TIME_ERROR_US ) ;
TEST_ASSERT_INT32_WITHIN ( threshold , sleep_time , diff_us ) ;
TEST_ASSERT_INT32_WITHIN ( threshold , sleep_time , diff_hs_us ) ;
fflush ( stdout ) ;
}
vTaskDelay ( 10 / portTICK_PERIOD_MS ) ;
}
}
TEST_CASE ( " light sleep and frequency switching " , " [deepsleep] " )
{
# ifndef CONFIG_PM_ENABLE
const int uart_clk_freq = REF_CLK_FREQ ;
CLEAR_PERI_REG_MASK ( UART_CONF0_REG ( CONFIG_CONSOLE_UART_NUM ) , UART_TICK_REF_ALWAYS_ON ) ;
uart_div_modify ( CONFIG_CONSOLE_UART_NUM , ( uart_clk_freq < < 4 ) / CONFIG_CONSOLE_UART_BAUDRATE ) ;
# endif
esp_sleep_enable_timer_wakeup ( 1000 ) ;
rtc_cpu_freq_t default_freq = rtc_clk_cpu_freq_get ( ) ;
for ( int i = 0 ; i < 1000 ; + + i ) {
if ( i % 2 = = 0 ) {
rtc_clk_cpu_freq_set_fast ( RTC_CPU_FREQ_XTAL ) ;
} else {
rtc_clk_cpu_freq_set_fast ( default_freq ) ;
}
printf ( " %d \n " , i ) ;
fflush ( stdout ) ;
esp_light_sleep_start ( ) ;
}
}
2017-11-10 05:26:11 +00:00
# ifndef CONFIG_FREERTOS_UNICORE
2017-09-20 09:17:51 +00:00
TEST_CASE ( " enter deep sleep on APP CPU and wake up using timer " , " [deepsleep][reset=DEEPSLEEP_RESET] " )
2016-12-08 14:22:10 +00:00
{
2017-04-21 04:32:50 +00:00
esp_sleep_enable_timer_wakeup ( 2000000 ) ;
2016-12-08 14:22:10 +00:00
do_deep_sleep_from_app_cpu ( ) ;
}
2017-11-10 05:26:11 +00:00
# endif
2016-12-08 14:22:10 +00:00
2016-12-14 08:38:45 +00:00
TEST_CASE ( " wake up using ext0 (13 high) " , " [deepsleep][ignore] " )
2016-12-08 14:22:10 +00:00
{
ESP_ERROR_CHECK ( rtc_gpio_init ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( gpio_pullup_dis ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( gpio_pulldown_en ( GPIO_NUM_13 ) ) ;
2018-03-14 05:54:45 +00:00
ESP_ERROR_CHECK ( esp_sleep_enable_ext0_wakeup ( GPIO_NUM_13 , ESP_EXT0_WAKEUP_LEVEL_HIGH ) ) ;
2016-12-08 14:22:10 +00:00
esp_deep_sleep_start ( ) ;
}
2016-12-14 08:38:45 +00:00
TEST_CASE ( " wake up using ext0 (13 low) " , " [deepsleep][ignore] " )
2016-12-08 14:22:10 +00:00
{
ESP_ERROR_CHECK ( rtc_gpio_init ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( gpio_pullup_en ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( gpio_pulldown_dis ( GPIO_NUM_13 ) ) ;
2018-03-14 05:54:45 +00:00
ESP_ERROR_CHECK ( esp_sleep_enable_ext0_wakeup ( GPIO_NUM_13 , ESP_EXT0_WAKEUP_LEVEL_LOW ) ) ;
2016-12-08 14:22:10 +00:00
esp_deep_sleep_start ( ) ;
}
2016-12-14 08:38:45 +00:00
TEST_CASE ( " wake up using ext1 when RTC_PERIPH is off (13 high) " , " [deepsleep][ignore] " )
2016-12-16 06:10:07 +00:00
{
// This test needs external pulldown
ESP_ERROR_CHECK ( rtc_gpio_init ( GPIO_NUM_13 ) ) ;
2017-04-21 04:32:50 +00:00
ESP_ERROR_CHECK ( esp_sleep_enable_ext1_wakeup ( BIT ( GPIO_NUM_13 ) , ESP_EXT1_WAKEUP_ANY_HIGH ) ) ;
2016-12-16 06:10:07 +00:00
esp_deep_sleep_start ( ) ;
}
2016-12-14 08:38:45 +00:00
TEST_CASE ( " wake up using ext1 when RTC_PERIPH is off (13 low) " , " [deepsleep][ignore] " )
2016-12-16 06:10:07 +00:00
{
// This test needs external pullup
ESP_ERROR_CHECK ( rtc_gpio_init ( GPIO_NUM_13 ) ) ;
2017-04-21 04:32:50 +00:00
ESP_ERROR_CHECK ( esp_sleep_enable_ext1_wakeup ( BIT ( GPIO_NUM_13 ) , ESP_EXT1_WAKEUP_ALL_LOW ) ) ;
2016-12-16 06:10:07 +00:00
esp_deep_sleep_start ( ) ;
}
2016-12-14 08:38:45 +00:00
TEST_CASE ( " wake up using ext1 when RTC_PERIPH is on (13 high) " , " [deepsleep][ignore] " )
2016-12-08 14:22:10 +00:00
{
ESP_ERROR_CHECK ( rtc_gpio_init ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( gpio_pullup_dis ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( gpio_pulldown_en ( GPIO_NUM_13 ) ) ;
2017-04-21 04:32:50 +00:00
ESP_ERROR_CHECK ( esp_sleep_pd_config ( ESP_PD_DOMAIN_RTC_PERIPH , ESP_PD_OPTION_ON ) ) ;
ESP_ERROR_CHECK ( esp_sleep_enable_ext1_wakeup ( BIT ( GPIO_NUM_13 ) , ESP_EXT1_WAKEUP_ANY_HIGH ) ) ;
2016-12-08 14:22:10 +00:00
esp_deep_sleep_start ( ) ;
}
2016-12-14 08:38:45 +00:00
TEST_CASE ( " wake up using ext1 when RTC_PERIPH is on (13 low) " , " [deepsleep][ignore] " )
2016-12-08 14:22:10 +00:00
{
ESP_ERROR_CHECK ( rtc_gpio_init ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( gpio_pullup_en ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( gpio_pulldown_dis ( GPIO_NUM_13 ) ) ;
2017-04-21 04:32:50 +00:00
ESP_ERROR_CHECK ( esp_sleep_pd_config ( ESP_PD_DOMAIN_RTC_PERIPH , ESP_PD_OPTION_ON ) ) ;
ESP_ERROR_CHECK ( esp_sleep_enable_ext1_wakeup ( BIT ( GPIO_NUM_13 ) , ESP_EXT1_WAKEUP_ALL_LOW ) ) ;
2016-12-08 14:22:10 +00:00
esp_deep_sleep_start ( ) ;
}
2018-03-16 06:57:35 +00:00
2018-03-20 06:43:48 +00:00
static float get_time_ms ( void )
2018-03-16 06:57:35 +00:00
{
gettimeofday ( & tv_stop , NULL ) ;
float dt = ( tv_stop . tv_sec - tv_start . tv_sec ) * 1e3 f +
( tv_stop . tv_usec - tv_start . tv_usec ) * 1e-3 f ;
2018-03-29 06:24:59 +00:00
return fabs ( dt ) ;
2018-03-16 06:57:35 +00:00
}
static uint32_t get_cause ( )
{
uint32_t wakeup_cause = REG_GET_FIELD ( RTC_CNTL_WAKEUP_STATE_REG , \
RTC_CNTL_WAKEUP_CAUSE ) ;
return wakeup_cause ;
}
// This test case verifies deactivation of trigger for wake up sources
2018-03-20 06:43:48 +00:00
TEST_CASE ( " disable source trigger behavior " , " [deepsleep] " )
2018-03-16 06:57:35 +00:00
{
float dt = 0 ;
2018-04-04 07:05:50 +00:00
printf ( " Setup timer and ext0 to wake up immediately from GPIO_13 \n " ) ;
2018-03-16 06:57:35 +00:00
// Setup ext0 configuration to wake up almost immediately
// The wakeup time is proportional to input capacitance * pullup resistance
ESP_ERROR_CHECK ( rtc_gpio_init ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( gpio_pullup_en ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( gpio_pulldown_dis ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( esp_sleep_enable_ext0_wakeup ( GPIO_NUM_13 , ESP_EXT0_WAKEUP_LEVEL_HIGH ) ) ;
// Setup timer to wakeup with timeout
esp_sleep_enable_timer_wakeup ( 2000000 ) ;
// Save start time
gettimeofday ( & tv_start , NULL ) ;
esp_light_sleep_start ( ) ;
2018-03-20 06:43:48 +00:00
dt = get_time_ms ( ) ;
2018-03-16 06:57:35 +00:00
printf ( " Ext0 sleep time = %d \n " , ( int ) dt ) ;
// Check wakeup from Ext0 using time measurement because wakeup cause is
// not available in light sleep mode
2018-04-04 07:05:50 +00:00
TEST_ASSERT_INT32_WITHIN ( 100 , 100 , ( int ) dt ) ;
2018-03-16 06:57:35 +00:00
TEST_ASSERT ( ( get_cause ( ) & RTC_EXT0_TRIG_EN ) ! = 0 ) ;
// Disable Ext0 source. Timer source should be triggered
2018-03-20 06:43:48 +00:00
ESP_ERROR_CHECK ( esp_sleep_disable_wakeup_source ( ESP_SLEEP_WAKEUP_EXT0 ) ) ;
printf ( " Disable ext0 trigger and leave timer active. \n " ) ;
2018-03-16 06:57:35 +00:00
gettimeofday ( & tv_start , NULL ) ;
esp_light_sleep_start ( ) ;
2018-03-20 06:43:48 +00:00
dt = get_time_ms ( ) ;
2018-03-16 06:57:35 +00:00
printf ( " Timer sleep time = %d \n " , ( int ) dt ) ;
TEST_ASSERT_INT32_WITHIN ( 500 , 2000 , ( int ) dt ) ;
2018-04-04 07:05:50 +00:00
// Additionally check wakeup cause
2018-03-16 06:57:35 +00:00
TEST_ASSERT ( ( get_cause ( ) & RTC_TIMER_TRIG_EN ) ! = 0 ) ;
// Disable timer source.
2018-03-20 06:43:48 +00:00
ESP_ERROR_CHECK ( esp_sleep_disable_wakeup_source ( ESP_SLEEP_WAKEUP_TIMER ) ) ;
2018-03-16 06:57:35 +00:00
// Setup ext0 configuration to wake up immediately
ESP_ERROR_CHECK ( rtc_gpio_init ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( gpio_pullup_en ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( gpio_pulldown_dis ( GPIO_NUM_13 ) ) ;
ESP_ERROR_CHECK ( esp_sleep_enable_ext0_wakeup ( GPIO_NUM_13 , ESP_EXT0_WAKEUP_LEVEL_HIGH ) ) ;
2018-03-20 06:43:48 +00:00
printf ( " Disable timer trigger to wake up from ext0 source. \n " ) ;
2018-03-16 06:57:35 +00:00
gettimeofday ( & tv_start , NULL ) ;
esp_light_sleep_start ( ) ;
2018-03-20 06:43:48 +00:00
dt = get_time_ms ( ) ;
2018-03-16 06:57:35 +00:00
printf ( " Ext0 sleep time = %d \n " , ( int ) dt ) ;
2018-04-04 07:05:50 +00:00
TEST_ASSERT_INT32_WITHIN ( 100 , 100 , ( int ) dt ) ;
2018-03-16 06:57:35 +00:00
TEST_ASSERT ( ( get_cause ( ) & RTC_EXT0_TRIG_EN ) ! = 0 ) ;
// Check error message when source is already disabled
2018-03-20 06:43:48 +00:00
esp_err_t err_code = esp_sleep_disable_wakeup_source ( ESP_SLEEP_WAKEUP_TIMER ) ;
2018-03-16 06:57:35 +00:00
TEST_ASSERT ( err_code = = ESP_ERR_INVALID_STATE ) ;
}
2018-06-04 07:39:18 +00:00
static RTC_DATA_ATTR struct timeval start ;
static void trigger_deepsleep ( void )
{
printf ( " Trigger deep sleep. Waiting 30 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 ( ) - 1000000 ) ;
esp_set_time_from_rtc ( ) ;
// Delay for time error accumulation.
vTaskDelay ( 30000 / portTICK_RATE_MS ) ;
// Save start time. Deep sleep.
gettimeofday ( & start , NULL ) ;
esp_sleep_enable_timer_wakeup ( 1000 ) ;
esp_deep_sleep_start ( ) ;
}
static void check_time_deepsleep ( void )
{
struct timeval stop ;
RESET_REASON reason = rtc_get_reset_reason ( 0 ) ;
TEST_ASSERT ( reason = = DEEPSLEEP_RESET ) ;
gettimeofday ( & stop , NULL ) ;
// Time dt_ms must in any case be positive.
int dt_ms = ( stop . tv_sec - start . tv_sec ) * 1000 + ( stop . tv_usec - start . tv_usec ) / 1000 ;
printf ( " delta time = %d \n " , dt_ms ) ;
TEST_ASSERT_MESSAGE ( dt_ms > 0 , " Time in deep sleep is negative " ) ;
}
2018-06-21 11:58:24 +00:00
TEST_CASE_MULTIPLE_STAGES ( " check a time after wakeup from deep sleep " , " [deepsleep][reset=DEEPSLEEP_RESET][timeout=60] " , trigger_deepsleep , check_time_deepsleep ) ;