#pragma once namespace PortmegaAVR0 { #if defined(ARDUINO_AVR_NANO_EVERY) && defined(__AVR_ATmega4809__) #include "include/NanoEveryRegister.h" #include #else #error "This library only tested with Arduino Nano Every Board (ATmega4809)." #endif #define INLINE inline __attribute__((always_inline)) using Register8 = volatile uint8_t *; // ------------------ VPORTs ----------------------------------------------------------------------------------------------- // // Direction constexpr Register8 regVPORTdir(const uint8_t pin) { using namespace Pins::Addr; return (Register8) (baseAddr[pin].vport + addrOffset.vDir); } // Output Level constexpr Register8 regVPORTout(const uint8_t pin) { using namespace Pins::Addr; return (Register8) (baseAddr[pin].vport + addrOffset.vOut); } // Input Level Status constexpr Register8 regVPORTin(const uint8_t pin) { using namespace Pins::Addr; return (Register8) (baseAddr[pin].vport + addrOffset.vIn); } // Interrupt Flag constexpr Register8 regVPORTflag(const uint8_t pin) { using namespace Pins::Addr; return (Register8) (baseAddr[pin].vport + addrOffset.vFlag); } // ------------------ NORMAL PORTs ----------------------------------------------------------------------------------------- // // Pin Mode is Input constexpr Register8 regPORTdirClear(const uint8_t pin) { using namespace Pins::Addr; return (Register8) (baseAddr[pin].port + addrOffset.dirClear); } // Input Level Status constexpr Register8 regPORTin(const uint8_t pin) { using namespace Pins::Addr; return (Register8) (baseAddr[pin].port + addrOffset.in); } // Pin Mode is Output constexpr Register8 regPORTdirSet(const uint8_t pin) { using namespace Pins::Addr; return (Register8) (baseAddr[pin].port + addrOffset.dirSet); } // Pin Level High constexpr Register8 regPORToutSet(const uint8_t pin) { using namespace Pins::Addr; return (Register8) (baseAddr[pin].port + addrOffset.outSet); } // Pin Level Low constexpr Register8 regPORToutClear(const uint8_t pin) { using namespace Pins::Addr; return (Register8) (baseAddr[pin].port + addrOffset.outClear); } // Pin Level Toggle constexpr Register8 regPORToutToggle(const uint8_t pin) { using namespace Pins::Addr; return (Register8) (baseAddr[pin].port + addrOffset.outToggle); } // Interrupt Flag constexpr Register8 regPORTflag(const uint8_t pin) { using namespace Pins::Addr; return (Register8) (baseAddr[pin].port + addrOffset.flag); } // ------------------ SPECIALs ------------------ // // SlewRate constexpr Register8 regPortCtrl(const uint8_t pin) { using namespace Pins::Addr; return (Register8) (baseAddr[pin].port + addrOffset.portCtrl); } // Invert, Input-Level, Pullup, Interrupt constexpr Register8 regPinCtrl(const uint8_t pin) { using namespace Pins::Addr; return (Register8) (baseAddr[pin].port + baseAddr[pin].pinCtrl); } // Pin Bitmaske constexpr uint8_t getMask(const uint8_t pin) { using namespace Pins::Addr; return (baseAddr[pin].mask); } } /* struct Interface { virtual void init() = 0; virtual void setOn() = 0; virtual void setOff() = 0; virtual void toggle() = 0; virtual void enableSlewRate() = 0; virtual void disableSlewRate() = 0; virtual void enableInvertIO() = 0; virtual void disableInvertIO() = 0; virtual void INLINE enablePullup() = 0; virtual void INLINE disablePullup() = 0; }; */ template class Pin //: public virtual Interface { static_assert(pin < 22, "Pin number too large, valid range 0...21"); constexpr void specialTreatmentI2Cpins (void) { using namespace PortmegaAVR0; if ((pin == 18) || (pin == 19)) { // because of pin double assignment TWI0.MCTRLA = 0; // I2C Master Mode disable TWI0.SCTRLA = 0; // I2C Slave Mode disable } if (pin == 18) { // PA2 switch to Input, prevents that the PF2 and PA2 are outputs at the same time // PF2 is the standard I/O Pin, PA2 is used for I2C *regPinCtrl(22) = *regPinCtrl(22) & ~PORT_PULLUPEN_bm; *regVPORTdir(22) = *regVPORTdir(22) & ~getMask(22); } if (pin == 19) { // PA3 switch to Input, prevents that the PF3 and PA3 are outputs at the same time // PF3 is the standard I/O Pin, PA3 is used for I2C *regPinCtrl(23) = *regPinCtrl(23) & ~PORT_PULLUPEN_bm; *regVPORTdir(23) = *regVPORTdir(23) & ~getMask(23); } } protected: // Outputs void INLINE initOutput() { using namespace PortmegaAVR0; specialTreatmentI2Cpins(); *regVPORTdir(pin) = *regVPORTdir(pin) | getMask(pin); } void INLINE setOn() { using namespace PortmegaAVR0; *regVPORTout(pin) = *regVPORTout(pin) | getMask(pin); } void INLINE setOff() { using namespace PortmegaAVR0; *regVPORTout(pin) = *regVPORTout(pin) & ~getMask(pin); } void INLINE toggle() { using namespace PortmegaAVR0; *regVPORTin(pin) = getMask(pin); } // Specials // Bit 0 SlewRate, valid for the complete port void INLINE enableSlewRate() { using namespace PortmegaAVR0; *regPortCtrl(pin) = *regPortCtrl(pin) | PORT_SRL_bm; } void INLINE disableSlewRate() { using namespace PortmegaAVR0; *regPortCtrl(pin) = *regPortCtrl(pin) & ~PORT_SRL_bm; } void INLINE enableInvertIO() { using namespace PortmegaAVR0; *regPinCtrl(pin) = *regPinCtrl(pin) | PORT_INVEN_bm; } // Bit 7 Inverted I/O void INLINE disableInvertIO() { using namespace PortmegaAVR0; *regPinCtrl(pin) = *regPinCtrl(pin) & ~PORT_INVEN_bm; } }; template class OutputPin : protected Pin //, public virtual Interface { public: using Pin::setOn; using Pin::setOff; using Pin::toggle; using Pin::enableSlewRate; using Pin::disableSlewRate; using Pin::enableInvertIO; using Pin::disableInvertIO; void INLINE init() { Pin::initOutput(); } void INLINE set(const bool value) { if(value) setOn(); else setOff(); } bool INLINE operator = (const bool value) { set(value); return value; } bool INLINE operator () (const bool value) { set(value); return value; } INLINE operator bool() const { return Pin::isOn(); } };