mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
179 lines
4.5 KiB
C
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();
|
|
}
|