FastArduino  v1.7
C++ library to build fast but small Arduino/AVR projects
timer.h
Go to the documentation of this file.
1 // Copyright 2016-2021 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 
182 namespace 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  {
265  DISCONNECTED,
267  TOGGLE,
273  NON_INVERTING,
279  INVERTING
280  };
281 
285  enum class TimerInputCapture : uint8_t
286  {
288  RISING_EDGE,
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:
717  Timer(const Timer<NTIMER_>&) = delete;
718  Timer<NTIMER_>& operator=(const Timer<NTIMER_>&) = delete;
719 
723  using TYPE = typename TRAIT::TYPE;
724 
729 
733  using PRESCALER = typename PRESCALERS_TRAIT::TYPE;
734 
738  static constexpr const TYPE TIMER_MAX = TRAIT::MAX_COUNTER - 1;
739 
743  static constexpr const TYPE PWM_MAX = TRAIT::MAX_PWM;
744 
749  static constexpr const board::DigitalPin ICP_PIN = TRAIT::ICP_PIN;
750 
764  Timer(TimerMode timer_mode, PRESCALER prescaler, TimerInterrupt interrupts = TimerInterrupt(0))
765  : tccra_{timer_mode_TCCRA(timer_mode)},
766  tccrb_{uint8_t(timer_mode_TCCRB(timer_mode) | TRAIT::TCCRB_prescaler(prescaler))},
767  timsk_{TRAIT::TIMSK_int_mask(uint8_t(interrupts))}
768  {}
769 
784  {
785  timsk_ = TRAIT::TIMSK_int_mask(uint8_t(interrupts));
786  // Check if timer is currently running
787  if (TRAIT::TCCRB) utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, timsk_);
788  }
789 
803  {
804  timsk_ |= TRAIT::TIMSK_int_mask(uint8_t(interrupts));
805  // Check if timer is currently running
806  if (TRAIT::TCCRB) utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, timsk_);
807  }
808 
821  {
822  timsk_ &= bits::COMPL(TRAIT::TIMSK_int_mask(uint8_t(interrupts)));
823  // Check if timer is currently running
824  if (TRAIT::TCCRB) utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, timsk_);
825  }
826 
836  bool are_interrupts_enabled(TimerInterrupt interrupts) const
837  {
838  uint8_t mask = TRAIT::TIMSK_int_mask(uint8_t(interrupts));
839  return (TRAIT::TIMSK_ & mask) == mask;
840  }
841 
851  {
852  static_assert(TRAIT::ICES_TCCRB != 0, "TIMER must support Input Capture");
853  utils::set_mask(tccrb_, TRAIT::ICES_TCCRB, input_capture_TCCRB(input_capture));
854  // Check if timer is currently running
855  if (TRAIT::TCCRB) TRAIT::TCCRB = tccrb_;
856  }
857 
862  {
863  static_assert(TRAIT::ICES_TCCRB != 0, "TIMER must support Input Capture");
864  return TRAIT::TCCRB & TRAIT::ICES_TCCRB ? TimerInputCapture::RISING_EDGE : TimerInputCapture::FALLING_EDGE;
865  }
866 
874  void set_capture_noise_canceller(bool cancel_noise)
875  {
876  static_assert(TRAIT::ICNC_TCCRB != 0, "TIMER must support Input Capture");
877  if (cancel_noise)
878  tccrb_ |= TRAIT::ICNC_TCCRB;
879  else
880  tccrb_ &= ~TRAIT::ICNC_TCCRB;
881  // Check if timer is currently running
882  if (TRAIT::TCCRB) TRAIT::TCCRB = tccrb_;
883  }
884 
890  {
891  static_assert(TRAIT::ICNC_TCCRB != 0, "TIMER must support Input Capture");
892  return TRAIT::TCCRB & TRAIT::ICNC_TCCRB;
893  }
894 
899  void set_timer_mode(TimerMode timer_mode)
900  {
901  utils::set_mask(tccra_, TRAIT::MODE_MASK_TCCRA, timer_mode_TCCRA(timer_mode));
902  utils::set_mask(tccrb_, TRAIT::MODE_MASK_TCCRB, timer_mode_TCCRB(timer_mode));
903  // Check if timer is currently running
904  if (TRAIT::TCCRB)
905  {
906  if (!TRAIT::TCCRA.is_no_reg()) TRAIT::TCCRA = tccra_;
907  TRAIT::TCCRB = tccrb_;
908  }
909  }
910 
918  {
919  return timer_mode(tccra_, tccrb_);
920  }
921 
926  void set_prescaler(PRESCALER prescaler)
927  {
928  utils::set_mask(tccrb_, TRAIT::CS_MASK_TCCRB, TRAIT::TCCRB_prescaler(prescaler));
929  // Check if timer is currently running
930  if (TRAIT::TCCRB) TRAIT::TCCRB = tccrb_;
931  }
932 
946  void begin(TYPE max = 0)
947  {
948  synchronized begin_(max);
949  }
950 
964  void begin_(TYPE max = 0)
965  {
966  if (!TRAIT::TCCRA.is_no_reg()) TRAIT::TCCRA = tccra_;
967  TRAIT::TCCRB = tccrb_;
968  // Set timer counter compare match
969  TRAIT::OCRA = max;
970  if (!TRAIT::CTC_MAX.is_no_reg()) TRAIT::CTC_MAX = max;
971  TRAIT::TCNT = 0;
972  // Set timer interrupt mode (set interrupt on OCRnA compare match)
973  utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, timsk_);
974  }
975 
985  void reset(TYPE ticks = 0)
986  {
987  if (sizeof(TYPE) > 1)
988  synchronized reset_(ticks);
989  else
990  reset_(ticks);
991  }
992 
1003  void reset_(TYPE ticks = 0)
1004  {
1005  TRAIT::TCNT = ticks;
1006  }
1007 
1016  {
1017  if (sizeof(TYPE) > 1)
1018  synchronized return ticks_();
1019  else
1020  return ticks_();
1021  }
1022 
1032  {
1033  return TRAIT::TCNT;
1034  }
1035 
1047  {
1048  synchronized suspend_interrupts_();
1049  }
1050 
1062  {
1063  // Clear timer interrupt mode
1064  utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, uint8_t(0));
1065  }
1066 
1078  {
1079  synchronized resume_interrupts_();
1080  }
1081 
1093  {
1094  // Reset timer counter
1095  TRAIT::TCNT = 0;
1096  // Set timer interrupt mode (set interrupt on OCRnA compare match)
1097  utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, timsk_);
1098  }
1099 
1107  {
1108  return (TRAIT::TIMSK_ & TRAIT::TIMSK_MASK) == 0;
1109  }
1110 
1122  {
1123  synchronized suspend_timer_();
1124  }
1125 
1137  {
1138  // Check if timer is currently running, and force clock select to 0 (timer stopped)
1139  if (TRAIT::TCCRB) TRAIT::TCCRB = tccrb_ & uint8_t(~TRAIT::CS_MASK_TCCRB);
1140  }
1141 
1153  {
1154  synchronized resume_timer_();
1155  }
1156 
1168  {
1169  // Check if timer is currently running
1170  TRAIT::TCCRB = tccrb_;
1171  }
1172 
1183  void end()
1184  {
1185  synchronized end_();
1186  }
1187 
1198  void end_()
1199  {
1200  // Stop timer
1201  TRAIT::TCCRB = 0;
1202  // Clear timer interrupt mode (set interrupt on OCRnA compare match)
1203  utils::set_mask((volatile uint8_t&) TRAIT::TIMSK_, TRAIT::TIMSK_MASK, uint8_t(0));
1204  }
1205 
1213  template<uint8_t COM> void set_output_mode(TimerOutputMode mode)
1214  {
1215  static_assert(COM < TRAIT::COM_COUNT, "COM must exist for TIMER");
1216  using COM_TRAIT = board_traits::Timer_COM_trait<NTIMER, COM>;
1217  utils::set_mask(tccra_, COM_TRAIT::COM_MASK, convert_COM<COM>(mode));
1218  }
1219 
1230  template<uint8_t COM> void set_max(TYPE max)
1231  {
1232  static_assert(COM < TRAIT::COM_COUNT, "COM must exist for TIMER");
1233  using COM_TRAIT = board_traits::Timer_COM_trait<NTIMER, COM>;
1234  synchronized
1235  {
1236  if (max)
1237  utils::set_mask((volatile uint8_t&) TRAIT::TCCRA, COM_TRAIT::COM_MASK, tccra_);
1238  else
1239  utils::set_mask((volatile uint8_t&) TRAIT::TCCRA, COM_TRAIT::COM_MASK,
1240  convert_COM<COM>(TimerOutputMode::DISCONNECTED));
1241  COM_TRAIT::OCR = max;
1242  }
1243  }
1244 
1245  protected:
1247  Timer(uint8_t tccra, uint8_t tccrb, uint8_t timsk = 0) : tccra_{tccra}, tccrb_{tccrb}, timsk_{timsk} {}
1248 
1249  template<uint8_t COM> static constexpr uint8_t convert_COM(TimerOutputMode output_mode)
1250  {
1251  using COM_TRAIT = board_traits::Timer_COM_trait<NTIMER, COM>;
1252  if (output_mode == TimerOutputMode::TOGGLE) return COM_TRAIT::COM_TOGGLE;
1253  if (output_mode == TimerOutputMode::INVERTING) return COM_TRAIT::COM_SET;
1254  if (output_mode == TimerOutputMode::NON_INVERTING) return COM_TRAIT::COM_CLEAR;
1255  return COM_TRAIT::COM_NORMAL;
1256  }
1257 
1258  static constexpr bool TIMSK_int_mask_IS_SUPPORTED(TimerInterrupt interrupt)
1259  {
1260  return (TRAIT::TIMSK_int_mask(UINT8_MAX) & TRAIT::TIMSK_int_mask(uint8_t(interrupt)))
1261  == TRAIT::TIMSK_int_mask(uint8_t(interrupt));
1262  }
1263 
1264  static constexpr uint8_t timer_mode_TCCRA(TimerMode timer_mode)
1265  {
1266  if (timer_mode == TimerMode::CTC) return TRAIT::CTC_TCCRA;
1267  if (timer_mode == TimerMode::FAST_PWM) return TRAIT::F_PWM_TCCRA;
1268  if (timer_mode == TimerMode::PHASE_CORRECT_PWM) return TRAIT::PC_PWM_TCCRA;
1269  return 0;
1270  }
1271  static constexpr uint8_t timer_mode_TCCRB(TimerMode timer_mode)
1272  {
1273  if (timer_mode == TimerMode::CTC) return TRAIT::CTC_TCCRB;
1274  if (timer_mode == TimerMode::FAST_PWM) return TRAIT::F_PWM_TCCRB;
1275  if (timer_mode == TimerMode::PHASE_CORRECT_PWM) return TRAIT::PC_PWM_TCCRB;
1276  return 0;
1277  }
1278 
1279  static constexpr bool is_timer_mode(TimerMode mode, uint8_t TCCRA, uint8_t TCCRB)
1280  {
1281  return utils::is_mask_equal(TCCRA, TRAIT::MODE_MASK_TCCRA, timer_mode_TCCRA(mode))
1282  && utils::is_mask_equal(TCCRB, TRAIT::MODE_MASK_TCCRB, timer_mode_TCCRB(mode));
1283  }
1284  static constexpr TimerMode timer_mode(uint8_t TCCRA, uint8_t TCCRB)
1285  {
1286  if (is_timer_mode(TimerMode::CTC, TCCRA, TCCRB)) return TimerMode::CTC;
1287  if (is_timer_mode(TimerMode::FAST_PWM, TCCRA, TCCRB)) return TimerMode::FAST_PWM;
1288  if (is_timer_mode(TimerMode::PHASE_CORRECT_PWM, TCCRA, TCCRB)) return TimerMode::PHASE_CORRECT_PWM;
1289  return TimerMode::NORMAL;
1290  }
1291 
1292  static constexpr uint8_t input_capture_TCCRB(TimerInputCapture input_capture)
1293  {
1294  return (input_capture == TimerInputCapture::RISING_EDGE ? TRAIT::ICES_TCCRB : 0);
1295  }
1296 
1297  uint8_t tccra_;
1298  uint8_t tccrb_;
1299  uint8_t timsk_;
1301  };
1302 
1304 
1305  // All PCI-related methods called by pre-defined ISR are defined here
1306  //====================================================================
1307 
1308  struct isr_handler
1309  {
1310  template<board::Timer NTIMER_> static constexpr board::Timer check_timer()
1311  {
1312  using TRAIT = board_traits::Timer_trait<NTIMER_>;
1313  static_assert(TRAIT::PRESCALERS != board_traits::TimerPrescalers::PRESCALERS_NONE,
1314  "TIMER_NUM must be an actual Timer in target MCU");
1315  return NTIMER_;
1316  }
1317 
1318  template<uint8_t TIMER_NUM_> static constexpr board::Timer check_timer()
1319  {
1320  constexpr board::Timer NTIMER = (board::Timer) TIMER_NUM_;
1321  return check_timer<NTIMER>();
1322  }
1323 
1324  template<uint8_t TIMER_NUM_> static constexpr board::Timer check_timer_capture()
1325  {
1326  constexpr board::Timer NTIMER = check_timer<TIMER_NUM_>();
1327  static_assert(board_traits::Timer_trait<NTIMER>::ICES_TCCRB != 0,
1328  "TIMER_NUM must be Timer supporting capture");
1329  return NTIMER;
1330  }
1331 
1332  template<uint8_t TIMER_NUM_, typename T, typename HANDLER_, void (HANDLER_::*CALLBACK_)(T)>
1333  static void timer_capture_method_helper()
1334  {
1335  static constexpr board::Timer NTIMER = check_timer_capture<TIMER_NUM_>();
1336  using TRAIT = board_traits::Timer_trait<NTIMER>;
1337  static_assert(sizeof(typename TRAIT::TYPE) == sizeof(T),
1338  "CALLBACK argument is not the proper type (should be same as Timer bits size)");
1339  T capture = TRAIT::ICR;
1340  interrupt::CallbackHandler<void (HANDLER_::*)(T), CALLBACK_>::call(capture);
1341  }
1342 
1343  template<uint8_t TIMER_NUM_, typename HANDLER_, void (HANDLER_::*CALLBACK_)(uint8_t)>
1344  static void timer_capture_method()
1345  {
1346  timer_capture_method_helper<TIMER_NUM_, uint8_t, HANDLER_, CALLBACK_>();
1347  }
1348 
1349  template<uint8_t TIMER_NUM_, typename HANDLER_, void (HANDLER_::*CALLBACK_)(uint16_t)>
1350  static void timer_capture_method()
1351  {
1352  timer_capture_method_helper<TIMER_NUM_, uint16_t, HANDLER_, CALLBACK_>();
1353  }
1354 
1355  template<uint8_t TIMER_NUM_, typename T, void (*CALLBACK_)(T)> static void timer_capture_function_helper()
1356  {
1357  static constexpr board::Timer NTIMER = check_timer_capture<TIMER_NUM_>();
1358  using TRAIT = board_traits::Timer_trait<NTIMER>;
1359  static_assert(sizeof(typename TRAIT::TYPE) == sizeof(T),
1360  "CALLBACK argument is not the proper type (should be same as Timer bits size)");
1361  T capture = TRAIT::ICR;
1362  CALLBACK_(capture);
1363  }
1364 
1365  template<uint8_t TIMER_NUM_, void (*CALLBACK_)(uint8_t)> static void timer_capture_function()
1366  {
1367  timer_capture_function_helper<TIMER_NUM_, uint8_t, CALLBACK_>();
1368  }
1369 
1370  template<uint8_t TIMER_NUM_, void (*CALLBACK_)(uint16_t)> static void timer_capture_function()
1371  {
1372  timer_capture_function_helper<TIMER_NUM_, uint16_t, CALLBACK_>();
1373  }
1374  };
1376 }
1377 
1378 #endif /* TIMER_HH */
1379 
timer::Timer::set_capture_noise_canceller
void set_capture_noise_canceller(bool cancel_noise)
Set or clear the noise canceller for input capture on this timer.
Definition: timer.h:874
timer::TimerInterrupt
TimerInterrupt
Defines the interrupts that can be handled by a timer.
Definition: timer.h:229
board::Timer
Timer
Defines all timers available for ATmega644.
Definition: atmega_xx4.h:316
timer::Timer::set_input_capture
void set_input_capture(TimerInputCapture input_capture)
Set the input capture mode for this timer.
Definition: timer.h:850
timer::Calculator::PhaseCorrectPWM_prescaler
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
timer::Calculator::CTC_counter
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
timer::Calculator::PulseTimer_prescaler
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
timer::Timer::resume_timer_
void resume_timer_()
Resume this timer, ie restart counting (ticks() will start changing again).
Definition: timer.h:1167
timer::TimerOutputMode::DISCONNECTED
@ DISCONNECTED
No connection for this pin: pin is unaffected by timer operation.
timer::Timer::PWM_MAX
static constexpr const TYPE PWM_MAX
The maximum value that can be set to this timer's counter in PWM mode.
Definition: timer.h:743
timer::Timer::get_timer_mode
TimerMode get_timer_mode() const
Get current time mode.
Definition: timer.h:917
timer::TimerMode::NORMAL
@ NORMAL
Timer "Normal" mode: counter is incremented up to maximum value (0xFF for 8-bits Timer,...
timer::Timer::NTIMER
static constexpr const board::Timer NTIMER
The Board timer used by this Timer.
Definition: timer.h:708
timer::Timer::set_timer_mode
void set_timer_mode(TimerMode timer_mode)
Change timer mode.
Definition: timer.h:899
timer::Timer::input_capture
TimerInputCapture input_capture() const
Return the current TimerInputCapture used by this timer.
Definition: timer.h:861
timer::Calculator::FastPWM_frequency
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
timer::Timer::suspend_timer
void suspend_timer()
Suspend this timer, ie stop this timer counting (ticks() will not change then).
Definition: timer.h:1121
timer::Timer< NTIMER >::PRESCALER
typename PRESCALERS_TRAIT::TYPE PRESCALER
The enum type listing all available precaler values for this timer.
Definition: timer.h:733
bits::COMPL
static constexpr uint8_t COMPL(uint8_t value)
Return the uint8_t 2-complement of a byte.
Definition: bits.h:253
timer::Calculator::us_to_ticks
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
timer
Defines all API to manipulate AVR Timers.
Definition: pulse_timer.h:116
timer::Timer::suspend_interrupts
void suspend_interrupts()
Temporarily suspend this timer: the timer does not generate any interrupt any longer.
Definition: timer.h:1046
timer::Calculator::tick_prescaler
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
timer::Timer::is_interrupt_suspended
bool is_interrupt_suspended()
Check if this timer interrupts are currently suspended, i.e.
Definition: timer.h:1106
timer::Calculator::PWM_ICR_frequency
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
timer::Timer::set_prescaler
void set_prescaler(PRESCALER prescaler)
Change prescaler for this timer.
Definition: timer.h:926
interrupt
Defines API to handle AVR interruptions.
Definition: int.h:100
timer::operator|
constexpr TimerInterrupt operator|(TimerInterrupt i1, TimerInterrupt i2)
Combine 2 timer interrupts for use with Timer.set_interrupts().
Definition: timer.h:254
timer::Timer::ticks
TYPE ticks()
Return the current counter value for this timer.
Definition: timer.h:1015
timer::Timer::disable_interrupts
void disable_interrupts(TimerInterrupt interrupts)
Remove interrupts from the current list of enabled interrupts triggered by this timer.
Definition: timer.h:820
timer::Timer::resume_interrupts
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:1077
timer::Timer::begin
void begin(TYPE max=0)
Start this timer in the currently selected mode, with the provided prescaler value and max value.
Definition: timer.h:946
timer::Timer::reset_
void reset_(TYPE ticks=0)
Reset current counter to ticks .
Definition: timer.h:1003
timer::Calculator::PWM_MAX
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
timer::Timer::TIMER_MAX
static constexpr const TYPE TIMER_MAX
The maximum value that can be set to this timer's counter.
Definition: timer.h:738
timer::Timer::end_
void end_()
Completely stop this timer: timer interrupts are disabled and counter is stopped.
Definition: timer.h:1198
timer::Timer::end
void end()
Completely stop this timer: timer interrupts are disabled and counter is stopped.
Definition: timer.h:1183
timer::Timer::has_capture_noise_canceller
bool has_capture_noise_canceller() const
Tell whether noise canceller for this timer's input capture is active or not.
Definition: timer.h:889
timer::Timer::ICP_PIN
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:749
timer::Timer::are_interrupts_enabled
bool are_interrupts_enabled(TimerInterrupt interrupts) const
Test if interrupts are currently enabled for this timers.
Definition: timer.h:836
timer::Timer
General API to handle an AVR timer.
Definition: timer.h:705
timer::Timer::enable_interrupts
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:802
timer::Calculator::NTIMER
static constexpr const board::Timer NTIMER
The timer for which calculation methods are provided.
Definition: timer.h:307
timer::Timer< NTIMER >::TYPE
typename TRAIT::TYPE TYPE
The type of this timer's counter (either uint8_t or uint16_t).
Definition: timer.h:723
timer::Timer::set_output_mode
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:1213
timer::Calculator::is_adequate_for_CTC
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
utilities.h
General utilities API that have broad application in programs.
timer::Timer::suspend_interrupts_
void suspend_interrupts_()
Temporarily suspend this timer: the timer does not generate any interrupt any longer.
Definition: timer.h:1061
timer::Timer::Timer
Timer(TimerMode timer_mode, PRESCALER prescaler, TimerInterrupt interrupts=TimerInterrupt(0))
Construct a new Timer handler and initialize its mode.
Definition: timer.h:764
timer::TimerInputCapture::RISING_EDGE
@ RISING_EDGE
Input capture needed on rising edge of ICP pin.
timer::TimerMode
TimerMode
Defines the mode of operation of a timer.
Definition: timer.h:188
timer::Calculator::CTC_frequency
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
timer::Timer::set_max
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:1230
bits::BV16
static constexpr uint16_t BV16(uint8_t bit)
Create a uint16_t bitmask for the given bit number.
Definition: bits.h:148
utils::is_mask_equal
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:332
timer::Calculator
Defines a set of calculation methods for the given NTIMER_ The behavior of these methods is specific ...
Definition: timer.h:302
timer::Timer::resume_interrupts_
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:1092
timer::Timer::reset
void reset(TYPE ticks=0)
Reset current counter to ticks .
Definition: timer.h:985
timer::Timer::set_interrupts
void set_interrupts(TimerInterrupt interrupts=TimerInterrupt(0))
Set the list of interrupts that must be triggered by this timer.
Definition: timer.h:783
timer::TimerInputCapture
TimerInputCapture
Defines the type of input capture we want for a timer.
Definition: timer.h:286
timer::TimerInterrupt::OVERFLOW
@ OVERFLOW
This interrupt occurs when the counter overflows it maximum value.
timer::Calculator::PRESCALER
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
timer::Timer::begin_
void begin_(TYPE max=0)
Start this timer in the currently selected mode, with the provided prescaler value and max value.
Definition: timer.h:964
interrupts.h
General API for handling AVR interrupt vectors.
timer::Calculator::TYPE
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
timer::Calculator::FastPWM_prescaler
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
utils::set_mask
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:320
timer::Calculator::PhaseCorrectPWM_frequency
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
timer::Timer::suspend_timer_
void suspend_timer_()
Suspend this timer, ie stop this timer counting (ticks() will not change then).
Definition: timer.h:1136
timer::TimerOutputMode
TimerOutputMode
Defines the "connection" between this timer and specific PWM output pins.
Definition: timer.h:263
timer::Calculator::PulseTimer_value
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
timer::Calculator::ticks_to_us
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
timer::Calculator::PWM_ICR_prescaler
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
timer::Timer::resume_timer
void resume_timer()
Resume this timer, ie restart counting (ticks() will start changing again).
Definition: timer.h:1152
timer::Calculator::CTC_prescaler
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
timer::Calculator::PWM_ICR_counter
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
board::DigitalPin
DigitalPin
Defines all available digital input/output pins of ATmega644, with reference to Arduino MEGA pins.
Definition: atmega_xx4.h:76
timer::Timer::ticks_
TYPE ticks_()
Return the current counter value for this timer.
Definition: timer.h:1031