-
Notifications
You must be signed in to change notification settings - Fork 0
/
RealTimeClock.h
169 lines (149 loc) · 5.05 KB
/
RealTimeClock.h
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*****************************************************************************
*
* SAMD21 Low Power Extensions
*
* file: RealTimeClock.h
* encoding: UTF-8
* created: 03.02.2023
*
*****************************************************************************
*
* Copyright (C) 2023 Jens B.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*
*****************************************************************************/
#pragma once
#include "System.h"
namespace SAMD21LPE
{
/**
* SAMD21 RTC in 32 bit counter mode for periodic interrupt callback (CMSIS based implementation)
*
* Compatibility:
*
* - alternative to Arduino library RTCZero
*
* Background:
*
* Arduino library RTCZero does not support:
* - RTC counter mode
* - selectable generic clock
*/
class RealTimeClock
{
public:
RealTimeClock(const RealTimeClock&) = delete;
void operator=(const RealTimeClock&) = delete;
static RealTimeClock& instance();
private:
RealTimeClock() = default;
~RealTimeClock() = default;
public:
/**
* setup RTC as 32 bit counter (mode 0) and start counter
* execution time: 2t
*
* @param clkGenId GCLKGEN ID 0..7
* @param clkGenFrequency frequency of GCLKGEN [Hz]
* @param clkDiv GCLK prescaler 2^clkDiv 0..10
* @param durationScale unit/scale of duration 0: RTC clock ticks, 1: 1 s, 1000: 1 ms (default), 1000000: 1 µs
* @param clearOnTimer zero counter when timer expires, default disabled
* @param irqPriority 0 (highest) .. 3 (lowest, default), must be 3 to use SysTick dependent operations in ISR
*
* notes:
* - timer resolution depends on clock frequency and prescaler setup: 2^clkDiv/clkGenFrequency -> 1 s @ clkGenFrequency=1 kHz, clkDiv=10
* - counter will be zeroed and started
* - counter will overflow with clearOnTimer = false or will be zeroed periodically with clearOnTimer = true
* - with a clock frequency of 1 kHz the counter will overflow after 49.7 days
* - adjust clkGenFrequency and clkDiv to provide the required timing resolution and jitter
* - for durationScale > 0 the raw counter value is calculated using unsigned 64 bits
* integer arithmetics: counterValue = clkGenFrequency/clkDiv*duration/durationScale
* - max. execution time: t = 6/clkGenFrequency + 3/fAPBA -> ~6 ms @ clkGenFrequency=1 kHz, fAPBA=CLK_MAIN/APBA_DIV=8 MHz
*/
void enable(uint8_t clkGenId, uint32_t clkGenFrequency, uint8_t clkDiv = 10, uint32_t durationScale = 1000U, bool clearOnTimer = false, uint8_t irqPriority = 3);
/**
* disable RTC module and RTC generic clock (will stop counter)
* execution time: 1t
*/
void disable();
/**
* convert duration to clock ticks
* @param duration timer duration
*/
uint32_t toClockTicks(uint32_t duration) const;
/**
* start timer
* execution time: 1t in clearOnTimer mode, otherwise 2t
* @param duration timer duration
* @param periodic single if false, periodic if true
* @param callback function to call at timer interrupt, optional
*/
void start(uint32_t duration, bool periodic = false, void (*callback)() = nullptr);
/**
* cancel timer (counter will continue)
*/
void cancel();
/**
* set scaled counter value
* execution time: 1t
* @param duration counter value
*/
void setElapsed(uint32_t duration);
/**
* get scaled counter value
* execution time: 0t in requestCounter() callback, otherwise 1t
* @return elapsed duration
*/
uint32_t getElapsed() const;
/**
* get raw counter value
* execution time: 0t in requestCounter() callback, otherwise 1t
* @return elapsed duration
*/
uint32_t getCounter() const;
/**
* request counter value
*
* note: use getCounter() or getElapsed() to retrieve counter value in callback
*/
void requestCounter(void (*callback)());
/**
* wait until RTC read or write sync is completed
* execution time: 1t
*
* note: sync is an integrated part of all RTC operations except the timer ISR handler
*/
void sync() const;
public:
/**
* RTC interrupt handler
*
* note: call sync() with configuration "periodic & !clearOnTimer" before accessing RTC in ISR to prevent peripheral bus stall
*/
static void isrHandler();
protected:
uint16_t clkDiv = 0; // 1..1024
uint32_t clkGenFrequency = 0; // [Hz]
uint32_t durationScale = 0; // 0, 1, 1000, 1000000
uint32_t durationTicks = 0;
uint32_t lastCounter = 0;
bool clearOnTimer = false;
bool periodic = false;
bool counterAvailable = false;
void (*rtcHandler)() = nullptr;
void (*counterCallback)() = nullptr;
};
}