FastArduino  v1.7
C++ library to build fast but small Arduino/AVR projects
pci.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 
25 #ifndef PCI_HH
26 #define PCI_HH
27 
28 #include "boards/board.h"
29 #include "boards/board_traits.h"
30 #include <avr/interrupt.h>
31 #include "interrupts.h"
32 #include "utilities.h"
33 
44 #define REGISTER_PCI_ISR_METHOD(PCI_NUM, HANDLER, CALLBACK, PIN, ...) \
45  ISR(CAT3(PCINT, PCI_NUM, _vect)) \
46  { \
47  interrupt::isr_handler_pci::pci_method<PCI_NUM, HANDLER, CALLBACK, PIN, ##__VA_ARGS__>(); \
48  }
49 
59 #define REGISTER_PCI_ISR_FUNCTION(PCI_NUM, CALLBACK, PIN, ...) \
60  ISR(CAT3(PCINT, PCI_NUM, _vect)) \
61  { \
62  interrupt::isr_handler_pci::pci_function<PCI_NUM, CALLBACK, PIN, ##__VA_ARGS__>(); \
63  }
64 
74 #define REGISTER_PCI_ISR_EMPTY(PCI_NUM, PIN, ...) \
75  extern "C" void CAT3(PCINT, PCI_NUM, _vect)(void) NAKED_SIGNAL; \
76  void CAT3(PCINT, PCI_NUM, _vect)(void) \
77  { \
78  interrupt::isr_handler_pci::check_pci_pins<PCI_NUM, PIN, ##__VA_ARGS__>(); \
79  __asm__ __volatile__("reti" ::); \
80  }
81 
88 #define DECL_PCI_ISR_HANDLERS_FRIEND \
89  friend struct interrupt::isr_handler_pci; \
90  DECL_PCINT_ISR_FRIENDS
91 
92 namespace board
93 {
94  template<InterruptPin PCI> constexpr DigitalPin PCI_PIN() INLINE;
98  template<InterruptPin PCI> constexpr DigitalPin PCI_PIN()
99  {
100  return DigitalPin(uint8_t(PCI));
101  }
102 };
103 
104 namespace interrupt
105 {
106  // All PCI-related methods called by pre-defined ISR are defined here
107  //====================================================================
108 
110  struct isr_handler_pci
111  {
112  template<uint8_t PCI_NUM_, board::InterruptPin PCIPIN_>
113  static constexpr uint8_t get_pci_pin_bit()
114  {
115  constexpr board::DigitalPin PIN = board::PCI_PIN<PCIPIN_>();
116  using PINTRAIT = board_traits::DigitalPin_trait<PIN>;
117  using PORTTRAIT = board_traits::Port_trait<PINTRAIT::PORT>;
118  return bits::BV8(PINTRAIT::BIT) << PORTTRAIT::PCI_SHIFT;
119  }
120 
121  template<uint8_t PCI_NUM_> static void check_pci_pins() {}
122 
123  template<uint8_t PCI_NUM_, board::InterruptPin PCIPIN1_, board::InterruptPin... PCIPINS_>
124  static void check_pci_pins()
125  {
126  static_assert(board_traits::PCI_trait<PCI_NUM_>::SUPPORTED, "PCI_NUM must support PCI");
127  constexpr board::DigitalPin PIN = board::PCI_PIN<PCIPIN1_>();
128  using PINTRAIT = board_traits::DigitalPin_trait<PIN>;
129  using PORTTRAIT = board_traits::Port_trait<PINTRAIT::PORT>;
130  using PCITRAIT = board_traits::PCI_trait<PCI_NUM_>;
131  static_assert(PORTTRAIT::PCINT == PCI_NUM_, "PIN PORT must use this PCINT");
132  static_assert(PCITRAIT::PCI_MASK & get_pci_pin_bit<PCI_NUM_, PCIPIN1_>(),
133  "PIN must be a PCI within this PCINT");
134  // Check other pins
135  check_pci_pins<PCI_NUM_, PCIPINS_...>();
136  }
137 
138  template<uint8_t PCI_NUM_, typename HANDLER_, void (HANDLER_::*CALLBACK_)(), board::InterruptPin... PCIPINS_>
139  static void pci_method()
140  {
141  // Check pin is compliant
142  check_pci_pins<PCI_NUM_, PCIPINS_...>();
143  // Call handler back
144  interrupt::CallbackHandler<void (HANDLER_::*)(), CALLBACK_>::call();
145  }
146 
147  template<uint8_t PCI_NUM_, void (*CALLBACK_)(), board::InterruptPin... PCIPINS_> static void pci_function()
148  {
149  // Check pin is compliant
150  check_pci_pins<PCI_NUM_, PCIPINS_...>();
151  // Call handler back
152  CALLBACK_();
153  }
154  };
156 
175  template<uint8_t PCINT_> class PCISignal
176  {
177  private:
178  using TRAIT = board_traits::PCI_trait<PCINT_>;
179 
180  public:
181  PCISignal(const PCISignal<PCINT_>&) = delete;
182  PCISignal<PCINT_>& operator=(const PCISignal<PCINT_>&) = delete;
183 
185  //NOTE this constructor exists only to add a static_assert checked when
186  // PCISignal is constructed not when its template type gets instantiated.
187  PCISignal()
188  {
189  static_assert(TRAIT::SUPPORTED, "PCINT_ must be a valid PCINT number");
190  }
192 
194  static constexpr const uint8_t PCINT = PCINT_;
195 
210  void enable()
211  {
212  synchronized TRAIT::PCICR_ |= TRAIT::PCICR_MASK;
213  }
214 
227  void disable()
228  {
229  synchronized TRAIT::PCICR_ &= bits::COMPL(TRAIT::PCICR_MASK);
230  }
231 
242  void clear()
243  {
244  synchronized TRAIT::PCIFR_ |= TRAIT::PCIFR_MASK;
245  }
246 
261  void set_enable_pins(uint8_t mask)
262  {
263  synchronized TRAIT::PCMSK_ = mask;
264  }
265 
285  void enable_pins(uint8_t mask)
286  {
287  synchronized TRAIT::PCMSK_ |= mask;
288  }
289 
309  void disable_pins(uint8_t mask)
310  {
311  synchronized TRAIT::PCMSK_ &= bits::COMPL(mask);
312  }
313 
327  template<board::InterruptPin PIN> void enable_pin()
328  {
329  check_pin_pci<PIN>();
330  enable_pins(isr_handler_pci::get_pci_pin_bit<PCINT, PIN>());
331  }
332 
345  template<board::InterruptPin PIN> void disable_pin()
346  {
347  check_pin_pci<PIN>();
348  disable_pins(isr_handler_pci::get_pci_pin_bit<PCINT, PIN>());
349  }
350 
365  void enable_()
366  {
367  TRAIT::PCICR_ |= TRAIT::PCICR_MASK;
368  }
369 
382  void disable_()
383  {
384  TRAIT::PCICR_ &= bits::COMPL(TRAIT::PCICR_MASK);
385  }
386 
397  void clear_()
398  {
399  TRAIT::PCIFR_ |= TRAIT::PCIFR_MASK;
400  }
401 
416  void set_enable_pins_(uint8_t mask)
417  {
418  TRAIT::PCMSK_ = mask;
419  }
420 
440  void enable_pins_(uint8_t mask)
441  {
442  TRAIT::PCMSK_ |= mask;
443  }
444 
464  void disable_pins_(uint8_t mask)
465  {
466  TRAIT::PCMSK_ &= bits::COMPL(mask);
467  }
468 
482  template<board::InterruptPin PIN> void enable_pin_()
483  {
484  check_pin_pci<PIN>();
485  enable_pins_(isr_handler_pci::get_pci_pin_bit<PCINT, PIN>());
486  }
487 
500  template<board::InterruptPin PIN> void disable_pin_()
501  {
502  check_pin_pci<PIN>();
503  disable_pins_(isr_handler_pci::get_pci_pin_bit<PCINT, PIN>());
504  }
505 
506  private:
507  template<board::InterruptPin PIN> void check_pin_pci()
508  {
509  isr_handler_pci::check_pci_pins<PCINT, PIN>();
510  }
511  };
512 
532  template<board::InterruptPin PIN> struct PCIType
533  {
534  private:
535  using PIN_TRAIT = board_traits::DigitalPin_trait<board::PCI_PIN<PIN>()>;
536  using PORT_TRAIT = board_traits::Port_trait<PIN_TRAIT::PORT>;
537 
538  public:
540  static constexpr const uint8_t PCINT = PORT_TRAIT::PCINT;
543  };
544 
566  template<board::InterruptPin PIN>
567  using PCI_SIGNAL = typename PCIType<PIN>::TYPE;
568 
572  template<board::Port PORT>
574 }
575 
576 #endif /* PCI_HH */
577 
interrupt::PCISignal::enable_pin_
void enable_pin_()
Enable Pin Change Interrupts for PIN.
Definition: pci.h:482
board::PCI_PIN
constexpr DigitalPin PCI_PIN() INLINE
Convert an InterruptPin to the matching DigitalPin.
Definition: pci.h:98
interrupt::PCISignal::set_enable_pins_
void set_enable_pins_(uint8_t mask)
Set the exact list of pins, in this PCINT, for which Pin Change Interrupts must be enabled.
Definition: pci.h:416
interrupt::PCISignal::disable_pins
void disable_pins(uint8_t mask)
Disable pin change interrupts for several pins of this PCINT.
Definition: pci.h:309
interrupt::PCI_SIGNAL
typename PCIType< PIN >::TYPE PCI_SIGNAL
Useful alias type to the PCISignal type matching a given board::InterruptPin.
Definition: pci.h:567
interrupt::PCISignal::disable_
void disable_()
Disable all pin change interrupts for this PCISignal.
Definition: pci.h:382
bits::COMPL
static constexpr uint8_t COMPL(uint8_t value)
Return the uint8_t 2-complement of a byte.
Definition: bits.h:253
interrupt
Defines API to handle AVR interruptions.
Definition: int.h:100
bits::BV8
static constexpr uint8_t BV8(uint8_t bit)
Create a uint8_t bitmask for the given bit number.
Definition: bits.h:41
interrupt::PCISignal::enable_pin
void enable_pin()
Enable Pin Change Interrupts for PIN.
Definition: pci.h:327
board
Defines all types and constants specific to support Arduino MEGA board (ATmega644 MCU target).
Definition: atmega_xx4.h:39
board::InterruptPin
InterruptPin
Defines all digital output pins of ATmega644, usable as pin change interrupt (PCI) pins.
Definition: atmega_xx4.h:259
interrupt::PCISignal::clear_
void clear_()
Clear the interrupt flag for this pin change interrupt vector.
Definition: pci.h:397
utilities.h
General utilities API that have broad application in programs.
interrupt::PCISignal::disable_pins_
void disable_pins_(uint8_t mask)
Disable pin change interrupts for several pins of this PCINT.
Definition: pci.h:464
interrupt::PCISignal::disable
void disable()
Disable all pin change interrupts handled by this PCISignal.
Definition: pci.h:227
interrupt::PCISignal::enable
void enable()
Enable pin change interrupts handled by this PCISignal.
Definition: pci.h:210
board::BIT
constexpr uint8_t BIT() INLINE
Determine the bit position, inside its IO port, of the given DigitalPin.
Definition: gpio.h:37
interrupt::PCISignal
Handler of a Pin Change Interrupt vector.
Definition: pci.h:176
interrupt::PCISignal::enable_pins_
void enable_pins_(uint8_t mask)
Enable pin change interrupts for several pins of this PCINT.
Definition: pci.h:440
interrupt::PCISignal::enable_
void enable_()
Enable pin change interrupts for this PCISignal.
Definition: pci.h:365
interrupts.h
General API for handling AVR interrupt vectors.
interrupt::PCISignal::enable_pins
void enable_pins(uint8_t mask)
Enable pin change interrupts for several pins of this PCINT.
Definition: pci.h:285
interrupt::PCISignal::disable_pin
void disable_pin()
Disable Pin Change Interrupts for PIN.
Definition: pci.h:345
interrupt::PCISignal::clear
void clear()
Clear the interrupt flag for this pin change interrupt vector.
Definition: pci.h:242
interrupt::PCISignal::disable_pin_
void disable_pin_()
Disable Pin Change Interrupts for PIN.
Definition: pci.h:500
interrupt::PCIType
Helper class that easily converts a PIN into the right PCISignal.
Definition: pci.h:533
board::DigitalPin
DigitalPin
Defines all available digital input/output pins of ATmega644, with reference to Arduino MEGA pins.
Definition: atmega_xx4.h:76
INLINE
#define INLINE
Specific GCC attribute to force the compiler to always inline code of a given function.
Definition: defines.h:57
interrupt::PCISignal::set_enable_pins
void set_enable_pins(uint8_t mask)
Set the exact list of pins, in this PCINT, for which Pin Change Interrupts must be enabled.
Definition: pci.h:261