Skip to content

Commit 77b4a7b

Browse files
committed
Merge pull request #1097 from jeremybrodt/rtcwakeup
MAX32600MBED,MAXWSNENV - addressed low-power ticker corner cases
2 parents ffd5586 + d2ee036 commit 77b4a7b

File tree

4 files changed

+120
-52
lines changed

4 files changed

+120
-52
lines changed

libraries/mbed/targets/cmsis/TARGET_Maxim/TARGET_MAX32600/system_max32600.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ void SystemInit(void)
115115
{
116116
set_pwr_regs();
117117

118-
// enable instruction cache
118+
// Enable instruction cache
119119
ICC_Enable();
120120

121121
low_level_init();
@@ -135,9 +135,16 @@ void SystemInit(void)
135135
MXC_F_PWRMAN_PWR_RST_CTRL_IO_ACTIVE |
136136
MXC_F_PWRMAN_PWR_RST_CTRL_PULLUPS_ENABLED);
137137

138+
// Clear the first boot flag. Use low_level_init() if special handling is required.
139+
MXC_PWRSEQ->reg0 &= ~MXC_F_PWRSEQ_REG0_PWR_FIRST_BOOT;
140+
141+
// Enable the regulator
138142
MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_CHZYEN_RUN;
139143

140-
// set systick to the RTC input 32.768kHz clock, not system clock; this is needed to keep JTAG alive during sleep
144+
// Mask all wakeups
145+
MXC_PWRSEQ->msk_flags = 0xFFFFFFFF;
146+
147+
// Set systick to the RTC input 32.768kHz clock, not system clock; this is needed to keep JTAG alive during sleep
141148
MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_RTOS_MODE;
142149

143150
SystemCoreClockUpdate();

libraries/mbed/targets/cmsis/TARGET_Maxim/TARGET_MAX32610/system_max32610.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ void SystemInit(void)
118118
// Turn off PADX
119119
MXC_IOMAN->padx_control = 0x00000441;
120120

121-
// enable instruction cache
121+
// Enable instruction cache
122122
ICC_Enable();
123123

124124
low_level_init();
@@ -138,9 +138,16 @@ void SystemInit(void)
138138
MXC_F_PWRMAN_PWR_RST_CTRL_IO_ACTIVE |
139139
MXC_F_PWRMAN_PWR_RST_CTRL_PULLUPS_ENABLED);
140140

141+
// Clear the first boot flag. Use low_level_init() if special handling is required.
142+
MXC_PWRSEQ->reg0 &= ~MXC_F_PWRSEQ_REG0_PWR_FIRST_BOOT;
143+
144+
// Enable the regulator
141145
MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_CHZYEN_RUN;
142146

143-
// set systick to the RTC input 32.768kHz clock, not system clock; this is needed to keep JTAG alive during sleep
147+
// Mask all wakeups
148+
MXC_PWRSEQ->msk_flags = 0xFFFFFFFF;
149+
150+
// Set systick to the RTC input 32.768kHz clock, not system clock; this is needed to keep JTAG alive during sleep
144151
MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_RTOS_MODE;
145152

146153
SystemCoreClockUpdate();

libraries/mbed/targets/hal/TARGET_Maxim/TARGET_MAX32600/rtc_api.c

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
#define PRESCALE_VAL MXC_E_RTC_PRESCALE_DIV_2_0 // Set the divider for the 4kHz clock
4242
#define SHIFT_AMT (MXC_E_RTC_PRESCALE_DIV_2_12 - PRESCALE_VAL)
4343

44+
#define WINDOW 1000
45+
4446
static int rtc_inited = 0;
4547
static volatile uint32_t overflow_cnt = 0;
4648

@@ -50,6 +52,7 @@ static uint64_t rtc_read64(void);
5052
static void overflow_handler(void)
5153
{
5254
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_OVERFLOW;
55+
MXC_PWRSEQ->flags = MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER;
5356
overflow_cnt++;
5457
}
5558

@@ -69,20 +72,31 @@ void rtc_init(void)
6972
// Enable the clock to the RTC
7073
MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN;
7174

72-
// Set the clock divider
73-
MXC_RTCTMR->prescale = PRESCALE_VAL;
74-
75-
// Enable the overflow interrupt
76-
MXC_RTCTMR->inten |= MXC_F_RTC_FLAGS_OVERFLOW;
77-
7875
// Prepare interrupt handlers
7976
NVIC_SetVector(RTC0_IRQn, (uint32_t)lp_ticker_irq_handler);
8077
NVIC_EnableIRQ(RTC0_IRQn);
8178
NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler);
8279
NVIC_EnableIRQ(RTC3_IRQn);
8380

84-
// Enable the RTC
85-
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE;
81+
// Enable wakeup on RTC rollover
82+
MXC_PWRSEQ->msk_flags &= ~MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER;
83+
84+
/* RTC registers are only reset on a power cycle. Do not reconfigure the RTC
85+
* if it is already running.
86+
*/
87+
if (!(MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_ENABLE)) {
88+
// Set the clock divider
89+
MXC_RTCTMR->prescale = PRESCALE_VAL;
90+
91+
// Enable the overflow interrupt
92+
MXC_RTCTMR->inten |= MXC_F_RTC_FLAGS_OVERFLOW;
93+
94+
// Restart the timer from 0
95+
MXC_RTCTMR->timer = 0;
96+
97+
// Enable the RTC
98+
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE;
99+
}
86100
}
87101

88102
//******************************************************************************
@@ -177,30 +191,42 @@ void rtc_write(time_t t)
177191
//******************************************************************************
178192
void lp_ticker_set_interrupt(timestamp_t timestamp)
179193
{
194+
uint32_t comp_value;
195+
uint64_t curr_ts64;
196+
uint64_t ts64;
197+
180198
// Note: interrupts are disabled before this function is called.
181199

182200
// Disable the alarm while it is prepared
183201
MXC_RTCTMR->inten &= ~MXC_F_RTC_INTEN_COMP0;
184-
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_COMP0; // clear interrupt
185-
186-
uint64_t curr_ts64 = rtc_read64();
187-
uint64_t ts64 = (uint64_t)timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL);
188-
if (ts64 < curr_ts64) {
189-
if (ts64 < (curr_ts64 - 1000)) {
190-
ts64 += 0x100000000ULL;
191-
} else {
192-
// This event has already occurred. Set the alarm to expire immediately.
193-
MXC_RTCTMR->comp[0] = MXC_RTCTMR->timer + 2;
194-
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
195-
return;
196-
}
202+
203+
curr_ts64 = rtc_read64();
204+
ts64 = (uint64_t)timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL);
205+
206+
// If this event is older than a recent window, it must be in the future
207+
if ((ts64 < (curr_ts64 - WINDOW)) && ((curr_ts64 - WINDOW) < curr_ts64)) {
208+
ts64 += 0x100000000ULL;
209+
}
210+
211+
uint32_t timer = MXC_RTCTMR->timer;
212+
if (ts64 <= curr_ts64) {
213+
// This event has already occurred. Set the alarm to expire immediately.
214+
comp_value = timer + 1;
215+
} else {
216+
comp_value = (ts64 << SHIFT_AMT) / 1000000;
217+
}
218+
219+
// Ensure that the compare value is far enough in the future to guarantee the interrupt occurs.
220+
if ((comp_value < (timer + 2)) && (comp_value > (timer - 10))) {
221+
comp_value = timer + 2;
197222
}
198223

199-
MXC_RTCTMR->comp[0] = (ts64 << SHIFT_AMT) / 1000000;
200-
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
224+
MXC_RTCTMR->comp[0] = comp_value;
225+
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_COMP0; // clear interrupt
226+
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0; // enable the interrupt
201227

202228
// Enable wakeup from RTC
203-
MXC_PWRSEQ->msk_flags &= ~(MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER | MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0);
229+
MXC_PWRSEQ->msk_flags &= ~MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0;
204230
}
205231

206232
//******************************************************************************
@@ -213,6 +239,7 @@ inline void lp_ticker_disable_interrupt(void)
213239
inline void lp_ticker_clear_interrupt(void)
214240
{
215241
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS;
242+
MXC_PWRSEQ->flags = MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0;
216243
}
217244

218245
//******************************************************************************

libraries/mbed/targets/hal/TARGET_Maxim/TARGET_MAX32610/rtc_api.c

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
#define PRESCALE_VAL MXC_E_RTC_PRESCALE_DIV_2_0 // Set the divider for the 4kHz clock
4242
#define SHIFT_AMT (MXC_E_RTC_PRESCALE_DIV_2_12 - PRESCALE_VAL)
4343

44+
#define WINDOW 1000
45+
4446
static int rtc_inited = 0;
4547
static volatile uint32_t overflow_cnt = 0;
4648

@@ -50,6 +52,7 @@ static uint64_t rtc_read64(void);
5052
static void overflow_handler(void)
5153
{
5254
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_OVERFLOW;
55+
MXC_PWRSEQ->flags = MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER;
5356
overflow_cnt++;
5457
}
5558

@@ -69,20 +72,31 @@ void rtc_init(void)
6972
// Enable the clock to the RTC
7073
MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN;
7174

72-
// Set the clock divider
73-
MXC_RTCTMR->prescale = PRESCALE_VAL;
74-
75-
// Enable the overflow interrupt
76-
MXC_RTCTMR->inten |= MXC_F_RTC_FLAGS_OVERFLOW;
77-
7875
// Prepare interrupt handlers
7976
NVIC_SetVector(RTC0_IRQn, (uint32_t)lp_ticker_irq_handler);
8077
NVIC_EnableIRQ(RTC0_IRQn);
8178
NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler);
8279
NVIC_EnableIRQ(RTC3_IRQn);
8380

84-
// Enable the RTC
85-
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE;
81+
// Enable wakeup on RTC rollover
82+
MXC_PWRSEQ->msk_flags &= ~MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER;
83+
84+
/* RTC registers are only reset on a power cycle. Do not reconfigure the RTC
85+
* if it is already running.
86+
*/
87+
if (!(MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_ENABLE)) {
88+
// Set the clock divider
89+
MXC_RTCTMR->prescale = PRESCALE_VAL;
90+
91+
// Enable the overflow interrupt
92+
MXC_RTCTMR->inten |= MXC_F_RTC_FLAGS_OVERFLOW;
93+
94+
// Restart the timer from 0
95+
MXC_RTCTMR->timer = 0;
96+
97+
// Enable the RTC
98+
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE;
99+
}
86100
}
87101

88102
//******************************************************************************
@@ -177,30 +191,42 @@ void rtc_write(time_t t)
177191
//******************************************************************************
178192
void lp_ticker_set_interrupt(timestamp_t timestamp)
179193
{
194+
uint32_t comp_value;
195+
uint64_t curr_ts64;
196+
uint64_t ts64;
197+
180198
// Note: interrupts are disabled before this function is called.
181199

182200
// Disable the alarm while it is prepared
183201
MXC_RTCTMR->inten &= ~MXC_F_RTC_INTEN_COMP0;
184-
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_COMP0; // clear interrupt
185-
186-
uint64_t curr_ts64 = rtc_read64();
187-
uint64_t ts64 = (uint64_t)timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL);
188-
if (ts64 < curr_ts64) {
189-
if (ts64 < (curr_ts64 - 1000)) {
190-
ts64 += 0x100000000ULL;
191-
} else {
192-
// This event has already occurred. Set the alarm to expire immediately.
193-
MXC_RTCTMR->comp[0] = MXC_RTCTMR->timer + 2;
194-
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
195-
return;
196-
}
202+
203+
curr_ts64 = rtc_read64();
204+
ts64 = (uint64_t)timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL);
205+
206+
// If this event is older than a recent window, it must be in the future
207+
if ((ts64 < (curr_ts64 - WINDOW)) && ((curr_ts64 - WINDOW) < curr_ts64)) {
208+
ts64 += 0x100000000ULL;
209+
}
210+
211+
uint32_t timer = MXC_RTCTMR->timer;
212+
if (ts64 <= curr_ts64) {
213+
// This event has already occurred. Set the alarm to expire immediately.
214+
comp_value = timer + 1;
215+
} else {
216+
comp_value = (ts64 << SHIFT_AMT) / 1000000;
217+
}
218+
219+
// Ensure that the compare value is far enough in the future to guarantee the interrupt occurs.
220+
if ((comp_value < (timer + 2)) && (comp_value > (timer - 10))) {
221+
comp_value = timer + 2;
197222
}
198223

199-
MXC_RTCTMR->comp[0] = (ts64 << SHIFT_AMT) / 1000000;
200-
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
224+
MXC_RTCTMR->comp[0] = comp_value;
225+
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_COMP0; // clear interrupt
226+
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0; // enable the interrupt
201227

202228
// Enable wakeup from RTC
203-
MXC_PWRSEQ->msk_flags &= ~(MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER | MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0);
229+
MXC_PWRSEQ->msk_flags &= ~MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0;
204230
}
205231

206232
//******************************************************************************
@@ -213,6 +239,7 @@ inline void lp_ticker_disable_interrupt(void)
213239
inline void lp_ticker_clear_interrupt(void)
214240
{
215241
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS;
242+
MXC_PWRSEQ->flags = MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0;
216243
}
217244

218245
//******************************************************************************

0 commit comments

Comments
 (0)