Implemented basic hardware support for transmitting

This commit is contained in:
BlackMark 2019-07-28 17:32:51 +02:00
parent a71035d4b7
commit 8e0ba5a463
2 changed files with 203 additions and 9 deletions

View File

@ -2,6 +2,8 @@
#include "config.hpp" #include "config.hpp"
#define FORCE_INLINE __attribute__((always_inline))
namespace uart { namespace uart {
enum class Mode { enum class Mode {
@ -17,17 +19,203 @@ enum class Driven {
BLOCKING, BLOCKING,
}; };
namespace detail {
struct Registers0 {
};
enum class SupportedHardware {
ATmega1284P,
};
template <SupportedHardware>
struct HardwareAbstraction {
};
template <>
struct HardwareAbstraction<SupportedHardware::ATmega1284P> {
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 <uint32_t baudRate>
static constexpr auto calcBaud()
{
return static_cast<uint16_t>((F_CPU / (16 * baudRate)) - 1);
}
struct DataBitsVal {
uint8_t ucsrcVal = 0;
uint8_t ucsrbVal = 0;
};
template <DataBits dataBits>
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 <Parity parity>
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 <StopBits stopBits>
static constexpr auto calcStopBits()
{
uint8_t stopBitsVal = 0;
if (stopBits == StopBits::TWO)
stopBitsVal = (1 << USBS0);
return stopBitsVal;
}
template <Mode mode>
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 <bool enable>
static constexpr auto calcRxState()
{
uint8_t enableVal = 0;
if (enable)
enableVal = (1 << RXEN0);
return enableVal;
}
template <bool enable>
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<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> template <Mode mode = Mode::ASYNCHRONOUS, class cfg = config<>, Driven driven = Driven::INTERRUPT>
class hardware0 { class hardware0 {
public: public:
using data_t = typename cfg::data_t; using data_t = typename cfg::data_t;
static constexpr auto DATA_BITS = cfg::DATA_BITS; static constexpr auto DATA_BITS = cfg::DATA_BITS;
static void init() {} static void init()
static void txByte(data_t byte)
{ {
static_cast<void>(byte); 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 rxByte() {}
@ -41,3 +229,5 @@ class hardware0 {
}; };
} // namespace uart } // namespace uart
#undef FORCE_INLINE

View File

@ -7,6 +7,8 @@
#include "../flash/flash.hpp" #include "../flash/flash.hpp"
#define FORCE_INLINE __attribute__((always_inline))
namespace uart { namespace uart {
namespace detail { namespace detail {
@ -33,7 +35,7 @@ class uart {
uart &operator=(const uart &) = delete; uart &operator=(const uart &) = delete;
uart &operator=(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); Driver::txByte(byte);
} }
@ -48,7 +50,7 @@ class uart {
return Driver::peek(); 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"); static_assert(Driver::DATA_BITS == DataBits::EIGHT, "Strings are only supported with 8 data bits");
@ -56,7 +58,7 @@ class uart {
txByte(ch); 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"); static_assert(Driver::DATA_BITS == DataBits::EIGHT, "Strings are only supported with 8 data bits");
@ -69,13 +71,13 @@ class uart {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Output stream overloads // Output stream overloads
uart &operator<<(const char *str) uart &operator<<(const char *str) FORCE_INLINE
{ {
txString(str); txString(str);
return *this; return *this;
} }
uart &operator<<(const ::detail::FlashString *str) uart &operator<<(const ::detail::FlashString *str) FORCE_INLINE
{ {
txString(str); txString(str);
return *this; return *this;
@ -266,3 +268,5 @@ class uart {
}; };
} // namespace uart } // namespace uart
#undef FORCE_INLINE