/
rtc_timer2.c
144 lines (111 loc) · 2.73 KB
/
rtc_timer2.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/**
RTC implementation with 32kHz crystal on Timer2 pins. Can also be used
with main crystal, but you need to calculate USEC_PER_TICK.
@file rtc_timer2.c
@brief RTC implementation with AVR async Timer2
@author Matej Kogovsek
@copyright LGPL 2.1
@note This file is part of mat-avr-lib
*/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
#include <avr/pgmspace.h>
#include "time.h"
const char RTC_IMPL[] PROGMEM = "TMR";
static struct rtc_t sw_time;
static int8_t sw_cal;
static uint32_t tmr_usec;
#define RTC_XTAL
#ifdef RTC_XTAL
#define USEC_PER_TICK 15625
#else
#warning RTC using CPU clock
// #define USEC_PER_TICK 8000
#endif
// ------------------------------------------------------------------
void rtc_start(void)
{
#ifdef RTC_XTAL
ASSR = _BV(AS2);
OCR2A = 16-1;
TCNT2 = 0;
TCCR2A = _BV(WGM21); // CTC operation
TCCR2B = _BV(CS21) | _BV(CS20); // prescale clk/32
while( ASSR & 0x1f );
#else
OCR2A = 250-1;
TCNT2 = 0;
TCCR2A = _BV(WGM21); // CTC operation
TCCR2B = _BV(CS22) | _BV(CS21); // prescale clk/256
#endif
TIFR2 = 0xff; // clear interrupt flags
TIMSK2 |= _BV(OCIE2A);
}
// ------------------------------------------------------------------
void rtc_stop(void)
{
TCCR2B = 0;
#ifdef RTC_XTAL
while( ASSR & 0x1f );
#endif
TIMSK2 = 0;
}
// ------------------------------------------------------------------
void rtc_init(void)
{
rtc_stop();
memset(&sw_time, 0, sizeof(sw_time));
sw_cal = 0;
rtc_start();
}
// ------------------------------------------------------------------
uint8_t rtc_getsec(void)
{
return sw_time.sec;
}
// ------------------------------------------------------------------
uint8_t rtc_gettime(struct rtc_t* t)
{
uint8_t g = SREG;
cli();
memcpy(t, &sw_time, sizeof(sw_time));
SREG = g;
return 0;
}
// ------------------------------------------------------------------
uint8_t rtc_settime(const struct rtc_t* t)
{
// month_days lookup table guard
if( t->mon < 1 || t->mon > 12 ) return 1;
uint8_t g = SREG;
cli();
tmr_usec = 0;
memcpy(&sw_time, t, sizeof(sw_time));
SREG = g;
if( 0 == TCCR2B ) { rtc_start(); }
return 0;
}
// ------------------------------------------------------------------
int8_t rtc_getcal(void)
{
return sw_cal;
}
// ------------------------------------------------------------------
void rtc_setcal(int8_t c)
{
sw_cal = c;
}
// ------------------------------------------------------------------
ISR(TIMER2_COMPA_vect)
{
tmr_usec += USEC_PER_TICK;
if( tmr_usec >= 1000000 ) {
tmr_usec -= sw_cal;
}
if( tmr_usec >= 1000000 ) {
tmr_usec -= 1000000;
rtc_inct(&sw_time);
}
}