From 8f551616f53f2d259fac37a89e35d8e42f4841f8 Mon Sep 17 00:00:00 2001 From: Nathael Pajani Date: Sun, 30 Jan 2022 04:25:51 +0100 Subject: [PATCH] Adding self-wakeup timer support --- core/system.c | 130 ++++++++++++++++++++++++++++++++++++++++++ include/core/pmu.h | 26 ++++++--- include/core/system.h | 84 +++++++++++++++++++++++++++ 3 files changed, 232 insertions(+), 8 deletions(-) diff --git a/core/system.c b/core/system.c index 2f0ff33..09ec18f 100644 --- a/core/system.c +++ b/core/system.c @@ -32,6 +32,7 @@ #include "core/lpc_regs.h" #include "core/lpc_core.h" #include "core/system.h" +#include "core/pmu.h" /* Private defines */ @@ -44,11 +45,15 @@ struct lpc_desc_private { uint32_t main_clock; uint8_t brown_out_detection_enabled; uint8_t need_IRC; + uint8_t need_watchdog; + uint8_t need_self_wakeup_timer; }; static struct lpc_desc_private lpc_private = { .main_clock = LPC_IRC_OSC_CLK, .brown_out_detection_enabled = 0, .need_IRC = 1, + .need_watchdog = 0, + .need_self_wakeup_timer = 0, }; /***************************************************************************** */ @@ -79,6 +84,30 @@ uint8_t system_brown_out_detection_enabled(void) return lpc_private.brown_out_detection_enabled; } +/* Store the watchdog requirement info */ +void system_need_watchdog(uint8_t val) +{ + lpc_private.need_watchdog = val; +} + +/* Return the status of watchdog config */ +uint8_t system_watchdog_enabled(void) +{ + return lpc_private.need_watchdog; +} + +/* Store the Self Wakeup timer requirement info */ +void system_need_self_wakeup_timer(uint8_t val) +{ + lpc_private.need_self_wakeup_timer = val; +} + +/* Return the status of Self Wakeup timer config */ +uint8_t system_self_wakeup_timer_enabled(void) +{ + return lpc_private.need_self_wakeup_timer; +} + /***************************************************************************** */ /* Power */ @@ -130,6 +159,22 @@ void subsystem_reset(uint32_t reset_bit) subsystem_reset_release(reset_bit); } + +/***************************************************************************** */ +/* Start logic */ +/***************************************************************************** */ +void enable_pin_intr_wake_source(uint32_t src) +{ + struct lpc_sys_config* sys_config = LPC_SYS_CONFIG; + sys_config->start_log_ctrl[0].wakeup_en |= src; +} +void enable_intr_wake_source(uint32_t src) +{ + struct lpc_sys_config* sys_config = LPC_SYS_CONFIG; + sys_config->start_log_ctrl[1].wakeup_en |= src; +} + + /***************************************************************************** */ /* System Clock */ /***************************************************************************** */ @@ -294,3 +339,88 @@ static inline void def_usleep(uint32_t us) void msleep(uint32_t ms) __attribute__ ((weak, alias ("def_msleep"))); void usleep(uint32_t us) __attribute__ ((weak, alias ("def_usleep"))); + +/***************************************************************************** */ +/* Self Wake-up timer functions */ +/***************************************************************************** */ +/* Turn ON the Self Wake-Up timer. + * - clk_src is one of LPC_WKT_USE_IRC, LPC_WKT_USE_10KHZ or LPC_WKT_USE_PIN_CLK + * Note that LPC_WKT_USE_IRC cannot be used for waking up from deep sleep or any + * power down mode. + */ + +static void (*wkt_callback)(void) = NULL; +void WKT_Handler(void) +{ + self_wakeup_timer_clear(); + if (wkt_callback != NULL) { + wkt_callback(); + } +} + +void self_wakeup_timer_on(uint8_t clk_src, void (*callback)(void)) +{ + struct lpc_pm_unit* pmu = LPC_PMU; + struct lpc_swt_wkt* swt = LPC_SWT_WKT; + + wkt_callback = callback; + system_need_self_wakeup_timer(1); + + subsystem_power(LPC_SYS_AHB_CLK_CTRL_WKT, 1); + + subsystem_reset(LPC_WKT_RESET_N); + + switch (clk_src) { + case LPC_WKT_USE_10KHZ: + pmu->deep_power_down_ctrl = LPC_WAKEUP_PIN_DISABLE | LPC_WAKEUP_CLK_10KHZ; + swt->control = LPC_WKT_CLK_SEL_10KHZ; + break; + case LPC_WKT_USE_IRC: + /* TODO */ + break; + case LPC_WKT_USE_PIN_CLK: + /* TODO */ + break; + default: + break; + } + + /* Enable the wake-up timer interrupt as a wakeup source */ + enable_intr_wake_source(LPC_WKT_INT_WAKEUP_EN); + + /* Interrupt enable */ + NVIC_EnableIRQ(WKT_IRQ); +} + +/* Turn OFF the Self Wake-Up timer. */ +void self_wakeup_timer_off(void) +{ + NVIC_DisableIRQ(WKT_IRQ); + self_wakeup_timer_clear(); + subsystem_reset_hold(LPC_WKT_RESET_N); + subsystem_power(LPC_SYS_AHB_CLK_CTRL_WKT, 0); +} + +/* Clear both the alarm flag and the counter value, effectively stopping + * the Self Wake-Up timer + */ +void self_wakeup_timer_clear(void) +{ + struct lpc_swt_wkt* swt = LPC_SWT_WKT; + swt->control |= LPC_WKT_ALARM_FLAG | LPC_WKT_CLEAR_COUNTER; +} + + +/* Start the Self Wake-Up timer. + * - timer_val is the value loaded in the decrementer. Delay depends on the clock + * source selected by "clk_src" parameter given to self_wakeup_timer_on(). + */ +void self_wakeup_timer_start(uint32_t timer_val) +{ + struct lpc_swt_wkt* swt = LPC_SWT_WKT; + + /* Set value */ + swt->count = timer_val; +} + + diff --git a/include/core/pmu.h b/include/core/pmu.h index 19232a8..d27f8fe 100644 --- a/include/core/pmu.h +++ b/include/core/pmu.h @@ -64,19 +64,29 @@ int read_gp_retain(uint32_t* values, uint8_t nb, uint8_t offset); /* Power Management Unit (PMU) */ struct lpc_pm_unit { - volatile uint32_t power_ctrl; /* 0x000 : Power control Register (R/W) */ - volatile uint32_t gp_data[4]; /* 0x004 to 0x010 : General purpose Register 0 to 3 (R/W) */ - volatile uint32_t deep_power_down_ctrl; /* 0x014 : Deep power down control register (R/W) */ + volatile uint32_t power_ctrl; /* 0x000 : PCON - Power control Register (R/W) */ + volatile uint32_t gp_data[4]; /* 0x004 to 0x010 : GPREG - General purpose Register 0 to 3 (R/W) */ + volatile uint32_t deep_power_down_ctrl; /* 0x014 : DPDCTRL - Deep power down control register (R/W) */ /* (WAKEUP pin control) */ }; #define LPC_PMU ((struct lpc_pm_unit *) LPC_PMU_BASE) -/* System config register */ -#define LPC_WAKEUP_PIN_HYST_MASK (0x01 << 10) -#define LPC_RTC_CLK_SRC_SHIFT 11 -#define LPC_RTC_CLK_SRC_MASK (0x0F << LPC_RTC_CLK_SRC_SHIFT) -/* See RTC section above for RTC Clock source selection bits */ +/* Power control register fields (PCON) */ +#define LPC_PM_DEFAULT 0x00 +#define LPC_PM_DEEP_SLEEP 0x01 +#define LPC_PM_POWER_DOWN 0x02 +#define LPC_PM_DEEP_POWER_DOWN 0x03 +#define LPC_PM_NO_DPD (0x01 << 3) + + +/* Deep power down control register fields */ +#define LPC_WAKEUP_PIN_HYST (0x01 << 0) +#define LPC_WAKEUP_PIN_DISABLE (0x01 << 1) +#define LPC_WAKEUP_CLK_10KHZ (0x01 << 2) +#define LPC_WAKEUP_LPOSC_IN_DPD (0x01 << 3) +#define LPC_WAKEUP_CLK_PIN_HYST (0x01 << 4) +#define LPC_WAKEUP_CLK_PIN_EN (0x01 << 5) #endif /* LPC_PMU_H */ diff --git a/include/core/system.h b/include/core/system.h index cba038a..aeb913c 100644 --- a/include/core/system.h +++ b/include/core/system.h @@ -57,6 +57,19 @@ void system_brown_out_detection_config(uint32_t level); /* Return the status of brown out detection config */ uint8_t system_brown_out_detection_enabled(void); +/* Store the watchdog requirement info */ +void system_need_watchdog(uint8_t val); + +/* Return the status of watchdog config */ +uint8_t system_watchdog_enabled(void); + +/* Store the Self Wakeup timer requirement info */ +void system_need_self_wakeup_timer(uint8_t val); + +/* Return the status of Self Wakeup timer config */ +uint8_t system_self_wakeup_timer_enabled(void); + + /***************************************************************************** */ /* System Clock */ /***************************************************************************** */ @@ -257,6 +270,77 @@ struct lpc_sys_config /* Pin interrupt wakeup enable */ #define LPC_PINT_WAKEUP_EN(x) (1 << (x)) +/* Interrupt sources wakeup enable */ +#define LPC_SPI0_INT_WAKEUP_EN (1 << 0) +#define LPC_SPI1_INT_WAKEUP_EN (1 << 1) +#define LPC_USART0_INT_WAKEUP_EN (1 << 3) +#define LPC_USART1_INT_WAKEUP_EN (1 << 4) +#define LPC_USART2_INT_WAKEUP_EN (1 << 5) +#define LPC_I2C1_INT_WAKEUP_EN (1 << 7) +#define LPC_I2C0_INT_WAKEUP_EN (1 << 8) +#define LPC_WWDT_INT_WAKEUP_EN (1 << 12) +#define LPC_BOD_INT_WAKEUP_EN (1 << 13) +#define LPC_WKT_INT_WAKEUP_EN (1 << 15) +#define LPC_I2C2_INT_WAKEUP_EN (1 << 21) +#define LPC_I2C3_INT_WAKEUP_EN ((1 << 31) || (1 << 22)) + +void enable_intr_wake_source(uint32_t src); +void enable_pin_intr_wake_source(uint32_t src); + + +#define LPC_RTC_CLK_SRC_SHIFT 11 +#define LPC_RTC_CLK_SRC_MASK (0x0F << LPC_RTC_CLK_SRC_SHIFT) +/* See RTC section above for RTC Clock source selection bits */ + + + +/***************************************************************************** */ +/* Self WakeUp Timer */ +/***************************************************************************** */ + +/* Self Wake-Up Timer (SWT or WKT) */ +struct lpc_swt_wkt +{ + volatile uint32_t control; /* 0x000 : CTRL - Control Register (R/W) */ + volatile uint32_t unused[2]; + volatile uint32_t count; /* 0x00C : COUNT - Count register (-/W) */ +}; +#define LPC_SWT_WKT ((struct lpc_swt_wkt *) LPC_SWT_BASE) + +/* Wake-Up timer */ +#define LPC_WKT_CLK_SEL_IRC (0x00 << 0) +#define LPC_WKT_CLK_SEL_10KHZ (0x01 << 0) +#define LPC_WKT_ALARM_FLAG (0x01 << 1) +#define LPC_WKT_CLEAR_COUNTER (0x01 << 2) +#define LPC_WKT_EXT_CLK_SEL (0x01 << 3) + +/* Helpers, unrelated to registers */ +#define LPC_WKT_USE_IRC 1 +#define LPC_WKT_USE_10KHZ 2 +#define LPC_WKT_USE_PIN_CLK 3 + +/* Turn ON the Self Wake-Up timer. + * - clk_src is one of LPC_WKT_USE_IRC, LPC_WKT_USE_10KHZ or LPC_WKT_USE_PIN_CLK + * Note that LPC_WKT_USE_IRC cannot be used for waking up from deep sleep or any + * power down mode. + */ +void self_wakeup_timer_on(uint8_t clk_src, void (*callback)(void)); + +/* Turn OFF the Self Wake-Up timer. */ +void self_wakeup_timer_off(void); + +/* Clear both the alarm flag and the counter value, effectively stopping + * the Self Wake-Up timer + */ +void self_wakeup_timer_clear(void); + +/* Start the Self Wake-Up timer. + * - timer_val is the value loaded in the decrementer. Delay depends on the clock + * source selected by "clk_src" parameter given to self_wakeup_timer_on(). + */ +void self_wakeup_timer_start(uint32_t timer_val); + + /***************************************************************************** */ /* Flash Control */ -- 2.43.0