mirror of https://github.com/ARMmbed/mbed-os.git
commit
8cad2b8ac0
|
@ -115,7 +115,7 @@ void SystemInit(void)
|
||||||
{
|
{
|
||||||
set_pwr_regs();
|
set_pwr_regs();
|
||||||
|
|
||||||
// enable instruction cache
|
// Enable instruction cache
|
||||||
ICC_Enable();
|
ICC_Enable();
|
||||||
|
|
||||||
low_level_init();
|
low_level_init();
|
||||||
|
@ -135,9 +135,16 @@ void SystemInit(void)
|
||||||
MXC_F_PWRMAN_PWR_RST_CTRL_IO_ACTIVE |
|
MXC_F_PWRMAN_PWR_RST_CTRL_IO_ACTIVE |
|
||||||
MXC_F_PWRMAN_PWR_RST_CTRL_PULLUPS_ENABLED);
|
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;
|
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;
|
MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_RTOS_MODE;
|
||||||
|
|
||||||
SystemCoreClockUpdate();
|
SystemCoreClockUpdate();
|
||||||
|
|
|
@ -118,7 +118,7 @@ void SystemInit(void)
|
||||||
// Turn off PADX
|
// Turn off PADX
|
||||||
MXC_IOMAN->padx_control = 0x00000441;
|
MXC_IOMAN->padx_control = 0x00000441;
|
||||||
|
|
||||||
// enable instruction cache
|
// Enable instruction cache
|
||||||
ICC_Enable();
|
ICC_Enable();
|
||||||
|
|
||||||
low_level_init();
|
low_level_init();
|
||||||
|
@ -138,9 +138,16 @@ void SystemInit(void)
|
||||||
MXC_F_PWRMAN_PWR_RST_CTRL_IO_ACTIVE |
|
MXC_F_PWRMAN_PWR_RST_CTRL_IO_ACTIVE |
|
||||||
MXC_F_PWRMAN_PWR_RST_CTRL_PULLUPS_ENABLED);
|
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;
|
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;
|
MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_RTOS_MODE;
|
||||||
|
|
||||||
SystemCoreClockUpdate();
|
SystemCoreClockUpdate();
|
||||||
|
|
|
@ -64,6 +64,8 @@
|
||||||
|
|
||||||
#define DEVICE_ERROR_PATTERN 1
|
#define DEVICE_ERROR_PATTERN 1
|
||||||
|
|
||||||
|
#define DEVICE_LOWPOWERTIMER 1
|
||||||
|
|
||||||
#define DEVICE_CAN 0
|
#define DEVICE_CAN 0
|
||||||
#define DEVICE_ETHERNET 0
|
#define DEVICE_ETHERNET 0
|
||||||
|
|
||||||
|
|
|
@ -32,62 +32,77 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "rtc_api.h"
|
#include "rtc_api.h"
|
||||||
|
#include "lp_ticker_api.h"
|
||||||
#include "cmsis.h"
|
#include "cmsis.h"
|
||||||
#include "rtc_regs.h"
|
#include "rtc_regs.h"
|
||||||
#include "pwrseq_regs.h"
|
#include "pwrseq_regs.h"
|
||||||
#include "clkman_regs.h"
|
#include "clkman_regs.h"
|
||||||
|
|
||||||
|
#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 int rtc_inited = 0;
|
||||||
static volatile uint32_t overflow_cnt = 0;
|
static volatile uint32_t overflow_cnt = 0;
|
||||||
static uint32_t overflow_alarm = 0;
|
|
||||||
|
static uint64_t rtc_read64(void);
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
static void overflow_handler(void)
|
static void overflow_handler(void)
|
||||||
{
|
{
|
||||||
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS;
|
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_OVERFLOW;
|
||||||
|
MXC_PWRSEQ->flags = MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER;
|
||||||
overflow_cnt++;
|
overflow_cnt++;
|
||||||
|
|
||||||
if (overflow_cnt == overflow_alarm) {
|
|
||||||
// Enable the comparator interrupt for the alarm
|
|
||||||
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//******************************************************************************
|
|
||||||
static void alarm_handler(void)
|
|
||||||
{
|
|
||||||
MXC_RTCTMR->inten &= ~MXC_F_RTC_INTEN_COMP0;
|
|
||||||
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
void rtc_init(void)
|
void rtc_init(void)
|
||||||
{
|
{
|
||||||
if(rtc_inited) {
|
if (rtc_inited) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rtc_inited = 1;
|
rtc_inited = 1;
|
||||||
|
|
||||||
|
overflow_cnt = 0;
|
||||||
|
|
||||||
// Enable the clock to the synchronizer
|
// Enable the clock to the synchronizer
|
||||||
MXC_CLKMAN->clk_ctrl_13_rtc_int_sync = MXC_E_CLKMAN_CLK_SCALE_ENABLED;
|
MXC_CLKMAN->clk_ctrl_13_rtc_int_sync = MXC_E_CLKMAN_CLK_SCALE_ENABLED;
|
||||||
|
|
||||||
// Enable the clock to the RTC
|
// Enable the clock to the RTC
|
||||||
MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN;
|
MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN;
|
||||||
|
|
||||||
// Set the divider from the 4kHz clock
|
|
||||||
MXC_RTCTMR->prescale = MXC_E_RTC_PRESCALE_DIV_2_0;
|
|
||||||
|
|
||||||
// Enable the overflow interrupt
|
|
||||||
MXC_RTCTMR->inten |= MXC_F_RTC_FLAGS_OVERFLOW;
|
|
||||||
|
|
||||||
// Prepare interrupt handlers
|
// Prepare interrupt handlers
|
||||||
NVIC_SetVector(RTC0_IRQn, (uint32_t)alarm_handler);
|
NVIC_SetVector(RTC0_IRQn, (uint32_t)lp_ticker_irq_handler);
|
||||||
NVIC_EnableIRQ(RTC0_IRQn);
|
NVIC_EnableIRQ(RTC0_IRQn);
|
||||||
NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler);
|
NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler);
|
||||||
NVIC_EnableIRQ(RTC3_IRQn);
|
NVIC_EnableIRQ(RTC3_IRQn);
|
||||||
|
|
||||||
|
// 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
|
// Enable the RTC
|
||||||
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE;
|
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
void lp_ticker_init(void)
|
||||||
|
{
|
||||||
|
rtc_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
|
@ -118,73 +133,117 @@ int rtc_isenabled(void)
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
time_t rtc_read(void)
|
time_t rtc_read(void)
|
||||||
{
|
{
|
||||||
unsigned int shift_amt;
|
|
||||||
uint32_t ovf_cnt_1, ovf_cnt_2, timer_cnt;
|
uint32_t ovf_cnt_1, ovf_cnt_2, timer_cnt;
|
||||||
|
uint32_t ovf1, ovf2;
|
||||||
// Account for a change in the default prescaler
|
|
||||||
shift_amt = MXC_E_RTC_PRESCALE_DIV_2_12 - MXC_RTCTMR->prescale;
|
|
||||||
|
|
||||||
// Ensure coherency between overflow_cnt and timer
|
// Ensure coherency between overflow_cnt and timer
|
||||||
do {
|
do {
|
||||||
ovf_cnt_1 = overflow_cnt;
|
ovf_cnt_1 = overflow_cnt;
|
||||||
|
ovf1 = MXC_RTCTMR->flags & MXC_F_RTC_FLAGS_OVERFLOW;
|
||||||
timer_cnt = MXC_RTCTMR->timer;
|
timer_cnt = MXC_RTCTMR->timer;
|
||||||
|
ovf2 = MXC_RTCTMR->flags & MXC_F_RTC_FLAGS_OVERFLOW;
|
||||||
ovf_cnt_2 = overflow_cnt;
|
ovf_cnt_2 = overflow_cnt;
|
||||||
} while (ovf_cnt_1 != ovf_cnt_2);
|
} while ((ovf_cnt_1 != ovf_cnt_2) || (ovf1 != ovf2));
|
||||||
|
|
||||||
return (timer_cnt >> shift_amt) + (ovf_cnt_1 << (32 - shift_amt));
|
// Account for an unserviced interrupt
|
||||||
|
if (ovf1) {
|
||||||
|
ovf_cnt_1++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (timer_cnt >> SHIFT_AMT) + (ovf_cnt_1 << (32 - SHIFT_AMT));
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
uint64_t rtc_read_us(void)
|
static uint64_t rtc_read64(void)
|
||||||
{
|
{
|
||||||
unsigned int shift_amt;
|
|
||||||
uint32_t ovf_cnt_1, ovf_cnt_2, timer_cnt;
|
uint32_t ovf_cnt_1, ovf_cnt_2, timer_cnt;
|
||||||
uint64_t currentUs;
|
uint32_t ovf1, ovf2;
|
||||||
|
uint64_t current_us;
|
||||||
// Account for a change in the default prescaler
|
|
||||||
shift_amt = MXC_E_RTC_PRESCALE_DIV_2_12 - MXC_RTCTMR->prescale;
|
|
||||||
|
|
||||||
// Ensure coherency between overflow_cnt and timer
|
// Ensure coherency between overflow_cnt and timer
|
||||||
do {
|
do {
|
||||||
ovf_cnt_1 = overflow_cnt;
|
ovf_cnt_1 = overflow_cnt;
|
||||||
|
ovf1 = MXC_RTCTMR->flags & MXC_F_RTC_FLAGS_OVERFLOW;
|
||||||
timer_cnt = MXC_RTCTMR->timer;
|
timer_cnt = MXC_RTCTMR->timer;
|
||||||
|
ovf2 = MXC_RTCTMR->flags & MXC_F_RTC_FLAGS_OVERFLOW;
|
||||||
ovf_cnt_2 = overflow_cnt;
|
ovf_cnt_2 = overflow_cnt;
|
||||||
} while (ovf_cnt_1 != ovf_cnt_2);
|
} while ((ovf_cnt_1 != ovf_cnt_2) || (ovf1 != ovf2));
|
||||||
|
|
||||||
currentUs = (((uint64_t)timer_cnt * 1000000) >> shift_amt) + (((uint64_t)ovf_cnt_1 * 1000000) << (32 - shift_amt));
|
// Account for an unserviced interrupt
|
||||||
|
if (ovf1) {
|
||||||
|
ovf_cnt_1++;
|
||||||
|
}
|
||||||
|
|
||||||
return currentUs;
|
current_us = (((uint64_t)timer_cnt * 1000000) >> SHIFT_AMT) + (((uint64_t)ovf_cnt_1 * 1000000) << (32 - SHIFT_AMT));
|
||||||
|
|
||||||
|
return current_us;
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
void rtc_write(time_t t)
|
void rtc_write(time_t t)
|
||||||
{
|
{
|
||||||
// Account for a change in the default prescaler
|
|
||||||
unsigned int shift_amt = MXC_E_RTC_PRESCALE_DIV_2_12 - MXC_RTCTMR->prescale;
|
|
||||||
|
|
||||||
MXC_RTCTMR->ctrl &= ~MXC_F_RTC_CTRL_ENABLE; // disable the timer while updating
|
MXC_RTCTMR->ctrl &= ~MXC_F_RTC_CTRL_ENABLE; // disable the timer while updating
|
||||||
MXC_RTCTMR->timer = t << shift_amt;
|
MXC_RTCTMR->timer = t << SHIFT_AMT;
|
||||||
overflow_cnt = t >> (32 - shift_amt);
|
overflow_cnt = t >> (32 - SHIFT_AMT);
|
||||||
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE; // enable the timer while updating
|
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE; // enable the timer while updating
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
void rtc_set_wakeup(uint64_t wakeupUs)
|
void lp_ticker_set_interrupt(timestamp_t timestamp)
|
||||||
{
|
{
|
||||||
// Account for a change in the default prescaler
|
uint32_t comp_value;
|
||||||
unsigned int shift_amt = MXC_E_RTC_PRESCALE_DIV_2_12 - MXC_RTCTMR->prescale;
|
uint64_t curr_ts64;
|
||||||
|
uint64_t ts64;
|
||||||
|
|
||||||
|
// Note: interrupts are disabled before this function is called.
|
||||||
|
|
||||||
// Disable the alarm while it is prepared
|
// Disable the alarm while it is prepared
|
||||||
MXC_RTCTMR->inten &= ~MXC_F_RTC_INTEN_COMP0;
|
MXC_RTCTMR->inten &= ~MXC_F_RTC_INTEN_COMP0;
|
||||||
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_COMP0; // clear interrupt
|
|
||||||
|
|
||||||
overflow_alarm = (wakeupUs >> (32 - shift_amt)) / 1000000;
|
curr_ts64 = rtc_read64();
|
||||||
|
ts64 = (uint64_t)timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL);
|
||||||
|
|
||||||
if (overflow_alarm == overflow_cnt) {
|
// If this event is older than a recent window, it must be in the future
|
||||||
MXC_RTCTMR->comp[0] = (wakeupUs << shift_amt) / 1000000;
|
if ((ts64 < (curr_ts64 - WINDOW)) && ((curr_ts64 - WINDOW) < curr_ts64)) {
|
||||||
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
|
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] = 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
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
inline void lp_ticker_disable_interrupt(void)
|
||||||
|
{
|
||||||
|
MXC_RTCTMR->inten &= ~MXC_F_RTC_INTEN_COMP0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
inline uint32_t lp_ticker_read(void)
|
||||||
|
{
|
||||||
|
return rtc_read64();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,20 +32,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sleep_api.h"
|
#include "sleep_api.h"
|
||||||
#include "us_ticker_api.h"
|
|
||||||
#include "cmsis.h"
|
#include "cmsis.h"
|
||||||
#include "pwrman_regs.h"
|
#include "pwrman_regs.h"
|
||||||
#include "pwrseq_regs.h"
|
#include "pwrseq_regs.h"
|
||||||
#include "ioman_regs.h"
|
#include "ioman_regs.h"
|
||||||
#include "rtc_regs.h"
|
#include "rtc_regs.h"
|
||||||
|
|
||||||
#define MIN_DEEP_SLEEP_US 500
|
|
||||||
|
|
||||||
uint64_t rtc_read_us(void);
|
|
||||||
void rtc_set_wakeup(uint64_t wakeupUs);
|
|
||||||
void us_ticker_deinit(void);
|
|
||||||
void us_ticker_set(timestamp_t timestamp);
|
|
||||||
|
|
||||||
static mxc_uart_regs_t *stdio_uart = (mxc_uart_regs_t*)STDIO_UART;
|
static mxc_uart_regs_t *stdio_uart = (mxc_uart_regs_t*)STDIO_UART;
|
||||||
|
|
||||||
// Normal wait mode
|
// Normal wait mode
|
||||||
|
@ -80,38 +72,11 @@ static void clearAllGPIOWUD(void)
|
||||||
// Low-power stop mode
|
// Low-power stop mode
|
||||||
void deepsleep(void)
|
void deepsleep(void)
|
||||||
{
|
{
|
||||||
uint64_t sleepStartRtcUs;
|
|
||||||
uint32_t sleepStartTickerUs;
|
|
||||||
int32_t sleepDurationUs;
|
|
||||||
uint64_t sleepEndRtcUs;
|
|
||||||
uint64_t elapsedUs;
|
|
||||||
|
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
|
|
||||||
// Wait for all STDIO characters to be sent. The UART clock will stop.
|
// Wait for all STDIO characters to be sent. The UART clock will stop.
|
||||||
while (stdio_uart->status & MXC_F_UART_STATUS_TX_BUSY);
|
while (stdio_uart->status & MXC_F_UART_STATUS_TX_BUSY);
|
||||||
|
|
||||||
// Record the current times
|
|
||||||
sleepStartRtcUs = rtc_read_us();
|
|
||||||
sleepStartTickerUs = us_ticker_read();
|
|
||||||
|
|
||||||
// Get the next mbed timer expiration
|
|
||||||
timestamp_t next_event = 0;
|
|
||||||
us_ticker_get_next_timestamp(&next_event);
|
|
||||||
sleepDurationUs = next_event - sleepStartTickerUs;
|
|
||||||
|
|
||||||
if (sleepDurationUs < MIN_DEEP_SLEEP_US) {
|
|
||||||
/* The next wakeup is too soon. */
|
|
||||||
__enable_irq();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable the us_ticker. It won't be clocked in DeepSleep
|
|
||||||
us_ticker_deinit();
|
|
||||||
|
|
||||||
// Prepare to wakeup from the RTC
|
|
||||||
rtc_set_wakeup(sleepStartRtcUs + sleepDurationUs);
|
|
||||||
|
|
||||||
// Prepare for LP1
|
// Prepare for LP1
|
||||||
uint32_t reg0 = MXC_PWRSEQ->reg0;
|
uint32_t reg0 = MXC_PWRSEQ->reg0;
|
||||||
reg0 &= ~MXC_F_PWRSEQ_REG0_PWR_SVM3EN_SLP; // disable VDD3 SVM during sleep mode
|
reg0 &= ~MXC_F_PWRSEQ_REG0_PWR_SVM3EN_SLP; // disable VDD3 SVM during sleep mode
|
||||||
|
@ -151,19 +116,8 @@ void deepsleep(void)
|
||||||
// Woke up from LP1
|
// Woke up from LP1
|
||||||
|
|
||||||
// The RTC timer does not update until the next tick
|
// The RTC timer does not update until the next tick
|
||||||
uint64_t tempUs = rtc_read_us();
|
uint32_t temp = MXC_RTCTMR->timer;
|
||||||
do {
|
while (MXC_RTCTMR->timer == temp);
|
||||||
sleepEndRtcUs = rtc_read_us();
|
|
||||||
} while(sleepEndRtcUs == tempUs);
|
|
||||||
|
|
||||||
// Get the elapsed time from the RTC. Wakeup could have been from some other event.
|
|
||||||
elapsedUs = sleepEndRtcUs - sleepStartRtcUs;
|
|
||||||
|
|
||||||
// Update the us_ticker. It was not clocked during DeepSleep
|
|
||||||
us_ticker_init();
|
|
||||||
us_ticker_set(sleepStartTickerUs + elapsedUs);
|
|
||||||
us_ticker_get_next_timestamp(&next_event);
|
|
||||||
us_ticker_set_interrupt(next_event);
|
|
||||||
|
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ static inline void inc_current_cnt(uint32_t inc) {
|
||||||
|
|
||||||
// Overflow the ticker when the us ticker overflows
|
// Overflow the ticker when the us ticker overflows
|
||||||
current_cnt += inc;
|
current_cnt += inc;
|
||||||
if(current_cnt > MAX_TICK_VAL) {
|
if (current_cnt > MAX_TICK_VAL) {
|
||||||
current_cnt -= (MAX_TICK_VAL + 1);
|
current_cnt -= (MAX_TICK_VAL + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ static inline int event_passed(uint64_t current, uint64_t event) {
|
||||||
// Determine if the event has already happened.
|
// Determine if the event has already happened.
|
||||||
// If the event is behind the current ticker, within a window,
|
// If the event is behind the current ticker, within a window,
|
||||||
// then the event has already happened.
|
// then the event has already happened.
|
||||||
if(((current < tick_win) && ((event < current) ||
|
if (((current < tick_win) && ((event < current) ||
|
||||||
(event > (MAX_TICK_VAL - (tick_win - current))))) ||
|
(event > (MAX_TICK_VAL - (tick_win - current))))) ||
|
||||||
((event < current) && (event > (current - tick_win)))) {
|
((event < current) && (event > (current - tick_win)))) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -169,7 +169,7 @@ uint32_t us_ticker_read(void)
|
||||||
{
|
{
|
||||||
uint64_t current_cnt1, current_cnt2;
|
uint64_t current_cnt1, current_cnt2;
|
||||||
uint32_t term_cnt, tmr_cnt;
|
uint32_t term_cnt, tmr_cnt;
|
||||||
int intfl1, intfl2;
|
uint32_t intfl1, intfl2;
|
||||||
|
|
||||||
if (!us_ticker_inited)
|
if (!us_ticker_inited)
|
||||||
us_ticker_init();
|
us_ticker_init();
|
||||||
|
@ -184,6 +184,7 @@ uint32_t us_ticker_read(void)
|
||||||
current_cnt2 = current_cnt;
|
current_cnt2 = current_cnt;
|
||||||
} while ((current_cnt1 != current_cnt2) || (intfl1 != intfl2));
|
} while ((current_cnt1 != current_cnt2) || (intfl1 != intfl2));
|
||||||
|
|
||||||
|
// Account for an unserviced interrupt
|
||||||
if (intfl1) {
|
if (intfl1) {
|
||||||
current_cnt1 += term_cnt;
|
current_cnt1 += term_cnt;
|
||||||
}
|
}
|
||||||
|
@ -197,6 +198,7 @@ uint32_t us_ticker_read(void)
|
||||||
void us_ticker_set_interrupt(timestamp_t timestamp)
|
void us_ticker_set_interrupt(timestamp_t timestamp)
|
||||||
{
|
{
|
||||||
// Note: interrupts are disabled before this function is called.
|
// Note: interrupts are disabled before this function is called.
|
||||||
|
|
||||||
US_TIMER->ctrl &= ~MXC_F_TMR_CTRL_ENABLE0; // disable timer
|
US_TIMER->ctrl &= ~MXC_F_TMR_CTRL_ENABLE0; // disable timer
|
||||||
|
|
||||||
if (US_TIMER->intfl) {
|
if (US_TIMER->intfl) {
|
||||||
|
|
|
@ -64,6 +64,8 @@
|
||||||
|
|
||||||
#define DEVICE_ERROR_PATTERN 1
|
#define DEVICE_ERROR_PATTERN 1
|
||||||
|
|
||||||
|
#define DEVICE_LOWPOWERTIMER 1
|
||||||
|
|
||||||
#define DEVICE_CAN 0
|
#define DEVICE_CAN 0
|
||||||
#define DEVICE_ETHERNET 0
|
#define DEVICE_ETHERNET 0
|
||||||
|
|
||||||
|
|
|
@ -32,62 +32,77 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "rtc_api.h"
|
#include "rtc_api.h"
|
||||||
|
#include "lp_ticker_api.h"
|
||||||
#include "cmsis.h"
|
#include "cmsis.h"
|
||||||
#include "rtc_regs.h"
|
#include "rtc_regs.h"
|
||||||
#include "pwrseq_regs.h"
|
#include "pwrseq_regs.h"
|
||||||
#include "clkman_regs.h"
|
#include "clkman_regs.h"
|
||||||
|
|
||||||
|
#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 int rtc_inited = 0;
|
||||||
static volatile uint32_t overflow_cnt = 0;
|
static volatile uint32_t overflow_cnt = 0;
|
||||||
static uint32_t overflow_alarm = 0;
|
|
||||||
|
static uint64_t rtc_read64(void);
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
static void overflow_handler(void)
|
static void overflow_handler(void)
|
||||||
{
|
{
|
||||||
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS;
|
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_OVERFLOW;
|
||||||
|
MXC_PWRSEQ->flags = MXC_F_PWRSEQ_MSK_FLAGS_RTC_ROLLOVER;
|
||||||
overflow_cnt++;
|
overflow_cnt++;
|
||||||
|
|
||||||
if (overflow_cnt == overflow_alarm) {
|
|
||||||
// Enable the comparator interrupt for the alarm
|
|
||||||
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//******************************************************************************
|
|
||||||
static void alarm_handler(void)
|
|
||||||
{
|
|
||||||
MXC_RTCTMR->inten &= ~MXC_F_RTC_INTEN_COMP0;
|
|
||||||
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
void rtc_init(void)
|
void rtc_init(void)
|
||||||
{
|
{
|
||||||
if(rtc_inited) {
|
if (rtc_inited) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rtc_inited = 1;
|
rtc_inited = 1;
|
||||||
|
|
||||||
|
overflow_cnt = 0;
|
||||||
|
|
||||||
// Enable the clock to the synchronizer
|
// Enable the clock to the synchronizer
|
||||||
MXC_CLKMAN->clk_ctrl_13_rtc_int_sync = MXC_E_CLKMAN_CLK_SCALE_ENABLED;
|
MXC_CLKMAN->clk_ctrl_13_rtc_int_sync = MXC_E_CLKMAN_CLK_SCALE_ENABLED;
|
||||||
|
|
||||||
// Enable the clock to the RTC
|
// Enable the clock to the RTC
|
||||||
MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN;
|
MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN;
|
||||||
|
|
||||||
// Set the divider from the 4kHz clock
|
|
||||||
MXC_RTCTMR->prescale = MXC_E_RTC_PRESCALE_DIV_2_0;
|
|
||||||
|
|
||||||
// Enable the overflow interrupt
|
|
||||||
MXC_RTCTMR->inten |= MXC_F_RTC_FLAGS_OVERFLOW;
|
|
||||||
|
|
||||||
// Prepare interrupt handlers
|
// Prepare interrupt handlers
|
||||||
NVIC_SetVector(RTC0_IRQn, (uint32_t)alarm_handler);
|
NVIC_SetVector(RTC0_IRQn, (uint32_t)lp_ticker_irq_handler);
|
||||||
NVIC_EnableIRQ(RTC0_IRQn);
|
NVIC_EnableIRQ(RTC0_IRQn);
|
||||||
NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler);
|
NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler);
|
||||||
NVIC_EnableIRQ(RTC3_IRQn);
|
NVIC_EnableIRQ(RTC3_IRQn);
|
||||||
|
|
||||||
|
// 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
|
// Enable the RTC
|
||||||
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE;
|
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
void lp_ticker_init(void)
|
||||||
|
{
|
||||||
|
rtc_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
|
@ -118,73 +133,117 @@ int rtc_isenabled(void)
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
time_t rtc_read(void)
|
time_t rtc_read(void)
|
||||||
{
|
{
|
||||||
unsigned int shift_amt;
|
|
||||||
uint32_t ovf_cnt_1, ovf_cnt_2, timer_cnt;
|
uint32_t ovf_cnt_1, ovf_cnt_2, timer_cnt;
|
||||||
|
uint32_t ovf1, ovf2;
|
||||||
// Account for a change in the default prescaler
|
|
||||||
shift_amt = MXC_E_RTC_PRESCALE_DIV_2_12 - MXC_RTCTMR->prescale;
|
|
||||||
|
|
||||||
// Ensure coherency between overflow_cnt and timer
|
// Ensure coherency between overflow_cnt and timer
|
||||||
do {
|
do {
|
||||||
ovf_cnt_1 = overflow_cnt;
|
ovf_cnt_1 = overflow_cnt;
|
||||||
|
ovf1 = MXC_RTCTMR->flags & MXC_F_RTC_FLAGS_OVERFLOW;
|
||||||
timer_cnt = MXC_RTCTMR->timer;
|
timer_cnt = MXC_RTCTMR->timer;
|
||||||
|
ovf2 = MXC_RTCTMR->flags & MXC_F_RTC_FLAGS_OVERFLOW;
|
||||||
ovf_cnt_2 = overflow_cnt;
|
ovf_cnt_2 = overflow_cnt;
|
||||||
} while (ovf_cnt_1 != ovf_cnt_2);
|
} while ((ovf_cnt_1 != ovf_cnt_2) || (ovf1 != ovf2));
|
||||||
|
|
||||||
return (timer_cnt >> shift_amt) + (ovf_cnt_1 << (32 - shift_amt));
|
// Account for an unserviced interrupt
|
||||||
|
if (ovf1) {
|
||||||
|
ovf_cnt_1++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (timer_cnt >> SHIFT_AMT) + (ovf_cnt_1 << (32 - SHIFT_AMT));
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
uint64_t rtc_read_us(void)
|
static uint64_t rtc_read64(void)
|
||||||
{
|
{
|
||||||
unsigned int shift_amt;
|
|
||||||
uint32_t ovf_cnt_1, ovf_cnt_2, timer_cnt;
|
uint32_t ovf_cnt_1, ovf_cnt_2, timer_cnt;
|
||||||
uint64_t currentUs;
|
uint32_t ovf1, ovf2;
|
||||||
|
uint64_t current_us;
|
||||||
// Account for a change in the default prescaler
|
|
||||||
shift_amt = MXC_E_RTC_PRESCALE_DIV_2_12 - MXC_RTCTMR->prescale;
|
|
||||||
|
|
||||||
// Ensure coherency between overflow_cnt and timer
|
// Ensure coherency between overflow_cnt and timer
|
||||||
do {
|
do {
|
||||||
ovf_cnt_1 = overflow_cnt;
|
ovf_cnt_1 = overflow_cnt;
|
||||||
|
ovf1 = MXC_RTCTMR->flags & MXC_F_RTC_FLAGS_OVERFLOW;
|
||||||
timer_cnt = MXC_RTCTMR->timer;
|
timer_cnt = MXC_RTCTMR->timer;
|
||||||
|
ovf2 = MXC_RTCTMR->flags & MXC_F_RTC_FLAGS_OVERFLOW;
|
||||||
ovf_cnt_2 = overflow_cnt;
|
ovf_cnt_2 = overflow_cnt;
|
||||||
} while (ovf_cnt_1 != ovf_cnt_2);
|
} while ((ovf_cnt_1 != ovf_cnt_2) || (ovf1 != ovf2));
|
||||||
|
|
||||||
currentUs = (((uint64_t)timer_cnt * 1000000) >> shift_amt) + (((uint64_t)ovf_cnt_1 * 1000000) << (32 - shift_amt));
|
// Account for an unserviced interrupt
|
||||||
|
if (ovf1) {
|
||||||
|
ovf_cnt_1++;
|
||||||
|
}
|
||||||
|
|
||||||
return currentUs;
|
current_us = (((uint64_t)timer_cnt * 1000000) >> SHIFT_AMT) + (((uint64_t)ovf_cnt_1 * 1000000) << (32 - SHIFT_AMT));
|
||||||
|
|
||||||
|
return current_us;
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
void rtc_write(time_t t)
|
void rtc_write(time_t t)
|
||||||
{
|
{
|
||||||
// Account for a change in the default prescaler
|
|
||||||
unsigned int shift_amt = MXC_E_RTC_PRESCALE_DIV_2_12 - MXC_RTCTMR->prescale;
|
|
||||||
|
|
||||||
MXC_RTCTMR->ctrl &= ~MXC_F_RTC_CTRL_ENABLE; // disable the timer while updating
|
MXC_RTCTMR->ctrl &= ~MXC_F_RTC_CTRL_ENABLE; // disable the timer while updating
|
||||||
MXC_RTCTMR->timer = t << shift_amt;
|
MXC_RTCTMR->timer = t << SHIFT_AMT;
|
||||||
overflow_cnt = t >> (32 - shift_amt);
|
overflow_cnt = t >> (32 - SHIFT_AMT);
|
||||||
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE; // enable the timer while updating
|
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_ENABLE; // enable the timer while updating
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
void rtc_set_wakeup(uint64_t wakeupUs)
|
void lp_ticker_set_interrupt(timestamp_t timestamp)
|
||||||
{
|
{
|
||||||
// Account for a change in the default prescaler
|
uint32_t comp_value;
|
||||||
unsigned int shift_amt = MXC_E_RTC_PRESCALE_DIV_2_12 - MXC_RTCTMR->prescale;
|
uint64_t curr_ts64;
|
||||||
|
uint64_t ts64;
|
||||||
|
|
||||||
|
// Note: interrupts are disabled before this function is called.
|
||||||
|
|
||||||
// Disable the alarm while it is prepared
|
// Disable the alarm while it is prepared
|
||||||
MXC_RTCTMR->inten &= ~MXC_F_RTC_INTEN_COMP0;
|
MXC_RTCTMR->inten &= ~MXC_F_RTC_INTEN_COMP0;
|
||||||
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_COMP0; // clear interrupt
|
|
||||||
|
|
||||||
overflow_alarm = (wakeupUs >> (32 - shift_amt)) / 1000000;
|
curr_ts64 = rtc_read64();
|
||||||
|
ts64 = (uint64_t)timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL);
|
||||||
|
|
||||||
if (overflow_alarm == overflow_cnt) {
|
// If this event is older than a recent window, it must be in the future
|
||||||
MXC_RTCTMR->comp[0] = (wakeupUs << shift_amt) / 1000000;
|
if ((ts64 < (curr_ts64 - WINDOW)) && ((curr_ts64 - WINDOW) < curr_ts64)) {
|
||||||
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
|
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] = 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
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
inline void lp_ticker_disable_interrupt(void)
|
||||||
|
{
|
||||||
|
MXC_RTCTMR->inten &= ~MXC_F_RTC_INTEN_COMP0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
inline uint32_t lp_ticker_read(void)
|
||||||
|
{
|
||||||
|
return rtc_read64();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,20 +32,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sleep_api.h"
|
#include "sleep_api.h"
|
||||||
#include "us_ticker_api.h"
|
|
||||||
#include "cmsis.h"
|
#include "cmsis.h"
|
||||||
#include "pwrman_regs.h"
|
#include "pwrman_regs.h"
|
||||||
#include "pwrseq_regs.h"
|
#include "pwrseq_regs.h"
|
||||||
#include "ioman_regs.h"
|
#include "ioman_regs.h"
|
||||||
#include "rtc_regs.h"
|
#include "rtc_regs.h"
|
||||||
|
|
||||||
#define MIN_DEEP_SLEEP_US 500
|
|
||||||
|
|
||||||
uint64_t rtc_read_us(void);
|
|
||||||
void rtc_set_wakeup(uint64_t wakeupUs);
|
|
||||||
void us_ticker_deinit(void);
|
|
||||||
void us_ticker_set(timestamp_t timestamp);
|
|
||||||
|
|
||||||
static mxc_uart_regs_t *stdio_uart = (mxc_uart_regs_t*)STDIO_UART;
|
static mxc_uart_regs_t *stdio_uart = (mxc_uart_regs_t*)STDIO_UART;
|
||||||
|
|
||||||
// Normal wait mode
|
// Normal wait mode
|
||||||
|
@ -80,38 +72,11 @@ static void clearAllGPIOWUD(void)
|
||||||
// Low-power stop mode
|
// Low-power stop mode
|
||||||
void deepsleep(void)
|
void deepsleep(void)
|
||||||
{
|
{
|
||||||
uint64_t sleepStartRtcUs;
|
|
||||||
uint32_t sleepStartTickerUs;
|
|
||||||
int32_t sleepDurationUs;
|
|
||||||
uint64_t sleepEndRtcUs;
|
|
||||||
uint64_t elapsedUs;
|
|
||||||
|
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
|
|
||||||
// Wait for all STDIO characters to be sent. The UART clock will stop.
|
// Wait for all STDIO characters to be sent. The UART clock will stop.
|
||||||
while (stdio_uart->status & MXC_F_UART_STATUS_TX_BUSY);
|
while (stdio_uart->status & MXC_F_UART_STATUS_TX_BUSY);
|
||||||
|
|
||||||
// Record the current times
|
|
||||||
sleepStartRtcUs = rtc_read_us();
|
|
||||||
sleepStartTickerUs = us_ticker_read();
|
|
||||||
|
|
||||||
// Get the next mbed timer expiration
|
|
||||||
timestamp_t next_event = 0;
|
|
||||||
us_ticker_get_next_timestamp(&next_event);
|
|
||||||
sleepDurationUs = next_event - sleepStartTickerUs;
|
|
||||||
|
|
||||||
if (sleepDurationUs < MIN_DEEP_SLEEP_US) {
|
|
||||||
/* The next wakeup is too soon. */
|
|
||||||
__enable_irq();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable the us_ticker. It won't be clocked in DeepSleep
|
|
||||||
us_ticker_deinit();
|
|
||||||
|
|
||||||
// Prepare to wakeup from the RTC
|
|
||||||
rtc_set_wakeup(sleepStartRtcUs + sleepDurationUs);
|
|
||||||
|
|
||||||
// Prepare for LP1
|
// Prepare for LP1
|
||||||
uint32_t reg0 = MXC_PWRSEQ->reg0;
|
uint32_t reg0 = MXC_PWRSEQ->reg0;
|
||||||
reg0 &= ~MXC_F_PWRSEQ_REG0_PWR_SVM3EN_SLP; // disable VDD3 SVM during sleep mode
|
reg0 &= ~MXC_F_PWRSEQ_REG0_PWR_SVM3EN_SLP; // disable VDD3 SVM during sleep mode
|
||||||
|
@ -151,19 +116,8 @@ void deepsleep(void)
|
||||||
// Woke up from LP1
|
// Woke up from LP1
|
||||||
|
|
||||||
// The RTC timer does not update until the next tick
|
// The RTC timer does not update until the next tick
|
||||||
uint64_t tempUs = rtc_read_us();
|
uint32_t temp = MXC_RTCTMR->timer;
|
||||||
do {
|
while (MXC_RTCTMR->timer == temp);
|
||||||
sleepEndRtcUs = rtc_read_us();
|
|
||||||
} while(sleepEndRtcUs == tempUs);
|
|
||||||
|
|
||||||
// Get the elapsed time from the RTC. Wakeup could have been from some other event.
|
|
||||||
elapsedUs = sleepEndRtcUs - sleepStartRtcUs;
|
|
||||||
|
|
||||||
// Update the us_ticker. It was not clocked during DeepSleep
|
|
||||||
us_ticker_init();
|
|
||||||
us_ticker_set(sleepStartTickerUs + elapsedUs);
|
|
||||||
us_ticker_get_next_timestamp(&next_event);
|
|
||||||
us_ticker_set_interrupt(next_event);
|
|
||||||
|
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ static inline void inc_current_cnt(uint32_t inc) {
|
||||||
|
|
||||||
// Overflow the ticker when the us ticker overflows
|
// Overflow the ticker when the us ticker overflows
|
||||||
current_cnt += inc;
|
current_cnt += inc;
|
||||||
if(current_cnt > MAX_TICK_VAL) {
|
if (current_cnt > MAX_TICK_VAL) {
|
||||||
current_cnt -= (MAX_TICK_VAL + 1);
|
current_cnt -= (MAX_TICK_VAL + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ static inline int event_passed(uint64_t current, uint64_t event) {
|
||||||
// Determine if the event has already happened.
|
// Determine if the event has already happened.
|
||||||
// If the event is behind the current ticker, within a window,
|
// If the event is behind the current ticker, within a window,
|
||||||
// then the event has already happened.
|
// then the event has already happened.
|
||||||
if(((current < tick_win) && ((event < current) ||
|
if (((current < tick_win) && ((event < current) ||
|
||||||
(event > (MAX_TICK_VAL - (tick_win - current))))) ||
|
(event > (MAX_TICK_VAL - (tick_win - current))))) ||
|
||||||
((event < current) && (event > (current - tick_win)))) {
|
((event < current) && (event > (current - tick_win)))) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -169,7 +169,7 @@ uint32_t us_ticker_read(void)
|
||||||
{
|
{
|
||||||
uint64_t current_cnt1, current_cnt2;
|
uint64_t current_cnt1, current_cnt2;
|
||||||
uint32_t term_cnt, tmr_cnt;
|
uint32_t term_cnt, tmr_cnt;
|
||||||
int intfl1, intfl2;
|
uint32_t intfl1, intfl2;
|
||||||
|
|
||||||
if (!us_ticker_inited)
|
if (!us_ticker_inited)
|
||||||
us_ticker_init();
|
us_ticker_init();
|
||||||
|
@ -184,6 +184,7 @@ uint32_t us_ticker_read(void)
|
||||||
current_cnt2 = current_cnt;
|
current_cnt2 = current_cnt;
|
||||||
} while ((current_cnt1 != current_cnt2) || (intfl1 != intfl2));
|
} while ((current_cnt1 != current_cnt2) || (intfl1 != intfl2));
|
||||||
|
|
||||||
|
// Account for an unserviced interrupt
|
||||||
if (intfl1) {
|
if (intfl1) {
|
||||||
current_cnt1 += term_cnt;
|
current_cnt1 += term_cnt;
|
||||||
}
|
}
|
||||||
|
@ -197,6 +198,7 @@ uint32_t us_ticker_read(void)
|
||||||
void us_ticker_set_interrupt(timestamp_t timestamp)
|
void us_ticker_set_interrupt(timestamp_t timestamp)
|
||||||
{
|
{
|
||||||
// Note: interrupts are disabled before this function is called.
|
// Note: interrupts are disabled before this function is called.
|
||||||
|
|
||||||
US_TIMER->ctrl &= ~MXC_F_TMR_CTRL_ENABLE0; // disable timer
|
US_TIMER->ctrl &= ~MXC_F_TMR_CTRL_ENABLE0; // disable timer
|
||||||
|
|
||||||
if (US_TIMER->intfl) {
|
if (US_TIMER->intfl) {
|
||||||
|
|
|
@ -71,7 +71,7 @@ int can_mode(can_t *obj, CanMode mode) {
|
||||||
break;
|
break;
|
||||||
case MODE_TEST_SILENT:
|
case MODE_TEST_SILENT:
|
||||||
LPC_CAN->CNTL |= CANCNTL_TEST;
|
LPC_CAN->CNTL |= CANCNTL_TEST;
|
||||||
LPC_CAN->TEST |= (CANCNTL_LBACK | CANTEST_SILENT);
|
LPC_CAN->TEST |= (CANTEST_LBACK | CANTEST_SILENT);
|
||||||
success = 1;
|
success = 1;
|
||||||
break;
|
break;
|
||||||
case MODE_TEST_GLOBAL:
|
case MODE_TEST_GLOBAL:
|
||||||
|
|
|
@ -177,12 +177,21 @@ void pin_mode(PinName pin, PinMode mode)
|
||||||
if (pin_index < 8) {
|
if (pin_index < 8) {
|
||||||
if ((gpio->CRL & (0x03 << (pin_index * 4))) == 0) { // MODE bits = Input mode
|
if ((gpio->CRL & (0x03 << (pin_index * 4))) == 0) { // MODE bits = Input mode
|
||||||
gpio->CRL |= (0x08 << (pin_index * 4)); // Set pull-up / pull-down
|
gpio->CRL |= (0x08 << (pin_index * 4)); // Set pull-up / pull-down
|
||||||
|
gpio->CRL &= ~(0x08 << ((pin_index * 4)-1)); // ENSURES GPIOx_CRL.CNFx.bit0 = 0
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((gpio->CRH & (0x03 << ((pin_index % 8) * 4))) == 0) { // MODE bits = Input mode
|
if ((gpio->CRH & (0x03 << ((pin_index % 8) * 4))) == 0) { // MODE bits = Input mode
|
||||||
gpio->CRH |= (0x08 << ((pin_index % 8) * 4)); // Set pull-up / pull-down
|
gpio->CRH |= (0x08 << ((pin_index % 8) * 4)); // Set pull-up / pull-down
|
||||||
|
gpio->CRH &= ~(0x08 << (((pin_index % 8) * 4)-1)); // ENSURES GPIOx_CRH.CNFx.bit0 = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Now it's time to setup properly if pullup or pulldown. This is done in ODR register:
|
||||||
|
// set pull-up => bit=1, set pull-down => bit = 0
|
||||||
|
if (mode == PullUp) {
|
||||||
|
gpio->ODR |= (0x01 << (pin_index)); // Set pull-up
|
||||||
|
} else{
|
||||||
|
gpio->ODR &= ~(0x01 << (pin_index)); // Set pull-down
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case OpenDrain:
|
case OpenDrain:
|
||||||
// Set open-drain for Output mode (General Purpose or Alternate Function)
|
// Set open-drain for Output mode (General Purpose or Alternate Function)
|
||||||
|
|
Loading…
Reference in New Issue