diff --git a/hardware0.hpp b/hardware0.hpp index 4c7ecb6..8183446 100644 --- a/hardware0.hpp +++ b/hardware0.hpp @@ -2,6 +2,8 @@ #include "config.hpp" +#define FORCE_INLINE __attribute__((always_inline)) + namespace uart { enum class Mode { @@ -17,17 +19,203 @@ enum class Driven { BLOCKING, }; +namespace detail { + +struct Registers0 { +}; + +enum class SupportedHardware { + ATmega1284P, +}; + +template +struct HardwareAbstraction { +}; + +template <> +struct HardwareAbstraction { + struct Reg0 { + static constexpr volatile auto *ioReg = &UDR0; + static constexpr volatile auto *controlStatusRegA = &UCSR0A; + static constexpr volatile auto *controlStatusRegB = &UCSR0B; + static constexpr volatile auto *controlStatusRegC = &UCSR0C; + static constexpr volatile auto *baudRateRegL = &UBRR0L; + static constexpr volatile auto *baudRateRegH = &UBRR0H; + }; + + struct Reg1 { + static constexpr volatile auto *ioReg = &UDR1; + static constexpr volatile auto *controlStatusRegA = &UCSR1A; + static constexpr volatile auto *controlStatusRegB = &UCSR1B; + static constexpr volatile auto *controlStatusRegC = &UCSR1C; + static constexpr volatile auto *baudRateRegL = &UBRR1L; + static constexpr volatile auto *baudRateRegH = &UBRR1H; + }; + + template + static constexpr auto calcBaud() + { + return static_cast((F_CPU / (16 * baudRate)) - 1); + } + + struct DataBitsVal { + uint8_t ucsrcVal = 0; + uint8_t ucsrbVal = 0; + }; + + template + static constexpr auto calcDataBits() + { + DataBitsVal dataBitsVal; + + switch (dataBits) { + case DataBits::FIVE: + dataBitsVal.ucsrcVal = 0; + break; + case DataBits::SIX: + dataBitsVal.ucsrcVal = (1 << UCSZ00); + break; + case DataBits::SEVEN: + dataBitsVal.ucsrcVal = (1 << UCSZ01); + break; + case DataBits::EIGHT: + dataBitsVal.ucsrcVal = (1 << UCSZ01) | (1 << UCSZ00); + break; + case DataBits::NINE: + dataBitsVal.ucsrcVal = (1 << UCSZ01) | (1 << UCSZ00); + dataBitsVal.ucsrbVal = (1 << UCSZ02); + break; + } + + return dataBitsVal; + } + + template + static constexpr auto calcParity() + { + uint8_t parityVal = 0; + + if (parity == Parity::EVEN) + parityVal = (1 << UPM01); + else if (parity == Parity::ODD) + parityVal = (1 << UPM01) | (1 << UPM00); + + return parityVal; + } + + template + static constexpr auto calcStopBits() + { + uint8_t stopBitsVal = 0; + + if (stopBits == StopBits::TWO) + stopBitsVal = (1 << USBS0); + + return stopBitsVal; + } + + template + static constexpr auto calcMode() + { + static_assert(mode != Mode::SPI, "SPI mode can not be used with uart"); + + uint8_t modeVal = 0; + + if (mode == Mode::SYNCHRONOUS_MASTER || mode == Mode::SYNCHRONOUS_SLAVE) { + modeVal = (1 << UMSEL00); + } + + return modeVal; + } + + template + static constexpr auto calcRxState() + { + uint8_t enableVal = 0; + + if (enable) + enableVal = (1 << RXEN0); + + return enableVal; + } + + template + static constexpr auto calcTxState() + { + uint8_t enableVal = 0; + + if (enable) + enableVal = (1 << TXEN0); + + return enableVal; + } + + static void setBaud(const uint16_t baudVal) + { + *Reg0::baudRateRegH = static_cast(baudVal >> 8); + *Reg0::baudRateRegL = static_cast(baudVal); + } + + template + static void setControlRegA() + { + *Reg0::controlStatusRegA = regVal; + } + + template + static void setControlRegB() + { + *Reg0::controlStatusRegB = regVal; + } + + template + static void setControlRegC() + { + *Reg0::controlStatusRegC = regVal; + } + + static void txByte(uint8_t byte) FORCE_INLINE + { + while (!(*Reg0::controlStatusRegA & (1 << UDRE0))) + ; + + *Reg0::ioReg = byte; + } +}; + +static constexpr auto currentHardware = SupportedHardware::ATmega1284P; + +} // 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() {} - - static void txByte(data_t byte) + static void init() { - static_cast(byte); + detail::HardwareAbstraction hal; + hal.setBaud(hal.calcBaud()); + + constexpr auto dataBitsVal = hal.calcDataBits(); + constexpr auto parityVal = hal.calcParity(); + constexpr auto stopBitsVal = hal.calcStopBits(); + constexpr auto modeVal = hal.calcMode(); + constexpr auto enableRx = hal.calcRxState(); + constexpr auto enableTx = hal.calcTxState(); + + constexpr uint8_t ucsr0b = dataBitsVal.ucsrbVal | enableRx | enableTx; + constexpr uint8_t ucsr0c = dataBitsVal.ucsrcVal | parityVal | stopBitsVal | modeVal; + + hal.setControlRegB(); + hal.setControlRegC(); + } + + static void txByte(data_t byte) FORCE_INLINE + { + detail::HardwareAbstraction hal; + hal.txByte(byte); } static data_t rxByte() {} @@ -41,3 +229,5 @@ class hardware0 { }; } // namespace uart + +#undef FORCE_INLINE diff --git a/uart.hpp b/uart.hpp index 5bc37dc..90f047a 100644 --- a/uart.hpp +++ b/uart.hpp @@ -7,6 +7,8 @@ #include "../flash/flash.hpp" +#define FORCE_INLINE __attribute__((always_inline)) + namespace uart { namespace detail { @@ -33,7 +35,7 @@ class uart { uart &operator=(const uart &) = delete; uart &operator=(uart &&) = delete; - static void txByte(typename Driver::data_t byte) + static void txByte(typename Driver::data_t byte) FORCE_INLINE { Driver::txByte(byte); } @@ -48,7 +50,7 @@ class uart { return Driver::peek(); } - static void txString(const char *str) + static void txString(const char *str) FORCE_INLINE { static_assert(Driver::DATA_BITS == DataBits::EIGHT, "Strings are only supported with 8 data bits"); @@ -56,7 +58,7 @@ class uart { txByte(ch); } - static void txString(const ::detail::FlashString *str) + static void txString(const ::detail::FlashString *str) FORCE_INLINE { static_assert(Driver::DATA_BITS == DataBits::EIGHT, "Strings are only supported with 8 data bits"); @@ -69,13 +71,13 @@ class uart { ////////////////////////////////////////////////////////////////////////// // Output stream overloads - uart &operator<<(const char *str) + uart &operator<<(const char *str) FORCE_INLINE { txString(str); return *this; } - uart &operator<<(const ::detail::FlashString *str) + uart &operator<<(const ::detail::FlashString *str) FORCE_INLINE { txString(str); return *this; @@ -266,3 +268,5 @@ class uart { }; } // namespace uart + +#undef FORCE_INLINE