mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-28 07:51:19 +01:00
Merge pull request #13394 from benpicco/atmega-rtc
cpu/atmega_common: implement emulated RTC support
This commit is contained in:
commit
e4f27b415e
@ -2,6 +2,7 @@ CPU = atmega256rfr2
|
||||
|
||||
FEATURES_PROVIDED += periph_adc
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_rtt
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
FEATURES_PROVIDED += periph_timer
|
||||
|
||||
@ -2,6 +2,7 @@ CPU = atmega256rfr2
|
||||
|
||||
FEATURES_PROVIDED += periph_adc
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_rtt
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
FEATURES_PROVIDED += periph_timer
|
||||
|
||||
@ -2,6 +2,7 @@ CPU = atmega128rfa1
|
||||
|
||||
FEATURES_PROVIDED += periph_adc
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_rtt
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
FEATURES_PROVIDED += periph_timer
|
||||
|
||||
@ -2,6 +2,7 @@ CPU = atmega256rfr2
|
||||
|
||||
FEATURES_PROVIDED += periph_adc
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_rtt
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
FEATURES_PROVIDED += periph_timer
|
||||
|
||||
@ -3,6 +3,7 @@ CPU = atmega1284p
|
||||
# Put defined MCU peripherals here (in alphabetical order)
|
||||
FEATURES_PROVIDED += periph_adc
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_rtt
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
FEATURES_PROVIDED += periph_timer
|
||||
|
||||
@ -3,6 +3,7 @@ CPU = atmega128rfa1
|
||||
# This board is based on an atmega CPU, thus import the features from it
|
||||
FEATURES_PROVIDED += periph_adc
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_rtt
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
FEATURES_PROVIDED += periph_timer
|
||||
|
||||
@ -6,3 +6,6 @@ FEATURES_PROVIDED += periph_gpio periph_gpio_irq
|
||||
FEATURES_PROVIDED += periph_pm
|
||||
FEATURES_PROVIDED += periph_cpuid
|
||||
FEATURES_PROVIDED += periph_wdt
|
||||
|
||||
FEATURES_CONFLICT += periph_rtc:periph_rtt
|
||||
FEATURES_CONFLICT_MSG += "On ATmega, the RTC and RTT use to the same hardware timer."
|
||||
|
||||
137
cpu/atmega_common/periph/rtc.c
Normal file
137
cpu/atmega_common/periph/rtc.c
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Benjamin Valentin
|
||||
*
|
||||
* 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 drivers_periph_rtc
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Basic RTC implementation based on a 1 Hz clock
|
||||
*
|
||||
* @note Unlike a real RTC, this emulated version is not guaranteed to keep
|
||||
* time across reboots or deep sleep.
|
||||
*
|
||||
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "periph/rtc.h"
|
||||
|
||||
/* In .noinit so we don't reset the counter on reboot */
|
||||
static struct tm tm_now __attribute__((section(".noinit")));
|
||||
static struct tm tm_alarm __attribute__((section(".noinit")));
|
||||
|
||||
static bool isr_flag;
|
||||
static rtc_alarm_cb_t alarm_cb;
|
||||
static void *alarm_cb_arg;
|
||||
|
||||
/* will be called every second */
|
||||
ISR(TIMER2_OVF_vect)
|
||||
{
|
||||
atmega_enter_isr();
|
||||
|
||||
isr_flag = !isr_flag;
|
||||
|
||||
if (++tm_now.tm_sec > 60) {
|
||||
rtc_tm_normalize(&tm_now);
|
||||
}
|
||||
|
||||
if (alarm_cb && rtc_tm_compare(&tm_now, &tm_alarm) == 0) {
|
||||
alarm_cb(alarm_cb_arg);
|
||||
}
|
||||
|
||||
atmega_exit_isr();
|
||||
}
|
||||
|
||||
void rtc_init(void)
|
||||
{
|
||||
static const struct tm zero = {0};
|
||||
|
||||
/* Disable all timer 2 interrupts */
|
||||
TIMSK2 = 0;
|
||||
|
||||
/* avoid negative time values on init (uninitialized memory) */
|
||||
if (!rtc_tm_valid(&tm_now)) {
|
||||
tm_now = zero;
|
||||
}
|
||||
|
||||
/* Select asynchronous 32 kHz clock source */
|
||||
ASSR = (1 << AS2);
|
||||
|
||||
/* select normal operation */
|
||||
TCCR2A = 0x0;
|
||||
|
||||
/* select divider 128 -> 1 Hz */
|
||||
TCCR2B = 0x5;
|
||||
|
||||
/* Clear interrupt flags */
|
||||
TIFR2 = (1 << OCF2B) | (1 << OCF2A) | (1 << TOV2);
|
||||
|
||||
/* Enable 8-bit overflow interrupt */
|
||||
TIMSK2 |= (1 << TOIE2);
|
||||
}
|
||||
|
||||
int rtc_set_time(struct tm *time)
|
||||
{
|
||||
/* second starts now */
|
||||
TCNT2 = 0;
|
||||
|
||||
tm_now = *time;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtc_get_time(struct tm *time)
|
||||
{
|
||||
bool tmp = isr_flag;
|
||||
|
||||
*time = tm_now;
|
||||
|
||||
/* check if interrupt happened while
|
||||
reading the time struct */
|
||||
if (isr_flag != tmp) {
|
||||
*time = tm_now;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtc_get_alarm(struct tm *time)
|
||||
{
|
||||
*time = tm_alarm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtc_set_alarm(struct tm *time, rtc_alarm_cb_t cb, void *arg)
|
||||
{
|
||||
rtc_tm_normalize(time);
|
||||
|
||||
alarm_cb = NULL; /* disable alarm */
|
||||
tm_alarm = *time;
|
||||
alarm_cb_arg = arg;
|
||||
alarm_cb = cb; /* enable alarm */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rtc_clear_alarm(void)
|
||||
{
|
||||
alarm_cb = NULL;
|
||||
}
|
||||
|
||||
void rtc_poweron(void)
|
||||
{
|
||||
power_timer2_enable();
|
||||
}
|
||||
|
||||
void rtc_poweroff(void)
|
||||
{
|
||||
power_timer2_disable();
|
||||
}
|
||||
@ -37,6 +37,7 @@
|
||||
#ifndef PERIPH_RTC_H
|
||||
#define PERIPH_RTC_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include "periph_conf.h"
|
||||
@ -169,6 +170,19 @@ uint32_t rtc_mktime(struct tm *t);
|
||||
*/
|
||||
void rtc_localtime(uint32_t time, struct tm *t);
|
||||
|
||||
/**
|
||||
* @brief Verify that a time struct @p t contains valid data.
|
||||
*
|
||||
* @note This function checks whether the fields of the
|
||||
* struct @p t are positive and within the bounds set
|
||||
* by @ref rtc_tm_normalize.
|
||||
*
|
||||
* @param[in] t The struct to be checked.
|
||||
*
|
||||
* @return true when valid, false if not
|
||||
*/
|
||||
bool rtc_tm_valid(const struct tm *t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -231,3 +231,34 @@ int rtc_tm_compare(const struct tm *a, const struct tm *b)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool rtc_tm_valid(const struct tm *t)
|
||||
{
|
||||
if (t->tm_sec < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t->tm_min < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t->tm_hour < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t->tm_mday < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t->tm_mon < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t->tm_year < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct tm norm = *t;
|
||||
rtc_tm_normalize(&norm);
|
||||
return rtc_tm_compare(t, &norm) == 0;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user