cpu/esp8266: add RTT implementation
This commit is contained in:
parent
d281d4843f
commit
464e3a8741
@ -3,3 +3,4 @@
|
|||||||
include $(RIOTCPU)/esp_common/Makefile.features
|
include $(RIOTCPU)/esp_common/Makefile.features
|
||||||
|
|
||||||
FEATURES_PROVIDED += arch_esp8266
|
FEATURES_PROVIDED += arch_esp8266
|
||||||
|
FEATURES_PROVIDED += periph_rtt
|
||||||
|
|||||||
@ -27,6 +27,12 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Memory marked with this attribute is retained during deep sleep
|
||||||
|
*/
|
||||||
|
#define BACKUP_RAM __attribute__((section(".rtc.bss")))
|
||||||
|
#define BACKUP_RAM_DATA __attribute__((section(".rtc.data")))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Length of the CPU_ID in octets
|
* @brief Length of the CPU_ID in octets
|
||||||
*/
|
*/
|
||||||
@ -217,6 +223,14 @@ typedef struct {
|
|||||||
#define RNG_DATA_REG_ADDR (0x3ff20e44)
|
#define RNG_DATA_REG_ADDR (0x3ff20e44)
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name RTT and RTC configuration
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define RTT_FREQUENCY (312500UL)
|
||||||
|
#define RTT_MAX_VALUE (0xFFFFFFFFUL)
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name SPI configuration
|
* @name SPI configuration
|
||||||
*
|
*
|
||||||
|
|||||||
@ -61,6 +61,7 @@ extern "C" {
|
|||||||
|
|
||||||
#define CONFIG_TASK_WDT_PANIC
|
#define CONFIG_TASK_WDT_PANIC
|
||||||
#define CONFIG_TASK_WDT_TIMEOUT_S (15)
|
#define CONFIG_TASK_WDT_TIMEOUT_S (15)
|
||||||
|
#define CONFIG_RESET_REASON (1)
|
||||||
|
|
||||||
#define CONFIG_WIFI_PPT_TASKSTACK_SIZE (3584)
|
#define CONFIG_WIFI_PPT_TASKSTACK_SIZE (3584)
|
||||||
#define CONFIG_MAIN_TASK_STACK_SIZE (2048)
|
#define CONFIG_MAIN_TASK_STACK_SIZE (2048)
|
||||||
|
|||||||
@ -4,6 +4,7 @@ PROVIDE ( uart0 = 0x60000000 );
|
|||||||
PROVIDE ( uart1 = 0x60000f00 );
|
PROVIDE ( uart1 = 0x60000f00 );
|
||||||
|
|
||||||
PROVIDE ( frc1 = 0x60000600 );
|
PROVIDE ( frc1 = 0x60000600 );
|
||||||
|
PROVIDE ( frc2 = 0x60000620 );
|
||||||
|
|
||||||
PROVIDE ( rtc_sys_info = 0x60001100 );
|
PROVIDE ( rtc_sys_info = 0x60001100 );
|
||||||
|
|
||||||
|
|||||||
@ -84,6 +84,13 @@ SECTIONS
|
|||||||
_rtc_data_end = ABSOLUTE(.);
|
_rtc_data_end = ABSOLUTE(.);
|
||||||
} > rtc_seg
|
} > rtc_seg
|
||||||
|
|
||||||
|
.rtc.bss :
|
||||||
|
{
|
||||||
|
_rtc_bss_start = ABSOLUTE(.);
|
||||||
|
*(.rtc.bss)
|
||||||
|
_rtc_bss_end = ABSOLUTE(.);
|
||||||
|
} > rtc_seg
|
||||||
|
|
||||||
.data : ALIGN(4)
|
.data : ALIGN(4)
|
||||||
{
|
{
|
||||||
_data_start = ABSOLUTE(.);
|
_data_start = ABSOLUTE(.);
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
void pm_set_lowest(void)
|
void pm_set_lowest(void)
|
||||||
{
|
{
|
||||||
DEBUG ("%s enter to sleep @%u\n", __func__, system_get_time());
|
DEBUG("%s enter to sleep @%u\n", __func__, system_get_time());
|
||||||
|
|
||||||
/* reset system watchdog timer */
|
/* reset system watchdog timer */
|
||||||
system_wdt_feed();
|
system_wdt_feed();
|
||||||
@ -36,7 +36,7 @@ void pm_set_lowest(void)
|
|||||||
__asm__ volatile ("waiti 0");
|
__asm__ volatile ("waiti 0");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DEBUG ("%s exit from sleep @%u\n", __func__, system_get_time());
|
DEBUG("%s exit from sleep @%u\n", __func__, system_get_time());
|
||||||
|
|
||||||
/* reset system watchdog timer */
|
/* reset system watchdog timer */
|
||||||
system_wdt_feed();
|
system_wdt_feed();
|
||||||
@ -44,13 +44,19 @@ void pm_set_lowest(void)
|
|||||||
|
|
||||||
void pm_off(void)
|
void pm_off(void)
|
||||||
{
|
{
|
||||||
DEBUG ("%s\n", __func__);
|
DEBUG("%s\n", __func__);
|
||||||
system_deep_sleep(0);
|
system_deep_sleep(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pm_reboot(void)
|
void pm_reboot(void)
|
||||||
{
|
{
|
||||||
DEBUG ("%s\n", __func__);
|
DEBUG("%s\n", __func__);
|
||||||
|
|
||||||
|
#ifdef MODULE_PERIPH_RTT
|
||||||
|
/* save counters */
|
||||||
|
extern void rtt_save_counter(void);
|
||||||
|
rtt_save_counter();
|
||||||
|
#endif
|
||||||
|
|
||||||
/* shut down WIFI and call system_restart_local after timer */
|
/* shut down WIFI and call system_restart_local after timer */
|
||||||
system_restart ();
|
system_restart ();
|
||||||
|
|||||||
233
cpu/esp8266/periph/rtt.c
Normal file
233
cpu/esp8266/periph/rtt.c
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Gunar Schorcht
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup cpu_esp8266
|
||||||
|
* @ingroup drivers_periph_rtt
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Low-level RTT driver implementation for ESP8266
|
||||||
|
*
|
||||||
|
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ENABLE_DEBUG (0)
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "cpu.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "periph/rtt.h"
|
||||||
|
|
||||||
|
#include "esp/common_macros.h"
|
||||||
|
#include "esp/dport_regs.h"
|
||||||
|
#include "esp/rtc_regs.h"
|
||||||
|
#include "sdk/sdk.h"
|
||||||
|
|
||||||
|
#define FRC2_CLK_DIV_256 2 /* divider for the 80 MHz AHB clock */
|
||||||
|
|
||||||
|
#define RTC_BSS_ATTR __attribute__((section(".rtc.bss")))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FRC2 is a 32-bit countup timer, triggers interrupt when reaches alarm value.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t load;
|
||||||
|
uint32_t count;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint32_t intr_hold : 1;
|
||||||
|
uint32_t reserved1 : 1;
|
||||||
|
uint32_t clk_div : 2;
|
||||||
|
uint32_t reserved2 : 2;
|
||||||
|
uint32_t reload : 1;
|
||||||
|
uint32_t enable : 1;
|
||||||
|
uint32_t intr_sta : 1;
|
||||||
|
uint32_t reserved3 : 23;
|
||||||
|
};
|
||||||
|
uint32_t val;
|
||||||
|
} ctrl;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint32_t clear : 1;
|
||||||
|
uint32_t reserved1: 31;
|
||||||
|
};
|
||||||
|
uint32_t val;
|
||||||
|
} intr;
|
||||||
|
uint32_t alarm;
|
||||||
|
} frc2_struct_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* linker script esp8266.peripherals.ld will make sure this points to the
|
||||||
|
* hardware register address
|
||||||
|
*/
|
||||||
|
extern volatile frc2_struct_t frc2;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t alarm; /**< alarm */
|
||||||
|
rtt_cb_t alarm_cb; /**< alarm callback */
|
||||||
|
rtt_cb_t overflow_cb; /**< overflow callback */
|
||||||
|
void *alarm_arg; /**< argument for alarm callback */
|
||||||
|
void *overflow_arg; /**< argument for overflow callback */
|
||||||
|
} rtt_config_t;
|
||||||
|
|
||||||
|
static rtt_config_t rtt_config;
|
||||||
|
|
||||||
|
static uint32_t RTC_BSS_ATTR _rtt_counter_saved;
|
||||||
|
static uint32_t RTC_BSS_ATTR _rtc_counter_saved;
|
||||||
|
|
||||||
|
extern uint32_t pm_rtc_clock_cali_proc(void);
|
||||||
|
extern uint32_t pm_rtc2usec(uint32_t rtc_cycles, uint32_t period);
|
||||||
|
|
||||||
|
void rtt_restore_counter(void);
|
||||||
|
|
||||||
|
void IRAM rtt_cb(void *arg)
|
||||||
|
{
|
||||||
|
/* triggered alarm */
|
||||||
|
uint32_t alarm = frc2.alarm;
|
||||||
|
|
||||||
|
if (alarm == rtt_config.alarm) {
|
||||||
|
rtt_cb_t alarm_cb = rtt_config.alarm_cb;
|
||||||
|
void * alarm_arg = rtt_config.alarm_arg;
|
||||||
|
/* clear the alarm first (includes setting next alarm to overflow) */
|
||||||
|
rtt_clear_alarm();
|
||||||
|
/* call the alarm handler afterwards if callback was defined*/
|
||||||
|
if (alarm_cb) {
|
||||||
|
alarm_cb(alarm_arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alarm == 0) {
|
||||||
|
/* set next alarm which is either an alarm if configured or overflow */
|
||||||
|
frc2.alarm = rtt_config.alarm;
|
||||||
|
/* call the overflow handler if configured */
|
||||||
|
if (rtt_config.overflow_cb) {
|
||||||
|
rtt_config.overflow_cb(rtt_config.overflow_arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtt_init(void)
|
||||||
|
{
|
||||||
|
DEBUG("%s saved rtt=%u rtc=%u\n",
|
||||||
|
__func__, _rtt_counter_saved, _rtc_counter_saved);
|
||||||
|
|
||||||
|
frc2.ctrl.clk_div = FRC2_CLK_DIV_256;
|
||||||
|
frc2.ctrl.reload = 0;
|
||||||
|
frc2.ctrl.intr_hold = 0;
|
||||||
|
frc2.ctrl.enable = 1;
|
||||||
|
|
||||||
|
/* initialize rtt_config structure after reboot or deep sleep */
|
||||||
|
rtt_clear_alarm();
|
||||||
|
rtt_clear_overflow_cb();
|
||||||
|
|
||||||
|
if (_rtt_counter_saved || _rtc_counter_saved) {
|
||||||
|
/* if not in init after power on, restore the RTT counter value */
|
||||||
|
rtt_restore_counter();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
frc2.load = 0;
|
||||||
|
DEBUG("%s after power on\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* emulate overflow interrupt */
|
||||||
|
frc2.alarm = 0;
|
||||||
|
|
||||||
|
ets_isr_attach (ETS_FRC2_INUM, rtt_cb, NULL);
|
||||||
|
ets_isr_unmask (BIT(ETS_FRC2_INUM));
|
||||||
|
DPORT.INT_ENABLE |= DPORT_INT_ENABLE_FRC2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtt_poweron(void)
|
||||||
|
{
|
||||||
|
/* power on simply reactivates the FRC2 counter */
|
||||||
|
frc2.ctrl.enable = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtt_poweroff(void)
|
||||||
|
{
|
||||||
|
/* power off simply deactivates the FRC2 counter */
|
||||||
|
frc2.ctrl.enable = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtt_set_overflow_cb(rtt_cb_t cb, void *arg)
|
||||||
|
{
|
||||||
|
/* there is no overflow interrupt, we emulate */
|
||||||
|
rtt_config.overflow_cb = cb;
|
||||||
|
rtt_config.overflow_arg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtt_clear_overflow_cb(void)
|
||||||
|
{
|
||||||
|
/* there is no overflow interrupt, we emulate */
|
||||||
|
rtt_config.overflow_cb = NULL;
|
||||||
|
rtt_config.overflow_arg = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rtt_get_counter(void)
|
||||||
|
{
|
||||||
|
return frc2.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtt_set_counter(uint32_t counter)
|
||||||
|
{
|
||||||
|
frc2.load = counter;
|
||||||
|
|
||||||
|
if (counter > frc2.alarm) {
|
||||||
|
/* overflow is the next interrupt event */
|
||||||
|
frc2.alarm = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg)
|
||||||
|
{
|
||||||
|
rtt_config.alarm = alarm;
|
||||||
|
rtt_config.alarm_cb = cb;
|
||||||
|
rtt_config.alarm_arg = arg;
|
||||||
|
|
||||||
|
if (frc2.count < alarm) {
|
||||||
|
frc2.alarm = alarm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rtt_get_alarm(void)
|
||||||
|
{
|
||||||
|
return rtt_config.alarm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtt_clear_alarm(void)
|
||||||
|
{
|
||||||
|
frc2.alarm = 0;
|
||||||
|
rtt_config.alarm = 0;
|
||||||
|
rtt_config.alarm_cb = NULL;
|
||||||
|
rtt_config.alarm_arg = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtt_save_counter(void)
|
||||||
|
{
|
||||||
|
/* save counters before going to sleep or reboot */
|
||||||
|
_rtt_counter_saved = frc2.count;
|
||||||
|
_rtc_counter_saved = RTC.COUNTER;
|
||||||
|
|
||||||
|
DEBUG("%s saved rtt=%u rtc=%u\n",
|
||||||
|
__func__, _rtt_counter_saved, _rtc_counter_saved);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtt_restore_counter(void)
|
||||||
|
{
|
||||||
|
uint32_t rtc_diff = RTC.COUNTER - _rtc_counter_saved;
|
||||||
|
uint32_t rtc_diff_us = pm_rtc2usec(rtc_diff, pm_rtc_clock_cali_proc());
|
||||||
|
uint32_t rtt_diff = RTT_US_TO_TICKS(rtc_diff_us);
|
||||||
|
|
||||||
|
frc2.load = _rtt_counter_saved + rtt_diff;
|
||||||
|
|
||||||
|
DEBUG("%s rtc_diff=%u rtt_diff=%u load=%u\n", __func__,
|
||||||
|
rtc_diff, rtt_diff, _rtt_counter_saved + rtt_diff);
|
||||||
|
}
|
||||||
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include "esp/common_macros.h"
|
#include "esp/common_macros.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_system.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "stdio_base.h"
|
#include "stdio_base.h"
|
||||||
#include "syscalls.h"
|
#include "syscalls.h"
|
||||||
@ -50,6 +51,13 @@ extern uint32_t hwrand (void);
|
|||||||
|
|
||||||
void esp_riot_init(void)
|
void esp_riot_init(void)
|
||||||
{
|
{
|
||||||
|
/* clear RTC bss data */
|
||||||
|
extern uint8_t _rtc_bss_start, _rtc_bss_end;
|
||||||
|
esp_reset_reason_t reset_reason = esp_reset_reason();
|
||||||
|
if (reset_reason != ESP_RST_DEEPSLEEP && reset_reason != ESP_RST_SW) {
|
||||||
|
memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start));
|
||||||
|
}
|
||||||
|
|
||||||
/* enable cached read from flash */
|
/* enable cached read from flash */
|
||||||
Cache_Read_Enable_New();
|
Cache_Read_Enable_New();
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
static const char *TAG = "reset_reason";
|
static const char *TAG = "reset_reason";
|
||||||
static uint32_t s_reset_reason;
|
static uint32_t s_reset_reason;
|
||||||
|
|
||||||
static inline void esp_reset_reason_clear_hint()
|
static inline void esp_reset_reason_clear_hint(void)
|
||||||
{
|
{
|
||||||
rtc_sys_info.hint = 0;
|
rtc_sys_info.hint = 0;
|
||||||
}
|
}
|
||||||
@ -46,7 +46,7 @@ static inline uint32_t esp_reset_reason_get_hint(uint32_t hw_reset)
|
|||||||
if (hw_reset == POWERON_RESET && rtc_sys_info.hint != ESP_RST_SW) {
|
if (hw_reset == POWERON_RESET && rtc_sys_info.hint != ESP_RST_SW) {
|
||||||
uint32_t *p = (uint32_t *)&rtc_sys_info;
|
uint32_t *p = (uint32_t *)&rtc_sys_info;
|
||||||
|
|
||||||
for (int i = 0; i < RTC_SYS_RAM_SIZE / sizeof(uint32_t); i++)
|
for (unsigned i = 0; i < RTC_SYS_RAM_SIZE / sizeof(uint32_t); i++)
|
||||||
*p++ = 0;
|
*p++ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,10 +73,19 @@ static inline uint32_t get_reset_reason(uint32_t rtc_reset_reason, uint32_t rese
|
|||||||
return reset_reason_hint;
|
return reset_reason_hint;
|
||||||
return ESP_RST_POWERON;
|
return ESP_RST_POWERON;
|
||||||
case EXT_RESET:
|
case EXT_RESET:
|
||||||
|
#ifdef RIOT_VERSION
|
||||||
|
if (reset_reason_hint == ESP_RST_DEEPSLEEP ||
|
||||||
|
reset_reason_hint == ESP_RST_SW ||
|
||||||
|
reset_reason_hint == ESP_RST_POWERON) {
|
||||||
|
return reset_reason_hint;
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (reset_reason_hint == ESP_RST_DEEPSLEEP) {
|
if (reset_reason_hint == ESP_RST_DEEPSLEEP) {
|
||||||
return reset_reason_hint;
|
return reset_reason_hint;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return ESP_RST_EXT;
|
return ESP_RST_EXT;
|
||||||
|
|
||||||
case SW_RESET:
|
case SW_RESET:
|
||||||
if (reset_reason_hint == ESP_RST_PANIC ||
|
if (reset_reason_hint == ESP_RST_PANIC ||
|
||||||
reset_reason_hint == ESP_RST_BROWNOUT ||
|
reset_reason_hint == ESP_RST_BROWNOUT ||
|
||||||
@ -113,7 +122,7 @@ void esp_reset_reason_init(void)
|
|||||||
esp_reset_reason_clear_hint();
|
esp_reset_reason_clear_hint();
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "RTC reset %u wakeup %u store %u, reason is %u", hw_reset, hw_wakeup, hint, s_reset_reason);
|
ESP_LOGD(TAG, "RTC reset %u wakeup %u store %u, reason is %u", hw_reset, hw_wakeup, hint, s_reset_reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user