Implemented hardware abstraction that both hardware0 and hardware1 can use

This commit is contained in:
BlackMark 2019-07-30 21:43:52 +02:00
parent fbd087808a
commit aac73447b3
3 changed files with 184 additions and 57 deletions

View File

@ -32,7 +32,7 @@ struct Registers0 {
static constexpr volatile auto *BAUD_REG_H = &UBRR0H; static constexpr volatile auto *BAUD_REG_H = &UBRR0H;
}; };
enum ControlFlagsA { enum class ControlFlagsA0 {
MULTI_PROC_COMM_MODE = MPCM0, MULTI_PROC_COMM_MODE = MPCM0,
SPEED_2X = U2X0, SPEED_2X = U2X0,
PARITY_ERROR = UPE0, PARITY_ERROR = UPE0,
@ -41,9 +41,10 @@ enum ControlFlagsA {
DATA_REG_EMPTY = UDRE0, DATA_REG_EMPTY = UDRE0,
TRANSMIT_COMPLETE = TXC0, TRANSMIT_COMPLETE = TXC0,
RECEIVE_COMPLETE = RXC0, RECEIVE_COMPLETE = RXC0,
}; };
enum ControlFlagsB { enum class ControlFlagsB0 {
TX_DATA_BIT_8 = TXB80, TX_DATA_BIT_8 = TXB80,
RX_DATA_BIT_8 = RXB80, RX_DATA_BIT_8 = RXB80,
CHAR_SIZE_2 = UCSZ02, CHAR_SIZE_2 = UCSZ02,
@ -54,7 +55,7 @@ enum ControlFlagsB {
RX_INT_ENABLE = RXCIE0, RX_INT_ENABLE = RXCIE0,
}; };
enum ControlFlagsC { enum class ControlFlagsC0 {
CLK_POLARITY = UCPOL0, CLK_POLARITY = UCPOL0,
CHAR_SIZE_0 = UCSZ00, CHAR_SIZE_0 = UCSZ00,
CHAR_SIZE_1 = UCSZ01, CHAR_SIZE_1 = UCSZ01,
@ -65,37 +66,32 @@ enum ControlFlagsC {
MODE_SEL_1 = UMSEL01, MODE_SEL_1 = UMSEL01,
}; };
static constexpr auto getLastRxError() {} constexpr int operator<<(const int &lhs, const ControlFlagsA0 &rhs)
static constexpr void set2xSpeed() {}
template <uint16_t BaudVal>
static inline void setBaudRate()
{ {
*Registers0::BAUD_REG_H = static_cast<uint8_t>(BaudVal >> 8); return lhs << static_cast<int>(rhs);
*Registers0::BAUD_REG_L = static_cast<uint8_t>(BaudVal);
} }
constexpr int operator<<(const int &lhs, const ControlFlagsB0 &rhs)
template <uint8_t RegVal>
static inline void setCtrlStatRegC()
{ {
*Registers0::CTRL_STAT_REG_C = RegVal; return lhs << static_cast<int>(rhs);
}
constexpr int operator<<(const int &lhs, const ControlFlagsC0 &rhs)
{
return lhs << static_cast<int>(rhs);
} }
#else #else
#error "This chip is not supported" #error "This chip is not supported"
#endif #endif
} // namespace detail template <class Registers, typename CtrlFlagsA, typename CtrlFlagsB, typename CtrlFlagsC, class cfg, Mode mode>
class Hardware {
template <Mode mode = Mode::ASYNCHRONOUS, class cfg = Config<>, Driven driven = Driven::INTERRUPT>
class Hardware0 {
public: public:
using data_t = typename cfg::data_t;
static constexpr auto DATA_BITS = cfg::DATA_BITS;
static void init() static void init()
{ {
detail::setBaudRate<calcBaud()>(); constexpr auto baudVal = calcBaud();
*Registers::BAUD_REG_H = static_cast<uint8_t>(baudVal >> 8);
*Registers::BAUD_REG_L = static_cast<uint8_t>(baudVal);
constexpr auto dataBitsVal = calcDataBits(); constexpr auto dataBitsVal = calcDataBits();
constexpr auto parityVal = calcParity(); constexpr auto parityVal = calcParity();
@ -107,59 +103,51 @@ class Hardware0 {
constexpr uint8_t controlRegB = dataBitsVal.regBVal | enableRx | enableTx; constexpr uint8_t controlRegB = dataBitsVal.regBVal | enableRx | enableTx;
constexpr uint8_t controlRegC = dataBitsVal.regCVal | parityVal | stopBitsVal | modeVal; constexpr uint8_t controlRegC = dataBitsVal.regCVal | parityVal | stopBitsVal | modeVal;
*detail::Registers0::CTRL_STAT_REG_B = controlRegB; *Registers::CTRL_STAT_REG_B = controlRegB;
detail::setCtrlStatRegC<controlRegC>(); *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: 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 { struct DataBitsVal {
uint8_t regCVal = 0; uint8_t regCVal = 0;
uint8_t regBVal = 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() static constexpr auto calcDataBits()
{ {
DataBitsVal dataBitsVal; DataBitsVal dataBitsVal;
switch (DATA_BITS) { switch (cfg::DATA_BITS) {
case DataBits::FIVE: case DataBits::FIVE:
dataBitsVal.regCVal = 0; dataBitsVal.regCVal = 0;
break; break;
case DataBits::SIX: case DataBits::SIX:
dataBitsVal.regCVal = (1 << detail::CHAR_SIZE_0); dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_0);
break; break;
case DataBits::SEVEN: case DataBits::SEVEN:
dataBitsVal.regCVal = (1 << detail::CHAR_SIZE_1); dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_1);
break; break;
case DataBits::EIGHT: 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; break;
case DataBits::NINE: case DataBits::NINE:
dataBitsVal.regCVal = (1 << detail::CHAR_SIZE_1) | (1 << detail::CHAR_SIZE_0); dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_1) | (1 << CtrlFlagsC::CHAR_SIZE_0);
dataBitsVal.regBVal = (1 << detail::CHAR_SIZE_2); dataBitsVal.regBVal = (1 << CtrlFlagsB::CHAR_SIZE_2);
break; break;
} }
@ -170,10 +158,10 @@ class Hardware0 {
{ {
uint8_t parityVal = 0; uint8_t parityVal = 0;
if (PARITY == Parity::EVEN) if (cfg::PARITY == Parity::EVEN)
parityVal = (1 << detail::PARITY_MODE_1); parityVal = (1 << CtrlFlagsC::PARITY_MODE_1);
else if (PARITY == Parity::ODD) else if (cfg::PARITY == Parity::ODD)
parityVal = (1 << detail::PARITY_MODE_1) | (1 << detail::PARITY_MODE_0); parityVal = (1 << CtrlFlagsC::PARITY_MODE_1) | (1 << CtrlFlagsC::PARITY_MODE_0);
return parityVal; return parityVal;
} }
@ -182,8 +170,8 @@ class Hardware0 {
{ {
uint8_t stopBitsVal = 0; uint8_t stopBitsVal = 0;
if (STOP_BITS == StopBits::TWO) if (cfg::STOP_BITS == StopBits::TWO)
stopBitsVal = (1 << detail::STOP_BIT_SEL); stopBitsVal = (1 << CtrlFlagsC::STOP_BIT_SEL);
return stopBitsVal; return stopBitsVal;
} }
@ -195,7 +183,7 @@ class Hardware0 {
uint8_t modeVal = 0; uint8_t modeVal = 0;
if (mode == Mode::SYNCHRONOUS_MASTER || mode == Mode::SYNCHRONOUS_SLAVE) { if (mode == Mode::SYNCHRONOUS_MASTER || mode == Mode::SYNCHRONOUS_SLAVE) {
modeVal = (1 << detail::MODE_SEL_0); modeVal = (1 << CtrlFlagsC::MODE_SEL_0);
} }
return modeVal; return modeVal;
@ -207,7 +195,7 @@ class Hardware0 {
uint8_t enableVal = 0; uint8_t enableVal = 0;
if (enable) if (enable)
enableVal = (1 << detail::RX_ENABLE); enableVal = (1 << CtrlFlagsB::RX_ENABLE);
return enableVal; return enableVal;
} }
@ -218,12 +206,39 @@ class Hardware0 {
uint8_t enableVal = 0; uint8_t enableVal = 0;
if (enable) if (enable)
enableVal = (1 << detail::TX_ENABLE); enableVal = (1 << CtrlFlagsB::TX_ENABLE);
return enableVal; return enableVal;
} }
}; };
} // namespace detail
template <Mode mode = Mode::ASYNCHRONOUS, class cfg = Config<>, 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<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, mode>;
};
} // namespace uart } // namespace uart
#undef FORCE_INLINE #undef FORCE_INLINE

View File

@ -1 +1,107 @@
#pragma once #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<int>(rhs);
}
constexpr int operator<<(const int &lhs, const ControlFlagsB1 &rhs)
{
return lhs << static_cast<int>(rhs);
}
constexpr int operator<<(const int &lhs, const ControlFlagsC1 &rhs)
{
return lhs << static_cast<int>(rhs);
}
#define HAS_UART1
#else
#error "This chip is not supported"
#endif
} // namespace detail
#ifdef HAS_UART1
template <Mode mode = Mode::ASYNCHRONOUS, class cfg = Config<>, 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<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, mode>;
};
#endif
} // namespace uart
#undef FORCE_INLINE

View File

@ -270,6 +270,12 @@ class Uart {
template <typename cfg = Config<>> template <typename cfg = Config<>>
using Uart0 = Uart<Hardware0<Mode::ASYNCHRONOUS, cfg>>; using Uart0 = Uart<Hardware0<Mode::ASYNCHRONOUS, cfg>>;
#ifdef HAS_UART1
template <typename cfg = Config<>>
using Uart1 = Uart<Hardware1<Mode::ASYNCHRONOUS, cfg>>;
#endif
} // namespace uart } // namespace uart
#undef FORCE_INLINE #undef FORCE_INLINE
#undef HAS_UART1