FastArduino v1.10
C++ library to build fast but small Arduino/AVR projects
Loading...
Searching...
No Matches
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 TIMER_HH
22#define TIMER_HH
23
24#include "boards/board_traits.h"
25#include <avr/interrupt.h>
26#include <stddef.h>
27#include "interrupts.h"
28#include "utilities.h"
29
30// Generic macros to register ISR on Timer
31//=========================================
40#define REGISTER_TIMER_COMPARE_ISR_METHOD(TIMER_NUM, HANDLER, CALLBACK) \
41 ISR(CAT3(TIMER, TIMER_NUM, _COMPA_vect)) \
42 { \
43 timer::isr_handler::check_timer<TIMER_NUM>(); \
44 interrupt::CallbackHandler<void (HANDLER::*)(), CALLBACK>::call(); \
45 }
46
54#define REGISTER_TIMER_COMPARE_ISR_FUNCTION(TIMER_NUM, CALLBACK) \
55 ISR(CAT3(TIMER, TIMER_NUM, _COMPA_vect)) \
56 { \
57 timer::isr_handler::check_timer<TIMER_NUM>(); \
58 interrupt::CallbackHandler<void (*)(), CALLBACK>::call(); \
59 }
60
67#define REGISTER_TIMER_COMPARE_ISR_EMPTY(TIMER_NUM) \
68 extern "C" void CAT3(TIMER, TIMER_NUM, _COMPA_vect)(void) NAKED_SIGNAL; \
69 void CAT3(TIMER, TIMER_NUM, _COMPA_vect)(void) \
70 { \
71 timer::isr_handler::check_timer<TIMER_NUM>(); \
72 __asm__ __volatile__("reti" ::); \
73 }
74
83#define REGISTER_TIMER_OVERFLOW_ISR_METHOD(TIMER_NUM, HANDLER, CALLBACK) \
84 ISR(CAT3(TIMER, TIMER_NUM, _OVF_vect)) \
85 { \
86 timer::isr_handler::check_timer<TIMER_NUM>(); \
87 interrupt::CallbackHandler<void (HANDLER::*)(), CALLBACK>::call(); \
88 }
89
97#define REGISTER_TIMER_OVERFLOW_ISR_FUNCTION(TIMER_NUM, CALLBACK) \
98 ISR(CAT3(TIMER, TIMER_NUM, _OVF_vect)) \
99 { \
100 timer::isr_handler::check_timer<TIMER_NUM>(); \
101 interrupt::CallbackHandler<void (*)(), CALLBACK>::call(); \
102 }
103
110#define REGISTER_TIMER_OVERFLOW_ISR_EMPTY(TIMER_NUM) \
111 extern "C" void CAT3(TIMER, TIMER_NUM, _OVF_vect)(void) NAKED_SIGNAL; \
112 void CAT3(TIMER, TIMER_NUM, _OVF_vect)(void) \
113 { \
114 timer::isr_handler::check_timer<TIMER_NUM>(); \
115 __asm__ __volatile__("reti" ::); \
116 }
117
126#define REGISTER_TIMER_CAPTURE_ISR_METHOD(TIMER_NUM, HANDLER, CALLBACK) \
127 ISR(CAT3(TIMER, TIMER_NUM, _CAPT_vect)) \
128 { \
129 timer::isr_handler::timer_capture_method<TIMER_NUM, HANDLER, CALLBACK>(); \
130 }
131
139#define REGISTER_TIMER_CAPTURE_ISR_FUNCTION(TIMER_NUM, CALLBACK) \
140 ISR(CAT3(TIMER, TIMER_NUM, _CAPT_vect)) \
141 { \
142 timer::isr_handler::timer_capture_function<TIMER_NUM, CALLBACK>(); \
143 }
144
151#define REGISTER_TIMER_CAPTURE_ISR_EMPTY(TIMER_NUM) \
152 extern "C" void CAT3(TIMER, TIMER_NUM, _CAPT_vect)(void) NAKED_SIGNAL; \
153 void CAT3(TIMER, TIMER_NUM, _CAPT_vect)(void) \
154 { \
155 timer::isr_handler::check_timer_capture<TIMER_NUM>(); \
156 __asm__ __volatile__("reti" ::); \
157 }
158
166#define DECL_TIMER_ISR_HANDLERS_FRIEND \
167 friend struct timer::isr_handler; \
168 DECL_TIMER_COMP_FRIENDS \
169 DECL_TIMER_OVF_FRIENDS \
170 DECL_TIMER_CAPT_FRIENDS
171
182namespace timer
183{
187 enum class TimerMode : uint8_t
188 {
194 NORMAL,
200 CTC,
210 FAST_PWM,
222 };
223
228 enum class TimerInterrupt : uint8_t
229 {
231 OVERFLOW = board_traits::TimerInterrupt::OVERFLOW,
233 OUTPUT_COMPARE_A = board_traits::TimerInterrupt::OUTPUT_COMPARE_A,
235 OUTPUT_COMPARE_B = board_traits::TimerInterrupt::OUTPUT_COMPARE_B,
240 OUTPUT_COMPARE_C = board_traits::TimerInterrupt::OUTPUT_COMPARE_C,
247 INPUT_CAPTURE = board_traits::TimerInterrupt::INPUT_CAPTURE
248 };
249
255 {
256 return TimerInterrupt(uint8_t(i1) | uint8_t(i2));
257 }
258
262 enum class TimerOutputMode : uint8_t
263 {
267 TOGGLE,
280 };
281
285 enum class TimerInputCapture : uint8_t
286 {
291 };
292
301 template<board::Timer NTIMER_> struct Calculator
302 {
303 public:
307 static constexpr const board::Timer NTIMER = NTIMER_;
308
309 private:
310 using TRAIT = board_traits::Timer_trait<NTIMER>;
311 using PRESCALERS_TRAIT = typename TRAIT::PRESCALERS_TRAIT;
312
313 public:
319 using TYPE = typename TRAIT::TYPE;
324 using PRESCALER = typename PRESCALERS_TRAIT::TYPE;
329 static constexpr const TYPE PWM_MAX = TRAIT::MAX_PWM;
330
341 static constexpr PRESCALER tick_prescaler(uint32_t us_per_tick)
342 {
343 return best_tick_prescaler(PRESCALERS_TRAIT::ALL_PRESCALERS, us_per_tick);
344 }
345
357 static constexpr uint32_t ticks_to_us(PRESCALER prescaler, TYPE ticks)
358 {
359 return uint32_t(ticks) * bits::BV16(uint8_t(prescaler)) / INST_PER_US;
360 }
361
373 static constexpr TYPE us_to_ticks(PRESCALER prescaler, uint32_t us)
374 {
375 return TYPE(us * INST_PER_US / bits::BV16(uint8_t(prescaler)));
376 }
377
390 static constexpr PRESCALER CTC_prescaler(uint32_t us)
391 {
392 return best_prescaler(PRESCALERS_TRAIT::ALL_PRESCALERS, us);
393 }
394
406 static constexpr uint32_t CTC_frequency(PRESCALER prescaler)
407 {
408 return F_CPU / bits::BV16(uint8_t(prescaler));
409 }
410
423 static constexpr TYPE CTC_counter(PRESCALER prescaler, uint32_t us)
424 {
425 return (TYPE) prescaler_quotient(prescaler, us) - 1;
426 }
427
445 static constexpr bool is_adequate_for_CTC(PRESCALER prescaler, uint32_t us)
446 {
447 return prescaler_is_adequate(prescaler_quotient(prescaler, us));
448 }
449
461 static constexpr PRESCALER FastPWM_prescaler(uint16_t pwm_frequency)
462 {
463 return best_frequency_prescaler(PRESCALERS_TRAIT::ALL_PRESCALERS, pwm_frequency * (PWM_MAX + 1UL));
464 }
465
477 static constexpr uint16_t FastPWM_frequency(PRESCALER prescaler)
478 {
479 return F_CPU / bits::BV16(uint8_t(prescaler)) / (PWM_MAX + 1UL);
480 }
481
493 static constexpr PRESCALER PhaseCorrectPWM_prescaler(uint16_t pwm_frequency)
494 {
495 return best_frequency_prescaler(PRESCALERS_TRAIT::ALL_PRESCALERS, pwm_frequency * (2UL * PWM_MAX));
496 }
497
509 static constexpr uint16_t PhaseCorrectPWM_frequency(PRESCALER prescaler)
510 {
511 return F_CPU / bits::BV16(uint8_t(prescaler)) / (2UL * PWM_MAX);
512 }
513
527 static constexpr PRESCALER PulseTimer_prescaler(uint16_t max_pulse_width_us, uint16_t pulse_frequency)
528 {
529 return TRAIT::IS_16BITS ? PWM_ICR_prescaler(pulse_frequency) : CTC_prescaler(max_pulse_width_us);
530 }
531
547 static constexpr TYPE PulseTimer_value(PRESCALER prescaler, uint16_t period_us)
548 {
549 return CTC_counter(prescaler, period_us);
550 }
551
569 static constexpr PRESCALER PWM_ICR_prescaler(uint16_t pwm_frequency)
570 {
571 return best_frequency_prescaler(PRESCALERS_TRAIT::ALL_PRESCALERS, pwm_frequency * (TRAIT::MAX_PWM + 1UL));
572 }
573
591 static constexpr uint16_t PWM_ICR_frequency(PRESCALER prescaler, uint16_t counter)
592 {
593 return F_CPU / bits::BV16(uint8_t(prescaler)) / counter;
594 }
595
613 static constexpr uint16_t PWM_ICR_counter(PRESCALER prescaler, uint16_t pwm_frequency)
614 {
615 return F_CPU / bits::BV16(uint8_t(prescaler)) / pwm_frequency;
616 }
617
618 private:
619 static constexpr uint32_t prescaler_quotient(PRESCALER prescaler, uint32_t us)
620 {
621 return (INST_PER_US * us) / bits::BV16(uint8_t(prescaler));
622 }
623
624 static constexpr uint32_t prescaler_remainder(PRESCALER prescaler, uint32_t us)
625 {
626 return (INST_PER_US * us) % bits::BV16(uint8_t(prescaler));
627 }
628
629 static constexpr bool prescaler_is_adequate(uint32_t quotient)
630 {
631 return (quotient > 1) && (quotient < TRAIT::MAX_COUNTER);
632 }
633
634 template<size_t N> static constexpr PRESCALER best_prescaler(const PRESCALER (&prescalers)[N], uint32_t us)
635 {
636 // Find the best prescaler:
637 // - quotient is in ]1; MAX_COUNTER[
638 // - smallest remainder
639 // - largest quotient
640 uint32_t smallest_remainder = UINT32_MAX;
641 uint32_t largest_quotient = 0;
642 PRESCALER current = prescalers[N - 1];
643 for (size_t i = 0; i < N; ++i)
644 {
645 PRESCALER prescaler = prescalers[i];
646 uint32_t quotient = prescaler_quotient(prescaler, us);
647 if (prescaler_is_adequate(quotient))
648 {
649 uint32_t remainder = prescaler_remainder(prescaler, us);
650 if (remainder > smallest_remainder) continue;
651 if ((remainder == smallest_remainder) && (quotient <= largest_quotient)) continue;
652 current = prescaler;
653 smallest_remainder = remainder;
654 largest_quotient = quotient;
655 }
656 }
657 return current;
658 }
659
660 static constexpr bool prescaler_is_adequate_for_frequency(PRESCALER prescaler, uint32_t freq)
661 {
662 return (F_CPU / (uint32_t) bits::BV16(uint8_t(prescaler))) > freq;
663 }
664
665 template<size_t N>
666 static constexpr PRESCALER best_frequency_prescaler(const PRESCALER (&prescalers)[N], uint32_t freq)
667 {
668 // Best prescaler is biggest possible divider, hence try all prescalers from largest to smallest
669 for (size_t i = 0; i < N; ++i)
670 {
671 PRESCALER prescaler = prescalers[N - 1 - i];
672 if (prescaler_is_adequate_for_frequency(prescaler, freq)) return prescaler;
673 }
674 // If no prescaler is adequate then return largest divider
675 return prescalers[N - 1];
676 }
677
678 static constexpr bool prescaler_is_adequate_for_tick(PRESCALER prescaler, uint32_t us)
679 {
680 return (prescaler_quotient(prescaler, us) >= 1);
681 }
682
683 template<size_t N> static constexpr PRESCALER best_tick_prescaler(const PRESCALER (&prescalers)[N], uint32_t us)
684 {
685 // Best prescaler is biggest possible divider, hence try all prescalers from largest to smallest
686 for (size_t i = 0; i < N; ++i)
687 {
688 PRESCALER prescaler = prescalers[N - 1 - i];
689 if (prescaler_is_adequate_for_tick(prescaler, us)) return prescaler;
690 }
691 // If no prescaler is adequate then return largest divider
692 return prescalers[N - 1];
693 }
694 };
695
704 template<board::Timer NTIMER_> class Timer
705 {
706 public:
708 static constexpr const board::Timer NTIMER = NTIMER_;
709
710 protected:
712 using TRAIT = board_traits::Timer_trait<NTIMER>;
713 using PRESCALERS_TRAIT = typename TRAIT::PRESCALERS_TRAIT;
715
716 public:
718 Timer(const Timer&) = delete;
719 Timer& operator=(const Timer&) = delete;
721
725 using TYPE = typename TRAIT::TYPE;
726
731
735 using PRESCALER = typename PRESCALERS_TRAIT::TYPE;
736
740 static constexpr const TYPE TIMER_MAX = TRAIT::MAX_COUNTER - 1;
741
745 static constexpr const TYPE PWM_MAX = TRAIT::MAX_PWM;
746
751 static constexpr const board::DigitalPin ICP_PIN = TRAIT::ICP_PIN;
752
766 Timer(TimerMode timer_mode, PRESCALER prescaler, TimerInterrupt interrupts = TimerInterrupt(0))
767 : tccra_{timer_mode_TCCRA(timer_mode)},
768 tccrb_{uint8_t(timer_mode_TCCRB(timer_mode) | TRAIT::TCCRB_prescaler(prescaler))},
769 timsk_{TRAIT::TIMSK_int_mask(uint8_t(interrupts))}
770 {}
771
786 {
787 timsk_ = TRAIT::TIMSK_int_mask(uint8_t(interrupts));
788 // Check if timer is currently running
789 if (TRAIT::TCCRB) utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, timsk_);
790 }
791
805 {
806 timsk_ |= TRAIT::TIMSK_int_mask(uint8_t(interrupts));
807 // Check if timer is currently running
808 if (TRAIT::TCCRB) utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, timsk_);
809 }
810
823 {
824 timsk_ &= bits::COMPL(TRAIT::TIMSK_int_mask(uint8_t(interrupts)));
825 // Check if timer is currently running
826 if (TRAIT::TCCRB) utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, timsk_);
827 }
828
839 {
840 uint8_t mask = TRAIT::TIMSK_int_mask(uint8_t(interrupts));
841 return (TRAIT::TIMSK_ & mask) == mask;
842 }
843
853 {
854 static_assert(TRAIT::ICES_TCCRB != 0, "TIMER must support Input Capture");
855 utils::set_mask(tccrb_, TRAIT::ICES_TCCRB, input_capture_TCCRB(input_capture));
856 // Check if timer is currently running
857 if (TRAIT::TCCRB) TRAIT::TCCRB = tccrb_;
858 }
859
864 {
865 static_assert(TRAIT::ICES_TCCRB != 0, "TIMER must support Input Capture");
866 return TRAIT::TCCRB & TRAIT::ICES_TCCRB ? TimerInputCapture::RISING_EDGE : TimerInputCapture::FALLING_EDGE;
867 }
868
876 void set_capture_noise_canceller(bool cancel_noise)
877 {
878 static_assert(TRAIT::ICNC_TCCRB != 0, "TIMER must support Input Capture");
879 if (cancel_noise)
880 tccrb_ |= TRAIT::ICNC_TCCRB;
881 else
882 tccrb_ &= ~TRAIT::ICNC_TCCRB;
883 // Check if timer is currently running
884 if (TRAIT::TCCRB) TRAIT::TCCRB = tccrb_;
885 }
886
892 {
893 static_assert(TRAIT::ICNC_TCCRB != 0, "TIMER must support Input Capture");
894 return TRAIT::TCCRB & TRAIT::ICNC_TCCRB;
895 }
896
901 void set_timer_mode(TimerMode timer_mode)
902 {
903 utils::set_mask(tccra_, TRAIT::MODE_MASK_TCCRA, timer_mode_TCCRA(timer_mode));
904 utils::set_mask(tccrb_, TRAIT::MODE_MASK_TCCRB, timer_mode_TCCRB(timer_mode));
905 // Check if timer is currently running
906 if (TRAIT::TCCRB)
907 {
908 if (!TRAIT::TCCRA.is_no_reg()) TRAIT::TCCRA = tccra_;
909 TRAIT::TCCRB = tccrb_;
910 }
911 }
912
920 {
921 return timer_mode(tccra_, tccrb_);
922 }
923
928 void set_prescaler(PRESCALER prescaler)
929 {
930 utils::set_mask(tccrb_, TRAIT::CS_MASK_TCCRB, TRAIT::TCCRB_prescaler(prescaler));
931 // Check if timer is currently running
932 if (TRAIT::TCCRB) TRAIT::TCCRB = tccrb_;
933 }
934
948 void begin(TYPE max = 0)
949 {
950 synchronized begin_(max);
951 }
952
966 void begin_(TYPE max = 0)
967 {
968 if (!TRAIT::TCCRA.is_no_reg()) TRAIT::TCCRA = tccra_;
969 TRAIT::TCCRB = tccrb_;
970 // Set timer counter compare match
971 TRAIT::OCRA = max;
972 if (!TRAIT::CTC_MAX.is_no_reg()) TRAIT::CTC_MAX = max;
973 TRAIT::TCNT = 0;
974 // Set timer interrupt mode (set interrupt on OCRnA compare match)
975 utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, timsk_);
976 }
977
987 void reset(TYPE ticks = 0)
988 {
989 if (sizeof(TYPE) > 1)
990 synchronized reset_(ticks);
991 else
992 reset_(ticks);
993 }
994
1006 {
1007 TRAIT::TCNT = ticks;
1008 }
1009
1018 {
1019 if (sizeof(TYPE) > 1)
1020 synchronized return ticks_();
1021 else
1022 return ticks_();
1023 }
1024
1034 {
1035 return TRAIT::TCNT;
1036 }
1037
1049 {
1050 synchronized suspend_interrupts_();
1051 }
1052
1064 {
1065 // Clear timer interrupt mode
1066 utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, uint8_t(0));
1067 }
1068
1080 {
1081 synchronized resume_interrupts_();
1082 }
1083
1095 {
1096 // Reset timer counter
1097 TRAIT::TCNT = 0;
1098 // Set timer interrupt mode (set interrupt on OCRnA compare match)
1099 utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, timsk_);
1100 }
1101
1109 {
1110 return (TRAIT::TIMSK_ & TRAIT::TIMSK_MASK) == 0;
1111 }
1112
1124 {
1125 synchronized suspend_timer_();
1126 }
1127
1139 {
1140 // Check if timer is currently running, and force clock select to 0 (timer stopped)
1141 if (TRAIT::TCCRB) TRAIT::TCCRB = tccrb_ & uint8_t(~TRAIT::CS_MASK_TCCRB);
1142 }
1143
1155 {
1156 synchronized resume_timer_();
1157 }
1158
1170 {
1171 // Check if timer is currently running
1172 TRAIT::TCCRB = tccrb_;
1173 }
1174
1185 void end()
1186 {
1187 synchronized end_();
1188 }
1189
1200 void end_()
1201 {
1202 // Stop timer
1203 TRAIT::TCCRB = 0;
1204 // Clear timer interrupt mode (set interrupt on OCRnA compare match)
1205 utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, uint8_t(0));
1206 }
1207
1215 template<uint8_t COM> void set_output_mode(TimerOutputMode mode)
1216 {
1217 static_assert(COM < TRAIT::COM_COUNT, "COM must exist for TIMER");
1218 using COM_TRAIT = board_traits::Timer_COM_trait<NTIMER, COM>;
1219 utils::set_mask(tccra_, COM_TRAIT::COM_MASK, convert_COM<COM>(mode));
1220 }
1221
1232 template<uint8_t COM> void set_max(TYPE max)
1233 {
1234 static_assert(COM < TRAIT::COM_COUNT, "COM must exist for TIMER");
1235 using COM_TRAIT = board_traits::Timer_COM_trait<NTIMER, COM>;
1236 synchronized
1237 {
1238 if (max)
1239 utils::set_mask((volatile uint8_t&) TRAIT::TCCRA, COM_TRAIT::COM_MASK, tccra_);
1240 else
1241 utils::set_mask((volatile uint8_t&) TRAIT::TCCRA, COM_TRAIT::COM_MASK,
1242 convert_COM<COM>(TimerOutputMode::DISCONNECTED));
1243 COM_TRAIT::OCR = max;
1244 }
1245 }
1246
1247 protected:
1249 Timer(uint8_t tccra, uint8_t tccrb, uint8_t timsk = 0) : tccra_{tccra}, tccrb_{tccrb}, timsk_{timsk} {}
1250
1251 template<uint8_t COM> static constexpr uint8_t convert_COM(TimerOutputMode output_mode)
1252 {
1253 using COM_TRAIT = board_traits::Timer_COM_trait<NTIMER, COM>;
1254 if (output_mode == TimerOutputMode::TOGGLE) return COM_TRAIT::COM_TOGGLE;
1255 if (output_mode == TimerOutputMode::INVERTING) return COM_TRAIT::COM_SET;
1256 if (output_mode == TimerOutputMode::NON_INVERTING) return COM_TRAIT::COM_CLEAR;
1257 return COM_TRAIT::COM_NORMAL;
1258 }
1259
1260 static constexpr bool TIMSK_int_mask_IS_SUPPORTED(TimerInterrupt interrupt)
1261 {
1262 return (TRAIT::TIMSK_int_mask(UINT8_MAX) & TRAIT::TIMSK_int_mask(uint8_t(interrupt)))
1263 == TRAIT::TIMSK_int_mask(uint8_t(interrupt));
1264 }
1265
1266 static constexpr uint8_t timer_mode_TCCRA(TimerMode timer_mode)
1267 {
1268 if (timer_mode == TimerMode::CTC) return TRAIT::CTC_TCCRA;
1269 if (timer_mode == TimerMode::FAST_PWM) return TRAIT::F_PWM_TCCRA;
1270 if (timer_mode == TimerMode::PHASE_CORRECT_PWM) return TRAIT::PC_PWM_TCCRA;
1271 return 0;
1272 }
1273 static constexpr uint8_t timer_mode_TCCRB(TimerMode timer_mode)
1274 {
1275 if (timer_mode == TimerMode::CTC) return TRAIT::CTC_TCCRB;
1276 if (timer_mode == TimerMode::FAST_PWM) return TRAIT::F_PWM_TCCRB;
1277 if (timer_mode == TimerMode::PHASE_CORRECT_PWM) return TRAIT::PC_PWM_TCCRB;
1278 return 0;
1279 }
1280
1281 static constexpr bool is_timer_mode(TimerMode mode, uint8_t TCCRA, uint8_t TCCRB)
1282 {
1283 return utils::is_mask_equal(TCCRA, TRAIT::MODE_MASK_TCCRA, timer_mode_TCCRA(mode))
1284 && utils::is_mask_equal(TCCRB, TRAIT::MODE_MASK_TCCRB, timer_mode_TCCRB(mode));
1285 }
1286 static constexpr TimerMode timer_mode(uint8_t TCCRA, uint8_t TCCRB)
1287 {
1288 if (is_timer_mode(TimerMode::CTC, TCCRA, TCCRB)) return TimerMode::CTC;
1289 if (is_timer_mode(TimerMode::FAST_PWM, TCCRA, TCCRB)) return TimerMode::FAST_PWM;
1290 if (is_timer_mode(TimerMode::PHASE_CORRECT_PWM, TCCRA, TCCRB)) return TimerMode::PHASE_CORRECT_PWM;
1291 return TimerMode::NORMAL;
1292 }
1293
1294 static constexpr uint8_t input_capture_TCCRB(TimerInputCapture input_capture)
1295 {
1296 return (input_capture == TimerInputCapture::RISING_EDGE ? TRAIT::ICES_TCCRB : 0);
1297 }
1298
1299 uint8_t tccra_;
1300 uint8_t tccrb_;
1301 uint8_t timsk_;
1303 };
1304
1306
1307 // All PCI-related methods called by pre-defined ISR are defined here
1308 //====================================================================
1309
1310 struct isr_handler
1311 {
1312 template<board::Timer NTIMER_> static constexpr board::Timer check_timer()
1313 {
1314 using TRAIT = board_traits::Timer_trait<NTIMER_>;
1315 static_assert(TRAIT::PRESCALERS != board_traits::TimerPrescalers::PRESCALERS_NONE,
1316 "TIMER_NUM must be an actual Timer in target MCU");
1317 return NTIMER_;
1318 }
1319
1320 template<uint8_t TIMER_NUM_> static constexpr board::Timer check_timer()
1321 {
1322 constexpr board::Timer NTIMER = (board::Timer) TIMER_NUM_;
1323 return check_timer<NTIMER>();
1324 }
1325
1326 template<uint8_t TIMER_NUM_> static constexpr board::Timer check_timer_capture()
1327 {
1328 constexpr board::Timer NTIMER = check_timer<TIMER_NUM_>();
1329 static_assert(board_traits::Timer_trait<NTIMER>::ICES_TCCRB != 0,
1330 "TIMER_NUM must be Timer supporting capture");
1331 return NTIMER;
1332 }
1333
1334 template<uint8_t TIMER_NUM_, typename T, typename HANDLER_, void (HANDLER_::*CALLBACK_)(T)>
1335 static void timer_capture_method_helper()
1336 {
1337 static constexpr board::Timer NTIMER = check_timer_capture<TIMER_NUM_>();
1338 using TRAIT = board_traits::Timer_trait<NTIMER>;
1339 static_assert(sizeof(typename TRAIT::TYPE) == sizeof(T),
1340 "CALLBACK argument is not the proper type (should be same as Timer bits size)");
1341 T capture = TRAIT::ICR;
1342 interrupt::CallbackHandler<void (HANDLER_::*)(T), CALLBACK_>::call(capture);
1343 }
1344
1345 template<uint8_t TIMER_NUM_, typename HANDLER_, void (HANDLER_::*CALLBACK_)(uint8_t)>
1346 static void timer_capture_method()
1347 {
1348 timer_capture_method_helper<TIMER_NUM_, uint8_t, HANDLER_, CALLBACK_>();
1349 }
1350
1351 template<uint8_t TIMER_NUM_, typename HANDLER_, void (HANDLER_::*CALLBACK_)(uint16_t)>
1352 static void timer_capture_method()
1353 {
1354 timer_capture_method_helper<TIMER_NUM_, uint16_t, HANDLER_, CALLBACK_>();
1355 }
1356
1357 template<uint8_t TIMER_NUM_, typename T, void (*CALLBACK_)(T)> static void timer_capture_function_helper()
1358 {
1359 static constexpr board::Timer NTIMER = check_timer_capture<TIMER_NUM_>();
1360 using TRAIT = board_traits::Timer_trait<NTIMER>;
1361 static_assert(sizeof(typename TRAIT::TYPE) == sizeof(T),
1362 "CALLBACK argument is not the proper type (should be same as Timer bits size)");
1363 T capture = TRAIT::ICR;
1364 CALLBACK_(capture);
1365 }
1366
1367 template<uint8_t TIMER_NUM_, void (*CALLBACK_)(uint8_t)> static void timer_capture_function()
1368 {
1369 timer_capture_function_helper<TIMER_NUM_, uint8_t, CALLBACK_>();
1370 }
1371
1372 template<uint8_t TIMER_NUM_, void (*CALLBACK_)(uint16_t)> static void timer_capture_function()
1373 {
1374 timer_capture_function_helper<TIMER_NUM_, uint16_t, CALLBACK_>();
1375 }
1376 };
1378}
1379
1380#endif /* TIMER_HH */
General API to handle an AVR timer.
Definition: timer.h:705
void set_output_mode(TimerOutputMode mode)
Change the output mode for this timer; this enables connection between this timer to one of its assoc...
Definition: timer.h:1215
TYPE ticks()
Return the current counter value for this timer.
Definition: timer.h:1017
void set_capture_noise_canceller(bool cancel_noise)
Set or clear the noise canceller for input capture on this timer.
Definition: timer.h:876
void set_max(TYPE max)
Change the maximum value for this timer, in relation to one of its associated digital output pins.
Definition: timer.h:1232
Timer(TimerMode timer_mode, PRESCALER prescaler, TimerInterrupt interrupts=TimerInterrupt(0))
Construct a new Timer handler and initialize its mode.
Definition: timer.h:766
static constexpr const board::Timer NTIMER
The Board timer used by this Timer.
Definition: timer.h:708
void enable_interrupts(TimerInterrupt interrupts)
Add new interrupts to be enabled to the current list of interrupts that must be triggered by this tim...
Definition: timer.h:804
void suspend_interrupts()
Temporarily suspend this timer: the timer does not generate any interrupt any longer.
Definition: timer.h:1048
void begin(TYPE max=0)
Start this timer in the currently selected mode, with the provided prescaler value and max value.
Definition: timer.h:948
void disable_interrupts(TimerInterrupt interrupts)
Remove interrupts from the current list of enabled interrupts triggered by this timer.
Definition: timer.h:822
void reset_(TYPE ticks=0)
Reset current counter to ticks .
Definition: timer.h:1005
bool are_interrupts_enabled(TimerInterrupt interrupts) const
Test if interrupts are currently enabled for this timers.
Definition: timer.h:838
typename TRAIT::TYPE TYPE
The type of this timer's counter (either uint8_t or uint16_t).
Definition: timer.h:725
void suspend_interrupts_()
Temporarily suspend this timer: the timer does not generate any interrupt any longer.
Definition: timer.h:1063
void suspend_timer_()
Suspend this timer, ie stop this timer counting (ticks() will not change then).
Definition: timer.h:1138
void resume_interrupts()
Resume this timer if it was previously suspended: the timer's counter is reset and the timer starts g...
Definition: timer.h:1079
TYPE ticks_()
Return the current counter value for this timer.
Definition: timer.h:1033
void reset(TYPE ticks=0)
Reset current counter to ticks .
Definition: timer.h:987
static constexpr const TYPE TIMER_MAX
The maximum value that can be set to this timer's counter.
Definition: timer.h:740
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 resume_timer_()
Resume this timer, ie restart counting (ticks() will start changing again).
Definition: timer.h:1169
bool has_capture_noise_canceller() const
Tell whether noise canceller for this timer's input capture is active or not.
Definition: timer.h:891
void suspend_timer()
Suspend this timer, ie stop this timer counting (ticks() will not change then).
Definition: timer.h:1123
TimerMode get_timer_mode() const
Get current time mode.
Definition: timer.h:919
void set_input_capture(TimerInputCapture input_capture)
Set the input capture mode for this timer.
Definition: timer.h:852
void end()
Completely stop this timer: timer interrupts are disabled and counter is stopped.
Definition: timer.h:1185
static constexpr const TYPE PWM_MAX
The maximum value that can be set to this timer's counter in PWM mode.
Definition: timer.h:745
void set_prescaler(PRESCALER prescaler)
Change prescaler for this timer.
Definition: timer.h:928
TimerInputCapture input_capture() const
Return the current TimerInputCapture used by this timer.
Definition: timer.h:863
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
static constexpr const board::DigitalPin ICP_PIN
The pin that is used for Input Capture feature, if supported by this timer, or board::DigitalPin::NON...
Definition: timer.h:751
void set_interrupts(TimerInterrupt interrupts=TimerInterrupt(0))
Set the list of interrupts that must be triggered by this timer.
Definition: timer.h:785
bool is_interrupt_suspended()
Check if this timer interrupts are currently suspended, i.e.
Definition: timer.h:1108
void set_timer_mode(TimerMode timer_mode)
Change timer mode.
Definition: timer.h:901
void resume_interrupts_()
Resume this timer if it was previously suspended: the timer's counter is reset and the timer starts g...
Definition: timer.h:1094
void resume_timer()
Resume this timer, ie restart counting (ticks() will start changing again).
Definition: timer.h:1154
General API for handling AVR interrupt vectors.
static constexpr uint8_t COMPL(uint8_t value)
Return the uint8_t 2-complement of a byte.
Definition: bits.h:253
static constexpr uint16_t BV16(uint8_t bit)
Create a uint16_t bitmask for the given bit number.
Definition: bits.h:148
DigitalPin
Defines all available digital input/output pins of the target MCU.
Definition: empty.h:56
Timer
Defines all timers available for target MCU.
Definition: empty.h:112
Defines API to handle AVR interruptions.
Definition: int.h:100
Defines all API to manipulate AVR Timers.
Definition: pulse_timer.h:116
constexpr TimerInterrupt operator|(TimerInterrupt i1, TimerInterrupt i2)
Combine 2 timer interrupts for use with Timer.set_interrupts().
Definition: timer.h:254
TimerOutputMode
Defines the "connection" between this timer and specific PWM output pins.
Definition: timer.h:263
@ TOGGLE
Pin is toggled on Compare Match.
@ NON_INVERTING
Pin is cleared on Compare Match.
@ INVERTING
Pin is set on Compare Match.
@ DISCONNECTED
No connection for this pin: pin is unaffected by timer operation.
TimerMode
Defines the mode of operation of a timer.
Definition: timer.h:188
@ NORMAL
Timer "Normal" mode: counter is incremented up to maximum value (0xFF for 8-bits Timer,...
@ CTC
Timer "Clear Timer on Compare match" mode: counter is incremented until it reaches "TOP" (OCRxA regis...
@ FAST_PWM
Timer "Fast Phase Width Modulation" mode: counter is incremented until it reaches MAX value (0xFF for...
@ PHASE_CORRECT_PWM
Timer "Phase Correct Pulse Width Modulation" mode: counter is incremented until MAX (0xFF for 8-bits ...
TimerInputCapture
Defines the type of input capture we want for a timer.
Definition: timer.h:286
@ FALLING_EDGE
Input capture needed on falling edge of ICP pin.
@ RISING_EDGE
Input capture needed on rising edge of ICP pin.
TimerInterrupt
Defines the interrupts that can be handled by a timer.
Definition: timer.h:229
@ OVERFLOW
This interrupt occurs when the counter overflows it maximum value.
@ OUTPUT_COMPARE_C
This interrupt occurs when the counter reached OCRC.
@ OUTPUT_COMPARE_A
This interrupt occurs when the counter reached OCRA.
@ OUTPUT_COMPARE_B
This interrupt occurs when the counter reached OCRB.
@ INPUT_CAPTURE
This interrupt occurs during input capture, i.e.
constexpr bool is_mask_equal(T actual, T mask, T expected)
Common utility to check if 2 values are equal according to a mask.
Definition: utilities.h:364
void set_mask(volatile T &reg, T mask, T value)
Common utility to force a part of the value of a register, designated by a bit mask.
Definition: utilities.h:352
Defines a set of calculation methods for the given NTIMER_ The behavior of these methods is specific ...
Definition: timer.h:302
static constexpr uint16_t PWM_ICR_counter(PRESCALER prescaler, uint16_t pwm_frequency)
Computes the ideal counter TOP value to use for this timer, when used in timer::PulseTimer,...
Definition: timer.h:613
static constexpr PRESCALER tick_prescaler(uint32_t us_per_tick)
Computes the ideal prescaler to use for this timer, in order to generate timer ticks of us_per_tick m...
Definition: timer.h:341
static constexpr PRESCALER PhaseCorrectPWM_prescaler(uint16_t pwm_frequency)
Computes the ideal prescaler value to use for this timer, in TimerMode::PHASE_CORRECT_PWM mode,...
Definition: timer.h:493
static constexpr PRESCALER PWM_ICR_prescaler(uint16_t pwm_frequency)
Computes the ideal prescaler value to use for this timer, when used in timer::PulseTimer,...
Definition: timer.h:569
static constexpr PRESCALER FastPWM_prescaler(uint16_t pwm_frequency)
Computes the ideal prescaler value to use for this timer, in TimerMode::FAST_PWM mode,...
Definition: timer.h:461
static constexpr TYPE PulseTimer_value(PRESCALER prescaler, uint16_t period_us)
Computes the ideal value to use for this timer, when used in timer::PulseTimer, in order to produce a...
Definition: timer.h:547
static constexpr uint32_t ticks_to_us(PRESCALER prescaler, TYPE ticks)
Computes the number of microseconds reached for a given number of ticks with a given prescaler.
Definition: timer.h:357
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
typename TRAIT::TYPE TYPE
The timer type: either uint8_t or uint16_t; this is defined and not changeable for each Timer.
Definition: timer.h:319
typename PRESCALERS_TRAIT::TYPE PRESCALER
The type (enum) of the possible prescaler values for this timer; this is defined and not changeable f...
Definition: timer.h:324
static constexpr uint16_t PhaseCorrectPWM_frequency(PRESCALER prescaler)
Computes the frequency at which this timer would perform, in TimerMode::PHASE_CORRECT_PWM mode,...
Definition: timer.h:509
static constexpr const TYPE PWM_MAX
The maximum value you can use for this timer in PWM modes: using this value will set PWM duty as 100%...
Definition: timer.h:329
static constexpr uint16_t PWM_ICR_frequency(PRESCALER prescaler, uint16_t counter)
Computes the frequency at which this timer would perform, when used in timer::PulseTimer,...
Definition: timer.h:591
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
static constexpr uint16_t FastPWM_frequency(PRESCALER prescaler)
Computes the frequency at which this timer would perform, in TimerMode::FAST_PWM mode,...
Definition: timer.h:477
static constexpr const board::Timer NTIMER
The timer for which calculation methods are provided.
Definition: timer.h:307
static constexpr uint32_t CTC_frequency(PRESCALER prescaler)
Computes the frequency at which this timer would perform, in TimerMode::CTC mode, if it was using pre...
Definition: timer.h:406
static constexpr bool is_adequate_for_CTC(PRESCALER prescaler, uint32_t us)
Verifies that the given prescaler prescaler is suitable for this timer in TimerMode::CTC in order to ...
Definition: timer.h:445
static constexpr PRESCALER PulseTimer_prescaler(uint16_t max_pulse_width_us, uint16_t pulse_frequency)
Computes the ideal prescaler value to use for this timer, when used in timer::PulseTimer,...
Definition: timer.h:527
static constexpr TYPE us_to_ticks(PRESCALER prescaler, uint32_t us)
Computes the number of ticks needed for reaching the given us microseconds with a given prescaler.
Definition: timer.h:373
General utilities API that have broad application in programs.