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_f1.c
2020-10-23 00:46:26 +02:00

207 lines
5.1 KiB
C

/*
* Copyright (C) 2014 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 Low-level RTT driver implementation for STM32F1
*
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
*
* @}
*/
#include "cpu.h"
#include "periph/rtt.h"
#include "periph_conf.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#define RTT_PRESCALER ((RTT_CLOCK_FREQUENCY / RTT_FREQUENCY) - 1 )
#define RTT_FLAG_RTOFF ((uint16_t)0x0020) /**< RTC Operation OFF flag */
#define RTT_FLAG_RSF ((uint16_t)0x0008) /**< Registers Synchronized flag */
#define RTT_FLAG_OW ((uint16_t)0x0004) /**< Overflow flag */
#define RTT_FLAG_ALR ((uint16_t)0x0002) /**< Alarm flag */
#define RTT_FLAG_SEC ((uint16_t)0x0001) /**< Second flag */
static inline void _rtt_enter_config_mode(void);
static inline void _rtt_leave_config_mode(void);
/*
* callback and argument for an active alarm
*/
static rtt_cb_t alarm_cb;
static void *alarm_arg;
/*
* callback and argument for overflow callback
*/
static rtt_cb_t overflow_cb;
static void *overflow_arg;
void rtt_init(void)
{
rtt_poweron();
/* configure interrupt */
NVIC_SetPriority(RTT_IRQ, RTT_IRQ_PRIO);
NVIC_EnableIRQ(RTT_IRQ);
/* clear RSF flag */
RTT_DEV->CRL &= ~(RTT_FLAG_RSF);
_rtt_enter_config_mode();
/* Reset RTC counter MSB word */
RTT_DEV->CNTH = 0x0000;
/* Set RTC counter LSB word */
RTT_DEV->CNTL = 0x0000;
/* set prescaler */
RTT_DEV->PRLH = ((RTT_PRESCALER>>16)&0x000f);
RTT_DEV->PRLL = (RTT_PRESCALER&0xffff);
_rtt_leave_config_mode();
}
void rtt_set_overflow_cb(rtt_cb_t cb, void *arg)
{
overflow_cb = cb;
overflow_arg = arg;
_rtt_enter_config_mode();
/* Enable overflow interrupt */
RTT_DEV->CRH |= RTC_CRH_OWIE;
_rtt_leave_config_mode();
}
void rtt_clear_overflow_cb(void)
{
_rtt_enter_config_mode();
/* Clear overflow interrupt */
RTT_DEV->CRH &= ~(RTC_CRH_OWIE);
_rtt_leave_config_mode();
}
uint32_t rtt_get_counter(void)
{
/* wait for synchronization */
while (!(RTT_DEV->CRL & RTT_FLAG_RSF)) {}
return (((uint32_t)RTT_DEV->CNTH << 16 ) | (uint32_t)(RTT_DEV->CNTL));
}
void rtt_set_counter(uint32_t counter)
{
_rtt_enter_config_mode();
/* Set RTC counter MSB word */
RTT_DEV->CNTH = counter >> 16;
/* Set RTC counter LSB word */
RTT_DEV->CNTL = (counter & 0xffff);
_rtt_leave_config_mode();
}
uint32_t rtt_get_alarm(void)
{
/* wait for synchronization */
while (!(RTT_DEV->CRL & RTT_FLAG_RSF)) {}
return (((uint32_t)RTT_DEV->ALRH << 16 ) | (uint32_t)(RTT_DEV->ALRL));
}
void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg)
{
_rtt_enter_config_mode();
/* Disable alarm*/
RTT_DEV->CRH &= ~RTC_CRH_ALRIE;
/* Save new cb and argument */
alarm_cb = cb;
alarm_arg = arg;
/* Set the alarm MSB word */
RTT_DEV->ALRH = alarm >> 16;
/* Set the alarm LSB word */
RTT_DEV->ALRL = (alarm & 0xffff);
/* Enable alarm interrupt */
RTT_DEV->CRH |= RTC_CRH_ALRIE;
_rtt_leave_config_mode();
}
void rtt_clear_alarm(void)
{
_rtt_enter_config_mode();
/* Disable alarm interrupt */
RTT_DEV->CRH &= ~RTC_CRH_ALRIE;
/* Set the ALARM MSB word to reset value */
RTT_DEV->ALRH = 0xffff;
/* Set the ALARM LSB word to reset value */
RTT_DEV->ALRL = 0xffff;
_rtt_leave_config_mode();
}
void rtt_poweron(void)
{
periph_clk_en(APB1, RCC_APB1ENR_BKPEN); /* enable BKP, Clock */
/* RTC clock source configuration */
PWR->CR |= PWR_CR_DBP; /* Allow access to BKP Domain */
RCC->BDCR |= RCC_BDCR_LSEON; /* Enable LSE OSC */
while(!(RCC->BDCR & RCC_BDCR_LSERDY)) {} /* Wait till LSE is ready */
RCC->BDCR |= RCC_BDCR_RTCSEL_LSE; /* Select the RTC Clock Source */
RCC->BDCR |= RCC_BDCR_RTCEN; /* enable RTC */
}
void rtt_poweroff(void)
{
PWR->CR |= PWR_CR_DBP; /* Allow access to BKP Domain */
RCC->BDCR &= ~RCC_BDCR_RTCEN; /* disable RTC */
periph_clk_dis(APB1, RCC_APB1ENR_BKPEN); /* disable BKP, Clock */
}
static inline void _rtt_enter_config_mode(void)
{
/* Loop until RTOFF flag is set */
while (!(RTT_DEV->CRL & RTT_FLAG_RTOFF)) {}
/* enter configuration mode */
RTT_DEV->CRL |= RTC_CRL_CNF;
}
static inline void _rtt_leave_config_mode(void)
{
/* leave configuration mode */
RTT_DEV->CRL &= ~RTC_CRL_CNF;
/* Loop until RTOFF flag is set */
while (!(RTT_DEV->CRL & RTT_FLAG_RTOFF)) {}
}
void RTT_ISR(void)
{
if (RTT_DEV->CRL & RTC_CRL_ALRF) {
RTT_DEV->CRL &= ~(RTC_CRL_ALRF);
if (alarm_cb) {
alarm_cb(alarm_arg);
}
}
if (RTT_DEV->CRL & RTC_CRL_OWF) {
RTT_DEV->CRL &= ~(RTC_CRL_OWF);
if (overflow_cb) {
overflow_cb(overflow_arg);
}
}
cortexm_isr_end();
}