diff --git a/hardware0.hpp b/hardware0.hpp index 4bc9204..9014a41 100644 --- a/hardware0.hpp +++ b/hardware0.hpp @@ -32,7 +32,7 @@ struct Registers0 { static constexpr volatile auto *BAUD_REG_H = &UBRR0H; }; -enum ControlFlagsA { +enum class ControlFlagsA0 { MULTI_PROC_COMM_MODE = MPCM0, SPEED_2X = U2X0, PARITY_ERROR = UPE0, @@ -41,9 +41,10 @@ enum ControlFlagsA { DATA_REG_EMPTY = UDRE0, TRANSMIT_COMPLETE = TXC0, RECEIVE_COMPLETE = RXC0, + }; -enum ControlFlagsB { +enum class ControlFlagsB0 { TX_DATA_BIT_8 = TXB80, RX_DATA_BIT_8 = RXB80, CHAR_SIZE_2 = UCSZ02, @@ -54,7 +55,7 @@ enum ControlFlagsB { RX_INT_ENABLE = RXCIE0, }; -enum ControlFlagsC { +enum class ControlFlagsC0 { CLK_POLARITY = UCPOL0, CHAR_SIZE_0 = UCSZ00, CHAR_SIZE_1 = UCSZ01, @@ -65,37 +66,32 @@ enum ControlFlagsC { MODE_SEL_1 = UMSEL01, }; -static constexpr auto getLastRxError() {} -static constexpr void set2xSpeed() {} - -template -static inline void setBaudRate() +constexpr int operator<<(const int &lhs, const ControlFlagsA0 &rhs) { - *Registers0::BAUD_REG_H = static_cast(BaudVal >> 8); - *Registers0::BAUD_REG_L = static_cast(BaudVal); + return lhs << static_cast(rhs); } - -template -static inline void setCtrlStatRegC() +constexpr int operator<<(const int &lhs, const ControlFlagsB0 &rhs) { - *Registers0::CTRL_STAT_REG_C = RegVal; + return lhs << static_cast(rhs); +} +constexpr int operator<<(const int &lhs, const ControlFlagsC0 &rhs) +{ + return lhs << static_cast(rhs); } #else #error "This chip is not supported" #endif -} // namespace detail - -template , Driven driven = Driven::INTERRUPT> -class Hardware0 { +template +class Hardware { public: - using data_t = typename cfg::data_t; - static constexpr auto DATA_BITS = cfg::DATA_BITS; - static void init() { - detail::setBaudRate(); + constexpr auto baudVal = calcBaud(); + + *Registers::BAUD_REG_H = static_cast(baudVal >> 8); + *Registers::BAUD_REG_L = static_cast(baudVal); constexpr auto dataBitsVal = calcDataBits(); constexpr auto parityVal = calcParity(); @@ -107,59 +103,51 @@ class Hardware0 { constexpr uint8_t controlRegB = dataBitsVal.regBVal | enableRx | enableTx; constexpr uint8_t controlRegC = dataBitsVal.regCVal | parityVal | stopBitsVal | modeVal; - *detail::Registers0::CTRL_STAT_REG_B = controlRegB; - detail::setCtrlStatRegC(); + *Registers::CTRL_STAT_REG_B = controlRegB; + *Registers::CTRL_STAT_REG_C = controlRegC; } - static void txByte(data_t byte) FORCE_INLINE + static void txByte(typename cfg::data_t byte) { - while (!(*detail::Registers0::CTRL_STAT_REG_A & (1 << UDRE0))) + while (!(*Registers::CTRL_STAT_REG_A & (1 << CtrlFlagsA::DATA_REG_EMPTY))) ; - *detail::Registers0::IO_REG = byte; + *Registers::IO_REG = byte; } - static data_t rxByte() {} - - static data_t peek() {} - private: - static constexpr auto BAUD_RATE = cfg::BAUD_RATE; - static constexpr auto PARITY = cfg::PARITY; - static constexpr auto STOP_BITS = cfg::STOP_BITS; - - static constexpr auto calcBaud() - { - // The actual formula is (F_CPU / (16 * baudRate)) - 1, but this one has the advantage of rounding correctly - constexpr auto baudVal = (F_CPU + 8 * BAUD_RATE) / (16 * BAUD_RATE) - 1; - return baudVal; - } - struct DataBitsVal { uint8_t regCVal = 0; uint8_t regBVal = 0; }; + static constexpr auto calcBaud() + { + // The actual formula is (F_CPU / (16 * baudRate)) - 1, but this one has the advantage of rounding correctly + constexpr auto baudVal = (F_CPU + 8 * cfg::BAUD_RATE) / (16 * cfg::BAUD_RATE) - 1; + return baudVal; + } + static constexpr auto calcDataBits() { DataBitsVal dataBitsVal; - switch (DATA_BITS) { + switch (cfg::DATA_BITS) { case DataBits::FIVE: dataBitsVal.regCVal = 0; break; case DataBits::SIX: - dataBitsVal.regCVal = (1 << detail::CHAR_SIZE_0); + dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_0); break; case DataBits::SEVEN: - dataBitsVal.regCVal = (1 << detail::CHAR_SIZE_1); + dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_1); break; case DataBits::EIGHT: - dataBitsVal.regCVal = (1 << detail::CHAR_SIZE_1) | (1 << detail::CHAR_SIZE_0); + dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_1) | (1 << CtrlFlagsC::CHAR_SIZE_0); break; case DataBits::NINE: - dataBitsVal.regCVal = (1 << detail::CHAR_SIZE_1) | (1 << detail::CHAR_SIZE_0); - dataBitsVal.regBVal = (1 << detail::CHAR_SIZE_2); + dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_1) | (1 << CtrlFlagsC::CHAR_SIZE_0); + dataBitsVal.regBVal = (1 << CtrlFlagsB::CHAR_SIZE_2); break; } @@ -170,10 +158,10 @@ class Hardware0 { { uint8_t parityVal = 0; - if (PARITY == Parity::EVEN) - parityVal = (1 << detail::PARITY_MODE_1); - else if (PARITY == Parity::ODD) - parityVal = (1 << detail::PARITY_MODE_1) | (1 << detail::PARITY_MODE_0); + if (cfg::PARITY == Parity::EVEN) + parityVal = (1 << CtrlFlagsC::PARITY_MODE_1); + else if (cfg::PARITY == Parity::ODD) + parityVal = (1 << CtrlFlagsC::PARITY_MODE_1) | (1 << CtrlFlagsC::PARITY_MODE_0); return parityVal; } @@ -182,8 +170,8 @@ class Hardware0 { { uint8_t stopBitsVal = 0; - if (STOP_BITS == StopBits::TWO) - stopBitsVal = (1 << detail::STOP_BIT_SEL); + if (cfg::STOP_BITS == StopBits::TWO) + stopBitsVal = (1 << CtrlFlagsC::STOP_BIT_SEL); return stopBitsVal; } @@ -195,7 +183,7 @@ class Hardware0 { uint8_t modeVal = 0; if (mode == Mode::SYNCHRONOUS_MASTER || mode == Mode::SYNCHRONOUS_SLAVE) { - modeVal = (1 << detail::MODE_SEL_0); + modeVal = (1 << CtrlFlagsC::MODE_SEL_0); } return modeVal; @@ -207,7 +195,7 @@ class Hardware0 { uint8_t enableVal = 0; if (enable) - enableVal = (1 << detail::RX_ENABLE); + enableVal = (1 << CtrlFlagsB::RX_ENABLE); return enableVal; } @@ -218,12 +206,39 @@ class Hardware0 { uint8_t enableVal = 0; if (enable) - enableVal = (1 << detail::TX_ENABLE); + enableVal = (1 << CtrlFlagsB::TX_ENABLE); return enableVal; } }; +} // namespace detail + +template , Driven driven = Driven::INTERRUPT> +class Hardware0 { + public: + using data_t = typename cfg::data_t; + static constexpr auto DATA_BITS = cfg::DATA_BITS; + + static void init() + { + HardwareImpl::init(); + } + + static void txByte(data_t byte) FORCE_INLINE + { + HardwareImpl::txByte(byte); + } + + static data_t rxByte() {} + + static data_t peek() {} + + private: + using HardwareImpl = detail::Hardware; +}; + } // namespace uart #undef FORCE_INLINE diff --git a/hardware1.hpp b/hardware1.hpp index 6f70f09..88e0f17 100644 --- a/hardware1.hpp +++ b/hardware1.hpp @@ -1 +1,107 @@ #pragma once + +#include "hardware0.hpp" + +#define FORCE_INLINE __attribute__((always_inline)) + +namespace uart { + +namespace detail { + +#if defined(__AVR_ATmega1284P__) + +struct Registers1 { + static constexpr volatile auto *IO_REG = &UDR1; + static constexpr volatile auto *CTRL_STAT_REG_A = &UCSR1A; + static constexpr volatile auto *CTRL_STAT_REG_B = &UCSR1B; + static constexpr volatile auto *CTRL_STAT_REG_C = &UCSR1C; + static constexpr volatile auto *BAUD_REG_L = &UBRR1L; + static constexpr volatile auto *BAUD_REG_H = &UBRR1H; +}; + +enum class ControlFlagsA1 { + MULTI_PROC_COMM_MODE = MPCM1, + SPEED_2X = U2X1, + PARITY_ERROR = UPE1, + DATA_OVER_RUN = DOR1, + FRAME_ERROR = FE1, + DATA_REG_EMPTY = UDRE1, + TRANSMIT_COMPLETE = TXC1, + RECEIVE_COMPLETE = RXC1, +}; + +enum class ControlFlagsB1 { + TX_DATA_BIT_8 = TXB81, + RX_DATA_BIT_8 = RXB81, + CHAR_SIZE_2 = UCSZ12, + TX_ENABLE = TXEN1, + RX_ENABLE = RXEN1, + DATA_REG_EMPTY_INT_ENABLE = UDRIE1, + TX_INT_ENABLE = TXCIE1, + RX_INT_ENABLE = RXCIE1, +}; + +enum class ControlFlagsC1 { + CLK_POLARITY = UCPOL1, + CHAR_SIZE_0 = UCSZ10, + CHAR_SIZE_1 = UCSZ11, + STOP_BIT_SEL = USBS1, + PARITY_MODE_0 = UPM10, + PARITY_MODE_1 = UPM11, + MODE_SEL_0 = UMSEL10, + MODE_SEL_1 = UMSEL11, +}; + +constexpr int operator<<(const int &lhs, const ControlFlagsA1 &rhs) +{ + return lhs << static_cast(rhs); +} +constexpr int operator<<(const int &lhs, const ControlFlagsB1 &rhs) +{ + return lhs << static_cast(rhs); +} +constexpr int operator<<(const int &lhs, const ControlFlagsC1 &rhs) +{ + return lhs << static_cast(rhs); +} + +#define HAS_UART1 + +#else +#error "This chip is not supported" +#endif + +} // namespace detail + +#ifdef HAS_UART1 + +template , Driven driven = Driven::INTERRUPT> +class Hardware1 { + public: + using data_t = typename cfg::data_t; + static constexpr auto DATA_BITS = cfg::DATA_BITS; + + static void init() + { + HardwareImpl::init(); + } + + static void txByte(data_t byte) FORCE_INLINE + { + HardwareImpl::txByte(byte); + } + + static data_t rxByte() {} + + static data_t peek() {} + + private: + using HardwareImpl = detail::Hardware; +}; + +#endif + +} // namespace uart + +#undef FORCE_INLINE diff --git a/uart.hpp b/uart.hpp index d4ec466..3883855 100644 --- a/uart.hpp +++ b/uart.hpp @@ -270,6 +270,12 @@ class Uart { template > using Uart0 = Uart>; +#ifdef HAS_UART1 +template > +using Uart1 = Uart>; +#endif + } // namespace uart #undef FORCE_INLINE +#undef HAS_UART1