From 6dbbc8f33a625f007c1ec752d400ee08c27f0f20 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 4 Dec 2019 03:10:16 +0100 Subject: [PATCH 1/5] cpu/lpc2387: rtc: remove _rtc_set() Calling localtime() adds considerable overhead. There are easier ways to set the date to 1970. For tests/periph_rtc this results in this ROM change: master: text data bss dec hex 31328 240 98064 129632 1fa60 with this patch: text data bss dec hex 20036 140 98168 118344 1ce48 --- cpu/lpc2387/periph/rtc.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/cpu/lpc2387/periph/rtc.c b/cpu/lpc2387/periph/rtc.c index e17f24291c..0dd2c45cfc 100644 --- a/cpu/lpc2387/periph/rtc.c +++ b/cpu/lpc2387/periph/rtc.c @@ -40,9 +40,6 @@ static rtc_alarm_cb_t _cb; /* Argument to alarm callback */ static void *_cb_arg; -/* internal function to set time based on time_t */ -static void _rtc_set(time_t time); - void RTC_IRQHandler(void) __attribute__((interrupt("IRQ"))); void rtc_init(void) @@ -56,10 +53,10 @@ void rtc_init(void) RTC_CCR = CCR_CLKSRC; /* Clock from external 32 kHz Osc. */ - /* initialize clock with valid unix compatible values - * If RTC_YEAR contains an value larger unix time_t we must reset. */ + /* initialize clock with valid unix compatible values */ if (RTC_YEAR > 2037) { - _rtc_set(0); + struct tm localt = { .tm_year = 70 }; + rtc_set_time(&localt); } rtc_poweron(); @@ -201,10 +198,3 @@ void RTC_IRQHandler(void) VICVectAddr = 0; /* Acknowledge Interrupt */ } - -static void _rtc_set(time_t time) -{ - struct tm *localt; - localt = localtime(&time); /* convert seconds to broken-down time */ - rtc_set_time(localt); -} From 80dde82c86b33c396a616c4b74f5cc33ba13796a Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 5 Dec 2019 22:09:39 +0100 Subject: [PATCH 2/5] cpu/lpc2387: clear POR bit if we woke from Deep Sleep RSIR is 0x1 (POR) if we woke from Deep Sleep. This makes it hard to distinguish between real power-on and waking from Deep Sleep, which is why the Backup RAM signature was introduced. However, calling cpu_woke_from_backup() a second time will always return true, as the signature will have been set up by early boot then. Thus, clear the POR bit if the signature was already in place. The result is: RSIR == 0 -> woke from sleep RSIR == 1 -> cold boot --- cpu/lpc2387/cpu.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cpu/lpc2387/cpu.c b/cpu/lpc2387/cpu.c index 1f5cc7a3fc..26111eb920 100644 --- a/cpu/lpc2387/cpu.c +++ b/cpu/lpc2387/cpu.c @@ -166,6 +166,11 @@ bool cpu_woke_from_backup(void) return false; } + /* When we wake from Deep Sleep only POR is set, just like in the real + * POR case. Clear the bit to create a new, distinct state. + */ + RSIR |= RSIR_POR; + return true; } From 64107dd3a95d3ca300c585a81c811b036c478e78 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 5 Dec 2019 22:30:35 +0100 Subject: [PATCH 3/5] cpu/lpc2387: rtc: only initialize RTC after cold boot or external reset On the MCB2388 plugging the power will result in both the POR and EXTR bit being set. Not sure if this is a property of the board, but it means RTC is also reset after programming, so it behaves just like Backup RAM. If we woke from Deep Sleep the POR bit will be cleared, so the RTC is not reset. --- cpu/lpc2387/periph/rtc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cpu/lpc2387/periph/rtc.c b/cpu/lpc2387/periph/rtc.c index 0dd2c45cfc..5518c1da73 100644 --- a/cpu/lpc2387/periph/rtc.c +++ b/cpu/lpc2387/periph/rtc.c @@ -53,8 +53,10 @@ void rtc_init(void) RTC_CCR = CCR_CLKSRC; /* Clock from external 32 kHz Osc. */ - /* initialize clock with valid unix compatible values */ - if (RTC_YEAR > 2037) { + /* Initialize clock to a a sane and predictable default + * after cold boot or external reset. + */ + if ((RSIR == RSIR_POR) || (RSIR == (RSIR_POR | RSIR_EXTR))) { struct tm localt = { .tm_year = 70 }; rtc_set_time(&localt); } From 76e19602a29820d0dda400b18b9587ff114a30e4 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Mon, 9 Dec 2019 15:01:57 +0100 Subject: [PATCH 4/5] cpu/lpc2387: rename cpu_woke_from_backup() The function would always return `true` after early boot, so it is not very useful for applications. Now it will only (but always) return true when we woke from Deep Sleep *after* early boot. This makes it behave the same ways as the function of the same name on SAME54. Rename the existing function to cpu_backup_ram_is_initialized() to better match it's semantics. --- cpu/arm7_common/arm7_init.c | 2 +- cpu/lpc2387/cpu.c | 2 +- cpu/lpc2387/include/cpu.h | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cpu/arm7_common/arm7_init.c b/cpu/arm7_common/arm7_init.c index 75cb2d45cf..f9619eae9d 100644 --- a/cpu/arm7_common/arm7_init.c +++ b/cpu/arm7_common/arm7_init.c @@ -88,7 +88,7 @@ static inline void _init_data(void) #ifdef CPU_HAS_BACKUP_RAM /* only initialize battery backup on cold boot */ - if (cpu_woke_from_backup()) { + if (cpu_backup_ram_is_initialized()) { return; } diff --git a/cpu/lpc2387/cpu.c b/cpu/lpc2387/cpu.c index 26111eb920..dcea9fc280 100644 --- a/cpu/lpc2387/cpu.c +++ b/cpu/lpc2387/cpu.c @@ -139,7 +139,7 @@ void cpu_init(void) /* RSIR will only have POR bit set even when waking up from Deep Power Down * Use signature in battery RAM to discriminate between Deep Power Down and POR */ -bool cpu_woke_from_backup(void) +bool cpu_backup_ram_is_initialized(void) { static char signature[] __attribute__((section(".backup.data"))) = { 'R', 'I', 'O', 'T' diff --git a/cpu/lpc2387/include/cpu.h b/cpu/lpc2387/include/cpu.h index ecc188e823..c7dd8a3fc3 100644 --- a/cpu/lpc2387/include/cpu.h +++ b/cpu/lpc2387/include/cpu.h @@ -60,7 +60,14 @@ static inline void cpu_print_last_instruction(void) /** * @brief Returns true if the CPU woke from Deep Sleep */ -bool cpu_woke_from_backup(void); +static inline bool cpu_woke_from_backup(void) { + return RSIR == 0; +} + +/** + * @brief Returns true if the backup RAM has been initialized + */ +bool cpu_backup_ram_is_initialized(void); /** * @brief The CPU has RAM that is retained in the deepest sleep mode. From 9f4920329bc9cbfd5d596bde3d09c568c1235c74 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Mon, 9 Dec 2019 15:03:24 +0100 Subject: [PATCH 5/5] cpu/lpc2387: clear BODR if POR is set From the data sheet: > **Note:** Only in case when a reset occurs and the POR = 0, the BODR bit indicates if the V DD(DCDC)(3V3) voltage was below 2.6 V or not. So the value of BODR is undefined if POR is set. Clear it to bring it to a defined state. --- cpu/lpc2387/cpu.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cpu/lpc2387/cpu.c b/cpu/lpc2387/cpu.c index dcea9fc280..15b93af1e3 100644 --- a/cpu/lpc2387/cpu.c +++ b/cpu/lpc2387/cpu.c @@ -145,6 +145,13 @@ bool cpu_backup_ram_is_initialized(void) 'R', 'I', 'O', 'T' }; + /* Only in case when a reset occurs and the POR = 0, the BODR bit + * indicates if the V_DD (3V3) voltage was below 2.6 V or not. + */ + if ((RSIR & (RSIR_BODR | RSIR_POR)) == (RSIR_BODR | RSIR_POR)) { + RSIR |= RSIR_BODR; + } + /* external reset */ if (RSIR & RSIR_EXTR) { return false;