LSH-Core
Deterministic firmware core for Controllino-based Labo Smart Home nodes
 
Loading...
Searching...
No Matches
avr_fast_io.hpp
Go to the documentation of this file.
1
21#ifndef LSH_CORE_INTERNAL_AVR_FAST_IO_HPP
22#define LSH_CORE_INTERNAL_AVR_FAST_IO_HPP
23
24#if (ARDUINO >= 100)
25#include <Arduino.h>
26#else
27#include <WProgram.h>
28#endif // (ARDUINO >= 100)
29
30#include <stdint.h>
31
32#include "internal/pin_tag.hpp"
33
34namespace lsh
35{
36namespace core
37{
38namespace avr
39{
48{
49 uint8_t mask = 0U;
50 volatile const uint8_t *pinPort = nullptr;
51 volatile uint8_t *outputPort = nullptr;
52 volatile uint8_t *modePort = nullptr;
53};
54
62{
63 uint8_t mask = 0U;
64 volatile uint8_t *pinPort = nullptr;
65 volatile uint8_t *modePort = nullptr;
66};
67
76{
77 uint8_t mask = 0U;
78 uint16_t inputAddress = 0U;
79 uint16_t outputAddress = 0U;
80 uint16_t modeAddress = 0U;
81};
82
83namespace detail
84{
85#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
86#define LSH_CORE_MEGA_IO_PIN_DESC(input_io_addr, output_io_addr, mode_io_addr, bit_index) \
87 StaticPinDescriptor \
88 { \
89 static_cast<uint8_t>(_BV(bit_index)), static_cast<uint16_t>((input_io_addr) + __SFR_OFFSET), \
90 static_cast<uint16_t>((output_io_addr) + __SFR_OFFSET), static_cast<uint16_t>((mode_io_addr) + __SFR_OFFSET) \
91 }
92
93#define LSH_CORE_MEGA_MEM_PIN_DESC(input_mem_addr, output_mem_addr, mode_mem_addr, bit_index) \
94 StaticPinDescriptor \
95 { \
96 static_cast<uint8_t>(_BV(bit_index)), static_cast<uint16_t>(input_mem_addr), static_cast<uint16_t>(output_mem_addr), \
97 static_cast<uint16_t>(mode_mem_addr) \
98 }
99
109inline constexpr StaticPinDescriptor kMegaPinDescriptors[] = {
110 LSH_CORE_MEGA_IO_PIN_DESC(0x0CU, 0x0EU, 0x0DU, 0), // 0 -> PORTE0
111 LSH_CORE_MEGA_IO_PIN_DESC(0x0CU, 0x0EU, 0x0DU, 1), // 1 -> PORTE1
112 LSH_CORE_MEGA_IO_PIN_DESC(0x0CU, 0x0EU, 0x0DU, 4), // 2 -> PORTE4
113 LSH_CORE_MEGA_IO_PIN_DESC(0x0CU, 0x0EU, 0x0DU, 5), // 3 -> PORTE5
114 LSH_CORE_MEGA_IO_PIN_DESC(0x12U, 0x14U, 0x13U, 5), // 4 -> PORTG5
115 LSH_CORE_MEGA_IO_PIN_DESC(0x0CU, 0x0EU, 0x0DU, 3), // 5 -> PORTE3
116 LSH_CORE_MEGA_MEM_PIN_DESC(0x100U, 0x102U, 0x101U, 3), // 6 -> PORTH3
117 LSH_CORE_MEGA_MEM_PIN_DESC(0x100U, 0x102U, 0x101U, 4), // 7 -> PORTH4
118 LSH_CORE_MEGA_MEM_PIN_DESC(0x100U, 0x102U, 0x101U, 5), // 8 -> PORTH5
119 LSH_CORE_MEGA_MEM_PIN_DESC(0x100U, 0x102U, 0x101U, 6), // 9 -> PORTH6
120 LSH_CORE_MEGA_IO_PIN_DESC(0x03U, 0x05U, 0x04U, 4), // 10 -> PORTB4
121 LSH_CORE_MEGA_IO_PIN_DESC(0x03U, 0x05U, 0x04U, 5), // 11 -> PORTB5
122 LSH_CORE_MEGA_IO_PIN_DESC(0x03U, 0x05U, 0x04U, 6), // 12 -> PORTB6
123 LSH_CORE_MEGA_IO_PIN_DESC(0x03U, 0x05U, 0x04U, 7), // 13 -> PORTB7
124 LSH_CORE_MEGA_MEM_PIN_DESC(0x103U, 0x105U, 0x104U, 1), // 14 -> PORTJ1
125 LSH_CORE_MEGA_MEM_PIN_DESC(0x103U, 0x105U, 0x104U, 0), // 15 -> PORTJ0
126 LSH_CORE_MEGA_MEM_PIN_DESC(0x100U, 0x102U, 0x101U, 1), // 16 -> PORTH1
127 LSH_CORE_MEGA_MEM_PIN_DESC(0x100U, 0x102U, 0x101U, 0), // 17 -> PORTH0
128 LSH_CORE_MEGA_IO_PIN_DESC(0x09U, 0x0BU, 0x0AU, 3), // 18 -> PORTD3
129 LSH_CORE_MEGA_IO_PIN_DESC(0x09U, 0x0BU, 0x0AU, 2), // 19 -> PORTD2
130 LSH_CORE_MEGA_IO_PIN_DESC(0x09U, 0x0BU, 0x0AU, 1), // 20 -> PORTD1
131 LSH_CORE_MEGA_IO_PIN_DESC(0x09U, 0x0BU, 0x0AU, 0), // 21 -> PORTD0
132 LSH_CORE_MEGA_IO_PIN_DESC(0x00U, 0x02U, 0x01U, 0), // 22 -> PORTA0
133 LSH_CORE_MEGA_IO_PIN_DESC(0x00U, 0x02U, 0x01U, 1), // 23 -> PORTA1
134 LSH_CORE_MEGA_IO_PIN_DESC(0x00U, 0x02U, 0x01U, 2), // 24 -> PORTA2
135 LSH_CORE_MEGA_IO_PIN_DESC(0x00U, 0x02U, 0x01U, 3), // 25 -> PORTA3
136 LSH_CORE_MEGA_IO_PIN_DESC(0x00U, 0x02U, 0x01U, 4), // 26 -> PORTA4
137 LSH_CORE_MEGA_IO_PIN_DESC(0x00U, 0x02U, 0x01U, 5), // 27 -> PORTA5
138 LSH_CORE_MEGA_IO_PIN_DESC(0x00U, 0x02U, 0x01U, 6), // 28 -> PORTA6
139 LSH_CORE_MEGA_IO_PIN_DESC(0x00U, 0x02U, 0x01U, 7), // 29 -> PORTA7
140 LSH_CORE_MEGA_IO_PIN_DESC(0x06U, 0x08U, 0x07U, 7), // 30 -> PORTC7
141 LSH_CORE_MEGA_IO_PIN_DESC(0x06U, 0x08U, 0x07U, 6), // 31 -> PORTC6
142 LSH_CORE_MEGA_IO_PIN_DESC(0x06U, 0x08U, 0x07U, 5), // 32 -> PORTC5
143 LSH_CORE_MEGA_IO_PIN_DESC(0x06U, 0x08U, 0x07U, 4), // 33 -> PORTC4
144 LSH_CORE_MEGA_IO_PIN_DESC(0x06U, 0x08U, 0x07U, 3), // 34 -> PORTC3
145 LSH_CORE_MEGA_IO_PIN_DESC(0x06U, 0x08U, 0x07U, 2), // 35 -> PORTC2
146 LSH_CORE_MEGA_IO_PIN_DESC(0x06U, 0x08U, 0x07U, 1), // 36 -> PORTC1
147 LSH_CORE_MEGA_IO_PIN_DESC(0x06U, 0x08U, 0x07U, 0), // 37 -> PORTC0
148 LSH_CORE_MEGA_IO_PIN_DESC(0x09U, 0x0BU, 0x0AU, 7), // 38 -> PORTD7
149 LSH_CORE_MEGA_IO_PIN_DESC(0x12U, 0x14U, 0x13U, 2), // 39 -> PORTG2
150 LSH_CORE_MEGA_IO_PIN_DESC(0x12U, 0x14U, 0x13U, 1), // 40 -> PORTG1
151 LSH_CORE_MEGA_IO_PIN_DESC(0x12U, 0x14U, 0x13U, 0), // 41 -> PORTG0
152 LSH_CORE_MEGA_MEM_PIN_DESC(0x109U, 0x10BU, 0x10AU, 7), // 42 -> PORTL7
153 LSH_CORE_MEGA_MEM_PIN_DESC(0x109U, 0x10BU, 0x10AU, 6), // 43 -> PORTL6
154 LSH_CORE_MEGA_MEM_PIN_DESC(0x109U, 0x10BU, 0x10AU, 5), // 44 -> PORTL5
155 LSH_CORE_MEGA_MEM_PIN_DESC(0x109U, 0x10BU, 0x10AU, 4), // 45 -> PORTL4
156 LSH_CORE_MEGA_MEM_PIN_DESC(0x109U, 0x10BU, 0x10AU, 3), // 46 -> PORTL3
157 LSH_CORE_MEGA_MEM_PIN_DESC(0x109U, 0x10BU, 0x10AU, 2), // 47 -> PORTL2
158 LSH_CORE_MEGA_MEM_PIN_DESC(0x109U, 0x10BU, 0x10AU, 1), // 48 -> PORTL1
159 LSH_CORE_MEGA_MEM_PIN_DESC(0x109U, 0x10BU, 0x10AU, 0), // 49 -> PORTL0
160 LSH_CORE_MEGA_IO_PIN_DESC(0x03U, 0x05U, 0x04U, 3), // 50 -> PORTB3
161 LSH_CORE_MEGA_IO_PIN_DESC(0x03U, 0x05U, 0x04U, 2), // 51 -> PORTB2
162 LSH_CORE_MEGA_IO_PIN_DESC(0x03U, 0x05U, 0x04U, 1), // 52 -> PORTB1
163 LSH_CORE_MEGA_IO_PIN_DESC(0x03U, 0x05U, 0x04U, 0), // 53 -> PORTB0
164 LSH_CORE_MEGA_IO_PIN_DESC(0x0FU, 0x11U, 0x10U, 0), // 54 -> PORTF0
165 LSH_CORE_MEGA_IO_PIN_DESC(0x0FU, 0x11U, 0x10U, 1), // 55 -> PORTF1
166 LSH_CORE_MEGA_IO_PIN_DESC(0x0FU, 0x11U, 0x10U, 2), // 56 -> PORTF2
167 LSH_CORE_MEGA_IO_PIN_DESC(0x0FU, 0x11U, 0x10U, 3), // 57 -> PORTF3
168 LSH_CORE_MEGA_IO_PIN_DESC(0x0FU, 0x11U, 0x10U, 4), // 58 -> PORTF4
169 LSH_CORE_MEGA_IO_PIN_DESC(0x0FU, 0x11U, 0x10U, 5), // 59 -> PORTF5
170 LSH_CORE_MEGA_IO_PIN_DESC(0x0FU, 0x11U, 0x10U, 6), // 60 -> PORTF6
171 LSH_CORE_MEGA_IO_PIN_DESC(0x0FU, 0x11U, 0x10U, 7), // 61 -> PORTF7
172 LSH_CORE_MEGA_MEM_PIN_DESC(0x106U, 0x108U, 0x107U, 0), // 62 -> PORTK0
173 LSH_CORE_MEGA_MEM_PIN_DESC(0x106U, 0x108U, 0x107U, 1), // 63 -> PORTK1
174 LSH_CORE_MEGA_MEM_PIN_DESC(0x106U, 0x108U, 0x107U, 2), // 64 -> PORTK2
175 LSH_CORE_MEGA_MEM_PIN_DESC(0x106U, 0x108U, 0x107U, 3), // 65 -> PORTK3
176 LSH_CORE_MEGA_MEM_PIN_DESC(0x106U, 0x108U, 0x107U, 4), // 66 -> PORTK4
177 LSH_CORE_MEGA_MEM_PIN_DESC(0x106U, 0x108U, 0x107U, 5), // 67 -> PORTK5
178 LSH_CORE_MEGA_MEM_PIN_DESC(0x106U, 0x108U, 0x107U, 6), // 68 -> PORTK6
179 LSH_CORE_MEGA_MEM_PIN_DESC(0x106U, 0x108U, 0x107U, 7), // 69 -> PORTK7
180};
181
182#undef LSH_CORE_MEGA_IO_PIN_DESC
183#undef LSH_CORE_MEGA_MEM_PIN_DESC
184
192[[nodiscard]] constexpr auto megaPinDescriptor(uint8_t pin) noexcept -> StaticPinDescriptor
193{
194 return (pin < (sizeof(kMegaPinDescriptors) / sizeof(kMegaPinDescriptors[0]))) ? kMegaPinDescriptors[pin] : StaticPinDescriptor{};
195}
196
200[[nodiscard]] constexpr auto hasConstexprMegaBinding(uint8_t pin) noexcept -> bool
201{
202 return megaPinDescriptor(pin).mask != 0U;
203}
204#endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
205
209[[nodiscard]] inline auto inputRegisterFromAddress(uint16_t address) noexcept -> volatile const uint8_t *
210{
211 // NOLINTNEXTLINE(performance-no-int-to-ptr): AVR descriptors intentionally store raw MMIO addresses.
212 return reinterpret_cast<volatile const uint8_t *>(address);
213}
214
218[[nodiscard]] inline auto outputRegisterFromAddress(uint16_t address) noexcept -> volatile uint8_t *
219{
220 // NOLINTNEXTLINE(performance-no-int-to-ptr): AVR descriptors intentionally store raw MMIO addresses.
221 return reinterpret_cast<volatile uint8_t *>(address);
222}
223
227[[nodiscard]] inline auto modeRegisterFromAddress(uint16_t address) noexcept -> volatile uint8_t *
228{
229 // NOLINTNEXTLINE(performance-no-int-to-ptr): AVR descriptors intentionally store raw MMIO addresses.
230 return reinterpret_cast<volatile uint8_t *>(address);
231}
232} // namespace detail
233
237[[nodiscard]] inline auto readPinBitMask(uint8_t pin) noexcept -> uint8_t
238{
239 return pgm_read_byte(digital_pin_to_bit_mask_PGM + pin);
240}
241
245[[nodiscard]] inline auto readPinPortIndex(uint8_t pin) noexcept -> uint8_t
246{
247 return pgm_read_byte(digital_pin_to_port_PGM + pin);
248}
249
253[[nodiscard]] inline auto inputRegister(uint8_t port) noexcept -> volatile const uint8_t *
254{
255 // NOLINTNEXTLINE(performance-no-int-to-ptr): AVR port lookup tables store raw MMIO addresses in PROGMEM.
256 return reinterpret_cast<volatile const uint8_t *>(pgm_read_word(port_to_input_PGM + port));
257}
258
262[[nodiscard]] inline auto outputRegister(uint8_t port) noexcept -> volatile uint8_t *
263{
264 // NOLINTNEXTLINE(performance-no-int-to-ptr): AVR port lookup tables store raw MMIO addresses in PROGMEM.
265 return reinterpret_cast<volatile uint8_t *>(pgm_read_word(port_to_output_PGM + port));
266}
267
271[[nodiscard]] inline auto modeRegister(uint8_t port) noexcept -> volatile uint8_t *
272{
273 // NOLINTNEXTLINE(performance-no-int-to-ptr): AVR port lookup tables store raw MMIO addresses in PROGMEM.
274 return reinterpret_cast<volatile uint8_t *>(pgm_read_word(port_to_mode_PGM + port));
275}
276
280[[nodiscard]] inline auto inputRegisterForPin(uint8_t pin) noexcept -> volatile const uint8_t *
281{
282 return inputRegister(readPinPortIndex(pin));
283}
284
288[[nodiscard]] inline auto outputRegisterForPin(uint8_t pin) noexcept -> volatile uint8_t *
289{
290 return outputRegister(readPinPortIndex(pin));
291}
292
296[[nodiscard]] inline auto modeRegisterForPin(uint8_t pin) noexcept -> volatile uint8_t *
297{
298 return modeRegister(readPinPortIndex(pin));
299}
300
304[[nodiscard]] inline auto makeFastInputPinBinding(uint8_t pin) noexcept -> FastInputPinBinding
305{
307}
308
312[[nodiscard]] inline auto makeFastOutputPinBinding(uint8_t pin) noexcept -> FastOutputPinBinding
313{
315}
316
324template <uint8_t Pin> [[nodiscard]] inline auto readPinBitMask(::lsh::core::PinTag<Pin>) noexcept -> uint8_t
325{
326#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
327 if constexpr (detail::hasConstexprMegaBinding(Pin))
328 {
329 constexpr StaticPinDescriptor descriptor = detail::megaPinDescriptor(Pin);
330 return descriptor.mask;
331 }
332#endif
333 return readPinBitMask(static_cast<uint8_t>(Pin));
334}
335
339template <uint8_t Pin> [[nodiscard]] inline auto inputRegisterForPin(::lsh::core::PinTag<Pin>) noexcept -> volatile const uint8_t *
340{
341#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
342 if constexpr (detail::hasConstexprMegaBinding(Pin))
343 {
344 constexpr StaticPinDescriptor descriptor = detail::megaPinDescriptor(Pin);
345 return detail::inputRegisterFromAddress(descriptor.inputAddress);
346 }
347#endif
348 return inputRegisterForPin(static_cast<uint8_t>(Pin));
349}
350
354template <uint8_t Pin> [[nodiscard]] inline auto outputRegisterForPin(::lsh::core::PinTag<Pin>) noexcept -> volatile uint8_t *
355{
356#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
357 if constexpr (detail::hasConstexprMegaBinding(Pin))
358 {
359 constexpr StaticPinDescriptor descriptor = detail::megaPinDescriptor(Pin);
360 return detail::outputRegisterFromAddress(descriptor.outputAddress);
361 }
362#endif
363 return outputRegisterForPin(static_cast<uint8_t>(Pin));
364}
365
369template <uint8_t Pin> [[nodiscard]] inline auto modeRegisterForPin(::lsh::core::PinTag<Pin>) noexcept -> volatile uint8_t *
370{
371#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
372 if constexpr (detail::hasConstexprMegaBinding(Pin))
373 {
374 constexpr StaticPinDescriptor descriptor = detail::megaPinDescriptor(Pin);
375 return detail::modeRegisterFromAddress(descriptor.modeAddress);
376 }
377#endif
378 return modeRegisterForPin(static_cast<uint8_t>(Pin));
379}
380
384template <uint8_t Pin> [[nodiscard]] inline auto makeFastInputPinBinding(::lsh::core::PinTag<Pin>) noexcept -> FastInputPinBinding
385{
386 // Materialize the constexpr descriptor into the same compact binding used
387 // by the runtime path so peripherals keep one direct-register hot path.
390}
391
395template <uint8_t Pin> [[nodiscard]] inline auto makeFastOutputPinBinding(::lsh::core::PinTag<Pin>) noexcept -> FastOutputPinBinding
396{
397 // The compile-time path resolves addresses here, but the peripheral still
398 // stores only the minimal mask/register pair needed by the hot write path.
401}
402} // namespace avr
403} // namespace core
404} // namespace lsh
405
406#endif // LSH_CORE_INTERNAL_AVR_FAST_IO_HPP
auto inputRegister(uint8_t port) noexcept -> volatile const uint8_t *
Converts one Arduino core port index to the AVR input register.
Definition avr_fast_io.hpp:253
auto readPinBitMask(uint8_t pin) noexcept -> uint8_t
Reads the fast-I/O bit mask for one runtime Arduino pin.
Definition avr_fast_io.hpp:237
auto inputRegisterFromAddress(uint16_t address) noexcept -> volatile const uint8_t *
Rebuilds a read-only AVR register pointer from a raw MMIO address.
Definition avr_fast_io.hpp:209
auto makeFastOutputPinBinding(uint8_t pin) noexcept -> FastOutputPinBinding
Builds the cached fast-output binding for one runtime pin.
Definition avr_fast_io.hpp:312
auto modeRegisterForPin(uint8_t pin) noexcept -> volatile uint8_t *
Resolves the AVR DDR register for one runtime Arduino pin.
Definition avr_fast_io.hpp:296
auto modeRegister(uint8_t port) noexcept -> volatile uint8_t *
Converts one Arduino core port index to the AVR DDR register.
Definition avr_fast_io.hpp:271
auto inputRegisterForPin(uint8_t pin) noexcept -> volatile const uint8_t *
Resolves the AVR input register for one runtime Arduino pin.
Definition avr_fast_io.hpp:280
auto outputRegisterForPin(uint8_t pin) noexcept -> volatile uint8_t *
Resolves the AVR output register for one runtime Arduino pin.
Definition avr_fast_io.hpp:288
auto makeFastInputPinBinding(uint8_t pin) noexcept -> FastInputPinBinding
Builds the cached fast-input binding for one runtime pin.
Definition avr_fast_io.hpp:304
auto outputRegisterFromAddress(uint16_t address) noexcept -> volatile uint8_t *
Rebuilds a writable AVR register pointer from a raw MMIO address.
Definition avr_fast_io.hpp:218
auto modeRegisterFromAddress(uint16_t address) noexcept -> volatile uint8_t *
Rebuilds a writable AVR DDR register pointer from a raw MMIO address.
Definition avr_fast_io.hpp:227
auto readPinPortIndex(uint8_t pin) noexcept -> uint8_t
Reads the Arduino core port index for one runtime pin.
Definition avr_fast_io.hpp:245
auto outputRegister(uint8_t port) noexcept -> volatile uint8_t *
Converts one Arduino core port index to the AVR output register.
Definition avr_fast_io.hpp:262
Compile-time pin tag used to route peripheral construction through constant pin paths.
Type-level wrapper around one Arduino pin number.
Definition pin_tag.hpp:41
Resolved fast-input binding for one Arduino pin.
Definition avr_fast_io.hpp:48
uint8_t mask
Final bit mask for the pin inside the AVR port.
Definition avr_fast_io.hpp:49
volatile uint8_t * outputPort
Final AVR output register used to disable the input pull-up.
Definition avr_fast_io.hpp:51
volatile const uint8_t * pinPort
Final AVR input register used to sample the pin state.
Definition avr_fast_io.hpp:50
volatile uint8_t * modePort
Final AVR DDR register used to force INPUT mode.
Definition avr_fast_io.hpp:52
Resolved fast-output binding for one Arduino pin.
Definition avr_fast_io.hpp:62
volatile uint8_t * modePort
Final AVR DDR register used to configure the pin direction.
Definition avr_fast_io.hpp:65
volatile uint8_t * pinPort
Final AVR output register used to drive the pin.
Definition avr_fast_io.hpp:64
uint8_t mask
Final bit mask for the pin inside the AVR port.
Definition avr_fast_io.hpp:63
Compile-time descriptor for one fully resolved AVR pin binding.
Definition avr_fast_io.hpp:76
uint8_t mask
Final bit mask for the pin inside the port.
Definition avr_fast_io.hpp:77
uint16_t inputAddress
Raw MMIO address of the input register.
Definition avr_fast_io.hpp:78
uint16_t modeAddress
Raw MMIO address of the DDR register.
Definition avr_fast_io.hpp:80
uint16_t outputAddress
Raw MMIO address of the output register.
Definition avr_fast_io.hpp:79