Skip to content

[MAX32600MBED,MAXWSNENV] addressed low-power ticker corner cases #1097

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 11, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ void SystemInit(void)
{
set_pwr_regs();

// enable instruction cache
// Enable instruction cache
ICC_Enable();

low_level_init();
Expand All @@ -135,9 +135,16 @@ void SystemInit(void)
MXC_F_PWRMAN_PWR_RST_CTRL_IO_ACTIVE |
MXC_F_PWRMAN_PWR_RST_CTRL_PULLUPS_ENABLED);

// Clear the first boot flag. Use low_level_init() if special handling is required.
MXC_PWRSEQ->reg0 &= ~MXC_F_PWRSEQ_REG0_PWR_FIRST_BOOT;

// Enable the regulator
MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_CHZYEN_RUN;

// set systick to the RTC input 32.768kHz clock, not system clock; this is needed to keep JTAG alive during sleep
// Mask all wakeups
MXC_PWRSEQ->msk_flags = 0xFFFFFFFF;

// Set systick to the RTC input 32.768kHz clock, not system clock; this is needed to keep JTAG alive during sleep
MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_RTOS_MODE;

SystemCoreClockUpdate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ void SystemInit(void)
// Turn off PADX
MXC_IOMAN->padx_control = 0x00000441;

// enable instruction cache
// Enable instruction cache
ICC_Enable();

low_level_init();
Expand All @@ -138,9 +138,16 @@ void SystemInit(void)
MXC_F_PWRMAN_PWR_RST_CTRL_IO_ACTIVE |
MXC_F_PWRMAN_PWR_RST_CTRL_PULLUPS_ENABLED);

// Clear the first boot flag. Use low_level_init() if special handling is required.
MXC_PWRSEQ->reg0 &= ~MXC_F_PWRSEQ_REG0_PWR_FIRST_BOOT;

// Enable the regulator
MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_CHZYEN_RUN;

// set systick to the RTC input 32.768kHz clock, not system clock; this is needed to keep JTAG alive during sleep
// Mask all wakeups
MXC_PWRSEQ->msk_flags = 0xFFFFFFFF;

// Set systick to the RTC input 32.768kHz clock, not system clock; this is needed to keep JTAG alive during sleep
MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_RTOS_MODE;

SystemCoreClockUpdate();
Expand Down
75 changes: 51 additions & 24 deletions libraries/mbed/targets/hal/TARGET_Maxim/TARGET_MAX32600/rtc_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
#define PRESCALE_VAL MXC_E_RTC_PRESCALE_DIV_2_0 // Set the divider for the 4kHz clock
#define SHIFT_AMT (MXC_E_RTC_PRESCALE_DIV_2_12 - PRESCALE_VAL)

#define WINDOW 1000

static int rtc_inited = 0;
static volatile uint32_t overflow_cnt = 0;

Expand All @@ -50,6 +52,7 @@ static uint64_t rtc_read64(void);
static void overflow_handler(void)
{
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_OVERFLOW;
MXC_PWRSEQ->flags = MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER;
overflow_cnt++;
}

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

// Set the clock divider
MXC_RTCTMR->prescale = PRESCALE_VAL;

// Enable the overflow interrupt
MXC_RTCTMR->inten |= MXC_F_RTC_FLAGS_OVERFLOW;

// Prepare interrupt handlers
NVIC_SetVector(RTC0_IRQn, (uint32_t)lp_ticker_irq_handler);
NVIC_EnableIRQ(RTC0_IRQn);
NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler);
NVIC_EnableIRQ(RTC3_IRQn);

// Enable the RTC
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE;
// Enable wakeup on RTC rollover
MXC_PWRSEQ->msk_flags &= ~MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER;

/* RTC registers are only reset on a power cycle. Do not reconfigure the RTC
* if it is already running.
*/
if (!(MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_ENABLE)) {
// Set the clock divider
MXC_RTCTMR->prescale = PRESCALE_VAL;

// Enable the overflow interrupt
MXC_RTCTMR->inten |= MXC_F_RTC_FLAGS_OVERFLOW;

// Restart the timer from 0
MXC_RTCTMR->timer = 0;

// Enable the RTC
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE;
}
}

//******************************************************************************
Expand Down Expand Up @@ -177,30 +191,42 @@ void rtc_write(time_t t)
//******************************************************************************
void lp_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t comp_value;
uint64_t curr_ts64;
uint64_t ts64;

// Note: interrupts are disabled before this function is called.

// Disable the alarm while it is prepared
MXC_RTCTMR->inten &= ~MXC_F_RTC_INTEN_COMP0;
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_COMP0; // clear interrupt

uint64_t curr_ts64 = rtc_read64();
uint64_t ts64 = (uint64_t)timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL);
if (ts64 < curr_ts64) {
if (ts64 < (curr_ts64 - 1000)) {
ts64 += 0x100000000ULL;
} else {
// This event has already occurred. Set the alarm to expire immediately.
MXC_RTCTMR->comp[0] = MXC_RTCTMR->timer + 2;
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
return;
}

curr_ts64 = rtc_read64();
ts64 = (uint64_t)timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL);

// If this event is older than a recent window, it must be in the future
if ((ts64 < (curr_ts64 - WINDOW)) && ((curr_ts64 - WINDOW) < curr_ts64)) {
ts64 += 0x100000000ULL;
}

uint32_t timer = MXC_RTCTMR->timer;
if (ts64 <= curr_ts64) {
// This event has already occurred. Set the alarm to expire immediately.
comp_value = timer + 1;
} else {
comp_value = (ts64 << SHIFT_AMT) / 1000000;
}

// Ensure that the compare value is far enough in the future to guarantee the interrupt occurs.
if ((comp_value < (timer + 2)) && (comp_value > (timer - 10))) {
comp_value = timer + 2;
}

MXC_RTCTMR->comp[0] = (ts64 << SHIFT_AMT) / 1000000;
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
MXC_RTCTMR->comp[0] = comp_value;
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_COMP0; // clear interrupt
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0; // enable the interrupt

// Enable wakeup from RTC
MXC_PWRSEQ->msk_flags &= ~(MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER | MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0);
MXC_PWRSEQ->msk_flags &= ~MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0;
}

//******************************************************************************
Expand All @@ -213,6 +239,7 @@ inline void lp_ticker_disable_interrupt(void)
inline void lp_ticker_clear_interrupt(void)
{
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS;
MXC_PWRSEQ->flags = MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0;
}

//******************************************************************************
Expand Down
75 changes: 51 additions & 24 deletions libraries/mbed/targets/hal/TARGET_Maxim/TARGET_MAX32610/rtc_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
#define PRESCALE_VAL MXC_E_RTC_PRESCALE_DIV_2_0 // Set the divider for the 4kHz clock
#define SHIFT_AMT (MXC_E_RTC_PRESCALE_DIV_2_12 - PRESCALE_VAL)

#define WINDOW 1000

static int rtc_inited = 0;
static volatile uint32_t overflow_cnt = 0;

Expand All @@ -50,6 +52,7 @@ static uint64_t rtc_read64(void);
static void overflow_handler(void)
{
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_OVERFLOW;
MXC_PWRSEQ->flags = MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER;
overflow_cnt++;
}

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

// Set the clock divider
MXC_RTCTMR->prescale = PRESCALE_VAL;

// Enable the overflow interrupt
MXC_RTCTMR->inten |= MXC_F_RTC_FLAGS_OVERFLOW;

// Prepare interrupt handlers
NVIC_SetVector(RTC0_IRQn, (uint32_t)lp_ticker_irq_handler);
NVIC_EnableIRQ(RTC0_IRQn);
NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler);
NVIC_EnableIRQ(RTC3_IRQn);

// Enable the RTC
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE;
// Enable wakeup on RTC rollover
MXC_PWRSEQ->msk_flags &= ~MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER;

/* RTC registers are only reset on a power cycle. Do not reconfigure the RTC
* if it is already running.
*/
if (!(MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_ENABLE)) {
// Set the clock divider
MXC_RTCTMR->prescale = PRESCALE_VAL;

// Enable the overflow interrupt
MXC_RTCTMR->inten |= MXC_F_RTC_FLAGS_OVERFLOW;

// Restart the timer from 0
MXC_RTCTMR->timer = 0;

// Enable the RTC
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE;
}
}

//******************************************************************************
Expand Down Expand Up @@ -177,30 +191,42 @@ void rtc_write(time_t t)
//******************************************************************************
void lp_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t comp_value;
uint64_t curr_ts64;
uint64_t ts64;

// Note: interrupts are disabled before this function is called.

// Disable the alarm while it is prepared
MXC_RTCTMR->inten &= ~MXC_F_RTC_INTEN_COMP0;
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_COMP0; // clear interrupt

uint64_t curr_ts64 = rtc_read64();
uint64_t ts64 = (uint64_t)timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL);
if (ts64 < curr_ts64) {
if (ts64 < (curr_ts64 - 1000)) {
ts64 += 0x100000000ULL;
} else {
// This event has already occurred. Set the alarm to expire immediately.
MXC_RTCTMR->comp[0] = MXC_RTCTMR->timer + 2;
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
return;
}

curr_ts64 = rtc_read64();
ts64 = (uint64_t)timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL);

// If this event is older than a recent window, it must be in the future
if ((ts64 < (curr_ts64 - WINDOW)) && ((curr_ts64 - WINDOW) < curr_ts64)) {
ts64 += 0x100000000ULL;
}

uint32_t timer = MXC_RTCTMR->timer;
if (ts64 <= curr_ts64) {
// This event has already occurred. Set the alarm to expire immediately.
comp_value = timer + 1;
} else {
comp_value = (ts64 << SHIFT_AMT) / 1000000;
}

// Ensure that the compare value is far enough in the future to guarantee the interrupt occurs.
if ((comp_value < (timer + 2)) && (comp_value > (timer - 10))) {
comp_value = timer + 2;
}

MXC_RTCTMR->comp[0] = (ts64 << SHIFT_AMT) / 1000000;
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
MXC_RTCTMR->comp[0] = comp_value;
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_COMP0; // clear interrupt
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0; // enable the interrupt

// Enable wakeup from RTC
MXC_PWRSEQ->msk_flags &= ~(MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER | MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0);
MXC_PWRSEQ->msk_flags &= ~MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0;
}

//******************************************************************************
Expand All @@ -213,6 +239,7 @@ inline void lp_ticker_disable_interrupt(void)
inline void lp_ticker_clear_interrupt(void)
{
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS;
MXC_PWRSEQ->flags = MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0;
}

//******************************************************************************
Expand Down