1
0
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:
Francisco Molina 2021-06-11 18:00:16 +02:00
parent 92924ccad7
commit d9ee424b7c
No known key found for this signature in database
GPG Key ID: 3E94EAC3DBDEEDA8
14 changed files with 59 additions and 149 deletions

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -1,3 +1,6 @@
ifneq (,$(filter periph_rtt,$(USEMODULE)))
USEMODULE += periph_timer
endif
ifneq (,$(filter periph_i2c,$(USEMODULE)))
USEMODULE += core_thread_flags
endif

View File

@ -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.

View File

@ -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
*/

View File

@ -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);
}

View File

@ -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