risc-v/esp32c3: Support ESP32-C3 auto-sleep

This commit is contained in:
chenwen 2021-05-08 19:04:16 +08:00 committed by Alan Carvalho de Assis
parent e44ec9e48e
commit 9a99d813fa
19 changed files with 1784 additions and 38 deletions

View File

@ -657,6 +657,34 @@ config ESP32C3_WIFI_STA_DISCONNECT_PM
Select this option to enable power management for station when disconnected.
Chip will do modem-sleep when RF module is not in use anymore.
config EXAMPLE_WIFI_LISTEN_INTERVAL
int "Wi-Fi listen interval"
default 3
---help---
Interval for station to listen to beacon from AP. The unit of listen interval is one beacon interval.
For example, if beacon interval is 100 ms and listen interval is 3, the interval for station to listen
to beacon is 300 ms.
choice EXAMPLE_POWER_SAVE_MODE
prompt "Power save mode"
default EXAMPLE_POWER_SAVE_NONE
---help---
Power save mode for the ESP32-C3 to use. Modem sleep mode includes minimum and maximum power save modes.
In minimum power save mode, station wakes up every DTIM to receive beacon. Broadcast data will not be
lost because it is transmitted after DTIM. However, it can not save much more power if DTIM is short
for DTIM is determined by AP.
In maximum power save mode, station wakes up every listen interval to receive beacon. Broadcast data
may be lost because station may be in sleep state at DTIM time. If listen interval is longer, more power
is saved but broadcast data is more easy to lose.
config EXAMPLE_POWER_SAVE_NONE
bool "none"
config EXAMPLE_POWER_SAVE_MIN_MODEM
bool "minimum modem"
config EXAMPLE_POWER_SAVE_MAX_MODEM
bool "maximum modem"
endchoice
endmenu # ESP32C3_WIRELESS
menu "SPI Flash configuration"
@ -716,4 +744,20 @@ config ESP32C3_DMA_M2M_TEST_BUFSIZE
endmenu # GDMA Configuration
config ESP32C3_AUTO_SLEEP
bool "Auto-sleep"
default n
select PM
select ESP32C3_RT_TIMER
select ESP32C3_TIMER0
select ESP32C3_TICKLESS
---help---
Enable ESP32-C3 Auto-sleep
config ESP32C3_TICKLESS
bool "Enable ESP32-C3 tickless OS"
default n
select ARCH_HAVE_TICKLESS
select SCHED_TICKLESS
endif # ARCH_CHIP_ESP32C3

View File

@ -46,11 +46,17 @@ endif
# Specify our C code within this directory to be included
CHIP_CSRCS = esp32c3_allocateheap.c esp32c3_start.c esp32c3_idle.c
CHIP_CSRCS += esp32c3_irq.c esp32c3_timerisr.c
CHIP_CSRCS += esp32c3_irq.c
CHIP_CSRCS += esp32c3_clockconfig.c esp32c3_gpio.c
CHIP_CSRCS += esp32c3_lowputc.c
CHIP_CSRCS += esp32c3_systemreset.c esp32c3_resetcause.c
ifeq ($(CONFIG_SCHED_TICKLESS),y)
CHIP_CSRCS += esp32c3_tickless.c
else
CHIP_CSRCS += esp32c3_timerisr.c
endif
ifeq ($(CONFIG_ESP32C3_UART),y)
CHIP_CSRCS += esp32c3_serial.c
endif

View File

@ -22,6 +22,7 @@
* Included Files
****************************************************************************/
#include <stdint.h>
#include <nuttx/config.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
@ -30,6 +31,14 @@
#include "esp32c3.h"
#include "esp32c3_pm.h"
#ifdef CONFIG_ESP32C3_RT_TIMER
#include "esp32c3_rt_timer.h"
#endif
#ifdef CONFIG_SCHED_TICKLESS
#include "esp32c3_tickless.h"
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@ -58,6 +67,14 @@
#endif
#define PM_IDLE_DOMAIN 0 /* Revisit */
#ifndef MIN
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
#define EXPECTED_IDLE_TIME_US (800)
#define EARLY_WAKEUP_US (200)
#endif
/****************************************************************************
@ -75,9 +92,57 @@
#ifdef CONFIG_PM
static void up_idlepm(void)
{
irqstate_t flags;
#ifdef CONFIG_ESP32C3_AUTO_SLEEP
flags = spin_lock_irqsave(NULL);
if (esp32c3_pm_lockstatus() == 0 &&
(esp32c3_should_skip_light_sleep() == false))
{
uint64_t os_start_us;
uint64_t os_end_us;
uint64_t os_step_us;
uint64_t hw_start_us;
uint64_t hw_end_us;
uint64_t hw_step_us;
uint64_t rtc_diff_us;
struct timespec ts;
uint64_t os_idle_us = up_get_idletime();
uint64_t hw_idle_us = rt_timer_get_alarm();
uint64_t sleep_us = MIN(os_idle_us, hw_idle_us);
if (sleep_us > EXPECTED_IDLE_TIME_US)
{
esp32c3_sleep_enable_rtc_timer_wakeup(sleep_us - EARLY_WAKEUP_US);
up_timer_gettime(&ts);
os_start_us = (ts.tv_sec * USEC_PER_SEC +
ts.tv_nsec / NSEC_PER_USEC);
hw_start_us = rt_timer_time_us();
esp32c3_light_sleep_start(&rtc_diff_us);
hw_end_us = rt_timer_time_us();
up_timer_gettime(&ts);
os_end_us = (ts.tv_sec * USEC_PER_SEC +
ts.tv_nsec / NSEC_PER_USEC);
hw_step_us = rtc_diff_us - (hw_end_us - hw_start_us);
os_step_us = rtc_diff_us - (os_end_us - os_start_us);
DEBUGASSERT(hw_step_us > 0);
DEBUGASSERT(os_step_us > 0);
/* Adjust current RT timer by a certain value. */
rt_timer_calibration(hw_step_us);
/* Adjust system time by a certain value. */
up_step_idletime((uint32_t)os_step_us);
}
}
spin_unlock_irqrestore(NULL, flags);
#else /* CONFIG_ESP32C3_AUTO_SLEEP */
static enum pm_state_e oldstate = PM_NORMAL;
enum pm_state_e newstate;
irqstate_t flags;
int ret;
/* Decide, which power saving level can be obtained */
@ -159,6 +224,7 @@ static void up_idlepm(void)
pm_changestate(PM_IDLE_DOMAIN, PM_NORMAL);
#endif
}
#endif
}
#else
# define up_idlepm()

View File

@ -25,6 +25,7 @@
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/power/pm.h>
#ifdef CONFIG_PM
@ -43,12 +44,21 @@
#include "hardware/esp32c3_soc.h"
#include "hardware/esp32c3_uart.h"
#include "hardware/esp32c3_gpio.h"
#include "hardware/apb_ctrl_reg.h"
#include "esp32c3_attr.h"
#include "esp32c3_rtc.h"
#include "esp32c3_clockconfig.h"
#include "esp32c3_pm.h"
#ifdef CONFIG_ESP32C3_RT_TIMER
#include "esp32c3_rt_timer.h"
#endif
#ifdef CONFIG_SCHED_TICKLESS
#include "esp32c3_tickless.h"
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@ -99,6 +109,9 @@
#define RTC_USB_TRIG_EN BIT(14)
#define RTC_BROWNOUT_DET_TRIG_EN BIT(16)
#define PERIPH_INFORM_OUT_SLEEP_OVERHEAD_NO (1)
#define PERIPH_SKIP_SLEEP_NO (1)
/****************************************************************************
* Private Types
****************************************************************************/
@ -207,28 +220,31 @@ struct esp32c3_rtc_vddsdio_config_s
* Private Function Prototypes
****************************************************************************/
static inline uint32_t esp32c3_periph_ll_get_rst_en_mask
static inline uint32_t IRAM_ATTR esp32c3_periph_ll_get_rst_en_mask
(enum esp32c3_periph_module_e periph, bool enable);
static uint32_t IRAM_ATTR esp32c3_periph_ll_get_rst_en_reg(
enum esp32c3_periph_module_e periph);
static uint32_t IRAM_ATTR esp32c3_periph_ll_get_clk_en_reg(
enum esp32c3_periph_module_e periph);
static inline uint32_t esp32c3_periph_ll_get_clk_en_mask(
static inline uint32_t IRAM_ATTR esp32c3_periph_ll_get_clk_en_mask(
enum esp32c3_periph_module_e periph);
static inline bool IRAM_ATTR esp32c3_periph_ll_periph_enabled(
enum esp32c3_periph_module_e periph);
static inline void esp32c3_uart_tx_wait_idle(uint8_t uart_no);
static inline void IRAM_ATTR esp32c3_uart_tx_wait_idle(uint8_t uart_no);
static void IRAM_ATTR esp32c3_flush_uarts(void);
static void IRAM_ATTR esp32c3_suspend_uarts(void);
static void IRAM_ATTR esp32c3_resume_uarts(void);
static void esp32c3_timer_wakeup_prepare(void);
static uint32_t esp32c3_get_power_down_flags(void);
static void IRAM_ATTR esp32c3_timer_wakeup_prepare(void);
static uint32_t IRAM_ATTR esp32c3_get_power_down_flags(void);
static void IRAM_ATTR esp32c3_set_vddsdio_config(
struct esp32c3_rtc_vddsdio_config_s config);
static int IRAM_ATTR esp32c3_get_vddsdio_config(
struct esp32c3_rtc_vddsdio_config_s *config);
static int IRAM_ATTR esp32c3_light_sleep_inner(uint32_t pd_flags,
uint32_t time_us, struct esp32c3_rtc_vddsdio_config_s config);
static void esp32c3_periph_module_enable(
enum esp32c3_periph_module_e periph);
static void IRAM_ATTR esp32c3_perip_clk_init(void);
static int IRAM_ATTR esp32c3_sleep_start(uint32_t pd_flags);
/****************************************************************************
@ -247,6 +263,22 @@ static struct esp32c3_sleep_config_s s_config =
.wakeup_triggers = 0
};
static _Atomic uint32_t pm_wakelock = 0;
/* Inform peripherals of light sleep wakeup overhead time */
inform_out_sleep_overhead_cb_t
g_periph_inform_out_sleep_overhead_cb[PERIPH_INFORM_OUT_SLEEP_OVERHEAD_NO];
/* Indicates if light sleep shoule be skipped by peripherals. */
skip_light_sleep_cb_t g_periph_skip_sleep_cb[PERIPH_SKIP_SLEEP_NO];
static uint8_t ref_counts[PERIPH_MODULE_MAX] =
{
0
};
/****************************************************************************
* Private Functions
****************************************************************************/
@ -276,7 +308,7 @@ extern void esp_rom_delay_us(uint32_t us);
*
****************************************************************************/
static inline uint32_t esp32c3_periph_ll_get_rst_en_mask
static inline uint32_t IRAM_ATTR esp32c3_periph_ll_get_rst_en_mask
(enum esp32c3_periph_module_e periph, bool enable)
{
switch (periph)
@ -480,7 +512,7 @@ static uint32_t IRAM_ATTR esp32c3_periph_ll_get_clk_en_reg(
*
****************************************************************************/
static inline uint32_t esp32c3_periph_ll_get_clk_en_mask(
static inline uint32_t IRAM_ATTR esp32c3_periph_ll_get_clk_en_mask(
enum esp32c3_periph_module_e periph)
{
switch (periph)
@ -725,7 +757,7 @@ static void IRAM_ATTR esp32c3_resume_uarts(void)
*
****************************************************************************/
static uint32_t esp32c3_get_power_down_flags(void)
static uint32_t IRAM_ATTR esp32c3_get_power_down_flags(void)
{
uint32_t pd_flags = 0;
@ -1018,15 +1050,328 @@ static int IRAM_ATTR esp32c3_light_sleep_inner(uint32_t pd_flags,
return err;
}
/****************************************************************************
* Name: esp32c3_periph_module_enable
*
* Description:
* Enable peripheral module
*
* Input Parameters:
* periph - Periph module (one of enum esp32c3_periph_module_e values)
*
* Returned Value:
* None
*
****************************************************************************/
static void esp32c3_periph_module_enable(enum esp32c3_periph_module_e periph)
{
irqstate_t flags = enter_critical_section();
assert(periph < PERIPH_MODULE_MAX);
if (ref_counts[periph] == 0)
{
modifyreg32(esp32c3_periph_ll_get_clk_en_reg(periph), 0,
esp32c3_periph_ll_get_clk_en_mask(periph));
modifyreg32(esp32c3_periph_ll_get_rst_en_reg(periph),
esp32c3_periph_ll_get_rst_en_mask(periph, true), 0);
}
ref_counts[periph]++;
leave_critical_section(flags);
}
/****************************************************************************
* Name: esp32c3_perip_clk_init
*
* Description:
* This function disables clock of useless peripherals when cpu starts.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static void IRAM_ATTR esp32c3_perip_clk_init(void)
{
uint32_t common_perip_clk1 = 0;
/* Reset the communication peripherals like I2C, SPI,
* UART, I2S and bring them to known state.
*/
uint32_t common_perip_clk = SYSTEM_WDG_CLK_EN |
SYSTEM_I2S0_CLK_EN |
SYSTEM_UART1_CLK_EN |
SYSTEM_UART2_CLK_EN |
SYSTEM_SPI2_CLK_EN |
SYSTEM_I2C_EXT0_CLK_EN |
SYSTEM_UHCI0_CLK_EN |
SYSTEM_RMT_CLK_EN |
SYSTEM_LEDC_CLK_EN |
SYSTEM_UHCI1_CLK_EN |
SYSTEM_TIMERGROUP1_CLK_EN |
SYSTEM_SPI3_CLK_EN |
SYSTEM_SPI4_CLK_EN |
SYSTEM_I2C_EXT1_CLK_EN |
SYSTEM_TWAI_CLK_EN |
SYSTEM_I2S1_CLK_EN |
SYSTEM_SPI2_DMA_CLK_EN |
SYSTEM_SPI3_DMA_CLK_EN;
uint32_t hwcrypto_perip_clk = SYSTEM_CRYPTO_AES_CLK_EN |
SYSTEM_CRYPTO_SHA_CLK_EN |
SYSTEM_CRYPTO_RSA_CLK_EN;
uint32_t wifi_bt_sdio_clk = SYSTEM_WIFI_CLK_WIFI_EN |
SYSTEM_WIFI_CLK_BT_EN_M |
SYSTEM_WIFI_CLK_UNUSED_BIT5 |
SYSTEM_WIFI_CLK_UNUSED_BIT12;
/* Disable some peripheral clocks. */
modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, common_perip_clk, 0);
modifyreg32(SYSTEM_PERIP_RST_EN0_REG, 0, common_perip_clk);
modifyreg32(SYSTEM_PERIP_CLK_EN1_REG, common_perip_clk1, 0);
modifyreg32(SYSTEM_PERIP_RST_EN1_REG, 0, common_perip_clk1);
/* Disable hardware crypto clocks. */
modifyreg32(SYSTEM_PERIP_CLK_EN1_REG, hwcrypto_perip_clk, 0);
modifyreg32(SYSTEM_PERIP_RST_EN1_REG, 0, hwcrypto_perip_clk);
/* Disable WiFi/BT/SDIO clocks. */
modifyreg32(SYSTEM_WIFI_CLK_EN_REG, wifi_bt_sdio_clk, 0);
modifyreg32(SYSTEM_WIFI_CLK_EN_REG, 0, SYSTEM_WIFI_CLK_EN);
/* Set WiFi light sleep clock source to RTC slow clock */
REG_SET_FIELD(SYSTEM_BT_LPCK_DIV_INT_REG, SYSTEM_BT_LPCK_DIV_NUM, 0);
modifyreg32(SYSTEM_BT_LPCK_DIV_FRAC_REG, SYSTEM_LPCLK_SEL_8M,
SYSTEM_LPCLK_SEL_RTC_SLOW);
/* Enable RNG clock. */
esp32c3_periph_module_enable(PERIPH_RNG_MODULE);
}
/****************************************************************************
* Name: esp32c3_periph_should_skip_sleep
*
* Description:
* Indicates if light sleep shoule be skipped by peripherals
*
* Input Parameters:
* None
*
* Returned Value:
* True is returned on success. Otherwise false.
*
****************************************************************************/
static inline bool IRAM_ATTR esp32c3_periph_should_skip_sleep(void)
{
for (int i = 0; i < PERIPH_SKIP_SLEEP_NO; i++)
{
if (g_periph_skip_sleep_cb[i])
{
if (g_periph_skip_sleep_cb[i]() == true)
{
return true;
}
}
}
return false;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp32c3_sleep_enable_timer_wakeup
* Name: esp32c3_pm_register_skip_sleep_callback
*
* Description:
* Configure wake-up interval
* Unregister callback function of skipping light sleep.
*
* Input Parameters:
* None
*
* Returned Value:
* Zero (OK) is returned on success. Otherwise -1 (ERROR).
*
****************************************************************************/
int esp32c3_pm_register_skip_sleep_callback(skip_light_sleep_cb_t cb)
{
for (int i = 0; i < PERIPH_SKIP_SLEEP_NO; i++)
{
if (g_periph_skip_sleep_cb[i] == cb)
{
return OK;
}
else if (g_periph_skip_sleep_cb[i] == NULL)
{
g_periph_skip_sleep_cb[i] = cb;
return OK;
}
}
return ERROR;
}
/****************************************************************************
* Name: esp32c3_pm_unregister_skip_sleep_callback
*
* Description:
* Register callback function of skipping light sleep.
*
* Input Parameters:
* None
*
* Returned Value:
* Zero (OK) is returned on success. Otherwise -1 (ERROR).
*
****************************************************************************/
int esp32c3_pm_unregister_skip_sleep_callback(skip_light_sleep_cb_t cb)
{
for (int i = 0; i < PERIPH_SKIP_SLEEP_NO; i++)
{
if (g_periph_skip_sleep_cb[i] == cb)
{
g_periph_skip_sleep_cb[i] = NULL;
return OK;
}
}
return ERROR;
}
/****************************************************************************
* Name: esp32c3_should_skip_light_sleep
*
* Description:
* Indicates if light sleep shoule be skipped.
*
* Input Parameters:
* None
*
* Returned Value:
* True is returned on success. Otherwise false.
*
****************************************************************************/
bool IRAM_ATTR esp32c3_should_skip_light_sleep(void)
{
if (esp32c3_periph_should_skip_sleep() == true)
{
return true;
}
return false;
}
/****************************************************************************
* Name: esp32c3_pm_register_inform_out_sleep_overhead_callback
*
* Description:
* Register informing peripherals of light sleep wakeup overhead time
* callback function.
*
* Input Parameters:
* cb - callback function
*
* Returned Value:
* Zero (OK) is returned on success. Otherwise -1 (ERROR).
*
****************************************************************************/
int esp32c3_pm_register_inform_out_sleep_overhead_callback(
inform_out_sleep_overhead_cb_t cb)
{
for (int i = 0; i < PERIPH_INFORM_OUT_SLEEP_OVERHEAD_NO; i++)
{
if (g_periph_inform_out_sleep_overhead_cb[i] == cb)
{
return ERROR;
}
else if (g_periph_inform_out_sleep_overhead_cb[i] == NULL)
{
g_periph_inform_out_sleep_overhead_cb[i] = cb;
return OK;
}
}
return ERROR;
}
/****************************************************************************
* Name: esp32c3_pm_unregister_inform_out_sleep_overhead_callback
*
* Description:
* Unregister informing peripherals of light sleep wakeup overhead time
* callback function.
*
* Input Parameters:
* cb - callback function
*
* Returned Value:
* None
*
****************************************************************************/
int esp32c3_pm_unregister_inform_out_sleep_overhead_callback(
inform_out_sleep_overhead_cb_t cb)
{
for (int i = 0; i < PERIPH_INFORM_OUT_SLEEP_OVERHEAD_NO; i++)
{
if (g_periph_inform_out_sleep_overhead_cb[i] == cb)
{
g_periph_inform_out_sleep_overhead_cb[i] = NULL;
return OK;
}
}
return ERROR;
}
/****************************************************************************
* Name: esp32c3_periph_inform_out_sleep_overhead
*
* Description:
* Inform peripherals of light sleep wakeup overhead time
*
* Input Parameters:
* us - light sleep wakeup overhead time
*
* Returned Value:
* None
*
****************************************************************************/
void IRAM_ATTR esp32c3_periph_inform_out_sleep_overhead(uint32_t us)
{
for (int i = 0; i < PERIPH_INFORM_OUT_SLEEP_OVERHEAD_NO; i++)
{
if (g_periph_inform_out_sleep_overhead_cb[i])
{
g_periph_inform_out_sleep_overhead_cb[i](us);
}
}
}
/****************************************************************************
* Name: esp32c3_sleep_enable_rtc_timer_wakeup
*
* Description:
* Configure RTC TIMER wake-up interval
*
* Input Parameters:
* time_in_us - Configure wake-up time interval
@ -1036,12 +1381,31 @@ static int IRAM_ATTR esp32c3_light_sleep_inner(uint32_t pd_flags,
*
****************************************************************************/
void esp32c3_sleep_enable_timer_wakeup(uint64_t time_in_us)
void IRAM_ATTR esp32c3_sleep_enable_rtc_timer_wakeup(uint64_t time_in_us)
{
s_config.wakeup_triggers |= RTC_TIMER_TRIG_EN;
s_config.sleep_duration = time_in_us;
}
/****************************************************************************
* Name: esp32c3_sleep_enable_wifi_wakeup
*
* Description:
* Configure Wi-Fi wake-up source
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void esp32c3_sleep_enable_wifi_wakeup(void)
{
s_config.wakeup_triggers |= RTC_WIFI_TRIG_EN;
}
/****************************************************************************
* Name: esp32c3_light_sleep_start
*
@ -1049,14 +1413,14 @@ void esp32c3_sleep_enable_timer_wakeup(uint64_t time_in_us)
* Enter light sleep mode
*
* Input Parameters:
* None
* sleep_time - Actual sleep time
*
* Returned Value:
* 0 is returned on success or a negated errno value is returned
*
****************************************************************************/
int esp32c3_light_sleep_start(void)
int IRAM_ATTR esp32c3_light_sleep_start(uint64_t *sleep_time)
{
int ret = OK;
irqstate_t flags;
@ -1141,12 +1505,22 @@ int esp32c3_light_sleep_start(void)
}
}
esp32c3_periph_inform_out_sleep_overhead(
s_config.sleep_time_adjustment - sleep_time_overhead_in);
esp32c3_get_vddsdio_config(&vddsdio_config);
/* Enter sleep, then wait for flash to be ready on wakeup */
ret = esp32c3_light_sleep_inner(pd_flags, flash_enable_time_us,
vddsdio_config);
if (sleep_time != NULL)
{
*sleep_time = esp32c3_rtc_time_slowclk_to_us(esp32c3_rtc_time_get() -
s_config.rtc_ticks_at_sleep_start, s_config.rtc_clk_cal_period);
}
s_config.sleep_time_overhead_out = (esp32c3_cpu_cycle_count() -
s_config.ccount_ticks_record) / (esp32c3_clk_cpu_freq() / 1000000ULL);
@ -1175,6 +1549,7 @@ void esp32c3_pminit(void)
esp32c3_rtc_init();
esp32c3_rtc_clk_set();
esp32c3_perip_clk_init();
}
/****************************************************************************
@ -1193,11 +1568,41 @@ void esp32c3_pminit(void)
void esp32c3_pmstandby(uint64_t time_in_us)
{
uint64_t rtc_diff_us;
#ifdef CONFIG_ESP32C3_RT_TIMER
uint64_t hw_start_us;
uint64_t hw_end_us;
uint64_t hw_diff_us;
#endif
/* don't power down XTAL — powering it up takes different time on. */
fflush(stdout);
esp32c3_sleep_enable_timer_wakeup(time_in_us);
esp32c3_light_sleep_start();
esp32c3_sleep_enable_rtc_timer_wakeup(time_in_us);
#ifdef CONFIG_ESP32C3_RT_TIMER
/* Get rt-timer timestamp before entering sleep */
hw_start_us = rt_timer_time_us();
#endif
esp32c3_light_sleep_start(&rtc_diff_us);
#ifdef CONFIG_ESP32C3_RT_TIMER
/* Get rt-timer timestamp after waking up from sleep */
hw_end_us = rt_timer_time_us();
hw_diff_us = hw_end_us - hw_start_us;
DEBUGASSERT(rtc_diff_us > hw_diff_us);
rt_timer_calibration(rtc_diff_us - hw_diff_us);
#endif
#ifdef CONFIG_SCHED_TICKLESS
up_step_idletime((uint32_t)time_in_us);
#endif
pwrinfo("Returned from auto-sleep, slept for %" PRIu32 " ms\n",
(uint32_t)(rtc_diff_us) / 1000);
}
/****************************************************************************
@ -1259,8 +1664,47 @@ void IRAM_ATTR esp32c3_deep_sleep_start(void)
void esp32c3_pmsleep(uint64_t time_in_us)
{
fflush(stdout);
esp32c3_sleep_enable_timer_wakeup(time_in_us);
esp32c3_sleep_enable_rtc_timer_wakeup(time_in_us);
esp32c3_deep_sleep_start();
}
/****************************************************************************
* Name: esp32c3_pm_lockacquire
*
* Description:
* Take a power management lock
*
****************************************************************************/
void IRAM_ATTR esp32c3_pm_lockacquire(void)
{
++pm_wakelock;
}
/****************************************************************************
* Name: esp32c3_pm_lockrelease
*
* Description:
* Release the lock taken using esp32c3_pm_lockacquire.
*
****************************************************************************/
void IRAM_ATTR esp32c3_pm_lockrelease(void)
{
--pm_wakelock;
}
/****************************************************************************
* Name: esp32c3_pm_lockstatus
*
* Description:
* Return power management lock status.
*
****************************************************************************/
uint32_t IRAM_ATTR esp32c3_pm_lockstatus(void)
{
return pm_wakelock;
}
#endif /* CONFIG_PM */

View File

@ -30,6 +30,7 @@
****************************************************************************/
#include <stdint.h>
#include <stdbool.h>
#ifndef __ASSEMBLY__
@ -44,12 +45,26 @@ extern "C"
#ifdef CONFIG_PM
/****************************************************************************
* Public Types
****************************************************************************/
/* Callback function type for peripherals to
* know light sleep wakeup overhead.
*/
typedef void (*inform_out_sleep_overhead_cb_t)(uint32_t);
/* Callback function type for peripherals to skip light sleep. */
typedef bool (*skip_light_sleep_cb_t)(void);
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: esp32c3_sleep_enable_timer_wakeup
* Name: esp32c3_sleep_enable_rtc_timer_wakeup
*
* Description:
* Configure wake-up interval
@ -62,23 +77,23 @@ extern "C"
*
****************************************************************************/
void esp32c3_sleep_enable_timer_wakeup(uint64_t time_in_us);
void esp32c3_sleep_enable_rtc_timer_wakeup(uint64_t time_in_us);
/****************************************************************************
* Name: esp32c3_light_sleep_start
*
* Description:
* Enter sleep mode
* Enter light sleep mode
*
* Input Parameters:
* None
* sleep_time - Actual sleep time
*
* Returned Value:
* 0 is returned on success or a negated errno value is returned
*
****************************************************************************/
int esp32c3_light_sleep_start(void);
int esp32c3_light_sleep_start(uint64_t *sleep_time);
/****************************************************************************
* Name: esp32c3_pminit
@ -144,6 +159,136 @@ void esp32c3_deep_sleep_start(void);
void esp32c3_pmsleep(uint64_t time_in_us);
/****************************************************************************
* Name: esp32c3_pm_lockacquire
*
* Description:
* Take a power management lock
*
****************************************************************************/
void esp32c3_pm_lockacquire(void);
/****************************************************************************
* Name: esp32c3_pm_lockrelease
*
* Description:
* Release the lock taken using esp32c3_pm_lockacquire.
*
****************************************************************************/
void esp32c3_pm_lockrelease(void);
/****************************************************************************
* Name: esp32c3_pm_lockstatus
*
* Description:
* Return power management lock status.
*
****************************************************************************/
uint32_t esp32c3_pm_lockstatus(void);
/****************************************************************************
* Name: esp32c3_sleep_enable_wifi_wakeup
*
* Description:
* Configure Wi-Fi wake-up source
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void esp32c3_sleep_enable_wifi_wakeup(void);
/****************************************************************************
* Name: esp32c3_should_skip_light_sleep
*
* Description:
* Indicates if light sleep shoule be skipped.
*
* Input Parameters:
* None
*
* Returned Value:
* True is returned on success. Otherwise false.
*
****************************************************************************/
bool esp32c3_should_skip_light_sleep(void);
/****************************************************************************
* Name: esp32c3_pm_register_inform_out_sleep_overhead_callback
*
* Description:
* Register informing peripherals of light sleep wakeup overhead time
* callback function.
*
* Input Parameters:
* cb - callback function
*
* Returned Value:
* Zero (OK) is returned on success. Otherwise -1 (ERROR).
*
****************************************************************************/
int esp32c3_pm_register_inform_out_sleep_overhead_callback(
inform_out_sleep_overhead_cb_t cb);
/****************************************************************************
* Name: esp32c3_pm_unregister_inform_out_sleep_overhead_callback
*
* Description:
* Unregister informing peripherals of light sleep wakeup overhead time
* callback function.
*
* Input Parameters:
* cb - callback function
*
* Returned Value:
* None
*
****************************************************************************/
int esp32c3_pm_unregister_inform_out_sleep_overhead_callback(
inform_out_sleep_overhead_cb_t cb);
/****************************************************************************
* Name: esp32c3_pm_register_skip_sleep_callback
*
* Description:
* Unregister callback function of skipping light sleep.
*
* Input Parameters:
* None
*
* Returned Value:
* Zero (OK) is returned on success. Otherwise -1 (ERROR).
*
****************************************************************************/
int esp32c3_pm_register_skip_sleep_callback(skip_light_sleep_cb_t cb);
/****************************************************************************
* Name: esp32c3_pm_unregister_skip_sleep_callback
*
* Description:
* Register callback function of skipping light sleep.
*
* Input Parameters:
* None
*
* Returned Value:
* Zero (OK) is returned on success. Otherwise -1 (ERROR).
*
****************************************************************************/
int esp32c3_pm_unregister_skip_sleep_callback(skip_light_sleep_cb_t cb);
#endif /* CONFIG_PM */
#ifdef __cplusplus

View File

@ -41,6 +41,7 @@
#include "hardware/esp32c3_soc.h"
#include "esp32c3_tim.h"
#include "esp32c3_rt_timer.h"
#include "esp32c3_attr.h"
/****************************************************************************
* Pre-processor Definitions
@ -590,7 +591,7 @@ void rt_timer_delete(FAR struct rt_timer_s *timer)
*
****************************************************************************/
uint64_t rt_timer_time_us(void)
uint64_t IRAM_ATTR rt_timer_time_us(void)
{
uint64_t counter;
struct esp32c3_tim_dev_s *tim = s_esp32c3_tim_dev;
@ -600,6 +601,74 @@ uint64_t rt_timer_time_us(void)
return counter;
}
/****************************************************************************
* Name: rt_timer_get_alarm
*
* Description:
* Get the timestamp when the next timeout is expected to occur.
*
* Input Parameters:
* None
*
* Returned Value:
* Timestamp of the nearest timer event, in microseconds.
*
****************************************************************************/
uint64_t IRAM_ATTR rt_timer_get_alarm(void)
{
irqstate_t flags;
uint64_t counter;
struct esp32c3_tim_dev_s *tim = s_esp32c3_tim_dev;
uint64_t alarm_value = 0;
flags = enter_critical_section();
ESP32C3_TIM_GETCTR(tim, &counter);
ESP32C3_TIM_GETALRVL(tim, &alarm_value);
if (alarm_value <= counter)
{
alarm_value = 0;
}
else
{
alarm_value -= counter;
}
leave_critical_section(flags);
return alarm_value;
}
/****************************************************************************
* Name: rt_timer_calibration
*
* Description:
* Adjust current RT timer by a certain value.
*
* Input Parameters:
* time_us - adjustment to apply to RT timer, in microseconds
*
* Returned Value:
* None.
*
****************************************************************************/
void IRAM_ATTR rt_timer_calibration(uint64_t time_us)
{
uint64_t counter;
struct esp32c3_tim_dev_s *tim = s_esp32c3_tim_dev;
irqstate_t flags;
flags = enter_critical_section();
ESP32C3_TIM_GETCTR(tim, &counter);
counter += time_us;
ESP32C3_TIM_SETCTR(tim, counter);
ESP32C3_TIM_RLD_NOW(tim);
leave_critical_section(flags);
}
/****************************************************************************
* Name: esp32c3_rt_timer_init
*

View File

@ -166,6 +166,38 @@ void rt_timer_delete(struct rt_timer_s *timer);
uint64_t rt_timer_time_us(void);
/****************************************************************************
* Name: rt_timer_get_alarm
*
* Description:
* Get the timestamp when the next timeout is expected to occur.
*
* Input Parameters:
* None
*
* Returned Value:
* Timestamp of the nearest timer event, in microseconds.
*
****************************************************************************/
uint64_t rt_timer_get_alarm(void);
/****************************************************************************
* Name: rt_timer_calibration
*
* Description:
* Adjust current RT timer by a certain value.
*
* Input Parameters:
* time_us - adjustment to apply to RT timer, in microseconds
*
* Returned Value:
* None.
*
****************************************************************************/
void rt_timer_calibration(uint64_t time_us);
/****************************************************************************
* Name: esp32c3_rt_timer_init
*

View File

@ -30,6 +30,7 @@
#include "hardware/esp32c3_rtccntl.h"
#include "hardware/esp32c3_soc.h"
#include "hardware/esp32c3_system.h"
#include "hardware/esp32c3_syscon.h"
#include "hardware/esp32c3_tim.h"
#include "hardware/apb_ctrl_reg.h"
#include "hardware/bb_reg.h"
@ -1577,6 +1578,43 @@ void IRAM_ATTR esp32c3_rtc_init()
}
}
/****************************************************************************
* Name: esp32c3_rtc_get_time_us
*
* Description:
* Get current value of RTC counter in microseconds
*
* Input Parameters:
* None
*
* Returned Value:
* Current value of RTC counter in microseconds
*
****************************************************************************/
uint64_t esp32c3_rtc_get_time_us(void)
{
const uint32_t cal = getreg32(RTC_SLOW_CLK_CAL_REG);
const uint64_t rtc_this_ticks = esp32c3_rtc_time_get();
/* RTC counter result is up to 2^48, calibration factor is up to 2^24,
* for a 32kHz clock. We need to calculate (assuming no overflow):
* (ticks * cal) >> RTC_CLK_CAL_FRACT. An overflow in the (ticks * cal)
* multiplication would cause time to wrap around after approximately
* 13 days, which is probably not enough for some applications.
* Therefore multiplication is split into two terms, for the lower 32-bit
* and the upper 16-bit parts of "ticks", i.e.:
* ((ticks_low + 2^32 * ticks_high) * cal) >> RTC_CLK_CAL_FRACT
*/
const uint64_t ticks_low = rtc_this_ticks & UINT32_MAX;
const uint64_t ticks_high = rtc_this_ticks >> 32;
const uint64_t delta_time_us = ((ticks_low * cal) >> RTC_CLK_CAL_FRACT) +
((ticks_high * cal) << (32 - RTC_CLK_CAL_FRACT));
return delta_time_us;
}
/****************************************************************************
* Name: esp32c3_rtc_time_get
*

View File

@ -428,6 +428,22 @@ void esp32c3_rtc_clk_cpu_freq_get_config(
void esp32c3_rtc_sleep_set_wakeup_time(uint64_t t);
/****************************************************************************
* Name: esp32c3_rtc_get_time_us
*
* Description:
* Get current value of RTC counter in microseconds
*
* Input Parameters:
* None
*
* Returned Value:
* Current value of RTC counter in microseconds
*
****************************************************************************/
uint64_t esp32c3_rtc_get_time_us(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,607 @@
/****************************************************************************
* arch/risc-v/src/esp32c3/esp32c3_tickless.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Tickless OS Support.
*
* When CONFIG_SCHED_TICKLESS is enabled, all support for timer interrupts
* is suppressed and the platform specific code is expected to provide the
* following custom functions.
*
* void up_timer_initialize(void): Initializes the timer facilities.
* Called early in the initialization sequence (by up_initialize()).
* int up_timer_gettime(FAR struct timespec *ts): Returns the current
* time from the platform specific time source.
* int up_timer_cancel(void): Cancels the interval timer.
* int up_timer_start(FAR const struct timespec *ts): Start (or re-starts)
* the interval timer.
*
* The RTOS will provide the following interfaces for use by the platform-
* specific interval timer implementation:
*
* void sched_timer_expiration(void): Called by the platform-specific
* logic when the interval timer expires.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/clock.h>
#include <arch/board/board.h>
#include <arch/irq.h>
#include "esp32c3_attr.h"
#include "chip.h"
#include "esp32c3.h"
#include "esp32c3_irq.h"
#include "hardware/esp32c3_systimer.h"
#include "hardware/esp32c3_system.h"
#include "hardware/esp32c3_soc.h"
#include "esp32c3_rtc.h"
#ifdef CONFIG_SCHED_TICKLESS
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define ESP32C3_SYSTIMER_TICKS_PER_SEC (16 * 1000 * 1000)
#define CTICK_PER_SEC (ESP32C3_SYSTIMER_TICKS_PER_SEC)
#define CTICK_PER_USEC (CTICK_PER_SEC / USEC_PER_SEC)
#define SEC_2_CTICK(s) ((s) * CTICK_PER_SEC)
#define USEC_2_CTICK(us) ((us) * CTICK_PER_USEC)
#define NSEC_2_CTICK(nsec) (((nsec) * CTICK_PER_USEC) / NSEC_PER_USEC)
#define CTICK_2_SEC(tick) ((tick) / CTICK_PER_SEC)
#define CTICK_2_USEC(tick) ((tick) / CTICK_PER_USEC)
#define CTICK_2_NSEC(tick) ((tick) * 1000 / CTICK_PER_USEC)
#define CPU_TICKS_MAX (UINT32_MAX / 4 * 3)
/* The structure of the counter value in systimer */
struct systimer_counter_value_s
{
union
{
struct
{
uint64_t lo : SOC_SYSTIMER_BIT_WIDTH_LO; /* Low part of counter value */
uint64_t hi : SOC_SYSTIMER_BIT_WIDTH_HI; /* High part of counter value */
};
uint64_t val; /* counter value */
};
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static inline uint64_t up_tmr_getcounter(void);
static inline uint64_t up_tmr_getalarmvalue(void);
static inline void up_tmr_counter_advance(uint64_t tick);
static void IRAM_ATTR up_tmr_setcounter(uint64_t ticks);
static void IRAM_ATTR up_timer_expire(int irq, void *regs, FAR void *arg);
/****************************************************************************
* Private Data
****************************************************************************/
static bool g_timer_started; /* Whether an interval timer is being started */
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: up_tmr_getcounter
*
* Description:
* Return the total ticks of system since power-on.
*
* Input Parameters:
* None
*
* Returned Value:
* Total system ticks
*
****************************************************************************/
static inline uint64_t up_tmr_getcounter(void)
{
uint32_t lo;
uint32_t lo_start;
uint32_t hi;
/* Set the "update" bit and wait for acknowledgment */
REG_SET_BIT(SYS_TIMER_SYSTIMER_UNIT0_OP_REG, 1 << 30);
while (!REG_GET_BIT(SYS_TIMER_SYSTIMER_UNIT0_OP_REG, 1 << 29));
/* Read LO, HI, then LO again, check that LO returns the same value.
* This accounts for the case when an interrupt may happen between reading
* HI and LO values, and this function may get called from the ISR.
* In this case, the repeated read will return consistent values.
*/
lo_start = getreg32(SYS_TIMER_SYSTIMER_UNIT0_VALUE_HI_REG);
do
{
lo = lo_start;
hi = getreg32(SYS_TIMER_SYSTIMER_UNIT0_VALUE_HI_REG);
lo_start = getreg32(SYS_TIMER_SYSTIMER_UNIT0_VALUE_LO_REG);
}
while (lo_start != lo);
struct systimer_counter_value_s result =
{
.lo = lo,
.hi = hi
};
return result.val;
}
/****************************************************************************
* Name: up_tmr_getalarmvalue
*
* Description:
* Return the remaining ticks in the currently running timer.
*
* Input Parameters:
* None
*
* Returned Value:
* Remaining ticks
*
****************************************************************************/
static inline uint64_t up_tmr_getalarmvalue(void)
{
return ((uint64_t) getreg32(SYS_TIMER_SYSTIMER_TARGET0_HI_REG) << 32) \
| getreg32(SYS_TIMER_SYSTIMER_TARGET0_LO_REG);
}
/****************************************************************************
* Name: up_tmr_counter_advance
*
* Description:
* Adjust current system tick by a certain value
*
* Input Parameters:
* ticks - Adjustment to apply to system time, in microseconds
*
* Returned Value:
* None
*
****************************************************************************/
static inline void up_tmr_counter_advance(uint64_t tick)
{
/* set_counter_value */
putreg32(tick & 0xffffffff, SYS_TIMER_SYSTIMER_UNIT0_LOAD_LO_REG);
putreg32((tick >> 32) & 0xfffff, SYS_TIMER_SYSTIMER_UNIT0_LOAD_HI_REG);
/* apply_counter_value */
REG_SET_BIT(SYS_TIMER_SYSTIMER_UNIT0_LOAD_REG, SYS_TIMER_TIMER_UNIT0_LOAD);
}
/****************************************************************************
* Name: up_tmr_setcounter
*
* Description:
* Set the new value of the compare register
*
* Input Parameters:
* ticks - ticks for a timer operation
*
* Returned Value:
* None
*
****************************************************************************/
static void IRAM_ATTR up_tmr_setcounter(uint64_t ticks)
{
uint64_t alarm_ticks = up_tmr_getcounter() + ticks;
/* select_alarm_mode */
REG_CLR_BIT(SYS_TIMER_SYSTIMER_TARGET0_CONF_REG,
SYS_TIMER_TARGET0_PERIOD_MODE);
/* set alarm value */
putreg32(alarm_ticks & 0xffffffff, SYS_TIMER_SYSTIMER_TARGET0_LO_REG);
putreg32((alarm_ticks >> 32) & 0xfffff, SYS_TIMER_SYSTIMER_TARGET0_HI_REG);
/* apply alarm vaule */
REG_SET_BIT(SYS_TIMER_SYSTIMER_COMP0_LOAD_REG, SYS_TIMER_TIMER_COMP0_LOAD);
/* Enable alarm */
REG_SET_BIT(SYS_TIMER_SYSTIMER_CONF_REG, SYS_TIMER_TARGET0_WORK_EN);
/* Enable interrupt */
REG_SET_BIT(SYS_TIMER_SYSTIMER_INT_CLR_REG, SYS_TIMER_TARGET0_INT_CLR);
REG_SET_BIT(SYS_TIMER_SYSTIMER_INT_ENA_REG, SYS_TIMER_TARGET0_INT_ENA);
}
/****************************************************************************
* Name: up_timer_expire
*
* Description:
* Called as the IRQ handler for timer expiration.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static void IRAM_ATTR up_timer_expire(int irq, void *regs, FAR void *arg)
{
g_timer_started = false;
setbits(SYS_TIMER_TARGET0_INT_CLR, SYS_TIMER_SYSTIMER_INT_CLR_REG);
nxsched_timer_expiration();
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: up_timer_gettime
*
* Description:
* Return the elapsed time since power-up (or, more correctly, since
* up_timer_initialize() was called). This function is functionally
* equivalent to:
*
* int clock_gettime(clockid_t clockid, FAR struct timespec *ts);
*
* when clockid is CLOCK_MONOTONIC.
*
* This function provides the basis for reporting the current time and
* also is used to eliminate error build-up from small errors in interval
* time calculations.
*
* Provided by platform-specific code and called from the RTOS base code.
*
* Input Parameters:
* ts - Provides the location in which to return the up-time.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
* Assumptions:
* Called from the normal tasking context. The implementation must
* provide whatever mutual exclusion is necessary for correct operation.
* This can include disabling interrupts in order to assure atomic register
* operations.
*
****************************************************************************/
int IRAM_ATTR up_timer_gettime(FAR struct timespec *ts)
{
uint64_t ticks;
irqstate_t flags;
flags = enter_critical_section();
ticks = up_tmr_getcounter();
ts->tv_sec = CTICK_2_SEC(ticks);
ts->tv_nsec = CTICK_2_NSEC(ticks % CTICK_PER_SEC);
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: up_timer_cancel
*
* Description:
* Cancel the interval timer and return the time remaining on the timer.
* These two steps need to be as nearly atomic as possible.
* nxsched_timer_expiration() will not be called unless the timer is
* restarted with up_timer_start().
*
* If, as a race condition, the timer has already expired when this
* function is called, then that pending interrupt must be cleared so
* that up_timer_start() and the remaining time of zero should be
* returned.
*
* NOTE: This function may execute at a high rate with no timer running (as
* when pre-emption is enabled and disabled).
*
* Provided by platform-specific code and called from the RTOS base code.
*
* Input Parameters:
* ts - Location to return the remaining time. Zero should be returned
* if the timer is not active. ts may be zero in which case the
* time remaining is not returned.
*
* Returned Value:
* Zero (OK) is returned on success. A call to up_timer_cancel() when
* the timer is not active should also return success; a negated errno
* value is returned on any failure.
*
* Assumptions:
* May be called from interrupt level handling or from the normal tasking
* level. Interrupts may need to be disabled internally to assure
* non-reentrancy.
*
****************************************************************************/
int IRAM_ATTR up_timer_cancel(FAR struct timespec *ts)
{
uint64_t alarm_value;
uint64_t counter;
irqstate_t flags;
flags = enter_critical_section();
if (ts != NULL)
{
if (g_timer_started == false)
{
ts->tv_sec = 0;
ts->tv_nsec = 0;
}
else
{
alarm_value = up_tmr_getalarmvalue();
counter = up_tmr_getcounter();
if (alarm_value <= counter)
{
alarm_value = 0;
}
else
{
alarm_value -= counter;
}
ts->tv_sec = CTICK_2_SEC(alarm_value);
ts->tv_nsec = CTICK_2_NSEC(alarm_value % CTICK_PER_SEC);
}
}
g_timer_started = false;
REG_CLR_BIT(SYS_TIMER_SYSTIMER_CONF_REG, SYS_TIMER_TARGET0_WORK_EN);
REG_CLR_BIT(SYS_TIMER_SYSTIMER_INT_ENA_REG, SYS_TIMER_TARGET0_INT_ENA);
REG_SET_BIT(SYS_TIMER_SYSTIMER_INT_CLR_REG, SYS_TIMER_TARGET0_INT_CLR);
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: up_timer_start
*
* Description:
* Start the interval timer. nxsched_timer_expiration() will be
* called at the completion of the timeout (unless up_timer_cancel
* is called to stop the timing.
*
* Provided by platform-specific code and called from the RTOS base code.
*
* Input Parameters:
* ts - Provides the time interval until nxsched_timer_expiration() is
* called.
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
*
* Assumptions:
* May be called from interrupt level handling or from the normal tasking
* level. Interrupts may need to be disabled internally to assure
* non-reentrancy.
*
****************************************************************************/
int IRAM_ATTR up_timer_start(FAR const struct timespec *ts)
{
uint64_t cpu_ticks;
irqstate_t flags;
flags = enter_critical_section();
if (g_timer_started == true)
{
up_timer_cancel(NULL);
}
cpu_ticks = SEC_2_CTICK((uint64_t)ts->tv_sec) +
NSEC_2_CTICK((uint64_t)ts->tv_nsec);
up_tmr_setcounter(cpu_ticks);
g_timer_started = true;
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: up_timer_initialize
*
* Description:
* Initializes all platform-specific timer facilities. This function is
* called early in the initialization sequence by up_initialize().
* On return, the current up-time should be available from
* up_timer_gettime() and the interval timer is ready for use (but not
* actively timing.
*
* Provided by platform-specific code and called from the architecture-
* specific logic.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
* Assumptions:
* Called early in the initialization sequence before any special
* concurrency protections are required.
*
****************************************************************************/
void up_timer_initialize(void)
{
int cpuint;
g_timer_started = false;
/* Enable timer clock */
setbits(SYSTEM_SYSTIMER_CLK_EN, SYSTEM_PERIP_CLK_EN0_REG);
resetbits(SYSTEM_SYSTIMER_RST, SYSTEM_PERIP_RST_EN0_REG);
setbits(SYS_TIMER_CLK_EN, SYS_TIMER_SYSTIMER_CONF_REG);
/* Stall timer when stall CPU, specially when using JTAG to debug */
setbits(SYS_TIMER_TIMER_UNIT0_CORE0_STALL_EN, SYS_TIMER_SYSTIMER_CONF_REG);
/* NOTE: Timer 0 is an internal interrupt source so we do not need to
* attach any peripheral ID to the dedicated CPU interrupt.
*/
/* Attach the timer interrupt */
cpuint = esp32c3_request_irq(ESP32C3_PERIPH_SYSTIMER_T0,
ESP32C3_INT_PRIO_DEF,
ESP32C3_INT_LEVEL);
/* Attach the timer interrupt. */
irq_attach(ESP32C3_IRQ_SYSTIMER_T0, (xcpt_t)up_timer_expire, NULL);
/* Enable the allocated CPU interrupt. */
up_enable_irq(cpuint);
}
/****************************************************************************
* Name: up_get_idletime
*
* Description:
* This function returns the idle time.
*
* Input Parameters:
* None
*
* Returned Value:
* The time in system ticks remaining for idle.
* Zero means system is busy.
*
****************************************************************************/
uint32_t IRAM_ATTR up_get_idletime(void)
{
uint32_t us;
uint64_t alarm_value;
uint64_t counter;
irqstate_t flags;
flags = enter_critical_section();
if (g_timer_started == false)
{
us = 0;
}
else
{
alarm_value = up_tmr_getalarmvalue();
counter = up_tmr_getcounter();
if (alarm_value > counter)
{
us = CTICK_2_USEC(alarm_value - counter);
}
else
{
us = 0;
}
}
leave_critical_section(flags);
return us;
}
/****************************************************************************
* Name: up_step_idletime
*
* Description:
* Add system time by idletime_us.
*
* Input Parameters:
* us - Idle time(us)
*
* Returned Value:
* None
*
****************************************************************************/
void IRAM_ATTR up_step_idletime(uint32_t us)
{
uint64_t step_counter;
uint64_t alarm_value;
irqstate_t flags;
DEBUGASSERT(g_timer_started);
flags = enter_critical_section();
alarm_value = up_tmr_getalarmvalue();
step_counter = USEC_2_CTICK((uint64_t)us) + up_tmr_getcounter();
if (step_counter > alarm_value)
{
DEBUGASSERT(0);
}
up_tmr_counter_advance(step_counter);
leave_critical_section(flags);
}
#endif /* CONFIG_SCHED_TICKLESS */

View File

@ -0,0 +1,67 @@
/****************************************************************************
* arch/risc-v/src/esp32c3/esp32c3_tickless.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_RISCV_SRC_ESP32C3_ESP32C3_TICKLESS_H
#define __ARCH_RISCV_SRC_ESP32C3_ESP32C3_TICKLESS_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdint.h>
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: up_get_idletime
*
* Description:
* This function returns the idle time.
*
* Input Parameters:
* None
*
* Returned Value:
* The time in system ticks remaining for idle.
* Zero means system is busy.
*
****************************************************************************/
uint32_t up_get_idletime(void);
/****************************************************************************
* Name: up_step_idletime
*
* Description:
* Add system time by idletime_us.
*
* Input Parameters:
* idletime_us - Idle time(us)
*
* Returned Value:
* None
*
****************************************************************************/
void up_step_idletime(uint32_t idletime_us);
#endif /* __ARCH_RISCV_SRC_ESP32C3_ESP32C3_TICKLESS_H */

View File

@ -50,6 +50,7 @@
#include <nuttx/arch.h>
#include <nuttx/wireless/wireless.h>
#include "hardware/esp32c3_rtccntl.h"
#include "hardware/esp32c3_syscon.h"
#include "esp32c3.h"
#include "esp32c3_attr.h"
@ -58,6 +59,10 @@
#include "esp32c3_rt_timer.h"
#include "esp32c3_wifi_utils.h"
#ifdef CONFIG_PM
#include "esp32c3_pm.h"
#endif
#include "espidf_wifi.h"
/****************************************************************************
@ -90,6 +95,27 @@
#define ESP_MAX_STA_CONN (4)
#define ESP_WIFI_CHANNEL (6)
#ifndef CONFIG_EXAMPLE_WIFI_LISTEN_INTERVAL
#define CONFIG_EXAMPLE_WIFI_LISTEN_INTERVAL 3
#endif
#define DEFAULT_LISTEN_INTERVAL CONFIG_EXAMPLE_WIFI_LISTEN_INTERVAL
/* CONFIG_POWER_SAVE_MODEM */
#if defined(CONFIG_EXAMPLE_POWER_SAVE_MIN_MODEM)
# define DEFAULT_PS_MODE WIFI_PS_MIN_MODEM
#elif defined(CONFIG_EXAMPLE_POWER_SAVE_MAX_MODEM)
# define DEFAULT_PS_MODE WIFI_PS_MAX_MODEM
#elif defined(CONFIG_EXAMPLE_POWER_SAVE_NONE)
# define DEFAULT_PS_MODE WIFI_PS_NONE
#else
# define DEFAULT_PS_MODE WIFI_PS_NONE
#endif
#define RTC_CLK_CAL_FRACT (19)
#define SOC_WIFI_LIGHT_SLEEP_CLK_WIDTH (12)
/****************************************************************************
* Private Types
****************************************************************************/
@ -2062,7 +2088,7 @@ static void esp_evt_work_cb(FAR void *arg)
case WIFI_ADPT_EVT_STA_START:
wlinfo("INFO: Wi-Fi sta start\n");
g_sta_connected = false;
ret = esp_wifi_set_ps(WIFI_PS_NONE);
ret = esp_wifi_set_ps(DEFAULT_PS_MODE);
if (ret)
{
wlerr("ERROR: Failed to close PS\n");
@ -2334,24 +2360,30 @@ static void esp_dport_access_stall_other_cpu_end(void)
* Name: wifi_apb80m_request
*
* Description:
* Don't support
* Take Wi-Fi lock in auto-sleep
*
****************************************************************************/
static void wifi_apb80m_request(void)
{
#ifdef CONFIG_ESP32C3_AUTO_SLEEP
esp32c3_pm_lockacquire();
#endif
}
/****************************************************************************
* Name: wifi_apb80m_release
*
* Description:
* Don't support
* Release Wi-Fi lock in auto-sleep
*
****************************************************************************/
static void wifi_apb80m_release(void)
{
#ifdef CONFIG_ESP32C3_AUTO_SLEEP
esp32c3_pm_lockrelease();
#endif
}
/****************************************************************************
@ -3419,11 +3451,26 @@ static int esp_get_time(void *t)
/****************************************************************************
* Name: esp_clk_slowclk_cal_get_wrapper
*
* Description:
* Get the calibration value of RTC slow clock
*
* Input Parameters:
* None
*
* Returned Value:
* The calibration value obtained using rtc_clk_cal
*
****************************************************************************/
static uint32_t esp_clk_slowclk_cal_get_wrapper(void)
{
return 28639;
/* The bit width of Wi-Fi light sleep clock calibration is 12 while the one
* of system is 19. It should shift 19 - 12 = 7.
*/
return (getreg32(RTC_SLOW_CLK_CAL_REG) >> (RTC_CLK_CAL_FRACT -
SOC_WIFI_LIGHT_SLEEP_CLK_WIDTH));
}
/****************************************************************************
@ -4616,6 +4663,26 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config)
return ret;
}
#if SOC_WIFI_HW_TSF
ret = esp32c3_pm_register_skip_sleep_callback(
esp_wifi_internal_is_tsf_active);
if (ret != OK)
{
wlerr("ERROR: Failed to register skip sleep callback (0x%x)", ret);
return ret;
}
ret = esp32c3_pm_register_inform_out_sleep_overhead_callback(
esp_wifi_internal_update_light_sleep_wake_ahead_time);
if (ret != OK)
{
wlerr("ERROR: Failed to register overhead callback (0x%x)", ret);
return ret;
}
esp32c3_sleep_enable_wifi_wakeup();
#endif
return 0;
}
@ -4651,6 +4718,12 @@ esp_err_t esp_wifi_deinit(void)
return ret;
}
#if SOC_WIFI_HW_TSF
esp32c3_pm_unregister_skip_sleep_callback(
esp_wifi_internal_is_tsf_active);
esp32c3_pm_unregister_inform_out_sleep_overhead_callback(
esp_wifi_internal_update_light_sleep_wake_ahead_time);
#endif
return ret;
}
@ -4793,13 +4866,6 @@ int esp_wifi_adapter_init(void)
return OK;
}
ret = esp32c3_rt_timer_init();
if (ret < 0)
{
wlerr("ERROR: Failed to initialize RT timer error=%d\n", ret);
goto errout_init_timer;
}
sq_init(&g_wifi_evt_queue);
#ifdef CONFIG_ESP32C3_WIFI_SAVE_PARAM
@ -4867,8 +4933,6 @@ int esp_wifi_adapter_init(void)
errout_init_txdone:
esp_wifi_deinit();
errout_init_wifi:
esp32c3_rt_timer_deinit();
errout_init_timer:
esp_wifi_lock(false);
return ret;
}
@ -5145,6 +5209,7 @@ int esp_wifi_sta_password(struct iwreq *iwr, bool set)
memcpy(wifi_cfg.sta.password, pdata, len);
wifi_cfg.sta.pmf_cfg.capable = true;
wifi_cfg.sta.listen_interval = DEFAULT_LISTEN_INTERVAL;
ret = esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg);
if (ret)

View File

@ -117,4 +117,4 @@ int esp_wifi_scan_init(void);
#undef EXTERN
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_XTENSA_SRC_ESP32_ESP32_UTILS_H */
#endif /* __ARCH_RISCV_SRC_ESP32C3_ESP32C3_UTILS_H */

View File

@ -35,6 +35,8 @@
#define APB_CTRL_MEM_POWER_UP_REG (DR_REG_APB_CTRL_BASE + 0x0AC)
#define APB_CTRL_RETENTION_CTRL_REG (DR_REG_APB_CTRL_BASE + 0x0A0)
/* APB_CTRL_DC_MEM_FORCE_PU : R/W ;bitpos:[4] ;default: 1'b1 ; */
#define APB_CTRL_DC_MEM_FORCE_PU (BIT(4))
@ -70,4 +72,11 @@
#define APB_CTRL_ROM_POWER_UP_V 0x3
#define APB_CTRL_ROM_POWER_UP_S 0
/* APB_CTRL_RETENTION_LINK_ADDR : R/W ;bitpos:[26:0] ;default: 27'd0 ; */
#define APB_CTRL_RETENTION_LINK_ADDR 0x07FFFFFF
#define APB_CTRL_RETENTION_LINK_ADDR_M ((APB_CTRL_RETENTION_LINK_ADDR_V)<<(APB_CTRL_RETENTION_LINK_ADDR_S))
#define APB_CTRL_RETENTION_LINK_ADDR_V 0x7FFFFFF
#define APB_CTRL_RETENTION_LINK_ADDR_S 0
#endif /* __ARCH_RISCV_SRC_ESP32C3_HARDWARE_APB_CTRL_REG_H_ */

View File

@ -3615,4 +3615,13 @@
#define RTC_CNTL_CNTL_DATE_V 0xFFFFFFF
#define RTC_CNTL_CNTL_DATE_S 0
#define RTC_SLOW_CLK_CAL_REG RTC_CNTL_STORE1_REG
#define RTC_BOOT_TIME_LOW_REG RTC_CNTL_STORE2_REG
#define RTC_BOOT_TIME_HIGH_REG RTC_CNTL_STORE3_REG
#define RTC_XTAL_FREQ_REG RTC_CNTL_STORE4_REG
#define RTC_APB_FREQ_REG RTC_CNTL_STORE5_REG
#define RTC_ENTRY_ADDR_REG RTC_CNTL_STORE6_REG
#define RTC_RESET_CAUSE_REG RTC_CNTL_STORE6_REG
#define RTC_MEMORY_CRC_REG RTC_CNTL_STORE7_REG
#endif /* __ARCH_RISCV_SRC_ESP32C3_HARDWARE_ESP32C3_RTCCNTL_H */

View File

@ -303,4 +303,7 @@
#define REG_SET_FIELD(_r, _f, _v) (REG_WRITE((_r),((REG_READ(_r) & ~((_f##_V) << (_f##_S)))|(((_v) & (_f##_V))<<(_f##_S)))))
#define SOC_SYSTIMER_BIT_WIDTH_LO (32) /* Bit width of systimer low part */
#define SOC_SYSTIMER_BIT_WIDTH_HI (20) /* Bit width of systimer high part */
#endif /* __ARCH_RISCV_SRC_ESP32C3_HARDWARE_ESP32C3_SOC_H */

View File

@ -0,0 +1,68 @@
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_NSH_ARGCAT is not set
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
# CONFIG_NSH_CMDPARMS is not set
CONFIG_ARCH="risc-v"
CONFIG_ARCH_BOARD="esp32c3-devkit"
CONFIG_ARCH_BOARD_ESP32C3_DEVKIT=y
CONFIG_ARCH_CHIP="esp32c3"
CONFIG_ARCH_CHIP_ESP32C3=y
CONFIG_ARCH_CHIP_ESP32C3WROOM02=y
CONFIG_ARCH_INTERRUPTSTACK=1536
CONFIG_ARCH_RISCV=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARD_LOOPSPERMSEC=16717
CONFIG_BUILTIN=y
CONFIG_DRIVERS_IEEE80211=y
CONFIG_DRIVERS_WIRELESS=y
CONFIG_ESP32C3_AUTO_SLEEP=y
CONFIG_ESP32C3_WIRELESS=y
CONFIG_EXAMPLE_POWER_SAVE_MIN_MODEM=y
CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_IDLETHREAD_STACKSIZE=3072
CONFIG_INTELHEX_BINARY=y
CONFIG_LIBC_FLOATINGPOINT=y
CONFIG_NAME_MAX=48
CONFIG_NETDB_DNSCLIENT=y
CONFIG_NETDEV_LATEINIT=y
CONFIG_NETDEV_PHY_IOCTL=y
CONFIG_NETDEV_WIRELESS_IOCTL=y
CONFIG_NETINIT_DHCPC=y
CONFIG_NET_BROADCAST=y
CONFIG_NET_ETH_PKTSIZE=1514
CONFIG_NET_ICMP=y
CONFIG_NET_ICMP_SOCKET=y
CONFIG_NET_SOCKOPTS=y
CONFIG_NET_TCP=y
CONFIG_NET_UDP=y
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_LINELEN=64
CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_PTHREAD_MUTEX_TYPES=y
CONFIG_RAW_BINARY=y
CONFIG_SCHED_LPWORK=y
CONFIG_SCHED_WAITPID=y
CONFIG_SIG_DEFAULT=y
CONFIG_START_DAY=6
CONFIG_START_MONTH=12
CONFIG_START_YEAR=2011
CONFIG_SYSTEM_DHCPC_RENEW=y
CONFIG_SYSTEM_NSH=y
CONFIG_SYSTEM_PING=y
CONFIG_UART0_SERIAL_CONSOLE=y
CONFIG_USER_ENTRYPOINT="nsh_main"
CONFIG_WIRELESS=y
CONFIG_WIRELESS_WAPI=y
CONFIG_WIRELESS_WAPI_CMDTOOL=y
CONFIG_WIRELESS_WAPI_STACKSIZE=4096

View File

@ -0,0 +1,44 @@
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_NSH_ARGCAT is not set
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
# CONFIG_NSH_CMDPARMS is not set
CONFIG_ARCH="risc-v"
CONFIG_ARCH_BOARD="esp32c3-devkit"
CONFIG_ARCH_BOARD_ESP32C3_DEVKIT=y
CONFIG_ARCH_CHIP="esp32c3"
CONFIG_ARCH_CHIP_ESP32C3=y
CONFIG_ARCH_CHIP_ESP32C3WROOM02=y
CONFIG_ARCH_INTERRUPTSTACK=1536
CONFIG_ARCH_RISCV=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARD_LOOPSPERMSEC=15000
CONFIG_BUILTIN=y
CONFIG_DEV_ZERO=y
CONFIG_ESP32C3_TICKLESS=y
CONFIG_FS_PROCFS=y
CONFIG_IDLETHREAD_STACKSIZE=2048
CONFIG_INTELHEX_BINARY=y
CONFIG_LIBC_PERROR_STDOUT=y
CONFIG_LIBC_STRERROR=y
CONFIG_MAX_TASKS=16
CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_NSH_STRERROR=y
CONFIG_PREALLOC_TIMERS=0
CONFIG_RAW_BINARY=y
CONFIG_SCHED_WAITPID=y
CONFIG_START_DAY=29
CONFIG_START_MONTH=11
CONFIG_START_YEAR=2019
CONFIG_SYSTEM_NSH=y
CONFIG_UART0_SERIAL_CONSOLE=y
CONFIG_USER_ENTRYPOINT="nsh_main"

View File

@ -46,10 +46,16 @@
# include "esp32c3_spi.h"
#endif
#ifdef CONFIG_ESP32C3_RT_TIMER
# include "esp32c3_rt_timer.h"
#endif
#ifdef CONFIG_TIMER
# include "esp32c3_tim_lowerhalf.h"
#endif
#include "esp32c3_rtc.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@ -250,6 +256,14 @@ int esp32c3_bringup(void)
#endif /* CONFIG_ONESHOT */
#ifdef CONFIG_ESP32C3_RT_TIMER
ret = esp32c3_rt_timer_init();
if (ret < 0)
{
syslog(LOG_ERR, "Failed to initialize RT timer: %d\n", ret);
}
#endif
#ifdef CONFIG_ESP32C3_WIRELESS
#ifdef CONFIG_ESP32C3_WIFI_SAVE_PARAM