FastArduino v1.10
C++ library to build fast but small Arduino/AVR projects
Loading...
Searching...
No Matches
realtime_timer.h
Go to the documentation of this file.
1// Copyright 2016-2023 Jean-Francois Poilpret
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
16
21#ifndef RTT_HH
22#define RTT_HH
23
24#include "boards/io.h"
25#include <avr/interrupt.h>
26#include "interrupts.h"
27#include "timer.h"
28#include "time.h"
29#include "events.h"
30
44#define REGISTER_RTT_ISR(TIMER_NUM) \
45 ISR(CAT3(TIMER, TIMER_NUM, _COMPA_vect)) \
46 { \
47 timer::isr_handler_rtt::rtt<TIMER_NUM>(); \
48 }
49
64#define REGISTER_RTT_ISR_METHOD(TIMER_NUM, HANDLER, CALLBACK) \
65 ISR(CAT3(TIMER, TIMER_NUM, _COMPA_vect)) \
66 { \
67 timer::isr_handler_rtt::rtt_method<TIMER_NUM, HANDLER, CALLBACK>(); \
68 }
69
82#define REGISTER_RTT_ISR_FUNCTION(TIMER_NUM, CALLBACK) \
83 ISR(CAT3(TIMER, TIMER_NUM, _COMPA_vect)) \
84 { \
85 timer::isr_handler_rtt::rtt_function<TIMER_NUM, CALLBACK>(); \
86 }
87
102#define REGISTER_RTT_EVENT_ISR(TIMER_NUM, EVENT, PERIOD) \
103 ISR(CAT3(TIMER, TIMER_NUM, _COMPA_vect)) \
104 { \
105 timer::isr_handler_rtt::rtt_event<TIMER_NUM, EVENT, PERIOD>(); \
106 }
107
114#define DECL_RTT_ISR_HANDLERS_FRIEND \
115 friend struct timer::isr_handler_rtt; \
116 DECL_TIMER_COMP_FRIENDS
117
118namespace timer
119{
135 template<typename T> class RTTRawTime
136 {
137 public:
139 RTTRawTime(const RTTRawTime&) = default;
140 RTTRawTime& operator=(const RTTRawTime&) = default;
142
152 RTTRawTime(uint32_t millis, T counter, T max_counter)
153 : millis_{millis}, counter_{counter}, max_counter_{max_counter}
154 {}
155
160 static constexpr RTTRawTime<T> EMPTY_TIME{};
161
168 {
169 return time::RTTTime{millis_, uint16_t(ONE_MILLI_32 * counter_ / (1UL + max_counter_))};
170 }
171
172 private:
173 constexpr RTTRawTime() : buffer_{} {}
174
175 // This union is an ugly hack to trick the compiler so that it understands
176 // the default constructor just needs 0 initialization for EMPTY_TIME constant,
177 // and thus can accept the fact EMPTY_TIME is a pure constexpr
178 union
179 {
180 struct
181 {
182 uint32_t millis_;
183 T counter_;
184 T max_counter_;
185 };
186 uint8_t buffer_[sizeof(uint32_t) + 2 * sizeof(T)];
187 };
188 };
189
205 template<board::Timer NTIMER_> class RTT : private Timer<NTIMER_>
206 {
207 public:
209 static constexpr const board::Timer NTIMER = NTIMER_;
210
211 private:
212 using TRAIT = typename Timer<NTIMER>::TRAIT;
213 using TYPE = typename Timer<NTIMER>::TYPE;
214 using PRESCALER = typename Timer<NTIMER>::PRESCALER;
215
216 public:
222
231 {
233 }
234
251 uint32_t millis() const
252 {
253 synchronized return milliseconds_;
254 }
255
272 uint32_t millis_() const
273 {
274 return milliseconds_;
275 }
276
287 void delay(uint32_t ms) const
288 {
289 uint32_t end = millis() + ms + 1;
290 while (millis() < end) time::yield();
291 }
292
311 uint16_t micros() const
312 {
313 synchronized return compute_micros();
314 }
315
334 uint16_t micros_() const
335 {
336 return compute_micros();
337 }
338
354 {
355 synchronized return time_();
356 }
357
373 {
374 return time::RTTTime(milliseconds_, compute_micros());
375 }
376
394 {
395 synchronized return raw_time_();
396 }
397
415 {
416 return RAW_TIME{milliseconds_, (volatile TYPE&) TRAIT::TCNT, (volatile TYPE&) TRAIT::OCRA};
417 }
418
424 void millis(uint32_t ms)
425 {
426 synchronized
427 {
428 milliseconds_ = ms;
429 // Reset timer counter
430 TRAIT::TCNT = 0;
431 }
432 }
433
444 void begin()
445 {
446 synchronized begin_();
447 }
448
459 void begin_()
460 {
461 milliseconds_ = 0;
462 Timer<NTIMER>::begin_(MILLI_COUNTER);
463 }
464
474 void end()
475 {
477 }
478
490 void end_()
491 {
493 }
494
499 {
500 return *this;
501 }
502
503 private:
504 volatile uint32_t milliseconds_ = 0UL;
505
506 void on_timer()
507 {
508 ++milliseconds_;
509 }
510
511 using CALC = Calculator<NTIMER>;
512 static constexpr const PRESCALER MILLI_PRESCALER = CALC::CTC_prescaler(ONE_MILLI_32);
513 static constexpr const TYPE MILLI_COUNTER = CALC::CTC_counter(MILLI_PRESCALER, ONE_MILLI_32);
514
515 uint16_t compute_micros() const
516 {
517 return uint16_t(ONE_MILLI_32 * ((volatile TYPE&) TRAIT::TCNT) / (1UL + (volatile TYPE&) TRAIT::OCRA));
518 }
519
520 friend struct isr_handler_rtt;
521 };
522
534 template<typename EVENT, uint32_t PERIOD_MS = 1024> class RTTEventCallback
535 {
536 static_assert(events::Event_trait<EVENT>::IS_EVENT, "EVENT type must be an events::Event<T>");
537 static_assert((PERIOD_MS & (PERIOD_MS - 1)) == 0, "PERIOD_MS must be a power of 2");
538
539 public:
540 RTTEventCallback(const RTTEventCallback&) = delete;
541 RTTEventCallback& operator=(const RTTEventCallback&) = delete;
542
543 //FIXME we should allow Queue<EVENT, ?>
553 explicit RTTEventCallback(containers::Queue<EVENT>& event_queue) : event_queue_{event_queue} {}
554
555 private:
556 void on_rtt_change(uint32_t millis)
557 {
558 if ((millis & (PERIOD_MS - 1)) == 0) event_queue_.push_(EVENT{events::Type::RTT_TIMER});
559 }
560
561 containers::Queue<EVENT>& event_queue_;
562
563 friend struct isr_handler_rtt;
564 };
565
567
568 // All RTT-related methods called by pre-defined ISR are defined here
569 //====================================================================
570
571 struct isr_handler_rtt
572 {
573 template<uint8_t TIMER_NUM_> static void rtt()
574 {
575 static constexpr board::Timer NTIMER = isr_handler::check_timer<TIMER_NUM_>();
576 interrupt::HandlerHolder<RTT<NTIMER>>::handler()->on_timer();
577 }
578
579 template<uint8_t TIMER_NUM_, typename HANDLER_, void (HANDLER_::*CALLBACK_)(uint32_t)> static void rtt_method()
580 {
581 static constexpr board::Timer NTIMER = isr_handler::check_timer<TIMER_NUM_>();
582 auto handler = interrupt::HandlerHolder<RTT<NTIMER>>::handler();
583 handler->on_timer();
584 interrupt::CallbackHandler<void (HANDLER_::*)(uint32_t), CALLBACK_>::call(handler->millis());
585 }
586
587 template<uint8_t TIMER_NUM_, void (*CALLBACK_)(uint32_t)> static void rtt_function()
588 {
589 static constexpr board::Timer NTIMER = isr_handler::check_timer<TIMER_NUM_>();
590 auto handler = interrupt::HandlerHolder<RTT<NTIMER>>::handler();
591 handler->on_timer();
592 CALLBACK_(handler->millis());
593 }
594
595 template<uint8_t TIMER_NUM_, typename EVENT_, uint32_t PERIOD_> static void rtt_event()
596 {
597 static constexpr board::Timer NTIMER = isr_handler::check_timer<TIMER_NUM_>();
598 auto handler = interrupt::HandlerHolder<RTT<NTIMER>>::handler();
599 handler->on_timer();
600 interrupt::HandlerHolder<RTTEventCallback<EVENT_, PERIOD_>>::handler()->on_rtt_change(handler->millis());
601 }
602 };
604}
605
606#endif /* RTT_HH */
Queue of type T_ items.
Definition: queue.h:59
bool push_(TREF item)
Push item to the end of this queue, provided there is still available space in its ring buffer.
Structure used to hold a time value with microsecond precision.
Definition: time.h:50
Utility to generate events from an RTT instance at a given period.
RTTEventCallback(containers::Queue< EVENT > &event_queue)
Create a RTTEventCallback that will push periodic events to event_queue.
API to handle a real-time timer.
time::RTTTime time_() const
Elapsed time, in milliseconds and microseconds, since this timer has started.
uint16_t micros_() const
Compute the microseconds part (from 0 to 999) of the time that has elapsed, since this timer has star...
RAW_TIME raw_time() const
Elapsed time, in raw representation, since this timer has started.
Timer< NTIMER > & timer()
Get a reference to the underlying Timer of this RTT.
void end()
Stop this real-time timer, hence time gets not counted anymore.
void millis(uint32_t ms)
Reset the current milliseconds count of this RTT to the given value.
void begin_()
Start this real-time timer, hence elapsed time starts getting counted from then.
void end_()
Stop this real-time timer, hence time gets not counted anymore.
uint32_t millis() const
Elapsed time, in milliseconds, since this timer has started.
static constexpr const board::Timer NTIMER
The AVR timer used by this RTT.
void delay(uint32_t ms) const
Delay program execution for the given amount of milliseconds.
uint32_t millis_() const
Elapsed time, in milliseconds, since this timer has started.
void begin()
Start this real-time timer, hence elapsed time starts getting counted from then.
RTT()
Construct a new real-time timer handler and initializes its current time to 0ms.
uint16_t micros() const
Compute the microseconds part (from 0 to 999) of the time that has elapsed, since this timer has star...
time::RTTTime time() const
Elapsed time, in milliseconds and microseconds, since this timer has started.
RAW_TIME raw_time_() const
Elapsed time, in raw representation, since this timer has started.
Utility class to avoid costly instantiation of time::RTTTime from an interrupt routine.
time::RTTTime as_real_time() const
Convert this RTTRawTime instance to a fully usable time::RTTTime.
RTTRawTime(uint32_t millis, T counter, T max_counter)
Create a new RTTRawTime from millis milliseconds, and values from Timer counter value that will allow...
static constexpr RTTRawTime< T > EMPTY_TIME
A constant to signify "no time".
General API to handle an AVR timer.
Definition: timer.h:705
typename TRAIT::TYPE TYPE
The type of this timer's counter (either uint8_t or uint16_t).
Definition: timer.h:725
typename PRESCALERS_TRAIT::TYPE PRESCALER
The enum type listing all available precaler values for this timer.
Definition: timer.h:735
void end_()
Completely stop this timer: timer interrupts are disabled and counter is stopped.
Definition: timer.h:1200
void end()
Completely stop this timer: timer interrupts are disabled and counter is stopped.
Definition: timer.h:1185
void begin_(TYPE max=0)
Start this timer in the currently selected mode, with the provided prescaler value and max value.
Definition: timer.h:966
Support for events management.
General API for handling AVR interrupt vectors.
Timer
Defines all timers available for target MCU.
Definition: empty.h:112
const uint8_t RTT_TIMER
Type of events generated by timer::RTTEventCallback whenever elapsed RTT::millis() reaches a multiple...
Definition: events.h:112
void register_handler(Handler &handler)
Register a class instance containing methods that shall be called back by an ISR.
Definition: interrupts.h:185
void yield()
Utility method used by many FastArduino API in order to "yield" some processor time; concretely it ju...
Definition: time.cpp:22
Defines all API to manipulate AVR Timers.
Definition: pulse_timer.h:116
@ CTC
Timer "Clear Timer on Compare match" mode: counter is incremented until it reaches "TOP" (OCRxA regis...
@ OUTPUT_COMPARE_A
This interrupt occurs when the counter reached OCRA.
static constexpr TYPE CTC_counter(PRESCALER prescaler, uint32_t us)
Computes the value of counter to use for this timer, in TimerMode::CTC mode, with prescaler,...
Definition: timer.h:423
static constexpr PRESCALER CTC_prescaler(uint32_t us)
Computes the ideal prescaler value to use for this timer, in TimerMode::CTC mode, in order to be able...
Definition: timer.h:390
Simple time utilities.
Timer API.