mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
cpu/kinetis: use LPTMR as rtt backend
This commit is contained in:
parent
92924ccad7
commit
d9ee424b7c
@ -3,8 +3,8 @@ CPU_MODEL = mkw41z512vht4
|
||||
|
||||
# Put defined MCU peripherals here (in alphabetical order)
|
||||
FEATURES_PROVIDED += periph_adc
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_rtt
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_timer
|
||||
FEATURES_PROVIDED += periph_uart
|
||||
|
||||
|
@ -60,7 +60,7 @@ extern "C"
|
||||
* @name xtimer configuration
|
||||
* @{
|
||||
*/
|
||||
#if KINETIS_XTIMER_SOURCE_PIT
|
||||
#if IS_ACTIVE(KINETIS_XTIMER_SOURCE_PIT)
|
||||
/* PIT xtimer configuration */
|
||||
#define XTIMER_DEV (TIMER_PIT_DEV(0))
|
||||
#define XTIMER_CHAN (0)
|
||||
|
@ -72,7 +72,7 @@ extern "C"
|
||||
* @name xtimer configuration
|
||||
* @{
|
||||
*/
|
||||
#if KINETIS_XTIMER_SOURCE_PIT
|
||||
#if IS_ACTIVE(KINETIS_XTIMER_SOURCE_PIT)
|
||||
/* PIT xtimer configuration */
|
||||
#define XTIMER_DEV (TIMER_PIT_DEV(0))
|
||||
#define XTIMER_CHAN (0)
|
||||
|
@ -50,7 +50,7 @@ extern "C"
|
||||
* @name xtimer configuration
|
||||
* @{
|
||||
*/
|
||||
#if KINETIS_XTIMER_SOURCE_PIT
|
||||
#if IS_ACTIVE(KINETIS_XTIMER_SOURCE_PIT)
|
||||
/* PIT xtimer configuration */
|
||||
#define XTIMER_DEV (TIMER_PIT_DEV(0))
|
||||
#define XTIMER_CHAN (0)
|
||||
|
@ -15,7 +15,6 @@ config BOARD_PBA_D_01_KW2X
|
||||
select HAS_PERIPH_I2C
|
||||
select HAS_PERIPH_PWM
|
||||
select HAS_PERIPH_RTC
|
||||
select HAS_PERIPH_RTT
|
||||
select HAS_PERIPH_SPI
|
||||
select HAS_PERIPH_TIMER
|
||||
select HAS_PERIPH_UART
|
||||
|
@ -9,7 +9,6 @@ FEATURES_PROVIDED += periph_adc
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_pwm
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_rtt
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
FEATURES_PROVIDED += periph_timer
|
||||
FEATURES_PROVIDED += periph_uart
|
||||
|
@ -87,7 +87,7 @@ extern "C"
|
||||
* @name xtimer configuration
|
||||
* @{
|
||||
*/
|
||||
#if KINETIS_XTIMER_SOURCE_PIT
|
||||
#if IS_ACTIVE(KINETIS_XTIMER_SOURCE_PIT)
|
||||
/* PIT xtimer configuration */
|
||||
#define XTIMER_DEV (TIMER_PIT_DEV(0))
|
||||
#define XTIMER_CHAN (0)
|
||||
|
@ -83,7 +83,7 @@ extern "C"
|
||||
* @name xtimer configuration
|
||||
* @{
|
||||
*/
|
||||
#if KINETIS_XTIMER_SOURCE_PIT
|
||||
#if IS_ACTIVE(KINETIS_XTIMER_SOURCE_PIT)
|
||||
/* PIT xtimer configuration */
|
||||
#define XTIMER_DEV (TIMER_PIT_DEV(0))
|
||||
#define XTIMER_CHAN (0)
|
||||
|
@ -11,8 +11,6 @@ config CPU_COMMON_KINETIS
|
||||
select HAS_PERIPH_GPIO
|
||||
select HAS_PERIPH_GPIO_IRQ
|
||||
select HAS_PERIPH_PM
|
||||
select HAS_PERIPH_RTT_SET_COUNTER
|
||||
select HAS_PERIPH_RTT_OVERFLOW
|
||||
|
||||
config CPU_FAM_EA
|
||||
bool
|
||||
|
@ -1,3 +1,6 @@
|
||||
ifneq (,$(filter periph_rtt,$(USEMODULE)))
|
||||
USEMODULE += periph_timer
|
||||
endif
|
||||
ifneq (,$(filter periph_i2c,$(USEMODULE)))
|
||||
USEMODULE += core_thread_flags
|
||||
endif
|
||||
|
@ -14,8 +14,6 @@ endif
|
||||
|
||||
FEATURES_PROVIDED += periph_gpio
|
||||
FEATURES_PROVIDED += periph_gpio_irq
|
||||
FEATURES_PROVIDED += periph_rtt_set_counter
|
||||
FEATURES_PROVIDED += periph_rtt_overflow
|
||||
|
||||
# Parse parameters from CPU_MODEL using the kinetis-info.mk script in the same
|
||||
# directory as this Makefile.
|
||||
|
@ -157,18 +157,6 @@ enum {
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
#ifdef RTC
|
||||
/* All Kinetis CPUs have exactly one RTC hardware module, except for the KL02
|
||||
* family which don't have an RTC at all */
|
||||
/**
|
||||
* @name RTT and RTC configuration
|
||||
* @{
|
||||
*/
|
||||
#define RTT_FREQUENCY (1)
|
||||
#define RTT_MAX_VALUE (0xffffffff)
|
||||
/** @} */
|
||||
#endif
|
||||
|
||||
#ifndef DOXYGEN
|
||||
/**
|
||||
* @name GPIO pin modes
|
||||
@ -500,6 +488,30 @@ enum {
|
||||
#endif /* KINETIS_HAVE_LPTMR */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name RTT configuration
|
||||
* @{
|
||||
*/
|
||||
#define RTT_DEV (TIMER_LPTMR_DEV(0))
|
||||
#define RTT_MAX_VALUE (0x0000ffff)
|
||||
#define RTT_CLOCK_FREQUENCY (32768U) /* in Hz */
|
||||
#define RTT_MAX_FREQUENCY (32768U) /* in Hz */
|
||||
#define RTT_MIN_FREQUENCY (1U) /* in Hz */
|
||||
#ifndef RTT_FREQUENCY
|
||||
#define RTT_FREQUENCY RTT_MAX_FREQUENCY
|
||||
#endif
|
||||
#if IS_USED(PERIPH_RTT)
|
||||
/* On kinetis periph_rtt is built on top on an LPTIMER so if used it
|
||||
will conflict with xtimer, if a LPTIMER backend and RTT are needed
|
||||
consider using ztimer */
|
||||
#define KINETIS_XTIMER_SOURCE_PIT 1
|
||||
#endif
|
||||
/* When setting a new compare value, the value must be at least 5 more
|
||||
than the current sleep timer value. Otherwise, the timer compare
|
||||
event may be lost. */
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @brief UART hardware module types
|
||||
*/
|
||||
|
@ -14,13 +14,6 @@
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level RTT interface implementation for Freescale Kinetis
|
||||
* 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
|
||||
* RTT as a system real time clock.
|
||||
*
|
||||
* @author Johann Fischer <j.fischer@phytec.de>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
*
|
||||
@ -31,154 +24,62 @@
|
||||
#include "cpu.h"
|
||||
#include "bit.h"
|
||||
#include "periph/rtt.h"
|
||||
#include "periph/timer.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct {
|
||||
rtt_cb_t alarm_cb; /**< callback called from RTC alarm */
|
||||
void *alarm_arg; /**< argument passed to the callback */
|
||||
rtt_cb_t overflow_cb; /**< callback called when RTC overflows */
|
||||
void *overflow_arg; /**< argument passed to the callback */
|
||||
} rtt_state_t;
|
||||
static rtt_cb_t alarm_cb = NULL; /**< callback called from RTC alarm */
|
||||
static void *alarm_arg; /**< argument passed to the callback */
|
||||
static uint32_t alarm_value = 0;
|
||||
|
||||
static rtt_state_t rtt_callback;
|
||||
static void _rtt_cb(void *arg, int channel)
|
||||
{
|
||||
(void) arg;
|
||||
(void) channel;
|
||||
if (alarm_cb != NULL) {
|
||||
alarm_cb(alarm_arg);
|
||||
}
|
||||
}
|
||||
|
||||
void rtt_init(void)
|
||||
{
|
||||
/* Enable module clock gate */
|
||||
RTC_CLKEN();
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* Enable user mode access */
|
||||
bit_set32(&RTC->CR, RTC_CR_SUP_SHIFT);
|
||||
|
||||
/* Disable all RTC interrupts. */
|
||||
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)
|
||||
{
|
||||
rtt_callback.overflow_cb = cb;
|
||||
rtt_callback.overflow_arg = arg;
|
||||
bit_set32(&RTC->IER, RTC_IER_TOIE_SHIFT);
|
||||
}
|
||||
|
||||
void rtt_clear_overflow_cb(void)
|
||||
{
|
||||
bit_clear32(&RTC->IER, RTC_IER_TOIE_SHIFT);
|
||||
timer_init(RTT_DEV, RTT_FREQUENCY, _rtt_cb, NULL);
|
||||
alarm_value = 0;
|
||||
}
|
||||
|
||||
uint32_t rtt_get_counter(void)
|
||||
{
|
||||
uint32_t t;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
/* Read twice to make sure we get a stable reading */
|
||||
t = RTC->TSR;
|
||||
|
||||
if (t == RTC->TSR) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
/* Fallback if we are not getting stable readings */
|
||||
return t;
|
||||
return timer_read(RTT_DEV);
|
||||
}
|
||||
|
||||
void rtt_set_counter(uint32_t counter)
|
||||
{
|
||||
/* Disable time counter before writing to the timestamp register */
|
||||
bit_clear32(&RTC->SR, RTC_SR_TCE_SHIFT);
|
||||
RTC->TPR = 0;
|
||||
/* write TSR after TPR, as clearing TPR bit 14 will increment TSR */
|
||||
RTC->TSR = counter;
|
||||
/* Enable when done */
|
||||
bit_set32(&RTC->SR, RTC_SR_TCE_SHIFT);
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
*
|
||||
* Workaround: Set TAF to alarm - 1
|
||||
*/
|
||||
|
||||
/* Disable Timer Alarm Interrupt */
|
||||
bit_clear32(&RTC->IER, RTC_IER_TAIE_SHIFT);
|
||||
|
||||
RTC->TAR = alarm - 1;
|
||||
|
||||
rtt_callback.alarm_cb = cb;
|
||||
rtt_callback.alarm_arg = arg;
|
||||
|
||||
/* Enable Timer Alarm Interrupt */
|
||||
bit_set32(&RTC->IER, RTC_IER_TAIE_SHIFT);
|
||||
unsigned state = irq_disable();
|
||||
alarm_arg = arg;
|
||||
alarm_cb = cb;
|
||||
alarm_value = alarm;
|
||||
timer_set_absolute(RTT_DEV, 0, alarm % RTT_MAX_VALUE);
|
||||
irq_restore(state);
|
||||
}
|
||||
|
||||
uint32_t rtt_get_alarm(void)
|
||||
{
|
||||
return RTC->TAR + 1;
|
||||
return alarm_value;
|
||||
}
|
||||
|
||||
void rtt_clear_alarm(void)
|
||||
{
|
||||
/* Disable Timer Alarm Interrupt */
|
||||
bit_clear32(&RTC->IER, RTC_IER_TAIE_SHIFT);
|
||||
timer_clear(RTT_DEV, 0);
|
||||
}
|
||||
|
||||
/* RTC module has independent power suply. We can not really turn it on/off. */
|
||||
|
||||
void rtt_poweron(void)
|
||||
{
|
||||
/* Enable Time Counter */
|
||||
bit_set32(&RTC->SR, RTC_SR_TCE_SHIFT);
|
||||
timer_start(RTT_DEV);
|
||||
}
|
||||
|
||||
void rtt_poweroff(void)
|
||||
{
|
||||
/* Disable Time Counter */
|
||||
bit_clear32(&RTC->SR, RTC_SR_TCE_SHIFT);
|
||||
}
|
||||
|
||||
void isr_rtc(void)
|
||||
{
|
||||
if (RTC->SR & RTC_SR_TAF_MASK) {
|
||||
if (rtt_callback.alarm_cb != NULL) {
|
||||
/* Disable Timer Alarm Interrupt */
|
||||
bit_clear32(&RTC->IER, RTC_IER_TAIE_SHIFT);
|
||||
rtt_callback.alarm_cb(rtt_callback.alarm_arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (RTC->SR & RTC_SR_TOF_MASK) {
|
||||
if (rtt_callback.overflow_cb != NULL) {
|
||||
rtt_callback.overflow_cb(rtt_callback.overflow_arg);
|
||||
}
|
||||
}
|
||||
|
||||
cortexm_isr_end();
|
||||
timer_stop(RTT_DEV);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ DISABLE_MODULE += periph_init_rtt
|
||||
include $(RIOTBASE)/Makefile.include
|
||||
|
||||
# Put board specific dependencies here
|
||||
ifeq (stm32,$(CPU))
|
||||
ifneq (,$(filter stm32 kinetis,$(CPU)))
|
||||
ifneq (f1,$(CPU_FAM))
|
||||
# all stm32% but stm32f1 RTT are based on a 16 bit LPTIM, if using the default
|
||||
# 32768KHz configuration TICKS_TO_WAIT will overflow
|
||||
|
Loading…
Reference in New Issue
Block a user