Merge branch 'bugfix/light_sleep_wdt_fix' into 'master'
Fix occasional WDT reset in light sleep test See merge request idf/esp-idf!2374
This commit is contained in:
commit
827772df69
5 changed files with 125 additions and 1 deletions
|
@ -165,6 +165,16 @@ static inline void IRAM_ATTR timer_count_reload(void)
|
||||||
REG_WRITE(FRC_TIMER_LOAD_REG(1), REG_READ(FRC_TIMER_COUNT_REG(1)) - ALARM_OVERFLOW_VAL);
|
REG_WRITE(FRC_TIMER_LOAD_REG(1), REG_READ(FRC_TIMER_COUNT_REG(1)) - ALARM_OVERFLOW_VAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void esp_timer_impl_lock()
|
||||||
|
{
|
||||||
|
portENTER_CRITICAL(&s_time_update_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void esp_timer_impl_unlock()
|
||||||
|
{
|
||||||
|
portEXIT_CRITICAL(&s_time_update_lock);
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t IRAM_ATTR esp_timer_impl_get_time()
|
uint64_t IRAM_ATTR esp_timer_impl_get_time()
|
||||||
{
|
{
|
||||||
uint32_t timer_val;
|
uint32_t timer_val;
|
||||||
|
@ -317,9 +327,13 @@ void esp_timer_impl_advance(int64_t time_us)
|
||||||
|
|
||||||
portENTER_CRITICAL(&s_time_update_lock);
|
portENTER_CRITICAL(&s_time_update_lock);
|
||||||
uint64_t count = REG_READ(FRC_TIMER_COUNT_REG(1));
|
uint64_t count = REG_READ(FRC_TIMER_COUNT_REG(1));
|
||||||
|
/* Trigger an ISR to handle past alarms and set new one.
|
||||||
|
* ISR handler will run once we exit the critical section.
|
||||||
|
*/
|
||||||
|
REG_WRITE(FRC_TIMER_ALARM_REG(1), 0);
|
||||||
REG_WRITE(FRC_TIMER_LOAD_REG(1), 0);
|
REG_WRITE(FRC_TIMER_LOAD_REG(1), 0);
|
||||||
s_time_base_us += count / s_timer_ticks_per_us + time_us;
|
s_time_base_us += count / s_timer_ticks_per_us + time_us;
|
||||||
esp_timer_impl_set_alarm(esp_timer_get_next_alarm());
|
s_overflow_happened = false;
|
||||||
portEXIT_CRITICAL(&s_time_update_lock);
|
portEXIT_CRITICAL(&s_time_update_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,3 +84,18 @@ uint64_t esp_timer_impl_get_time();
|
||||||
* @return minimal period of periodic timer, in microseconds
|
* @return minimal period of periodic timer, in microseconds
|
||||||
*/
|
*/
|
||||||
uint64_t esp_timer_impl_get_min_period_us();
|
uint64_t esp_timer_impl_get_min_period_us();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief obtain internal critical section used esp_timer implementation
|
||||||
|
* This can be used when a sequence of calls to esp_timer has to be made,
|
||||||
|
* and it is necessary that the state of the timer is consistent between
|
||||||
|
* the calls. Should be treated in the same way as a spinlock.
|
||||||
|
* Call esp_timer_impl_unlock to release the lock
|
||||||
|
*/
|
||||||
|
void esp_timer_impl_lock();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief counterpart of esp_timer_impl_lock
|
||||||
|
*/
|
||||||
|
void esp_timer_impl_unlock();
|
||||||
|
|
|
@ -279,6 +279,11 @@ esp_err_t esp_light_sleep_start()
|
||||||
{
|
{
|
||||||
static portMUX_TYPE light_sleep_lock = portMUX_INITIALIZER_UNLOCKED;
|
static portMUX_TYPE light_sleep_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
portENTER_CRITICAL(&light_sleep_lock);
|
portENTER_CRITICAL(&light_sleep_lock);
|
||||||
|
/* We will be calling esp_timer_impl_advance inside DPORT access critical
|
||||||
|
* section. Make sure the code on the other CPU is not holding esp_timer
|
||||||
|
* lock, otherwise there will be deadlock.
|
||||||
|
*/
|
||||||
|
esp_timer_impl_lock();
|
||||||
s_config.rtc_ticks_at_sleep_start = rtc_time_get();
|
s_config.rtc_ticks_at_sleep_start = rtc_time_get();
|
||||||
uint64_t frc_time_at_start = esp_timer_get_time();
|
uint64_t frc_time_at_start = esp_timer_get_time();
|
||||||
DPORT_STALL_OTHER_CPU_START();
|
DPORT_STALL_OTHER_CPU_START();
|
||||||
|
@ -332,6 +337,7 @@ esp_err_t esp_light_sleep_start()
|
||||||
}
|
}
|
||||||
esp_set_time_from_rtc();
|
esp_set_time_from_rtc();
|
||||||
|
|
||||||
|
esp_timer_impl_unlock();
|
||||||
DPORT_STALL_OTHER_CPU_END();
|
DPORT_STALL_OTHER_CPU_END();
|
||||||
rtc_wdt_disable();
|
rtc_wdt_disable();
|
||||||
portEXIT_CRITICAL(&light_sleep_lock);
|
portEXIT_CRITICAL(&light_sleep_lock);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
#include "test_utils.h"
|
#include "test_utils.h"
|
||||||
|
#include "../esp_timer_impl.h"
|
||||||
|
|
||||||
#ifdef CONFIG_ESP_TIMER_PROFILING
|
#ifdef CONFIG_ESP_TIMER_PROFILING
|
||||||
#define WITH_PROFILING 1
|
#define WITH_PROFILING 1
|
||||||
|
@ -418,3 +419,62 @@ TEST_CASE("Can delete timer from callback", "[esp_timer]")
|
||||||
|
|
||||||
vSemaphoreDelete(args.notify_from_timer_cb);
|
vSemaphoreDelete(args.notify_from_timer_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("esp_timer_impl_advance moves time base correctly", "[esp_timer]")
|
||||||
|
{
|
||||||
|
ref_clock_init();
|
||||||
|
int64_t t0 = esp_timer_get_time();
|
||||||
|
const int64_t diff_us = 1000000;
|
||||||
|
esp_timer_impl_advance(diff_us);
|
||||||
|
int64_t t1 = esp_timer_get_time();
|
||||||
|
int64_t t_delta = t1 - t0;
|
||||||
|
printf("diff_us=%lld t1-t0=%lld\n", diff_us, t_delta);
|
||||||
|
TEST_ASSERT_INT_WITHIN(1000, diff_us, (int) t_delta);
|
||||||
|
ref_clock_deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("after esp_timer_impl_advance, timers run when expected", "[esp_timer]")
|
||||||
|
{
|
||||||
|
typedef struct {
|
||||||
|
int64_t cb_time;
|
||||||
|
} test_state_t;
|
||||||
|
|
||||||
|
void timer_func(void* varg) {
|
||||||
|
test_state_t* arg = (test_state_t*) varg;
|
||||||
|
arg->cb_time = ref_clock_get();
|
||||||
|
}
|
||||||
|
|
||||||
|
ref_clock_init();
|
||||||
|
|
||||||
|
test_state_t state = { 0 };
|
||||||
|
|
||||||
|
esp_timer_create_args_t timer_args = {
|
||||||
|
.callback = &timer_func,
|
||||||
|
.arg = &state
|
||||||
|
};
|
||||||
|
esp_timer_handle_t timer;
|
||||||
|
TEST_ESP_OK(esp_timer_create(&timer_args, &timer));
|
||||||
|
|
||||||
|
const int64_t interval = 10000;
|
||||||
|
const int64_t advance = 2000;
|
||||||
|
|
||||||
|
printf("test 1\n");
|
||||||
|
int64_t t_start = ref_clock_get();
|
||||||
|
esp_timer_start_once(timer, interval);
|
||||||
|
esp_timer_impl_advance(advance);
|
||||||
|
vTaskDelay(2 * interval / 1000 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
TEST_ASSERT_INT_WITHIN(portTICK_PERIOD_MS * 1000, interval - advance, state.cb_time - t_start);
|
||||||
|
|
||||||
|
printf("test 2\n");
|
||||||
|
state.cb_time = 0;
|
||||||
|
t_start = ref_clock_get();
|
||||||
|
esp_timer_start_once(timer, interval);
|
||||||
|
esp_timer_impl_advance(interval);
|
||||||
|
vTaskDelay(1);
|
||||||
|
|
||||||
|
TEST_ASSERT(state.cb_time > t_start);
|
||||||
|
|
||||||
|
ref_clock_deinit();
|
||||||
|
}
|
||||||
|
|
|
@ -91,6 +91,35 @@ TEST_CASE("light sleep stress test", "[deepsleep]")
|
||||||
vSemaphoreDelete(done);
|
vSemaphoreDelete(done);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
|
#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
|
||||||
#define MAX_SLEEP_TIME_ERROR_US 200
|
#define MAX_SLEEP_TIME_ERROR_US 200
|
||||||
#else
|
#else
|
||||||
|
|
Loading…
Reference in a new issue