Refactored hardware abstraction

This commit is contained in:
BlackMark 2019-07-30 20:29:38 +02:00
parent c03196493a
commit 65bbf5e96a

View File

@ -21,99 +21,140 @@ enum class Driven {
namespace detail { namespace detail {
enum class SupportedHardware { #if defined(__AVR_ATmega1284P__)
ATmega1284P,
struct Registers0 {
static constexpr volatile auto *IO_REG = &UDR0;
static constexpr volatile auto *CTRL_STAT_REG_A = &UCSR0A;
static constexpr volatile auto *CTRL_STAT_REG_B = &UCSR0B;
static constexpr volatile auto *CTRL_STAT_REG_C = &UCSR0C;
static constexpr volatile auto *BAUD_REG_L = &UBRR0L;
static constexpr volatile auto *BAUD_REG_H = &UBRR0H;
}; };
template <SupportedHardware> static constexpr auto getLastRxError() {}
struct HardwareAbstraction { static constexpr void set2xSpeed() {}
};
template <> template <uint16_t BaudVal>
struct HardwareAbstraction<SupportedHardware::ATmega1284P> { static inline void setBaudRate()
struct Reg0 { {
static constexpr volatile auto *ioReg = &UDR0; *Registers0::BAUD_REG_H = static_cast<uint8_t>(BaudVal >> 8);
static constexpr volatile auto *controlStatusRegA = &UCSR0A; *Registers0::BAUD_REG_L = static_cast<uint8_t>(BaudVal);
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 { template <uint8_t RegVal>
static constexpr volatile auto *ioReg = &UDR1; static inline void setCtrlStatRegC()
static constexpr volatile auto *controlStatusRegA = &UCSR1A; {
static constexpr volatile auto *controlStatusRegB = &UCSR1B; *Registers0::CTRL_STAT_REG_C = RegVal;
static constexpr volatile auto *controlStatusRegC = &UCSR1C; }
static constexpr volatile auto *baudRateRegL = &UBRR1L;
static constexpr volatile auto *baudRateRegH = &UBRR1H; #else
}; #error "This chip is not supported"
#endif
} // 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()
{
detail::setBaudRate<calcBaud()>();
constexpr auto dataBitsVal = calcDataBits();
constexpr auto parityVal = calcParity();
constexpr auto stopBitsVal = calcStopBits();
constexpr auto modeVal = calcMode();
constexpr auto enableRx = calcRxState<true>();
constexpr auto enableTx = calcTxState<true>();
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<controlRegC>();
}
static void txByte(data_t byte) FORCE_INLINE
{
while (!(*detail::Registers0::CTRL_STAT_REG_A & (1 << UDRE0)))
;
*detail::Registers0::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;
template <uint32_t baudRate>
static constexpr auto calcBaud() static constexpr auto calcBaud()
{ {
// The actual formula is (F_CPU / (16 * baudRate)) - 1, but this one has the advantage of rounding correctly // The actual formula is (F_CPU / (16 * baudRate)) - 1, but this one has the advantage of rounding correctly
constexpr auto baudVal = (F_CPU + 8 * baudRate) / (16 * baudRate) - 1; constexpr auto baudVal = (F_CPU + 8 * BAUD_RATE) / (16 * BAUD_RATE) - 1;
return baudVal; return baudVal;
} }
struct DataBitsVal { struct DataBitsVal {
uint8_t ucsrcVal = 0; uint8_t regCVal = 0;
uint8_t ucsrbVal = 0; uint8_t regBVal = 0;
}; };
template <DataBits dataBits>
static constexpr auto calcDataBits() static constexpr auto calcDataBits()
{ {
DataBitsVal dataBitsVal; DataBitsVal dataBitsVal;
switch (dataBits) { switch (DATA_BITS) {
case DataBits::FIVE: case DataBits::FIVE:
dataBitsVal.ucsrcVal = 0; dataBitsVal.regCVal = 0;
break; break;
case DataBits::SIX: case DataBits::SIX:
dataBitsVal.ucsrcVal = (1 << UCSZ00); dataBitsVal.regCVal = (1 << UCSZ00);
break; break;
case DataBits::SEVEN: case DataBits::SEVEN:
dataBitsVal.ucsrcVal = (1 << UCSZ01); dataBitsVal.regCVal = (1 << UCSZ01);
break; break;
case DataBits::EIGHT: case DataBits::EIGHT:
dataBitsVal.ucsrcVal = (1 << UCSZ01) | (1 << UCSZ00); dataBitsVal.regCVal = (1 << UCSZ01) | (1 << UCSZ00);
break; break;
case DataBits::NINE: case DataBits::NINE:
dataBitsVal.ucsrcVal = (1 << UCSZ01) | (1 << UCSZ00); dataBitsVal.regCVal = (1 << UCSZ01) | (1 << UCSZ00);
dataBitsVal.ucsrbVal = (1 << UCSZ02); dataBitsVal.regBVal = (1 << UCSZ02);
break; break;
} }
return dataBitsVal; return dataBitsVal;
} }
template <Parity parity>
static constexpr auto calcParity() static constexpr auto calcParity()
{ {
uint8_t parityVal = 0; uint8_t parityVal = 0;
if (parity == Parity::EVEN) if (PARITY == Parity::EVEN)
parityVal = (1 << UPM01); parityVal = (1 << UPM01);
else if (parity == Parity::ODD) else if (PARITY == Parity::ODD)
parityVal = (1 << UPM01) | (1 << UPM00); parityVal = (1 << UPM01) | (1 << UPM00);
return parityVal; return parityVal;
} }
template <StopBits stopBits>
static constexpr auto calcStopBits() static constexpr auto calcStopBits()
{ {
uint8_t stopBitsVal = 0; uint8_t stopBitsVal = 0;
if (stopBits == StopBits::TWO) if (STOP_BITS == StopBits::TWO)
stopBitsVal = (1 << USBS0); stopBitsVal = (1 << USBS0);
return stopBitsVal; return stopBitsVal;
} }
template <Mode mode>
static constexpr auto calcMode() static constexpr auto calcMode()
{ {
static_assert(mode != Mode::SPI, "SPI mode can not be used with uart"); static_assert(mode != Mode::SPI, "SPI mode can not be used with uart");
@ -148,83 +189,6 @@ struct HardwareAbstraction<SupportedHardware::ATmega1284P> {
return enableVal; return enableVal;
} }
static void setBaud(const uint16_t baudVal)
{
*Reg0::baudRateRegH = static_cast<uint8_t>(baudVal >> 8);
*Reg0::baudRateRegL = static_cast<uint8_t>(baudVal);
}
template <uint8_t regVal>
static void setControlRegA()
{
*Reg0::controlStatusRegA = regVal;
}
template <uint8_t regVal>
static void setControlRegB()
{
*Reg0::controlStatusRegB = regVal;
}
template <uint8_t regVal>
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 <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()
{
detail::HardwareAbstraction<detail::currentHardware> hal;
hal.setBaud(hal.calcBaud<BAUD_RATE>());
constexpr auto dataBitsVal = hal.calcDataBits<DATA_BITS>();
constexpr auto parityVal = hal.calcParity<PARITY>();
constexpr auto stopBitsVal = hal.calcStopBits<STOP_BITS>();
constexpr auto modeVal = hal.calcMode<mode>();
constexpr auto enableRx = hal.calcRxState<true>();
constexpr auto enableTx = hal.calcTxState<true>();
constexpr uint8_t ucsr0b = dataBitsVal.ucsrbVal | enableRx | enableTx;
constexpr uint8_t ucsr0c = dataBitsVal.ucsrcVal | parityVal | stopBitsVal | modeVal;
hal.setControlRegB<ucsr0b>();
hal.setControlRegC<ucsr0c>();
}
static void txByte(data_t byte) FORCE_INLINE
{
detail::HardwareAbstraction<detail::currentHardware> hal;
hal.txByte(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;
}; };
} // namespace uart } // namespace uart