From c7801e466d8a66e0c20773b129f42041f1a85cab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Fri, 16 Mar 2018 09:00:31 +0100 Subject: [PATCH] kinetis: Refactor RTT driver - Keep counter value between resets - Let kinetis_mcg_init manage the RTC oscillator, to avoid disrupting the core clock in certain configurations - Remove some unnecessary macros for hardware abstraction; all Kinetis CPUs which have an RTC only have a single RTC instance, and the ISRs and hardware registers are named the same way in all Kinetis CPU headers. --- cpu/kinetis/periph/rtt.c | 113 +++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 65 deletions(-) diff --git a/cpu/kinetis/periph/rtt.c b/cpu/kinetis/periph/rtt.c index b7b537062a..4bbf3240d0 100644 --- a/cpu/kinetis/periph/rtt.c +++ b/cpu/kinetis/periph/rtt.c @@ -15,7 +15,7 @@ * * @file * @brief Low-level RTT interface implementation for Freescale Kinetis - * MCUs. Freescale's RTC module is what RIOT calls a Real-Time + * MCUs. NXP's RTC module is what RIOT calls a Real-Time * Timer (RTT), a simple counter which counts seconds; RIOT Real- * Time Clocks (RTC) counts seconds, minutes, hours etc. We provide * an RTT->RTC wrapper layer in a separate file to allow using the @@ -29,16 +29,13 @@ #include #include "cpu.h" +#include "bit.h" #include "periph/rtt.h" #include "periph_conf.h" #define ENABLE_DEBUG (0) #include "debug.h" -#ifndef RTC_LOAD_CAP_BITS -#define RTC_LOAD_CAP_BITS 0 -#endif - typedef struct { rtt_cb_t alarm_cb; /**< callback called from RTC alarm */ void *alarm_arg; /**< argument passed to the callback */ @@ -50,58 +47,58 @@ static rtt_state_t rtt_callback; void rtt_init(void) { - RTC_Type *rtt = RTT_DEV; + /* Enable module clock gate */ + RTC_CLKEN(); - RTT_UNLOCK(); - /* Reset RTC */ - rtt->CR = RTC_CR_SWR_MASK; - /* cppcheck-suppress redundantAssignment - * reset routine */ - rtt->CR = 0; + /* At this point, the CPU core may be clocked by a clock derived from the + * RTC oscillator, avoid touching the oscillator enable bit (OSCE) in RTC_CR */ - if (rtt->SR & RTC_SR_TIF_MASK) { - /* Clear TIF by writing TSR. */ - rtt->TSR = 0; - } - - /* Enable RTC oscillator and non-supervisor mode accesses. */ - /* Enable load capacitance as configured by periph_conf.h */ - rtt->CR = RTC_CR_OSCE_MASK | RTC_CR_SUP_MASK | RTC_LOAD_CAP_BITS; - - /* Clear TAF by writing TAR. */ - rtt->TAR = 0xffffff42; + /* Enable user mode access */ + bit_set32(&RTC->CR, RTC_CR_SUP_SHIFT); /* Disable all RTC interrupts. */ - rtt->IER = 0; + RTC->IER = 0; + + /* The RTC module is only reset on VBAT power on reset, we try to preserve + * the seconds counter between reboots */ + if (RTC->SR & RTC_SR_TIF_MASK) { + /* Time Invalid Flag is set, clear TIF by writing TSR */ + + /* Stop counter to make TSR writable */ + bit_clear32(&RTC->SR, RTC_SR_TCE_SHIFT); + + RTC->TSR = 0; + } + + /* Clear the alarm flag TAF by writing a new alarm target to TAR */ + RTC->TAR = 0xffffffff; + + /* Enable RTC interrupts */ + NVIC_EnableIRQ(RTC_IRQn); rtt_poweron(); } void rtt_set_overflow_cb(rtt_cb_t cb, void *arg) { - RTC_Type *rtt = RTT_DEV; rtt_callback.overflow_cb = cb; rtt_callback.overflow_arg = arg; - rtt->IER |= RTC_IER_TOIE_MASK; + bit_set32(&RTC->IER, RTC_IER_TOIE_SHIFT); } void rtt_clear_overflow_cb(void) { - RTC_Type *rtt = RTT_DEV; - rtt_callback.overflow_cb = NULL; - rtt_callback.overflow_arg = NULL; - rtt->IER &= ~(RTC_IER_TOIE_MASK); + bit_clear32(&RTC->IER, RTC_IER_TOIE_SHIFT); } uint32_t rtt_get_counter(void) { - RTC_Type *rtt = RTT_DEV; uint32_t t; for (int i = 0; i < 3; i++) { /* Read twice to make sure we get a stable reading */ - t = rtt->TSR; + t = RTC->TSR; - if (t == rtt->TSR) { + if (t == RTC->TSR) { return t; } } @@ -111,13 +108,11 @@ uint32_t rtt_get_counter(void) void rtt_set_counter(uint32_t counter) { - RTC_Type *rtt = RTT_DEV; - /* Disable time counter before writing to the timestamp register */ - rtt->SR &= ~RTC_SR_TCE_MASK; - rtt->TSR = counter; + bit_clear32(&RTC->SR, RTC_SR_TCE_SHIFT); + RTC->TSR = counter; /* Enable when done */ - rtt->SR |= RTC_SR_TCE_MASK; + bit_set32(&RTC->SR, RTC_SR_TCE_SHIFT); } @@ -125,71 +120,59 @@ void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) { /* The alarm is triggered when TSR matches TAR, and TSR increments. This * seem counterintuitive as most users expect the alarm to trigger - * immediately when the counter becomes equal to the alarm time. */ - RTC_Type *rtt = RTT_DEV; + * immediately when the counter becomes equal to the alarm time. + * + * Workaround: Set TAF to alarm - 1 + */ /* Disable Timer Alarm Interrupt */ - rtt->IER &= ~(RTC_IER_TAIE_MASK); + bit_clear32(&RTC->IER, RTC_IER_TAIE_SHIFT); - rtt->TAR = alarm - 1; + RTC->TAR = alarm - 1; rtt_callback.alarm_cb = cb; rtt_callback.alarm_arg = arg; /* Enable Timer Alarm Interrupt */ - rtt->IER |= RTC_IER_TAIE_MASK; - - /* Enable RTC interrupts */ - NVIC_SetPriority(RTT_IRQ, RTT_IRQ_PRIO); - NVIC_EnableIRQ(RTT_IRQ); + bit_set32(&RTC->IER, RTC_IER_TAIE_SHIFT); } uint32_t rtt_get_alarm(void) { - RTC_Type *rtt = RTT_DEV; - return rtt->TAR + 1; + return RTC->TAR + 1; } void rtt_clear_alarm(void) { - RTC_Type *rtt = RTT_DEV; - /* Disable Timer Alarm Interrupt */ - rtt->IER &= ~RTC_IER_TAIE_MASK; - rtt->TAR = 0; - rtt_callback.alarm_cb = NULL; - rtt_callback.alarm_arg = NULL; + bit_clear32(&RTC->IER, RTC_IER_TAIE_SHIFT); } /* RTC module has independent power suply. We can not really turn it on/off. */ void rtt_poweron(void) { - RTC_Type *rtt = RTT_DEV; /* Enable Time Counter */ - rtt->SR |= RTC_SR_TCE_MASK; + bit_set32(&RTC->SR, RTC_SR_TCE_SHIFT); } void rtt_poweroff(void) { - RTC_Type *rtt = RTT_DEV; /* Disable Time Counter */ - rtt->SR &= ~RTC_SR_TCE_MASK; + bit_clear32(&RTC->SR, RTC_SR_TCE_SHIFT); } -void RTT_ISR(void) +void isr_rtc(void) { - RTC_Type *rtt = RTT_DEV; - - if (rtt->SR & RTC_SR_TAF_MASK) { + if (RTC->SR & RTC_SR_TAF_MASK) { if (rtt_callback.alarm_cb != NULL) { /* Disable Timer Alarm Interrupt */ - rtt->IER &= ~RTC_IER_TAIE_MASK; + bit_clear32(&RTC->IER, RTC_IER_TAIE_SHIFT); rtt_callback.alarm_cb(rtt_callback.alarm_arg); } } - if (rtt->SR & RTC_SR_TOF_MASK) { + if (RTC->SR & RTC_SR_TOF_MASK) { if (rtt_callback.overflow_cb != NULL) { rtt_callback.overflow_cb(rtt_callback.overflow_arg); }