Add automatic selection of double speed based on error

This commit is contained in:
BlackMark 2020-04-12 23:57:16 +02:00
parent ae03c8d43e
commit 04b6782ec4

View File

@ -4,6 +4,7 @@
#include "../type/type.hpp" #include "../type/type.hpp"
#include <math.h>
#include <stdint.h> #include <stdint.h>
#define FORCE_INLINE __attribute__((always_inline)) #define FORCE_INLINE __attribute__((always_inline))
@ -12,7 +13,6 @@ namespace uart {
enum class Mode { enum class Mode {
ASYNCHRONOUS, ASYNCHRONOUS,
ASYNCHRONOUS_2X,
SYNCHRONOUS_MASTER, SYNCHRONOUS_MASTER,
SYNCHRONOUS_SLAVE, SYNCHRONOUS_SLAVE,
SPI, SPI,
@ -46,7 +46,12 @@ class Hardware {
public: public:
static void init() FORCE_INLINE static void init() FORCE_INLINE
{ {
constexpr auto BaudVal = calcBaud(); constexpr auto AbsDoubleError = fabs(calcBaudError<true>());
constexpr auto AbsNormalError = fabs(calcBaudError<false>());
static_assert(AbsDoubleError <= 3.0 || AbsNormalError <= 3.0, "Baud rate error over 3%, probably unusable");
constexpr auto UseDoubleSpeed = (AbsDoubleError < AbsNormalError);
constexpr auto BaudVal = calcBaudVal<UseDoubleSpeed>();
*getRegPtr<Registers::BAUD_REG_H_ADDR>() = static_cast<uint8_t>(BaudVal >> 8); *getRegPtr<Registers::BAUD_REG_H_ADDR>() = static_cast<uint8_t>(BaudVal >> 8);
*getRegPtr<Registers::BAUD_REG_L_ADDR>() = static_cast<uint8_t>(BaudVal); *getRegPtr<Registers::BAUD_REG_L_ADDR>() = static_cast<uint8_t>(BaudVal);
@ -58,10 +63,12 @@ class Hardware {
constexpr auto EnableRx = calcRxState<true>(); constexpr auto EnableRx = calcRxState<true>();
constexpr auto EnableTx = calcTxState<true>(); constexpr auto EnableTx = calcTxState<true>();
constexpr auto InterruptVal = calcInterrupt(); constexpr auto InterruptVal = calcInterrupt();
constexpr auto DoubleSpeedVal = calcDoubleSpeedVal<UseDoubleSpeed>();
constexpr uint8_t ControlRegB = DataBitsValues.regBVal | EnableRx | EnableTx | InterruptVal; constexpr uint8_t ControlRegB = DataBitsValues.regBVal | EnableRx | EnableTx | InterruptVal;
constexpr uint8_t ControlRegC = DataBitsValues.regCVal | ParityVal | StopBitsVal | ModeVal; constexpr uint8_t ControlRegC = DataBitsValues.regCVal | ParityVal | StopBitsVal | ModeVal;
*getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() |= DoubleSpeedVal;
*getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() = ControlRegB; *getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() = ControlRegB;
*getRegPtr<Registers::CTRL_STAT_REG_C_ADDR>() = ControlRegC; *getRegPtr<Registers::CTRL_STAT_REG_C_ADDR>() = ControlRegC;
} }
@ -134,13 +141,39 @@ class Hardware {
uint8_t regBVal = 0; uint8_t regBVal = 0;
}; };
static constexpr auto calcBaud() template <bool DoubleSpeed = true>
static constexpr auto calcBaudVal()
{ {
// The actual formula is (F_CPU / (16 * baudRate)) - 1, but this one has the advantage of rounding correctly if constexpr (DoubleSpeed) {
constexpr auto BaudVal = (F_CPU + 8 * cfg::BAUD_RATE) / (16 * cfg::BAUD_RATE) - 1; constexpr auto BaudVal = static_cast<uint16_t>(round(F_CPU / (8.0 * cfg::BAUD_RATE) - 1));
return BaudVal; return BaudVal;
} }
constexpr auto BaudVal = static_cast<uint16_t>(round(F_CPU / (16.0 * cfg::BAUD_RATE) - 1));
return BaudVal;
}
template <uint16_t BaudVal, bool DoubleSpeed = true>
static constexpr auto calcBaudRate()
{
if constexpr (DoubleSpeed) {
constexpr auto BaudRate = static_cast<uint32_t>(round(F_CPU / (8.0 * (BaudVal + 1))));
return BaudRate;
}
constexpr auto BaudRate = static_cast<uint32_t>(round(F_CPU / (16.0 * (BaudVal + 1))));
return BaudRate;
}
template <bool DoubleSpeed = true>
static constexpr auto calcBaudError()
{
constexpr auto BaudVal = calcBaudVal<DoubleSpeed>();
constexpr auto ClosestBaudRate = calcBaudRate<BaudVal, DoubleSpeed>();
constexpr auto BaudError = (static_cast<double>(ClosestBaudRate) / cfg::BAUD_RATE - 1) * 100;
return BaudError;
}
static constexpr auto calcDataBits() static constexpr auto calcDataBits()
{ {
DataBitsVal dataBitsVal; DataBitsVal dataBitsVal;
@ -233,6 +266,17 @@ class Hardware {
return interruptVal; return interruptVal;
} }
template <bool DoubleSpeed>
static constexpr auto calcDoubleSpeedVal()
{
uint8_t doubleSpeedVal = 0;
if constexpr (DoubleSpeed)
doubleSpeedVal = (1 << CtrlFlagsA::SPEED_2X);
return doubleSpeedVal;
}
}; };
template <class Registers, typename CtrlFlagsA, typename CtrlFlagsB, typename CtrlFlagsC, class cfg, Mode mode> template <class Registers, typename CtrlFlagsA, typename CtrlFlagsB, typename CtrlFlagsC, class cfg, Mode mode>