diff --git a/io.hpp b/io.hpp index b9c29f2..8bbe3db 100644 --- a/io.hpp +++ b/io.hpp @@ -3,6 +3,7 @@ #include #include +#include ////////////////////////////////////////////////////////////////////////// // Preprocessor defines @@ -125,46 +126,60 @@ enum class Bus { namespace detail { +/* +The following works in avr-gcc 5.4.0, but is not legal C++, because ptr's are not legal constexpr's + constexpr auto *foo = ptr; + +Workaround is to store the the address of the ptr in a uintptr_t and reinterpret_cast it at call site +For this to work we need to temporarily disable the _SFR_IO8 macro so that the register macro just gives the address +*/ + +#undef _SFR_IO8 +#define _SFR_IO8 + #ifdef PORT_A_AVAILABLE -static constexpr volatile uint8_t *PORT_A_DIR_REG = &DDRA; -static constexpr volatile uint8_t *PORT_A_OUTPUT_REG = &PORTA; -static constexpr volatile uint8_t *PORT_A_INPUT_REG = &PINA; +static constexpr uintptr_t PORT_A_DIR_REG_ADDR = DDRA + __SFR_OFFSET; +static constexpr uintptr_t PORT_A_OUTPUT_REG_ADDR = PORTA + __SFR_OFFSET; +static constexpr uintptr_t PORT_A_INPUT_REG_ADDR = PINA + __SFR_OFFSET; #else -static constexpr volatile uint8_t *PORT_A_DIR_REG = nullptr; -static constexpr volatile uint8_t *PORT_A_OUTPUT_REG = nullptr; -static constexpr volatile uint8_t *PORT_A_INPUT_REG = nullptr; +static constexpr uintptr_t PORT_A_DIR_REG_ADDR = nullptr; +static constexpr uintptr_t PORT_A_OUTPUT_REG_ADDR = nullptr; +static constexpr uintptr_t PORT_A_INPUT_REG_ADDR = nullptr; #endif #ifdef PORT_B_AVAILABLE -static constexpr volatile uint8_t *PORT_B_DIR_REG = &DDRB; -static constexpr volatile uint8_t *PORT_B_OUTPUT_REG = &PORTB; -static constexpr volatile uint8_t *PORT_B_INPUT_REG = &PINB; +static constexpr uintptr_t PORT_B_DIR_REG_ADDR = DDRB + __SFR_OFFSET; +static constexpr uintptr_t PORT_B_OUTPUT_REG_ADDR = PORTB + __SFR_OFFSET; +static constexpr uintptr_t PORT_B_INPUT_REG_ADDR = PINB + __SFR_OFFSET; #else -static constexpr volatile uint8_t *PORT_B_DIR_REG = nullptr; -static constexpr volatile uint8_t *PORT_B_OUTPUT_REG = nullptr; -static constexpr volatile uint8_t *PORT_B_INPUT_REG = nullptr; +static constexpr uintptr_t PORT_B_DIR_REG_ADDR = nullptr; +static constexpr uintptr_t PORT_B_OUTPUT_REG_ADDR = nullptr; +static constexpr uintptr_t PORT_B_INPUT_REG_ADDR = nullptr; #endif #ifdef PORT_C_AVAILABLE -static constexpr volatile uint8_t *PORT_C_DIR_REG = &DDRC; -static constexpr volatile uint8_t *PORT_C_OUTPUT_REG = &PORTC; -static constexpr volatile uint8_t *PORT_C_INPUT_REG = &PINC; +static constexpr uintptr_t PORT_C_DIR_REG_ADDR = DDRC + __SFR_OFFSET; +static constexpr uintptr_t PORT_C_OUTPUT_REG_ADDR = PORTC + __SFR_OFFSET; +static constexpr uintptr_t PORT_C_INPUT_REG_ADDR = PINC + __SFR_OFFSET; #else -static constexpr volatile uint8_t *PORT_C_DIR_REG = nullptr; -static constexpr volatile uint8_t *PORT_C_OUTPUT_REG = nullptr; -static constexpr volatile uint8_t *PORT_C_INPUT_REG = nullptr; +static constexpr uintptr_t PORT_C_DIR_REG_ADDR = nullptr; +static constexpr uintptr_t PORT_C_OUTPUT_REG_ADDR = nullptr; +static constexpr uintptr_t PORT_C_INPUT_REG_ADDR = nullptr; #endif #ifdef PORT_D_AVAILABLE -static constexpr volatile uint8_t *PORT_D_DIR_REG = &DDRD; -static constexpr volatile uint8_t *PORT_D_OUTPUT_REG = &PORTD; -static constexpr volatile uint8_t *PORT_D_INPUT_REG = &PIND; +static constexpr uintptr_t PORT_D_DIR_REG_ADDR = DDRD + __SFR_OFFSET; +static constexpr uintptr_t PORT_D_OUTPUT_REG_ADDR = PORTD + __SFR_OFFSET; +static constexpr uintptr_t PORT_D_INPUT_REG_ADDR = PIND + __SFR_OFFSET; #else -static constexpr volatile uint8_t *PORT_D_DIR_REG = nullptr; -static constexpr volatile uint8_t *PORT_D_OUTPUT_REG = nullptr; -static constexpr volatile uint8_t *PORT_D_INPUT_REG = nullptr; +static constexpr uintptr_t PORT_D_DIR_REG_ADDR = nullptr; +static constexpr uintptr_t PORT_D_OUTPUT_REG_ADDR = nullptr; +static constexpr uintptr_t PORT_D_INPUT_REG_ADDR = nullptr; #endif +#undef _SFR_IO8 +#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET) + static constexpr auto getBus(const P pin) { // Upper 4 bits of pin encode which port this pin is on @@ -183,13 +198,13 @@ static constexpr auto getDDR(const Bus bus) { switch (static_cast(bus)) { case 0: // Bus::A - return PORT_A_DIR_REG; + return PORT_A_DIR_REG_ADDR; case 1: // Bus::B - return PORT_B_DIR_REG; + return PORT_B_DIR_REG_ADDR; case 2: // Bus::C - return PORT_C_DIR_REG; + return PORT_C_DIR_REG_ADDR; case 3: // Bus::D - return PORT_D_DIR_REG; + return PORT_D_DIR_REG_ADDR; } } @@ -197,13 +212,13 @@ static constexpr auto getPORT(const Bus bus) { switch (static_cast(bus)) { case 0: // Bus::A - return PORT_A_OUTPUT_REG; + return PORT_A_OUTPUT_REG_ADDR; case 1: // Bus::B - return PORT_B_OUTPUT_REG; + return PORT_B_OUTPUT_REG_ADDR; case 2: // Bus::C - return PORT_C_OUTPUT_REG; + return PORT_C_OUTPUT_REG_ADDR; case 3: // Bus::D - return PORT_D_OUTPUT_REG; + return PORT_D_OUTPUT_REG_ADDR; } } @@ -211,16 +226,22 @@ static constexpr auto getPIN(const Bus bus) { switch (static_cast(bus)) { case 0: // Bus::A - return PORT_A_INPUT_REG; + return PORT_A_INPUT_REG_ADDR; case 1: // Bus::B - return PORT_B_INPUT_REG; + return PORT_B_INPUT_REG_ADDR; case 2: // Bus::C - return PORT_C_INPUT_REG; + return PORT_C_INPUT_REG_ADDR; case 3: // Bus::D - return PORT_D_INPUT_REG; + return PORT_D_INPUT_REG_ADDR; } } +template +static inline volatile uint8_t *getRegPtr() +{ + return reinterpret_cast(Address); +} + } // namespace detail ////////////////////////////////////////////////////////////////////////// @@ -245,9 +266,9 @@ class Pin { constexpr auto pinBit = detail::getPinBit(pin); if (dir == Dir::IN) - *dirReg &= ~(1 << pinBit); + *detail::getRegPtr() &= ~(1 << pinBit); else if (dir == Dir::OUT) - *dirReg |= (1 << pinBit); + *detail::getRegPtr() |= (1 << pinBit); } static inline void pullup(const bool enable) FORCE_INLINE @@ -257,9 +278,9 @@ class Pin { constexpr auto pinBit = detail::getPinBit(pin); if (enable) - *portReg |= (1 << pinBit); + *detail::getRegPtr() |= (1 << pinBit); else - *portReg &= ~(1 << pinBit); + *detail::getRegPtr() &= ~(1 << pinBit); } static inline void write(const bool value) FORCE_INLINE @@ -269,9 +290,9 @@ class Pin { constexpr auto pinBit = detail::getPinBit(pin); if (value) - *portReg |= (1 << pinBit); + *detail::getRegPtr() |= (1 << pinBit); else - *portReg &= ~(1 << pinBit); + *detail::getRegPtr() &= ~(1 << pinBit); } static inline void toggle() FORCE_INLINE @@ -281,13 +302,13 @@ class Pin { constexpr auto pinReg = detail::getPIN(bus); constexpr auto pinBit = detail::getPinBit(pin); - *pinReg |= (1 << pinBit); + *detail::getRegPtr() |= (1 << pinBit); #else constexpr auto bus = detail::getBus(pin); constexpr auto portReg = detail::getPORT(bus); constexpr auto pinBit = detail::getPinBit(pin); - *portReg ^= (1 << pinBit); + *detail::getRegPtr() ^= (1 << pinBit); #endif } @@ -297,7 +318,7 @@ class Pin { constexpr auto pinReg = detail::getPIN(bus); constexpr auto pinBit = detail::getPinBit(pin); - if (*pinReg >> pinBit & 1) + if (*detail::getRegPtr() >> pinBit & 1) return true; return false; @@ -335,9 +356,9 @@ class Port { constexpr auto dirReg = detail::getDDR(port); if (dir == Dir::IN) - *dirReg = 0x00; + *detail::getRegPtr() = 0x00; else if (dir == Dir::OUT) - *dirReg = 0xFF; + *detail::getRegPtr() = 0xFF; } static inline void pullup(const bool enable) FORCE_INLINE @@ -345,16 +366,16 @@ class Port { constexpr auto portReg = detail::getPORT(port); if (enable) - *portReg = 0xFF; + *detail::getRegPtr() = 0xFF; else - *portReg = 0x00; + *detail::getRegPtr() = 0x00; } static inline void write(const uint8_t value) FORCE_INLINE { constexpr auto portReg = detail::getPORT(port); - *portReg = value; + *detail::getRegPtr() = value; } static inline void invert() FORCE_INLINE @@ -362,11 +383,11 @@ class Port { #ifdef HARDWARE_TOGGLE constexpr auto pinReg = detail::getPIN(port); - *pinReg = 0xFF; + *detail::getRegPtr() = 0xFF; #else constexpr auto portReg = detail::getPORT(port); - *portReg = ~(*portReg); + *detail::getRegPtr() = ~(*portReg); #endif } @@ -374,7 +395,7 @@ class Port { { constexpr auto pinReg = detail::getPIN(port); - return *pinReg; + return *detail::getRegPtr(); } inline Port &operator=(const uint8_t value) FORCE_INLINE