1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/efm32/periph/rtc_series1.c
2020-01-22 10:03:49 +01:00

179 lines
4.5 KiB
C

/*
* Copyright (C) 2016-2017 Bas Stottelaar <basstottelaar@gmail.com>
*
* 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_efm32
* @ingroup drivers_periph_rtc
* @{
*
* @file
* @brief RTC peripheral driver implementation for EFM32 Series 1 MCUs
*
* @author Bas Stottelaar <basstottelaar@gmail.com>
* @}
*/
#include <time.h>
#include "cpu.h"
#include "periph_conf.h"
#include "periph/rtc.h"
#include "em_cmu.h"
#include "em_rtcc.h"
#include "em_rtcc_utils.h"
#define RTC_YEAR_OFFSET (100) /**< RTCC has only two-digit notation */
typedef struct {
rtc_alarm_cb_t alarm_cb; /**< callback called from RTC interrupt */
void *alarm_arg; /**< argument passed to the callback */
uint32_t alarm_year; /**< alarm year */
} rtc_state_t;
static rtc_state_t rtc_state;
void rtc_init(void)
{
/* enable clocks */
CMU_ClockEnable(cmuClock_CORELE, true);
CMU_ClockEnable(cmuClock_RTCC, true);
/* reset and initialize peripheral */
RTCC_Init_TypeDef init = RTCC_INIT_DEFAULT;
init.enable = false;
init.presc = rtccCntPresc_32768;
init.cntMode = rtccCntModeCalendar;
RTCC_Reset();
RTCC_Init(&init);
/* initialize alarm channel */
RTCC_CCChConf_TypeDef init_channel = RTCC_CH_INIT_COMPARE_DEFAULT;
RTCC_ChannelInit(0, &init_channel);
/* enable interrupt */
NVIC_ClearPendingIRQ(RTCC_IRQn);
NVIC_EnableIRQ(RTCC_IRQn);
/* enable peripheral */
RTCC_Enable(true);
}
int rtc_set_time(struct tm *time)
{
rtc_tm_normalize(time);
RTCC_DateSet(
RTCC_Year2BCD(time->tm_year - RTC_YEAR_OFFSET) |
RTCC_Month2BCD(time->tm_mon) |
RTCC_DayOfMonth2BCD(time->tm_mday) |
RTCC_DayOfWeek2BCD(time->tm_wday));
RTCC_TimeSet(
RTCC_Hour2BCD(time->tm_hour) |
RTCC_Minute2BCD(time->tm_min) |
RTCC_Second2BCD(time->tm_sec));
return 0;
}
int rtc_get_time(struct tm *time)
{
uint32_t datestamp = RTCC_DateGet();
uint32_t timestamp = RTCC_TimeGet();
time->tm_year = RTCC_BCD2Year(datestamp) + RTC_YEAR_OFFSET;
time->tm_mon = RTCC_BCD2Month(datestamp);
time->tm_mday = RTCC_BCD2DayOfMonth(datestamp);
time->tm_wday = RTCC_BCD2DayOfWeek(datestamp);
time->tm_hour = RTCC_BCD2Hour(timestamp);
time->tm_min = RTCC_BCD2Minute(timestamp);
time->tm_sec = RTCC_BCD2Second(timestamp);
return 0;
}
int rtc_set_alarm(struct tm *time, rtc_alarm_cb_t cb, void *arg)
{
rtc_tm_normalize(time);
rtc_state.alarm_cb = cb;
rtc_state.alarm_arg = arg;
rtc_state.alarm_year = time->tm_year;
/* disable interrupt so it doesn't accidentally trigger */
RTCC_IntDisable(RTCC_IEN_CC0);
/* set compare registers */
RTCC_ChannelDateSet(0,
RTCC_Channel_Month2BCD(time->tm_mon) |
RTCC_Channel_Day2BCD(time->tm_mday));
RTCC_ChannelTimeSet(0,
RTCC_Channel_Hour2BCD(time->tm_hour) |
RTCC_Channel_Minute2BCD(time->tm_min) |
RTCC_Channel_Second2BCD(time->tm_sec));
/* enable the interrupt */
RTCC_IntClear(RTCC_IFC_CC0);
RTCC_IntEnable(RTCC_IEN_CC0);
return 0;
}
int rtc_get_alarm(struct tm *time)
{
uint32_t datestamp = RTCC_ChannelDateGet(0);
uint32_t timestamp = RTCC_ChannelTimeGet(0);
time->tm_year = rtc_state.alarm_year;
time->tm_mon = RTCC_Channel_BCD2Month(datestamp);
time->tm_mday = RTCC_Channel_BCD2Day(datestamp);
time->tm_hour = RTCC_Channel_BCD2Hour(timestamp);
time->tm_min = RTCC_Channel_BCD2Minute(timestamp);
time->tm_sec = RTCC_Channel_BCD2Second(timestamp);
return 0;
}
void rtc_clear_alarm(void)
{
rtc_state.alarm_cb = NULL;
rtc_state.alarm_arg = NULL;
rtc_state.alarm_year = 0;
RTCC_IntDisable(RTCC_IEN_CC0);
}
void rtc_poweron(void)
{
CMU_ClockEnable(cmuClock_RTCC, true);
}
void rtc_poweroff(void)
{
CMU_ClockEnable(cmuClock_RTCC, false);
}
void isr_rtcc(void)
{
if (RTCC_IntGet() & RTCC_IF_CC0) {
if (rtc_state.alarm_cb != NULL) {
/* check if year matches, otherwise alarm would go off each year */
if (RTCC_BCD2Year(RTCC_DateGet()) + RTC_YEAR_OFFSET == rtc_state.alarm_year) {
rtc_state.alarm_cb(rtc_state.alarm_arg);
}
}
RTCC_IntClear(RTCC_IFC_CC0);
}
cortexm_isr_end();
}