Moved hardware abstraction to separate header
This commit is contained in:
parent
6e45340993
commit
bdf4bd169e
157
hardware.hpp
Normal file
157
hardware.hpp
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.hpp"
|
||||||
|
|
||||||
|
#define FORCE_INLINE __attribute__((always_inline))
|
||||||
|
|
||||||
|
namespace uart {
|
||||||
|
|
||||||
|
enum class Mode {
|
||||||
|
ASYNCHRONOUS,
|
||||||
|
ASYNCHRONOUS_2X,
|
||||||
|
SYNCHRONOUS_MASTER,
|
||||||
|
SYNCHRONOUS_SLAVE,
|
||||||
|
SPI,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Driven {
|
||||||
|
INTERRUPT,
|
||||||
|
BLOCKING,
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <class Registers, typename CtrlFlagsA, typename CtrlFlagsB, typename CtrlFlagsC, class cfg, Mode mode>
|
||||||
|
class Hardware {
|
||||||
|
public:
|
||||||
|
static void init() FORCE_INLINE
|
||||||
|
{
|
||||||
|
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 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;
|
||||||
|
|
||||||
|
*Registers::CTRL_STAT_REG_B = controlRegB;
|
||||||
|
*Registers::CTRL_STAT_REG_C = controlRegC;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txByte(typename cfg::data_t byte) FORCE_INLINE
|
||||||
|
{
|
||||||
|
while (!(*Registers::CTRL_STAT_REG_A & (1 << CtrlFlagsA::DATA_REG_EMPTY)))
|
||||||
|
;
|
||||||
|
|
||||||
|
*Registers::IO_REG = byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
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 (cfg::DATA_BITS) {
|
||||||
|
case DataBits::FIVE:
|
||||||
|
dataBitsVal.regCVal = 0;
|
||||||
|
break;
|
||||||
|
case DataBits::SIX:
|
||||||
|
dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_0);
|
||||||
|
break;
|
||||||
|
case DataBits::SEVEN:
|
||||||
|
dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_1);
|
||||||
|
break;
|
||||||
|
case DataBits::EIGHT:
|
||||||
|
dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_1) | (1 << CtrlFlagsC::CHAR_SIZE_0);
|
||||||
|
break;
|
||||||
|
case DataBits::NINE:
|
||||||
|
dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_1) | (1 << CtrlFlagsC::CHAR_SIZE_0);
|
||||||
|
dataBitsVal.regBVal = (1 << CtrlFlagsB::CHAR_SIZE_2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataBitsVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto calcParity()
|
||||||
|
{
|
||||||
|
uint8_t parityVal = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto calcStopBits()
|
||||||
|
{
|
||||||
|
uint8_t stopBitsVal = 0;
|
||||||
|
|
||||||
|
if (cfg::STOP_BITS == StopBits::TWO)
|
||||||
|
stopBitsVal = (1 << CtrlFlagsC::STOP_BIT_SEL);
|
||||||
|
|
||||||
|
return stopBitsVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 << CtrlFlagsC::MODE_SEL_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return modeVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool enable>
|
||||||
|
static constexpr auto calcRxState()
|
||||||
|
{
|
||||||
|
uint8_t enableVal = 0;
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
enableVal = (1 << CtrlFlagsB::RX_ENABLE);
|
||||||
|
|
||||||
|
return enableVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool enable>
|
||||||
|
static constexpr auto calcTxState()
|
||||||
|
{
|
||||||
|
uint8_t enableVal = 0;
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
enableVal = (1 << CtrlFlagsB::TX_ENABLE);
|
||||||
|
|
||||||
|
return enableVal;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace uart
|
||||||
|
|
||||||
|
#undef FORCE_INLINE
|
143
hardware0.hpp
143
hardware0.hpp
@ -1,24 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
#include "hardware.hpp"
|
||||||
|
|
||||||
#define FORCE_INLINE __attribute__((always_inline))
|
#define FORCE_INLINE __attribute__((always_inline))
|
||||||
|
|
||||||
namespace uart {
|
namespace uart {
|
||||||
|
|
||||||
enum class Mode {
|
|
||||||
ASYNCHRONOUS,
|
|
||||||
ASYNCHRONOUS_2X,
|
|
||||||
SYNCHRONOUS_MASTER,
|
|
||||||
SYNCHRONOUS_SLAVE,
|
|
||||||
SPI,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Driven {
|
|
||||||
INTERRUPT,
|
|
||||||
BLOCKING,
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
#if defined(__AVR_ATmega1284P__)
|
#if defined(__AVR_ATmega1284P__)
|
||||||
@ -75,135 +63,6 @@ constexpr int operator<<(const int &lhs, const ControlFlagsC0 &rhs) { return lhs
|
|||||||
#error "This chip is not supported"
|
#error "This chip is not supported"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class Registers, typename CtrlFlagsA, typename CtrlFlagsB, typename CtrlFlagsC, class cfg, Mode mode>
|
|
||||||
class Hardware {
|
|
||||||
public:
|
|
||||||
static void init() FORCE_INLINE
|
|
||||||
{
|
|
||||||
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 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;
|
|
||||||
|
|
||||||
*Registers::CTRL_STAT_REG_B = controlRegB;
|
|
||||||
*Registers::CTRL_STAT_REG_C = controlRegC;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void txByte(typename cfg::data_t byte) FORCE_INLINE
|
|
||||||
{
|
|
||||||
while (!(*Registers::CTRL_STAT_REG_A & (1 << CtrlFlagsA::DATA_REG_EMPTY)))
|
|
||||||
;
|
|
||||||
|
|
||||||
*Registers::IO_REG = byte;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
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 (cfg::DATA_BITS) {
|
|
||||||
case DataBits::FIVE:
|
|
||||||
dataBitsVal.regCVal = 0;
|
|
||||||
break;
|
|
||||||
case DataBits::SIX:
|
|
||||||
dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_0);
|
|
||||||
break;
|
|
||||||
case DataBits::SEVEN:
|
|
||||||
dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_1);
|
|
||||||
break;
|
|
||||||
case DataBits::EIGHT:
|
|
||||||
dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_1) | (1 << CtrlFlagsC::CHAR_SIZE_0);
|
|
||||||
break;
|
|
||||||
case DataBits::NINE:
|
|
||||||
dataBitsVal.regCVal = (1 << CtrlFlagsC::CHAR_SIZE_1) | (1 << CtrlFlagsC::CHAR_SIZE_0);
|
|
||||||
dataBitsVal.regBVal = (1 << CtrlFlagsB::CHAR_SIZE_2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataBitsVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr auto calcParity()
|
|
||||||
{
|
|
||||||
uint8_t parityVal = 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr auto calcStopBits()
|
|
||||||
{
|
|
||||||
uint8_t stopBitsVal = 0;
|
|
||||||
|
|
||||||
if (cfg::STOP_BITS == StopBits::TWO)
|
|
||||||
stopBitsVal = (1 << CtrlFlagsC::STOP_BIT_SEL);
|
|
||||||
|
|
||||||
return stopBitsVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 << CtrlFlagsC::MODE_SEL_0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return modeVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool enable>
|
|
||||||
static constexpr auto calcRxState()
|
|
||||||
{
|
|
||||||
uint8_t enableVal = 0;
|
|
||||||
|
|
||||||
if (enable)
|
|
||||||
enableVal = (1 << CtrlFlagsB::RX_ENABLE);
|
|
||||||
|
|
||||||
return enableVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool enable>
|
|
||||||
static constexpr auto calcTxState()
|
|
||||||
{
|
|
||||||
uint8_t enableVal = 0;
|
|
||||||
|
|
||||||
if (enable)
|
|
||||||
enableVal = (1 << CtrlFlagsB::TX_ENABLE);
|
|
||||||
|
|
||||||
return enableVal;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <Mode mode = Mode::ASYNCHRONOUS, class cfg = Config<>, Driven driven = Driven::INTERRUPT>
|
template <Mode mode = Mode::ASYNCHRONOUS, class cfg = Config<>, Driven driven = Driven::INTERRUPT>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "hardware0.hpp"
|
#include "hardware.hpp"
|
||||||
|
|
||||||
#define FORCE_INLINE __attribute__((always_inline))
|
#define FORCE_INLINE __attribute__((always_inline))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user