Implemented hardware abstraction that both hardware0 and hardware1 can use
This commit is contained in:
parent
fbd087808a
commit
aac73447b3
129
hardware0.hpp
129
hardware0.hpp
@ -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
|
||||||
|
106
hardware1.hpp
106
hardware1.hpp
@ -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
|
||||||
|
6
uart.hpp
6
uart.hpp
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user