1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/stm32/periph/rtt_all.c
2024-01-29 14:44:10 -05:00

261 lines
7.2 KiB
C

/*
* Copyright (C) 2017 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_stm32
* @ingroup drivers_periph_rtt
* @{
*
* @file
* @brief RTT implementation using LPTIM1
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Andres Diaz <andres.diaz@andeselectronics.cl>
* @}
*/
#include <assert.h>
#include "cpu.h"
#include "irq.h"
#include "periph/rtt.h"
#include "stmclk.h"
/* this driver is only valid for STM CPUs that provide LPTIMERs */
#if defined(LPTIM1)
/* figure out the used pre-scaler */
#if (RTT_FREQUENCY == 32768)
#define PRE (0)
#elif (RTT_FREQUENCY == 16384)
#define PRE (LPTIM_CFGR_PRESC_0)
#elif (RTT_FREQUENCY == 8192)
#define PRE (LPTIM_CFGR_PRESC_1)
#elif (RTT_FREQUENCY == 4096)
#define PRE (LPTIM_CFGR_PRESC_1 | LPTIM_CFGR_PRESC_0)
#elif (RTT_FREQUENCY == 2048)
#define PRE (LPTIM_CFGR_PRESC_2)
#elif (RTT_FREQUENCY == 1024)
#define PRE (LPTIM_CFGR_PRESC_2 | LPTIM_CFGR_PRESC_0)
#elif (RTT_FREQUENCY == 512)
#define PRE (LPTIM_CFGR_PRESC_2 | LPTIM_CFGR_PRESC_1)
#elif (RTT_FREQUENCY == 256)
#define PRE (LPTIM_CFGR_PRESC)
#else
#error "RTT config: RTT_FREQUENCY not configured or invalid for your board"
#endif
#if defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7)
#define CLOCK_SRC_REG RCC->DCKCFGR2
#define CLOCK_SRC_MASK RCC_DCKCFGR2_LPTIM1SEL
#if IS_ACTIVE(CONFIG_BOARD_HAS_LSE)
#define CLOCK_SRC_CFG (RCC_DCKCFGR2_LPTIM1SEL_1 | RCC_DCKCFGR2_LPTIM1SEL_0)
#else
#define CLOCK_SRC_CFG (RCC_DCKCFGR2_LPTIM1SEL_0)
#endif
#elif defined(CPU_FAM_STM32L5)
#define CLOCK_SRC_REG RCC->CCIPR1
#define CLOCK_SRC_MASK RCC_CCIPR1_LPTIM1SEL
#if IS_ACTIVE(CONFIG_BOARD_HAS_LSE)
#define CLOCK_SRC_CFG (RCC_CCIPR1_LPTIM1SEL_1 | RCC_CCIPR1_LPTIM1SEL_0)
#else
#define CLOCK_SRC_CFG (RCC_CCIPR1_LPTIM1SEL_0)
#endif
#else
#define CLOCK_SRC_REG RCC->CCIPR
#define CLOCK_SRC_MASK RCC_CCIPR_LPTIM1SEL
#if IS_ACTIVE(CONFIG_BOARD_HAS_LSE)
#define CLOCK_SRC_CFG (RCC_CCIPR_LPTIM1SEL_1 | RCC_CCIPR_LPTIM1SEL_0)
#else
#define CLOCK_SRC_CFG (RCC_CCIPR_LPTIM1SEL_0)
#endif
#endif
#if defined(CPU_FAM_STM32WB)
/* IM32 is the interrupt line used to wakeup the CPU on WB but is not defined
in the CMSIS. According to the reference manual, this is the first bit in the
register. */
#define EXTI_IMR2_IM32 (1 << 0)
#endif
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32L5)
#define IMR_REG IMR2
#define EXTI_IMR_BIT EXTI_IMR2_IM32
#elif defined(CPU_FAM_STM32G0) || defined(CPU_FAM_STM32WL) || \
defined(CPU_FAM_STM32C0)
#define IMR_REG IMR1
#define EXTI_IMR_BIT EXTI_IMR1_IM29
#elif defined(CPU_FAM_STM32G4)
#define IMR_REG IMR2
#define EXTI_IMR_BIT EXTI_IMR2_IM37
#elif defined(CPU_FAM_STM32L0)
#define IMR_REG IMR
#define EXTI_IMR_BIT EXTI_IMR_IM29
#else
#define IMR_REG IMR
#define FTSR_REG FTSR
#define RTSR_REG RTSR
#define PR_REG PR
#define EXTI_FTSR_BIT EXTI_FTSR_TR23
#define EXTI_RTSR_BIT EXTI_RTSR_TR23
#define EXTI_IMR_BIT EXTI_IMR_MR23
#define EXTI_PR_BIT EXTI_PR_PR23
#endif
/* allocate memory for overflow and alarm callbacks + args */
static rtt_cb_t ovf_cb = NULL;
static void *ovf_arg;
static rtt_cb_t to_cb = NULL;
static void *to_arg;
void rtt_init(void)
{
/* Enable the low speed clock (LSE) */
stmclk_enable_lfclk();
/* power on the selected LPTIMER */
rtt_poweron();
/* stop the timer and reset configuration */
LPTIM1->CR = 0;
/* select low speed clock (LSI or LSE) */
CLOCK_SRC_REG &= ~(CLOCK_SRC_MASK);
CLOCK_SRC_REG |= CLOCK_SRC_CFG;
/* set configuration: prescale factor and external clock (LSI or LSE) */
LPTIM1->CFGR = PRE;
/* enable overflow and compare interrupts */
LPTIM1->IER = (LPTIM_IER_ARRMIE | LPTIM_IER_CMPMIE);
/* configure the EXTI channel, as RTT interrupts are routed through it.
* Needs to be configured to trigger on rising edges. */
EXTI->IMR_REG |= EXTI_IMR_BIT;
#if !defined(CPU_FAM_STM32L4) && !defined(CPU_FAM_STM32L0) && \
!defined(CPU_FAM_STM32WB) && !defined(CPU_FAM_STM32G4) && \
!defined(CPU_FAM_STM32G0) && !defined(CPU_FAM_STM32WL) && \
!defined(CPU_FAM_STM32L5) && !defined(CPU_FAM_STM32C0)
EXTI->FTSR_REG &= ~(EXTI_FTSR_BIT);
EXTI->RTSR_REG |= EXTI_RTSR_BIT;
EXTI->PR_REG = EXTI_PR_BIT;
#endif
#if defined(TIM6_DAC_LPTIM1_SHARED_IRQ)
NVIC_EnableIRQ(TIM6_DAC_LPTIM1_IRQn);
#else
NVIC_EnableIRQ(LPTIM1_IRQn);
#endif
/* enable timer */
LPTIM1->CR = LPTIM_CR_ENABLE;
/* set auto-reload value (timer needs to be enabled for this) */
LPTIM1->ICR = LPTIM_ICR_ARROKCF;
LPTIM1->ARR = RTT_MAX_VALUE;
while (!(LPTIM1->ISR & LPTIM_ISR_ARROK)) {}
/* start the timer */
LPTIM1->CR |= LPTIM_CR_CNTSTRT;
}
uint32_t rtt_get_counter(void)
{
uint32_t cnt;
do {
cnt = LPTIM1->CNT;
} while (cnt != LPTIM1->CNT);
return cnt;
}
void rtt_set_overflow_cb(rtt_cb_t cb, void *arg)
{
assert(cb);
unsigned is = irq_disable();
ovf_cb = cb;
ovf_arg = arg;
irq_restore(is);
}
void rtt_clear_overflow_cb(void)
{
ovf_cb = NULL;
}
void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg)
{
assert(cb && !(alarm & ~RTT_MAX_VALUE));
unsigned is = irq_disable();
LPTIM1->ICR = LPTIM_ICR_CMPOKCF;
to_cb = cb;
to_arg = arg;
LPTIM1->CMP = (uint16_t)alarm;
while (!(LPTIM1->ISR & LPTIM_ISR_CMPOK)) {}
irq_restore(is);
}
uint32_t rtt_get_alarm(void)
{
return LPTIM1->CMP;
}
void rtt_clear_alarm(void)
{
to_cb = NULL;
}
void rtt_poweron(void)
{
#ifdef RCC_APB1ENR1_LPTIM1EN
periph_clk_en(APB1, RCC_APB1ENR1_LPTIM1EN);
#elif defined(RCC_APBENR1_LPTIM1EN)
periph_clk_en(APB1, RCC_APBENR1_LPTIM1EN);
#else
periph_clk_en(APB1, RCC_APB1ENR_LPTIM1EN);
#endif
}
void rtt_poweroff(void)
{
#ifdef RCC_APB1ENR1_LPTIM1EN
periph_clk_dis(APB1, RCC_APB1ENR1_LPTIM1EN);
#elif defined(RCC_APBENR1_LPTIM1EN)
periph_clk_dis(APB1, RCC_APBENR1_LPTIM1EN);
#else
periph_clk_dis(APB1, RCC_APB1ENR_LPTIM1EN);
#endif
}
#if defined(CPU_FAM_STM32G0)
void isr_tim6_dac_lptim1(void)
#else
void isr_lptim1(void)
#endif
{
if (LPTIM1->ISR & LPTIM_ISR_CMPM) {
if (to_cb) {
/* 'consume' the callback (as it might be set again in the cb) */
rtt_cb_t tmp = to_cb;
to_cb = NULL;
tmp(to_arg);
}
}
if (LPTIM1->ISR & LPTIM_ISR_ARRM) {
if (ovf_cb) {
ovf_cb(ovf_arg);
}
}
LPTIM1->ICR = (LPTIM_ICR_ARRMCF | LPTIM_ICR_CMPMCF);
#if !defined(CPU_FAM_STM32L4) && !defined(CPU_FAM_STM32L0) && \
!defined(CPU_FAM_STM32WB) && !defined(CPU_FAM_STM32G4) && \
!defined(CPU_FAM_STM32G0) && !defined(CPU_FAM_STM32WL) && \
!defined(CPU_FAM_STM32L5) && !defined(CPU_FAM_STM32C0)
EXTI->PR_REG = EXTI_PR_BIT; /* only clear the associated bit */
#endif
cortexm_isr_end();
}
#endif /* LPTIM1 */