Оно?
template<UartList uart,
uint32_t Fclk,
uint32_t baudrate,
DataBits databits,
Parity parity,
StopBit stb,
Function func,
Interrupt irq,
FifoThreshold rxfifo,
FifoThreshold txfifo,
bool use_rxdma,
bool use_txdma>
struct UART
{
static constexpr UartList uart_ = uart;
static constexpr uint32_t Fclk_ = Fclk;
static constexpr uint32_t baudrate_ = baudrate;
static constexpr Parity parity_ = parity;
static constexpr StopBit stb_ = stb;
static constexpr DataBits databits_ = databits;
static constexpr Function func_ = func;
static constexpr Interrupt irq_ = irq;
static constexpr FifoThreshold rxfifo_ = rxfifo;
static constexpr FifoThreshold txfifo_ = txfifo;
static constexpr bool use_rxdma_ = use_rxdma;
static constexpr bool use_txdma_ = use_txdma;
static constexpr uint32_t timeout = static_cast<uint32_t>((static_cast<float>(Fclk)/static_cast<float>(baudrate))*32.0f);
static __forceinline void Init()
{
UART_TypeDef* U{reinterpret_cast<UART_TypeDef*>(uart_)};
constexpr float div = static_cast<float>(Fclk_)/(static_cast<float>(16*baudrate_));
static_assert ((div > 1.0f)&&(div < 65535.0f), "Bad UART clk divider");
constexpr uint16_t ibrd = static_cast<uint16_t>(div);
constexpr uint8_t fbrd = static_cast<uint8_t>((div - static_cast<float>(ibrd))*64.0f+0.5f)&0b111111;
static_assert ((ibrd != 0xFFFF)&&(fbrd != 0), "Illegal DIVFRAC");
// LCRH Register
constexpr uint32_t PEN = (parity_ != Parity::none) ? 1 << 1 : 0;
constexpr uint32_t EPS = (parity_ == Parity::even) ? 1 << 2 : 0;
constexpr uint32_t STP2 = (stb_ == StopBit::_2) ? 1 << 3 : 0;
constexpr uint32_t FEN = ((rxfifo_ != FifoThreshold::unused)&&
(txfifo_ != FifoThreshold::unused)) ? 1 << 4 : 0;
constexpr uint32_t WLEN = static_cast<uint32_t>(databits_) << 5;
constexpr uint32_t SPS = (parity_ == Parity::stick) ? 1 << 7 : 0;
constexpr uint32_t lcrh = PEN | EPS | STP2 | FEN | WLEN | SPS;
// IFLS Register
constexpr uint32_t RXSEL = (rxfifo_ != FifoThreshold::unused) ? static_cast<uint32_t>(rxfifo) << 3 : 0;
constexpr uint32_t TXSEL = (txfifo_ != FifoThreshold::unused) ? static_cast<uint32_t>(txfifo) : 0;
constexpr uint32_t ifls = TXSEL | RXSEL;
// DMACTL
constexpr uint32_t RXDMAE = (use_rxdma_) ? 1 << 0 : 0;
constexpr uint32_t TXDMAE = (use_txdma_) ? 1 << 1 : 0;
constexpr uint32_t dmactl = RXDMAE | TXDMAE;
// Config UART
U->CTL = static_cast<uint32_t>(func_) | 0b01;
U->IBRD = ibrd;
U->FBRD = fbrd;
U->LCRH = lcrh;
U->IFLS = ifls;
U->IMSC = static_cast<uint32_t>(irq_);
U->ICR = static_cast<uint32_t>(Interrupt::all);
U->DMACTL = dmactl;
}
};
int main()
{
using U = UART<UartList::_0, 48'000'000,
115200, DataBits::_8, Parity::none, StopBit::_1,
Function::rxen | Function::txen,
Interrupt::end_of_transmission | Interrupt::receive_timeout | Interrupt::receive_complete,
FifoThreshold::_1_8, FifoThreshold::_4_8,
false, false>;
U::Init();
...
}
Вот только смысл, который я вкладываю в подобное несколько отличается от описанного в статье на хабре. Я просто хочу получить компактный результат с проверками на этапе компиляции, автор статьи с хабра заморочился на столько, что сделал абстракции над отдельными битами! (он видимо не в курсе что под некоторые чипы, те же cc1352, вендоры не поставляют svd-файлы)
Потому как если бит RO, то писать в него нельзя, нужно же максимально защитить пользователя либины. А если тупой программист будет писать в порт, настроенный на вход? Это же ужас!
А то, что такие проблемы составляют 0.1% от общего числа и вычищаются почти сразу никого не волнует. Нужно защитить тупого программиста от тупых ошибок. Парень молодец, сам себе придумал проблему, сам её решил.
-
- Если у тебя так дофига много параметров, то их лучше засунуть в отдельный тип (класс) и его передавать как параметр. А то глаза сломаешь. - fk0(17.12.2019 12:08)
- Ага, я хочу использовать Type Traits - тогда можно вообще пихать в шаблон что-угодно. Главное, чтобы нужные поля присутствовали. evgeniy1294(1711 знак., 17.12.2019 12:41 - 12:44)
- Если у тебя так дофига много параметров, то их лучше засунуть в отдельный тип (класс) и его передавать как параметр. А то глаза сломаешь. - fk0(17.12.2019 12:08)