MCUXpresso: Update Low Power Ticker

1. Enable LPTICKER for K22, K24, K64, K66, K82, KL82F, KW24D
2. Change the implementation to only use the LPTMR which reduces
   the amount of interrupts generated which is required for tickless
   operation

Signed-off-by: Mahesh Mahadevan <mahesh.mahadevan@nxp.com>
pull/7009/head
Mahesh Mahadevan 2018-03-27 05:37:46 -05:00 committed by Bartek Szatkowski
parent 132dc87f3e
commit 0d0321a7f0
2 changed files with 24 additions and 148 deletions

View File

@ -17,72 +17,27 @@
#if DEVICE_LPTICKER
#include "lp_ticker_api.h"
#include "fsl_rtc.h"
#include "fsl_lptmr.h"
#include "cmsis.h"
#include "rtc_api.h"
const ticker_info_t* lp_ticker_get_info()
{
static const ticker_info_t info = {
32768, // 32kHz
32 // 32 bit counter
16 // 16 bit counter
};
return &info;
}
#define SEC_BITS (17)
#define SEC_SHIFT (15)
#define SEC_MASK ((1 << SEC_BITS) - 1)
#define TICKS_BITS (15)
#define TICKS_SHIFT (0)
#define TICKS_MASK ((1 << TICKS_BITS) - 1)
#define OSC32K_CLK_HZ (32768)
#define MAX_LPTMR_SLEEP ((1 << 16) - 1)
static bool lp_ticker_inited = false;
static timestamp_t lptmr_schedule = 0;
static void rtc_isr(void)
{
uint32_t sr = RTC->SR;
if (sr & RTC_SR_TOF_MASK) {
/* Reset RTC to 0 so it keeps counting. */
RTC_StopTimer(RTC);
RTC->TSR = 0;
RTC_StartTimer(RTC);
} else if (sr & RTC_SR_TAF_MASK) {
RTC_DisableInterrupts(RTC, kRTC_AlarmInterruptEnable);
RTC->TAR = 0; /* Write clears the IRQ flag */
/* Wait subsecond remainder. */
const uint32_t now_ticks = lp_ticker_read();
uint32_t delta_ticks =
lptmr_schedule >= now_ticks ? lptmr_schedule - now_ticks : (uint32_t)((uint64_t) lptmr_schedule + 0xFFFFFFFF - now_ticks);
lptmr_schedule = 0;
if (delta_ticks == 0) {
lp_ticker_irq_handler();
} else {
LPTMR_StopTimer(LPTMR0);
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
LPTMR_SetTimerPeriod(LPTMR0, delta_ticks);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
LPTMR_StartTimer(LPTMR0);
}
} else if (sr & RTC_SR_TIF_MASK) {
RTC_DisableInterrupts(RTC, kRTC_TimeOverflowInterruptEnable);
}
}
extern void rtc_setup_oscillator(RTC_Type *base);
static void lptmr_isr(void)
{
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
LPTMR_StopTimer(LPTMR0);
lp_ticker_irq_handler();
}
@ -94,42 +49,26 @@ void lp_ticker_init(void)
lptmr_config_t lptmrConfig;
if (!lp_ticker_inited) {
/* Setup low resolution clock - RTC */
if (!rtc_isenabled()) {
rtc_init();
RTC_StartTimer(RTC);
}
RTC->TAR = 0; /* Write clears the IRQ flag */
NVIC_ClearPendingIRQ(RTC_IRQn);
RTC_DisableInterrupts(RTC, kRTC_AlarmInterruptEnable | kRTC_SecondsInterruptEnable);
NVIC_SetVector(RTC_IRQn, (uint32_t) rtc_isr);
NVIC_EnableIRQ(RTC_IRQn);
/* Setup high resolution clock - LPTMR */
LPTMR_GetDefaultConfig(&lptmrConfig);
/* Setup the RTC 32KHz oscillator */
CLOCK_EnableClock(kCLOCK_Rtc0);
rtc_setup_oscillator(RTC);
/* Use 32kHz drive */
CLOCK_SetXtal32Freq(OSC32K_CLK_HZ);
lptmrConfig.prescalerClockSource = kLPTMR_PrescalerClock_2;
lptmrConfig.enableFreeRunning = true;
LPTMR_Init(LPTMR0, &lptmrConfig);
LPTMR_DisableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
NVIC_ClearPendingIRQ(LPTMR0_IRQn);
NVIC_SetVector(LPTMR0_IRQn, (uint32_t) lptmr_isr);
NVIC_SetVector(LPTMR0_IRQn, (uint32_t)lptmr_isr);
EnableIRQ(LPTMR0_IRQn);
lptmr_schedule = 0;
lp_ticker_inited = true;
} else {
/* In case of re-init we need to disable lp ticker interrupt. */
LPTMR_StopTimer(LPTMR0);
RTC_DisableInterrupts(RTC, kRTC_AlarmInterruptEnable);
RTC->TAR = 0; /* Write clears the IRQ flag */
lptmr_schedule = 0;
LPTMR_DisableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
}
}
@ -139,28 +78,7 @@ void lp_ticker_init(void)
*/
uint32_t lp_ticker_read(void)
{
uint32_t count;
uint32_t last_count;
/* TPR is increments every 32.768 kHz clock cycle. The TSR increments when
* bit 14 of the TPR transitions from a logic one (32768 ticks - 1 sec).
* After that TPR starts counting from 0.
*
* count value is built as follows:
* count[0 - 14] - ticks (RTC->TPR)
* count[15 - 31] - seconds (RTC->TSR)
*/
/* Loop until the same tick is read twice since this
* is ripple counter on a different clock domain.
*/
count = ((RTC->TSR << SEC_SHIFT) | (RTC->TPR & TICKS_MASK));
do {
last_count = count;
count = ((RTC->TSR << SEC_SHIFT) | (RTC->TPR & TICKS_MASK));
} while (last_count != count);
return count;
return LPTMR_GetCurrentTimerCount(LPTMR0);
}
/** Set interrupt for specified timestamp
@ -169,52 +87,13 @@ uint32_t lp_ticker_read(void)
*/
void lp_ticker_set_interrupt(timestamp_t timestamp)
{
lptmr_schedule = 0;
/* We get here absolute interrupt time-stamp in ticks which takes into account counter overflow.
* Since we use additional count-down timer to generate interrupt we need to calculate
* load value based on time-stamp.
*/
const uint32_t now_ticks = lp_ticker_read();
uint32_t delta_ticks =
timestamp >= now_ticks ? timestamp - now_ticks : (uint32_t)((uint64_t) timestamp + 0xFFFFFFFF - now_ticks);
if (delta_ticks == 0) {
/* The requested delay is less than the minimum resolution of this counter. */
delta_ticks = 1;
}
if (delta_ticks > MAX_LPTMR_SLEEP) {
/* Using RTC if wait time is over 16b (2s @32kHz). */
uint32_t delay_sec = delta_ticks >> 15;
RTC->TAR = RTC->TSR + delay_sec - 1;
RTC_EnableInterrupts(RTC, kRTC_AlarmInterruptEnable);
/* Store absolute interrupt time-stamp value for further processing in
* RTC interrupt handler (schedule remaining ticks using LPTMR). */
lptmr_schedule = timestamp;
} else {
/* Below RTC resolution using LPTMR. */
/* In case of re-schedule we need to disable RTC interrupt. */
RTC_DisableInterrupts(RTC, kRTC_AlarmInterruptEnable);
RTC->TAR = 0; /* Write clears the IRQ flag */
/* When the LPTMR is enabled, the CMR can be altered only when CSR[TCF] is set. When
* updating the CMR, the CMR must be written and CSR[TCF] must be cleared before the
* LPTMR counter has incremented past the new LPTMR compare value.
*
* When TEN is clear, it resets the LPTMR internal logic, including the CNR and TCF.
* When TEN is set, the LPTMR is enabled. While writing 1 to this field, CSR[5:1] must
* not be altered.
*/
LPTMR_StopTimer(LPTMR0);
LPTMR_SetTimerPeriod(LPTMR0, delta_ticks);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
LPTMR_StartTimer(LPTMR0);
if (timestamp == 0) {
timestamp = 1;
}
LPTMR_SetTimerPeriod(LPTMR0, timestamp);
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
LPTMR_StartTimer(LPTMR0);
}
void lp_ticker_fire_interrupt(void)
@ -228,7 +107,6 @@ void lp_ticker_fire_interrupt(void)
void lp_ticker_disable_interrupt(void)
{
LPTMR_DisableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
RTC_DisableInterrupts(RTC, kRTC_AlarmInterruptEnable);
}
/** Clear the low power ticker interrupt
@ -236,9 +114,7 @@ void lp_ticker_disable_interrupt(void)
*/
void lp_ticker_clear_interrupt(void)
{
RTC->TAR = 0; /* Write clears the IRQ flag */
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
lptmr_schedule = 0;
}
#endif /* DEVICE_LPTICKER */

View File

@ -522,7 +522,7 @@
"macros": ["CPU_MK22FN512VLH12", "FSL_RTOS_MBED"],
"inherits": ["Target"],
"detect_code": ["0231"],
"device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG"],
"device_has": ["LPTICKER", "ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG"],
"device_name": "MK22DN512xxx5"
},
"K22F": {
@ -568,7 +568,7 @@
"is_disk_virtual": true,
"inherits": ["Target"],
"detect_code": ["0218"],
"device_has": ["USTICKER", "ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG"],
"device_has": ["USTICKER", "LPTICKER", "ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG"],
"release_versions": ["2", "5"],
"device_name": "MKL82Z128xxx7"
},
@ -586,7 +586,7 @@
"macros": ["CPU_MKW24D512VHA5", "FSL_RTOS_MBED"],
"inherits": ["Target"],
"detect_code": ["0250"],
"device_has": ["ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"],
"device_has": ["LPTICKER", "ANALOGIN", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"],
"release_versions": ["2", "5"],
"device_name": "MKW24D512xxx5",
"bootloader_supported": true
@ -612,7 +612,7 @@
"public": false,
"macros": ["CPU_MK24FN1M0VDC12", "FSL_RTOS_MBED"],
"inherits": ["Target"],
"device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"],
"device_has": ["LPTICKER", "ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"],
"device_name": "MK24FN1M0xxx12"
},
"RO359B": {
@ -670,7 +670,7 @@
"extra_labels": ["Freescale", "MCUXpresso_MCUS", "KSDK2_MCUS", "KPSDK_MCUS", "KPSDK_CODE", "MCU_K64F"],
"is_disk_virtual": true,
"macros": ["CPU_MK64FN1M0VMD12", "FSL_RTOS_MBED", "TARGET_K64F"],
"device_has": ["USTICKER", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "FLASH"],
"device_has": ["USTICKER", "LPTICKER", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "FLASH"],
"device_name": "MK64FN1M0xxx12"
},
"HEXIWEAR": {
@ -682,7 +682,7 @@
"is_disk_virtual": true,
"default_toolchain": "ARM",
"detect_code": ["0214"],
"device_has": ["USTICKER", "ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"],
"device_has": ["USTICKER", "LPTICKER", "ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"],
"default_lib": "std",
"release_versions": ["2", "5"],
"device_name": "MK64FN1M0xxx12",
@ -697,7 +697,7 @@
"macros": ["CPU_MK66FN2M0VMD18", "FSL_RTOS_MBED"],
"inherits": ["Target"],
"detect_code": ["0311"],
"device_has": ["USTICKER", "ANALOGIN", "ANALOGOUT", "EMAC", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"],
"device_has": ["USTICKER", "LPTICKER", "ANALOGIN", "ANALOGOUT", "EMAC", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"],
"features": ["LWIP"],
"release_versions": ["2", "5"],
"device_name": "MK66FN2M0xxx18",
@ -715,7 +715,7 @@
"macros": ["CPU_MK82FN256VDC15", "FSL_RTOS_MBED"],
"inherits": ["Target"],
"detect_code": ["0217"],
"device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"],
"device_has": ["LPTICKER", "ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"],
"release_versions": ["2", "5"],
"device_name": "MK82FN256xxx15"
},