Compare commits

..

43 Commits

Author SHA1 Message Date
d1452b6dc0 Update uart example to use latest library version 2020-10-18 12:19:19 +02:00
e760cf541c Update submodule 2020-04-13 17:17:38 +02:00
6b90c1779f Adapt to new interrupt handling interface and change example back to atmega1284p 2020-04-13 16:43:48 +02:00
8bb1bd7397 Update uart submodule 2020-04-13 13:06:31 +02:00
24d17688c0 Add double speed test and change to atmega328p 2020-04-12 23:59:18 +02:00
414ebbebff Refactor uart utils to separate submodule 2020-04-07 03:54:40 +02:00
717a69c231 Updated uart submodule 2020-04-05 03:37:41 +02:00
f0abf335e5 Updated flash submodule 2020-04-05 00:02:33 +02:00
991a67bd86 Updated submodule 2020-02-21 17:50:02 +01:00
4d31f20714 Updated submodules and added MIT license file 2020-02-01 15:43:38 +01:00
85e6510cd5 Adapted to library change 2019-08-15 19:01:56 +02:00
2eefa7fd7f Changed toolchain to 9.1.0 and updated submodules 2019-08-15 18:49:53 +02:00
dd3e69daa3 Disabled unused interrupt vectors 2019-08-15 18:13:12 +02:00
cc5b375b44 Updated project settings 2019-08-15 17:43:11 +02:00
fcdce7cc1d Adapted example slightly and updated submodules 2019-08-14 20:00:40 +02:00
0354bc3020 Adapted interface to move more often used template parameters to the front 2019-08-05 20:06:42 +02:00
c74f1afcac Adapted to c++ clock header 2019-08-05 19:43:00 +02:00
823921dcd8 Added flushing test 2019-08-03 18:46:23 +02:00
2ba032c103 Added test for number conversion 2019-08-03 17:33:05 +02:00
dafb7ee059 Added test for stream operator overloading 2019-08-03 16:53:29 +02:00
9b4b0cac67 Adapted to new interface 2019-08-03 16:26:32 +02:00
2d54e4ea45 Updated submodule 2019-08-02 19:45:02 +02:00
d32e2a13e6 Fixed submodule url 2019-08-02 19:31:08 +02:00
5047b661af Changed example to use peeking 2019-08-02 18:22:38 +02:00
408ab83afb Changed example to use rx as well 2019-08-02 17:42:12 +02:00
e891e1019f Switched to only Uart1 for testing 2019-08-02 09:22:27 +02:00
4a25398c1e Added Uart1 example 2019-07-30 21:51:47 +02:00
48e312d076 Implemented test using Peter Fleury's c uart library 2019-07-30 18:32:32 +02:00
59a83a304b Used defaultet constructor for uart 2019-07-28 19:20:36 +02:00
011776a709 Removed test implementation 2019-07-28 18:11:23 +02:00
d952794c55 Refactored code to use capital letters for classes and added using namespace inside functions 2019-07-28 18:00:15 +02:00
9809b34bca Implemented optimal example to compare implementations 2019-07-28 17:33:42 +02:00
e71d103602 Added explicit selection of interrupt driven uart 2019-07-28 14:09:52 +02:00
d8aee7498d Removed unnecessary const qualifiers in template 2019-07-28 14:01:05 +02:00
5cd2b963fa Added proof of concept for using hardware0 in SPI mode 2019-07-28 12:16:09 +02:00
ab1d55ee6f Updated submodule 2019-07-28 10:35:32 +02:00
b66c33506c Implemented proof of concept for new library interface and added basic outline of new interface 2019-07-27 18:56:31 +02:00
2cb62d4fac Added flash submodule for flash strings 2019-07-27 13:38:45 +02:00
98bd0e1238 Added clock and io/uart submodules 2019-07-27 11:01:56 +02:00
f1de6c3701 Renamed library from usart to uart and wiped example to implement new library 2019-07-27 10:53:23 +02:00
0ec71af448 Used submodule branch as library source 2018-08-11 13:37:15 +02:00
8fa18f8e88 Merged changes from submodule branch 2016-10-29 17:22:34 +02:00
5ba8cc4ec3 Fixed submodule 2016-10-29 17:12:11 +02:00
15 changed files with 579 additions and 1192 deletions

12
.gitmodules vendored Normal file
View File

@ -0,0 +1,12 @@
[submodule "uart/io"]
path = uart/io
url = git@git.blackmark.me:avr/io.git
[submodule "uart/uart"]
path = uart/uart
url = git@git.blackmark.me:avr/uart.git
[submodule "uart/flash"]
path = uart/flash
url = git@git.blackmark.me:avr/flash.git
[submodule "uart/util"]
path = uart/util
url = git@git.blackmark.me:avr/util.git

View File

@ -1,50 +0,0 @@
#pragma once
#include <cstdint>
namespace uart {
enum class DataBits {
FIVE,
SIX,
SEVEN,
EIGHT,
NINE,
};
enum class StopBits {
ONE,
TWO,
};
enum class Parity {
NONE,
ODD,
EVEN,
};
namespace detail {
template <DataBits dataBits>
struct choose_data_type {
using type = std::uint8_t;
};
template <>
struct choose_data_type<DataBits::NINE> {
using type = std::uint16_t;
};
} // namespace detail
template <std::uint32_t baudRate = 9600, DataBits dataBits = DataBits::EIGHT, Parity parity = Parity::NONE,
StopBits stopBits = StopBits::ONE>
struct Config {
static constexpr auto BAUD_RATE = baudRate;
static constexpr auto DATA_BITS = dataBits;
static constexpr auto PARITY = parity;
static constexpr auto STOP_BITS = stopBits;
using data_t = typename detail::choose_data_type<DATA_BITS>::type;
};
} // namespace uart

View File

@ -1,423 +0,0 @@
#pragma once
#include "../clock.hpp"
#include <cmath>
#include <cstdint>
namespace uart {
enum class Mode {
ASYNCHRONOUS,
SYNCHRONOUS_MASTER,
SYNCHRONOUS_SLAVE,
SPI,
};
enum class Driven {
INTERRUPT,
BLOCKING,
};
namespace detail {
using reg_ptr_t = volatile std::uint8_t *;
template <std::uintptr_t Address>
static inline reg_ptr_t getRegPtr()
{
return reinterpret_cast<reg_ptr_t>(Address);
}
template <typename data_t, std::uint8_t Size>
struct RingBuffer {
std::uint8_t head;
std::uint8_t tail;
data_t buf[Size];
};
template <class Registers, typename CtrlFlagsA, typename CtrlFlagsB, typename CtrlFlagsC, class cfg, Driven driven,
Mode mode>
class Hardware {
public:
[[gnu::always_inline]] static void init()
{
constexpr auto AbsDoubleError = std::fabs(calcBaudError<true>());
constexpr auto AbsNormalError = std::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<std::uint8_t>(BaudVal >> 8);
*getRegPtr<Registers::BAUD_REG_L_ADDR>() = static_cast<std::uint8_t>(BaudVal);
constexpr auto DataBitsValues = calcDataBits();
constexpr auto ParityVal = calcParity();
constexpr auto StopBitsVal = calcStopBits();
constexpr auto ModeVal = calcMode();
constexpr auto EnableRx = calcRxState<true>();
constexpr auto EnableTx = calcTxState<true>();
constexpr auto InterruptVal = calcInterrupt();
constexpr std::uint8_t ControlRegB = DataBitsValues.regBVal | EnableRx | EnableTx | InterruptVal;
constexpr std::uint8_t ControlRegC = DataBitsValues.regCVal | ParityVal | StopBitsVal | ModeVal;
auto ctrlStatRegA = getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>();
if constexpr (UseDoubleSpeed)
*ctrlStatRegA = *ctrlStatRegA | (1 << CtrlFlagsA::SPEED_2X);
else
*ctrlStatRegA = *ctrlStatRegA & ~(1 << CtrlFlagsA::SPEED_2X);
*getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() = ControlRegB;
*getRegPtr<Registers::CTRL_STAT_REG_C_ADDR>() = ControlRegC;
}
[[gnu::always_inline]] static bool rxByteBlocking(typename cfg::data_t &byte)
{
if (*getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() & (1 << CtrlFlagsA::RECEIVE_COMPLETE)) {
byte = *getRegPtr<Registers::IO_REG_ADDR>();
return true;
}
return false;
}
[[gnu::always_inline]] static typename cfg::data_t rxByteInterrupt()
{
return *getRegPtr<Registers::IO_REG_ADDR>();
}
[[gnu::always_inline]] static bool txEmpty()
{
return *getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() & (1 << CtrlFlagsA::DATA_REG_EMPTY);
}
[[gnu::always_inline]] static bool txComplete()
{
return *getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() & (1 << CtrlFlagsA::TRANSMIT_COMPLETE);
}
[[gnu::always_inline]] static void clearTxComplete()
{
*getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() |= (1 << CtrlFlagsA::TRANSMIT_COMPLETE);
}
[[gnu::always_inline]] static void txByteBlocking(const typename cfg::data_t &byte)
{
while (!txEmpty())
;
*getRegPtr<Registers::IO_REG_ADDR>() = byte;
}
[[gnu::always_inline]] static void txByteInterrupt(volatile const typename cfg::data_t &byte)
{
*getRegPtr<Registers::IO_REG_ADDR>() = byte;
}
[[gnu::always_inline]] static bool peekBlocking()
{
if (*getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() & (1 << CtrlFlagsA::RECEIVE_COMPLETE)) {
return true;
}
return false;
}
[[gnu::always_inline]] static void enableDataRegEmptyInt()
{
auto ctrlStatRegB = getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>();
*ctrlStatRegB = *ctrlStatRegB | (1 << CtrlFlagsB::DATA_REG_EMPTY_INT_ENABLE);
}
[[gnu::always_inline]] static void disableDataRegEmptyInt()
{
auto ctrlStatRegB = getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>();
*ctrlStatRegB = *ctrlStatRegB & ~(1 << CtrlFlagsB::DATA_REG_EMPTY_INT_ENABLE);
}
private:
struct DataBitsVal {
std::uint8_t regCVal = 0;
std::uint8_t regBVal = 0;
};
template <bool DoubleSpeed = true>
static constexpr auto calcBaudVal()
{
if constexpr (DoubleSpeed) {
constexpr auto BaudVal = static_cast<std::uint16_t>(round(F_CPU / (8.0 * cfg::BAUD_RATE) - 1));
return BaudVal;
}
constexpr auto BaudVal = static_cast<std::uint16_t>(round(F_CPU / (16.0 * cfg::BAUD_RATE) - 1));
return BaudVal;
}
template <std::uint16_t BaudVal, bool DoubleSpeed = true>
static constexpr auto calcBaudRate()
{
if constexpr (DoubleSpeed) {
constexpr auto BaudRate = static_cast<std::uint32_t>(round(F_CPU / (8.0 * (BaudVal + 1))));
return BaudRate;
}
constexpr auto BaudRate = static_cast<std::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()
{
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()
{
std::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()
{
std::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");
std::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()
{
std::uint8_t enableVal = 0;
if (Enable)
enableVal = (1 << CtrlFlagsB::RX_ENABLE);
return enableVal;
}
template <bool Enable>
static constexpr auto calcTxState()
{
std::uint8_t enableVal = 0;
if (Enable)
enableVal = (1 << CtrlFlagsB::TX_ENABLE);
return enableVal;
}
static constexpr auto calcInterrupt()
{
std::uint8_t interruptVal = 0;
if (driven == Driven::INTERRUPT)
interruptVal = (1 << CtrlFlagsB::RX_INT_ENABLE);
return interruptVal;
}
};
template <class Registers, typename CtrlFlagsA, typename CtrlFlagsB, typename CtrlFlagsC, class cfg, Mode mode>
class BlockingHardware {
public:
using data_t = typename cfg::data_t;
static constexpr auto DATA_BITS = cfg::DATA_BITS;
[[gnu::always_inline]] static void init()
{
HardwareImpl::init();
}
[[gnu::always_inline]] static void txByte(const data_t &byte)
{
HardwareImpl::txByteBlocking(byte);
}
[[gnu::always_inline]] static bool rxByte(data_t &byte)
{
return HardwareImpl::rxByteBlocking(byte);
}
[[gnu::always_inline]] static bool peek(data_t &)
{
static_assert(util::always_false_v<data_t>, "Peek with data is not supported in blocking mode");
return false;
}
[[gnu::always_inline]] static bool peek()
{
return HardwareImpl::peekBlocking();
}
[[gnu::always_inline]] static void flushTx()
{
while (!HardwareImpl::txEmpty())
;
while (!HardwareImpl::txComplete())
;
HardwareImpl::clearTxComplete();
}
private:
using HardwareImpl = Hardware<Registers, CtrlFlagsA, CtrlFlagsB, CtrlFlagsC, cfg, Driven::BLOCKING, mode>;
};
template <class Registers, typename CtrlFlagsA, typename CtrlFlagsB, typename CtrlFlagsC, class cfg, Mode mode>
class InterruptHardware {
public:
using data_t = typename cfg::data_t;
static constexpr auto DATA_BITS = cfg::DATA_BITS;
[[gnu::always_inline]] static void txByte(const data_t &byte)
{
std::uint8_t tmpHead = (sm_txBuf.head + 1) % TX_BUFFER_SIZE;
while (tmpHead == sm_txBuf.tail)
;
sm_txBuf.buf[tmpHead] = byte;
sm_txBuf.head = tmpHead;
HardwareImpl::enableDataRegEmptyInt();
}
[[gnu::always_inline]] static bool rxByte(data_t &byte)
{
if (sm_rxBuf.head == sm_rxBuf.tail)
return false;
std::uint8_t tmpTail = (sm_rxBuf.tail + 1) % RX_BUFFER_SIZE;
byte = sm_rxBuf.buf[tmpTail];
sm_rxBuf.tail = tmpTail;
return true;
}
[[gnu::always_inline]] static bool peek(data_t &byte)
{
if (sm_rxBuf.head == sm_rxBuf.tail)
return false;
std::uint8_t tmpTail = (sm_rxBuf.tail + 1) % RX_BUFFER_SIZE;
byte = sm_rxBuf.buf[tmpTail];
return true;
}
[[gnu::always_inline]] static bool peek()
{
return (sm_rxBuf.head != sm_rxBuf.tail);
}
[[gnu::always_inline]] static void flushTx()
{
while (sm_txBuf.head != sm_txBuf.tail)
;
while (!HardwareImpl::txEmpty())
;
while (!HardwareImpl::txComplete())
;
HardwareImpl::clearTxComplete();
}
protected:
[[gnu::always_inline]] static void rxIntHandler()
{
const auto data = HardwareImpl::rxByteInterrupt();
const std::uint8_t tmpHead = (sm_rxBuf.head + 1) % RX_BUFFER_SIZE;
if (tmpHead != sm_rxBuf.tail) {
sm_rxBuf.head = tmpHead;
sm_rxBuf.buf[tmpHead] = data;
} else {
// TODO: Handle overflow
}
}
[[gnu::always_inline]] static void dataRegEmptyIntHandler()
{
if (sm_txBuf.head != sm_txBuf.tail) {
const std::uint8_t tmpTail = (sm_txBuf.tail + 1) % TX_BUFFER_SIZE;
sm_txBuf.tail = tmpTail;
HardwareImpl::txByteInterrupt(sm_txBuf.buf[tmpTail]);
} else
HardwareImpl::disableDataRegEmptyInt();
}
private:
using HardwareImpl = Hardware<Registers, CtrlFlagsA, CtrlFlagsB, CtrlFlagsC, cfg, Driven::INTERRUPT, mode>;
static constexpr auto TX_BUFFER_SIZE = 16;
static constexpr auto RX_BUFFER_SIZE = 16;
static volatile RingBuffer<data_t, TX_BUFFER_SIZE> sm_txBuf;
static volatile RingBuffer<data_t, RX_BUFFER_SIZE> sm_rxBuf;
};
template <class Registers, typename CtrlFlagsA, typename CtrlFlagsB, typename CtrlFlagsC, class cfg, Mode mode>
volatile RingBuffer<typename InterruptHardware<Registers, CtrlFlagsA, CtrlFlagsB, CtrlFlagsC, cfg, mode>::data_t,
InterruptHardware<Registers, CtrlFlagsA, CtrlFlagsB, CtrlFlagsC, cfg, mode>::TX_BUFFER_SIZE>
InterruptHardware<Registers, CtrlFlagsA, CtrlFlagsB, CtrlFlagsC, cfg, mode>::sm_txBuf = {0, 0, {0}};
template <class Registers, typename CtrlFlagsA, typename CtrlFlagsB, typename CtrlFlagsC, class cfg, Mode mode>
volatile RingBuffer<typename InterruptHardware<Registers, CtrlFlagsA, CtrlFlagsB, CtrlFlagsC, cfg, mode>::data_t,
InterruptHardware<Registers, CtrlFlagsA, CtrlFlagsB, CtrlFlagsC, cfg, mode>::RX_BUFFER_SIZE>
InterruptHardware<Registers, CtrlFlagsA, CtrlFlagsB, CtrlFlagsC, cfg, mode>::sm_rxBuf = {0, 0, {0}};
} // namespace detail
} // namespace uart

View File

@ -1,152 +0,0 @@
#pragma once
#include <cstdint>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include "config.hpp"
#include "hardware.hpp"
namespace uart {
namespace detail {
#if defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega328P__)
/*
The following works in avr-gcc 5.4.0, but is not legal C++, because ptr's are not legal constexpr's:
constexpr auto *foo = ptr;
Workaround is to store the the address of the ptr in a uintptr_t and reinterpret_cast it at call site.
The _SFR_ADDR macro in sfr_defs.h would give the address, but it does that by taking the address of the dereferenced
pointer and casts it to uint16_t, which is still not a legal constexpr.
The workaround therefore is to disable the pointer cast and dereference macro _MMIO_BYTE temporarily.
*/
#pragma push_macro("_MMIO_BYTE")
#undef _MMIO_BYTE
#define _MMIO_BYTE
struct Registers0 {
static constexpr std::uintptr_t IO_REG_ADDR = UDR0;
static constexpr std::uintptr_t CTRL_STAT_REG_A_ADDR = UCSR0A;
static constexpr std::uintptr_t CTRL_STAT_REG_B_ADDR = UCSR0B;
static constexpr std::uintptr_t CTRL_STAT_REG_C_ADDR = UCSR0C;
static constexpr std::uintptr_t BAUD_REG_L_ADDR = UBRR0L;
static constexpr std::uintptr_t BAUD_REG_H_ADDR = UBRR0H;
};
#pragma pop_macro("_MMIO_BYTE")
enum class ControlFlagsA0 {
MULTI_PROC_COMM_MODE = MPCM0,
SPEED_2X = U2X0,
PARITY_ERROR = UPE0,
DATA_OVER_RUN = DOR0,
FRAME_ERROR = FE0,
DATA_REG_EMPTY = UDRE0,
TRANSMIT_COMPLETE = TXC0,
RECEIVE_COMPLETE = RXC0,
};
enum class ControlFlagsB0 {
TX_DATA_BIT_8 = TXB80,
RX_DATA_BIT_8 = RXB80,
CHAR_SIZE_2 = UCSZ02,
TX_ENABLE = TXEN0,
RX_ENABLE = RXEN0,
DATA_REG_EMPTY_INT_ENABLE = UDRIE0,
TX_INT_ENABLE = TXCIE0,
RX_INT_ENABLE = RXCIE0,
};
enum class ControlFlagsC0 {
CLK_POLARITY = UCPOL0,
CHAR_SIZE_0 = UCSZ00,
CHAR_SIZE_1 = UCSZ01,
STOP_BIT_SEL = USBS0,
PARITY_MODE_0 = UPM00,
PARITY_MODE_1 = UPM01,
MODE_SEL_0 = UMSEL00,
MODE_SEL_1 = UMSEL01,
};
// clang-format off
constexpr int operator<<(const int &lhs, const ControlFlagsA0 &rhs) { return lhs << static_cast<int>(rhs); }
constexpr int operator<<(const int &lhs, const ControlFlagsB0 &rhs) { return lhs << static_cast<int>(rhs); }
constexpr int operator<<(const int &lhs, const ControlFlagsC0 &rhs) { return lhs << static_cast<int>(rhs); }
// clang-format on
#if defined(__AVR_ATmega328P__)
#define USART0_RX_vect USART_RX_vect
#define USART0_UDRE_vect USART_UDRE_vect
#endif
#else
#error "This chip is not supported"
#endif
} // namespace detail
template <class cfg = Config<>, Driven driven = Driven::INTERRUPT, Mode mode = Mode::ASYNCHRONOUS>
class Hardware0 : public detail::BlockingHardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, mode> {
};
template <class cfg, Mode mode>
class Hardware0<cfg, Driven::INTERRUPT, mode>
: public detail::InterruptHardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, mode> {
public:
[[gnu::always_inline]] static void init()
{
HardwareImpl::init();
sei();
}
private:
using HardwareImpl = detail::Hardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, Driven::INTERRUPT, mode>;
using InterruptHardwareImpl = detail::InterruptHardware<detail::Registers0, detail::ControlFlagsA0,
detail::ControlFlagsB0, detail::ControlFlagsC0, cfg, mode>;
// Must be friends with Uart interface to call these private handlers
template <class Driver>
friend class Uart;
[[gnu::always_inline]] static void rxIntHandler()
{
InterruptHardwareImpl::rxIntHandler();
}
[[gnu::always_inline]] static void dataRegEmptyIntHandler()
{
InterruptHardwareImpl::dataRegEmptyIntHandler();
}
};
} // namespace uart
//////////////////////////////////////////////////////////////////////////
// Forward declare interrupt functions to allow adding them as friends
extern "C" {
void USART0_RX_vect() __attribute__((signal));
void USART0_UDRE_vect() __attribute__((signal));
}
// clang-format off
#define REGISTER_UART0_INT_VECTORS(uart_type) \
ISR(USART0_RX_vect) \
{ \
uart_type::rxIntHandler(); \
} \
ISR(USART0_UDRE_vect) \
{ \
uart_type::dataRegEmptyIntHandler(); \
} \
struct _##uart_type {}
// clang-format on

View File

@ -1,157 +0,0 @@
#pragma once
#include <cstdint>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include "config.hpp"
#include "hardware.hpp"
namespace uart {
namespace detail {
#if defined(__AVR_ATmega1284P__)
/*
The following works in avr-gcc 5.4.0, but is not legal C++, because ptr's are not legal constexpr's:
constexpr auto *foo = ptr;
Workaround is to store the the address of the ptr in a uintptr_t and reinterpret_cast it at call site.
The _SFR_ADDR macro in sfr_defs.h would give the address, but it does that by taking the address of the dereferenced
pointer and casts it to uint16_t, which is still not a legal constexpr.
The workaround therefore is to disable the pointer cast and dereference macro _MMIO_BYTE temporarily.
*/
#pragma push_macro("_MMIO_BYTE")
#undef _MMIO_BYTE
#define _MMIO_BYTE
struct Registers1 {
static constexpr std::uintptr_t IO_REG_ADDR = UDR1;
static constexpr std::uintptr_t CTRL_STAT_REG_A_ADDR = UCSR1A;
static constexpr std::uintptr_t CTRL_STAT_REG_B_ADDR = UCSR1B;
static constexpr std::uintptr_t CTRL_STAT_REG_C_ADDR = UCSR1C;
static constexpr std::uintptr_t BAUD_REG_L_ADDR = UBRR1L;
static constexpr std::uintptr_t BAUD_REG_H_ADDR = UBRR1H;
};
#pragma pop_macro("_MMIO_BYTE")
enum class ControlFlagsA1 {
MULTI_PROC_COMM_MODE = MPCM1,
SPEED_2X = U2X1,
PARITY_ERROR = UPE1,
DATA_OVER_RUN = DOR1,
FRAME_ERROR = FE1,
DATA_REG_EMPTY = UDRE1,
TRANSMIT_COMPLETE = TXC1,
RECEIVE_COMPLETE = RXC1,
};
enum class ControlFlagsB1 {
TX_DATA_BIT_8 = TXB81,
RX_DATA_BIT_8 = RXB81,
CHAR_SIZE_2 = UCSZ12,
TX_ENABLE = TXEN1,
RX_ENABLE = RXEN1,
DATA_REG_EMPTY_INT_ENABLE = UDRIE1,
TX_INT_ENABLE = TXCIE1,
RX_INT_ENABLE = RXCIE1,
};
enum class ControlFlagsC1 {
CLK_POLARITY = UCPOL1,
CHAR_SIZE_0 = UCSZ10,
CHAR_SIZE_1 = UCSZ11,
STOP_BIT_SEL = USBS1,
PARITY_MODE_0 = UPM10,
PARITY_MODE_1 = UPM11,
MODE_SEL_0 = UMSEL10,
MODE_SEL_1 = UMSEL11,
};
// clang-format off
constexpr int operator<<(const int &lhs, const ControlFlagsA1 &rhs) { return lhs << static_cast<int>(rhs); }
constexpr int operator<<(const int &lhs, const ControlFlagsB1 &rhs) { return lhs << static_cast<int>(rhs); }
constexpr int operator<<(const int &lhs, const ControlFlagsC1 &rhs) { return lhs << static_cast<int>(rhs); }
// clang-format on
#define HAS_UART1
#endif
} // namespace detail
#ifdef HAS_UART1
template <class cfg = Config<>, Driven driven = Driven::INTERRUPT, Mode mode = Mode::ASYNCHRONOUS>
class Hardware1 : public detail::BlockingHardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, mode> {
};
template <class cfg, Mode mode>
class Hardware1<cfg, Driven::INTERRUPT, mode>
: public detail::InterruptHardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, mode> {
public:
[[gnu::always_inline]] static void init()
{
HardwareImpl::init();
sei();
}
private:
using HardwareImpl = detail::Hardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, Driven::INTERRUPT, mode>;
using InterruptHardwareImpl = detail::InterruptHardware<detail::Registers1, detail::ControlFlagsA1,
detail::ControlFlagsB1, detail::ControlFlagsC1, cfg, mode>;
// Must be friends with Uart interface to call these private handlers
template <class Driver>
friend class Uart;
[[gnu::always_inline]] static void rxIntHandler()
{
InterruptHardwareImpl::rxIntHandler();
}
[[gnu::always_inline]] static void dataRegEmptyIntHandler()
{
InterruptHardwareImpl::dataRegEmptyIntHandler();
}
};
#endif
} // namespace uart
//////////////////////////////////////////////////////////////////////////
#ifdef HAS_UART1
// Forward declare interrupt functions to allow adding them as friends
extern "C" {
void USART1_RX_vect() __attribute__((signal));
void USART1_UDRE_vect() __attribute__((signal));
}
// clang-format off
#define REGISTER_UART1_INT_VECTORS(uart_type) \
ISR(USART1_RX_vect) \
{ \
uart_type::rxIntHandler(); \
} \
ISR(USART1_UDRE_vect) \
{ \
uart_type::dataRegEmptyIntHandler(); \
} \
struct _##uart_type { \
}
// clang-format off
#endif

View File

@ -1,21 +0,0 @@
#pragma once
#include "config.hpp"
#include "../io/io.hpp"
#include "../util/util.hpp"
namespace uart {
template <io::P rxPin, io::P txPin, class cfg = Config<>>
class Software {
static_assert(util::always_false_v<cfg>, "Not implemented");
public:
using data_t = typename cfg::data_t;
static constexpr auto DATA_BITS = cfg::DATA_BITS;
static void init() {}
};
} // namespace uart

22
uart.atsln Normal file
View File

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Atmel Studio Solution File, Format Version 11.00
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{E66E83B9-2572-4076-B26E-6BE79FF3018A}") = "uart", "uart\uart.cppproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|AVR = Debug|AVR
Release|AVR = Release|AVR
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.ActiveCfg = Debug|AVR
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.Build.0 = Debug|AVR
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.ActiveCfg = Release|AVR
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.Build.0 = Release|AVR
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

389
uart.hpp
View File

@ -1,389 +0,0 @@
#pragma once
#include <limits>
#include <cstdint>
#include "config.hpp"
#include "software.hpp"
#include "hardware0.hpp"
#include "hardware1.hpp"
#include "../flash/flash.hpp"
#include "../util/util.hpp"
namespace uart {
namespace detail {
template <typename T, T Limit, std::size_t Base>
static constexpr std::size_t cntDigits()
{
T num = Limit;
std::size_t cnt = 0;
do {
num /= Base;
++cnt;
} while (num > 0);
return cnt;
}
template <typename T, std::size_t Base>
static constexpr std::size_t maxNumDigits()
{
constexpr T MinVal = std::numeric_limits<T>::min();
constexpr T MaxVal = std::numeric_limits<T>::max();
constexpr T MinDigits = cntDigits<T, MinVal, Base>();
constexpr T MaxDigits = cntDigits<T, MaxVal, Base>();
return (MinDigits < MaxDigits) ? MaxDigits : MinDigits;
}
} // namespace detail
template <class Driver>
class Uart {
public:
using data_t = typename Driver::data_t;
// Constructing a uart object does not initialize the driver to allow different specializations with the same
// back-end to exists at the same time
// Note that init must be called every time when switching specializations with the same back-end
Uart() = default;
// Moving and copying uart objects is not supported
Uart(const Uart &) = delete;
Uart(Uart &&) = delete;
Uart &operator=(const Uart &) = delete;
Uart &operator=(Uart &&) = delete;
// Before using the uart init must be called
static void init()
{
Driver::init();
}
static void txByte(const data_t &byte)
{
Driver::txByte(byte);
}
static bool rxByte(data_t &byte)
{
return Driver::rxByte(byte);
}
static bool peek(data_t &byte)
{
return Driver::peek(byte);
}
static bool peek()
{
return Driver::peek();
}
static void flushTx()
{
Driver::flushTx();
}
static void txString(const char *str)
{
static_assert(Driver::DATA_BITS == DataBits::EIGHT, "Strings are only supported with 8 data bits");
while (char ch = *str++)
txByte(ch);
}
static void txString(const ::detail::FlashString *str)
{
static_assert(Driver::DATA_BITS == DataBits::EIGHT, "Strings are only supported with 8 data bits");
const char *strIt = reinterpret_cast<const char *>(str);
while (char ch = pgm_read_byte(strIt++))
txByte(ch);
}
template <typename T, std::size_t Base = 10, std::size_t Padding = 0, char PadChar = '0', bool LowerCase = true>
static void txNumber(const T &val)
{
static_assert(std::is_integral_v<T>, "Only supported on integral types");
static_assert(Base >= 2, "Numbers with base less than 2 make no sense");
static_assert(Base <= 16, "Numbers with base higher than 16 are not supported");
static_assert(Padding <= detail::maxNumDigits<T, Base>(), "Cannot pad more than maximum length of number");
constexpr char AlphaChar = (LowerCase) ? 'a' : 'A';
constexpr std::size_t NumDigits = detail::maxNumDigits<T, Base>();
T digits = val;
if (digits < 0) {
digits = -digits;
txByte('-');
}
data_t buffer[NumDigits];
data_t *bufEnd = buffer + NumDigits - 1;
do {
const data_t lastDigit = digits % Base;
*bufEnd-- = (lastDigit < 10) ? ('0' + lastDigit) : (AlphaChar + lastDigit - 10);
digits /= Base;
} while (digits > 0);
if (Padding > 0) {
std::size_t strLen = buffer + NumDigits - (bufEnd + 1);
if (Padding > strLen) {
for (std::size_t i = Padding; i > strLen && bufEnd >= buffer; --i) {
*bufEnd-- = PadChar;
}
}
}
for (data_t *buf = bufEnd + 1; buf < buffer + NumDigits; ++buf)
txByte(*buf);
}
//////////////////////////////////////////////////////////////////////////
// Output stream overloads
Uart &operator<<(const char *str)
{
txString(str);
return *this;
}
Uart &operator<<(const ::detail::FlashString *str)
{
txString(str);
return *this;
}
Uart &operator<<(const char &val)
{
txByte(val);
return *this;
}
Uart &operator<<(const signed char &val)
{
txNumber(val);
return *this;
}
Uart &operator<<(const unsigned char &val)
{
txNumber(val);
return *this;
}
Uart &operator<<(const short &val)
{
txNumber(val);
return *this;
}
Uart &operator<<(const unsigned short &val)
{
txNumber(val);
return *this;
}
Uart &operator<<(const int &val)
{
txNumber(val);
return *this;
}
Uart &operator<<(const unsigned int &val)
{
txNumber(val);
return *this;
}
Uart &operator<<(const long &val)
{
txNumber(val);
return *this;
}
Uart &operator<<(const unsigned long &val)
{
txNumber(val);
return *this;
}
Uart &operator<<(const long long &val)
{
txNumber(val);
return *this;
}
Uart &operator<<(const unsigned long long &val)
{
txNumber(val);
return *this;
}
template <typename... Ts>
Uart &operator<<(float) const
{
static_assert(util::always_false_v<Ts...>, "Not supported by hardware");
}
template <typename... Ts>
Uart &operator<<(double) const
{
static_assert(util::always_false_v<Ts...>, "Not supported by hardware");
}
template <typename... Ts>
Uart &operator<<(long double) const
{
static_assert(util::always_false_v<Ts...>, "Not supported by hardware");
}
Uart &operator<<(const bool &val)
{
txString(val ? F("true") : F("false"));
return *this;
}
Uart &operator<<(const void *val)
{
txString(F("0x"));
txNumber<std::uint16_t, 16, 4, '0', false>(reinterpret_cast<std::uint16_t>(val));
return *this;
}
//////////////////////////////////////////////////////////////////////////
// Input stream overloads
template <typename... Ts>
Uart &operator>>(char &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned char &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(short &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned short &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(int &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned int &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(long &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned long &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(long long &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned long long &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(float &) const
{
static_assert(util::always_false_v<Ts...>, "Not supported by hardware");
}
template <typename... Ts>
Uart &operator>>(double &) const
{
static_assert(util::always_false_v<Ts...>, "Not supported by hardware");
}
template <typename... Ts>
Uart &operator>>(long double &) const
{
static_assert(util::always_false_v<Ts...>, "Not supported by hardware");
}
template <typename... Ts>
Uart &operator>>(bool &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(const void *&) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
private:
friend void ::USART0_RX_vect();
friend void ::USART0_UDRE_vect();
#ifdef HAS_UART1
friend void ::USART1_RX_vect();
friend void ::USART1_UDRE_vect();
#endif
[[gnu::always_inline]] static void rxIntHandler()
{
Driver::rxIntHandler();
}
[[gnu::always_inline]] static void dataRegEmptyIntHandler()
{
Driver::dataRegEmptyIntHandler();
}
};
template <typename cfg = Config<>>
using Uart0 = Uart<Hardware0<cfg, Driven::INTERRUPT, Mode::ASYNCHRONOUS>>;
#ifdef HAS_UART1
template <typename cfg = Config<>>
using Uart1 = Uart<Hardware1<cfg, Driven::INTERRUPT, Mode::ASYNCHRONOUS>>;
#endif
} // namespace uart
#undef HAS_UART1

4
uart/clock.hpp Normal file
View File

@ -0,0 +1,4 @@
#pragma once
#define F_CPU 16'000'000
#include <util/delay.h>

1
uart/flash Submodule

@ -0,0 +1 @@
Subproject commit 6edb2e5a21e0ce58ff2df936caee8b84e240a46b

1
uart/io Submodule

@ -0,0 +1 @@
Subproject commit 80de36ee7ee3e6b0842d5eaee81d54062cb496b2

283
uart/main.cpp Normal file
View File

@ -0,0 +1,283 @@
#include "clock.hpp"
#include <avr/interrupt.h>
#include <stdint.h>
#include "flash/flash.hpp"
#include "io/io.hpp"
#include "uart/uart.hpp"
using uart0_interface_t =
uart::Uart<uart::Hardware0<uart::Config<115200>, uart::Driven::INTERRUPT, uart::Mode::ASYNCHRONOUS>>;
using uart1_interface_t = uart::Uart1<>;
REGISTER_UART0_INT_VECTORS(uart0_interface_t);
REGISTER_UART1_INT_VECTORS(uart1_interface_t);
void doubleSpeedTest()
{
uart0_interface_t serial;
serial.init();
uint8_t counter = 100;
uint8_t data;
while (counter) {
if (serial.rxByte(data)) {
serial.txByte(data);
--counter;
}
}
serial << F("\r\n");
serial.flushTx();
}
void newUartUsage()
{
using namespace uart;
Uart<Hardware0<Config<115200>, Driven::BLOCKING, Mode::ASYNCHRONOUS>> serial;
serial.init();
serial << "New uart hi from RAM. " << F("New uart hi from flash\r\n");
while (false) {
uint8_t received = 0;
while (!serial.peek())
;
{
serial << F("Peeked: ");
serial.txByte(received);
serial << F("\r\n");
}
if (serial.rxByte(received)) {
serial << F("Received: ");
serial.txByte(received);
serial << F("\r\n");
}
}
serial.flushTx();
}
void newUartUsage2()
{
uart1_interface_t serial1;
auto ramString = "Hello World from RAM. ";
auto flashString = F("Hello World from flash\r\n");
serial1.init();
serial1 << ramString;
serial1 << flashString;
serial1.flushTx();
}
void newUartStreamOverloads()
{
using namespace uart;
Uart<Hardware0<Config<115200>, Driven::BLOCKING, Mode::ASYNCHRONOUS>> serial;
serial.init();
bool bVal = true;
char chVal = 'c';
signed char schVal = 's';
unsigned char uchVal = 'u';
short shVal = -12345;
unsigned short ushVal = 64123;
int iVal = -14321;
unsigned int uiVal = 32146;
long lVal = -571474496;
unsigned long ulVal = 2718958144;
long long llVal = -45197516864960;
unsigned long long ullVal = 4611685969606738496;
serial << F("Stream overload test:") << F("\r\n");
serial << F("bool : ") << bVal << F("\r\n");
serial << F("char : ") << chVal << F("\r\n");
serial << F("signed char : ") << schVal << F("\r\n");
serial << F("unsigned char : ") << uchVal << F("\r\n");
serial << F("short : ") << shVal << F("\r\n");
serial << F("unsigned short : ") << ushVal << F("\r\n");
serial << F("int : ") << iVal << F("\r\n");
serial << F("unsigned int : ") << uiVal << F("\r\n");
serial << F("long : ") << lVal << F("\r\n");
serial << F("unsigned long : ") << ulVal << F("\r\n");
serial << F("long long : ") << llVal << F("\r\n");
serial << F("unsigned long long : ") << ullVal << F("\r\n");
serial << F("const void : ") << &bVal << F("\r\n");
auto number = 0xBADF00D;
serial << F("Binary : 0b");
serial.txNumber<decltype(number), 2>(number);
serial << F("\r\n");
serial << F("Octal : 0");
serial.txNumber<decltype(number), 8>(number);
serial << F("\r\n");
serial << F("Decimal : ");
serial.txNumber<decltype(number), 10>(number);
serial << F("\r\n");
serial << F("Hex : 0x");
serial.txNumber<decltype(number), 16>(number);
serial << F("\r\n");
serial.flushTx();
}
namespace spi {
enum class Cpol {
MODE_0,
MODE_1,
};
enum class Cpha {
MODE_0,
MODE_1,
};
enum class DataOrder {
MSB,
LSB,
};
template <Cpol cpol, Cpha cpha, DataOrder dataOrder>
struct Config {
static constexpr auto CPOL_MODE = cpol;
static constexpr auto CPHA_MODE = cpha;
static constexpr auto DATA_ORDER = dataOrder;
};
template <class Driver>
struct spi {
spi()
{
Driver::init();
}
};
} // namespace spi
namespace uart {
template <class Config>
class Hardware0<Config, Driven::INTERRUPT, Mode::SPI> {
public:
static void init()
{
UCSR0C |= (1 << UMSEL01) | (1 << UMSEL00);
if (DATA_ORDER == spi::DataOrder::MSB)
UCSR0C &= ~(1 << UCSZ01);
else
UCSR0C |= (1 << UCSZ01);
if (CPOL_MODE == spi::Cpol::MODE_0)
UCSR0C &= ~(1 << UCPOL0);
else
UCSR0C |= (1 << UCPOL0);
if (CPHA_MODE == spi::Cpha::MODE_0)
UCSR0C &= ~(1 << UCSZ00);
else
UCSR0C |= (1 << UCSZ00);
}
private:
static constexpr auto CPOL_MODE = Config::CPOL_MODE;
static constexpr auto CPHA_MODE = Config::CPHA_MODE;
static constexpr auto DATA_ORDER = Config::DATA_ORDER;
};
} // namespace uart
void spiTest()
{
using config = spi::Config<spi::Cpol::MODE_0, spi::Cpha::MODE_0, spi::DataOrder::MSB>;
using uartspi = uart::Hardware0<config, uart::Driven::INTERRUPT, uart::Mode::SPI>;
spi::spi<uartspi> uartSpi;
}
static inline void initUart(const uint32_t baudRate)
{
UBRR0 = static_cast<uint16_t>((F_CPU + 8 * baudRate) / (16 * baudRate) - 1);
UCSR0A = 0;
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
}
static inline void txUart(uint8_t byte)
{
while (!(UCSR0A & (1 << UDRE0)))
;
UDR0 = byte;
}
static inline void txString(const char *str)
{
while (char ch = *str++)
txUart(ch);
}
static inline void txString(const detail::FlashString *str)
{
const char *strIt = reinterpret_cast<const char *>(str);
while (char ch = pgm_read_byte(strIt++))
txUart(ch);
}
static inline void flushTx()
{
while (!(UCSR0A & (1 << UDRE0)))
;
while (!(UCSR0A & (1 << TXC0)))
;
UCSR0A |= (1 << TXC0);
}
void optimalUartTest()
{
auto ramString = "Hello World from RAM. ";
auto flashString = F("Hello World from flash\r\n");
initUart(115200);
txString(ramString);
txString(flashString);
flushTx();
}
int main()
{
sei();
doubleSpeedTest();
newUartUsage2();
optimalUartTest();
newUartStreamOverloads();
txString(F("\r\n"));
flushTx();
spiTest();
return 0;
}

1
uart/uart Submodule

@ -0,0 +1 @@
Subproject commit 119de3244588b19b4afb06f33f66f22bb80a89b5

254
uart/uart.cppproj Normal file
View File

@ -0,0 +1,254 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="14.0">
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<ProjectVersion>7.0</ProjectVersion>
<ToolchainName>com.Atmel.AVRGCC8.CPP</ToolchainName>
<ProjectGuid>dce6c7e3-ee26-4d79-826b-08594b9ad897</ProjectGuid>
<avrdevice>ATmega1284P</avrdevice>
<avrdeviceseries>none</avrdeviceseries>
<OutputType>Executable</OutputType>
<Language>CPP</Language>
<OutputFileName>$(MSBuildProjectName)</OutputFileName>
<OutputFileExtension>.elf</OutputFileExtension>
<OutputDirectory>$(MSBuildProjectDirectory)\$(Configuration)</OutputDirectory>
<AssemblyName>uart</AssemblyName>
<Name>uart</Name>
<RootNamespace>uart</RootNamespace>
<ToolchainFlavour>avr-g++-9.1.0</ToolchainFlavour>
<KeepTimersRunning>true</KeepTimersRunning>
<OverrideVtor>false</OverrideVtor>
<CacheFlash>true</CacheFlash>
<ProgFlashFromRam>true</ProgFlashFromRam>
<RamSnippetAddress>0x20000000</RamSnippetAddress>
<UncachedRange />
<preserveEEPROM>true</preserveEEPROM>
<OverrideVtorValue>exception_table</OverrideVtorValue>
<BootSegment>2</BootSegment>
<ResetRule>0</ResetRule>
<eraseonlaunchrule>0</eraseonlaunchrule>
<EraseKey />
<avrtool>
</avrtool>
<avrtoolserialnumber>J41800099437</avrtoolserialnumber>
<avrdeviceexpectedsignature>0x1E950F</avrdeviceexpectedsignature>
<com_atmel_avrdbg_tool_jtagicemkii>
<ToolOptions>
<InterfaceProperties>
<IspClock>0</IspClock>
</InterfaceProperties>
<InterfaceName>ISP</InterfaceName>
</ToolOptions>
<ToolType>com.atmel.avrdbg.tool.jtagicemkii</ToolType>
<ToolNumber>070000004699</ToolNumber>
<ToolName>JTAGICE mkII</ToolName>
</com_atmel_avrdbg_tool_jtagicemkii>
<avrtoolinterface>ISP</avrtoolinterface>
<avrtoolinterfaceclock>125000</avrtoolinterfaceclock>
<AAFDebugger>
<AAFDebugFiles>
<DebugFile>
<path>\Debug\uart.lss</path>
<AAFSetting>
<Label>Lss Files</Label>
<Extention>.lss</Extention>
<Regex>^\s*(?&lt;address&gt;[a-f0-9]*):\s*.*$</Regex>
<DebugEnabled>true</DebugEnabled>
<RegexGroups>address</RegexGroups>
<DebuggerExpression>$pc</DebuggerExpression>
</AAFSetting>
</DebugFile>
</AAFDebugFiles>
</AAFDebugger>
<AsfFrameworkConfig>
<framework-data xmlns="">
<options />
<configurations />
<files />
<documentation help="" />
<offline-documentation help="" />
<dependencies>
<content-extension eid="atmel.asf" uuidref="Atmel.ASF" version="3.46.0" />
</dependencies>
</framework-data>
</AsfFrameworkConfig>
<com_atmel_avrdbg_tool_atmelice>
<ToolOptions>
<InterfaceProperties>
<IspClock>125000</IspClock>
<JtagDbgClock>5000000</JtagDbgClock>
</InterfaceProperties>
<InterfaceName>ISP</InterfaceName>
</ToolOptions>
<ToolType>com.atmel.avrdbg.tool.atmelice</ToolType>
<ToolNumber>J41800099437</ToolNumber>
<ToolName>Atmel-ICE</ToolName>
</com_atmel_avrdbg_tool_atmelice>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<ToolchainSettings>
<AvrGccCpp>
<avrgcc.common.Device>-mmcu=atmega1284p</avrgcc.common.Device>
<avrgcc.common.optimization.RelaxBranches>True</avrgcc.common.optimization.RelaxBranches>
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcc.compiler.symbols.DefSymbols>
<ListValues>
<Value>NDEBUG</Value>
</ListValues>
</avrgcc.compiler.symbols.DefSymbols>
<avrgcc.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.3.300\include</Value>
</ListValues>
</avrgcc.compiler.directories.IncludePaths>
<avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
<avrgcc.compiler.warnings.ExtraWarnings>True</avrgcc.compiler.warnings.ExtraWarnings>
<avrgcc.compiler.warnings.Pedantic>True</avrgcc.compiler.warnings.Pedantic>
<avrgcc.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -std=c11</avrgcc.compiler.miscellaneous.OtherFlags>
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcccpp.compiler.symbols.DefSymbols>
<ListValues>
<Value>NDEBUG</Value>
</ListValues>
</avrgcccpp.compiler.symbols.DefSymbols>
<avrgcccpp.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.3.300\include</Value>
</ListValues>
</avrgcccpp.compiler.directories.IncludePaths>
<avrgcccpp.compiler.optimization.level>Optimize for size (-Os)</avrgcccpp.compiler.optimization.level>
<avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcccpp.compiler.warnings.AllWarnings>True</avrgcccpp.compiler.warnings.AllWarnings>
<avrgcccpp.compiler.warnings.Pedantic>True</avrgcccpp.compiler.warnings.Pedantic>
<avrgcccpp.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -Wextra -std=c++17</avrgcccpp.compiler.miscellaneous.OtherFlags>
<avrgcccpp.linker.libraries.Libraries>
<ListValues>
<Value>libm</Value>
</ListValues>
</avrgcccpp.linker.libraries.Libraries>
<avrgcccpp.assembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.3.300\include</Value>
</ListValues>
</avrgcccpp.assembler.general.IncludePaths>
</AvrGccCpp>
</ToolchainSettings>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<ToolchainSettings>
<AvrGccCpp>
<avrgcc.common.Device>-mmcu=atmega1284p</avrgcc.common.Device>
<avrgcc.common.optimization.RelaxBranches>True</avrgcc.common.optimization.RelaxBranches>
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcc.compiler.symbols.DefSymbols>
<ListValues>
<Value>DEBUG</Value>
</ListValues>
</avrgcc.compiler.symbols.DefSymbols>
<avrgcc.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.3.300\include</Value>
</ListValues>
</avrgcc.compiler.directories.IncludePaths>
<avrgcc.compiler.optimization.level>Optimize (-O1)</avrgcc.compiler.optimization.level>
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcc.compiler.optimization.DebugLevel>Maximum (-g3)</avrgcc.compiler.optimization.DebugLevel>
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
<avrgcc.compiler.warnings.ExtraWarnings>True</avrgcc.compiler.warnings.ExtraWarnings>
<avrgcc.compiler.warnings.Pedantic>True</avrgcc.compiler.warnings.Pedantic>
<avrgcc.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -std=c11</avrgcc.compiler.miscellaneous.OtherFlags>
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcccpp.compiler.symbols.DefSymbols>
<ListValues>
<Value>DEBUG</Value>
</ListValues>
</avrgcccpp.compiler.symbols.DefSymbols>
<avrgcccpp.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.3.300\include</Value>
</ListValues>
</avrgcccpp.compiler.directories.IncludePaths>
<avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcccpp.compiler.optimization.DebugLevel>Maximum (-g3)</avrgcccpp.compiler.optimization.DebugLevel>
<avrgcccpp.compiler.warnings.AllWarnings>True</avrgcccpp.compiler.warnings.AllWarnings>
<avrgcccpp.compiler.warnings.Pedantic>True</avrgcccpp.compiler.warnings.Pedantic>
<avrgcccpp.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -Wextra -std=c++17</avrgcccpp.compiler.miscellaneous.OtherFlags>
<avrgcccpp.linker.libraries.Libraries>
<ListValues>
<Value>libm</Value>
</ListValues>
</avrgcccpp.linker.libraries.Libraries>
<avrgcccpp.assembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.3.300\include</Value>
</ListValues>
</avrgcccpp.assembler.general.IncludePaths>
<avrgcccpp.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcccpp.assembler.debugging.DebugLevel>
</AvrGccCpp>
</ToolchainSettings>
</PropertyGroup>
<ItemGroup>
<Compile Include="clock.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="flash\flash.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="io\io.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="main.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="uart\config.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="uart\hardware.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="uart\hardware0.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="uart\hardware1.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="uart\software.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="uart\uart.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="util\func.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="util\type.hpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="util\util.hpp">
<SubType>compile</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="io" />
<Folder Include="flash" />
<Folder Include="util" />
<Folder Include="uart" />
</ItemGroup>
<Import Project="$(AVRSTUDIO_EXE_PATH)\\Vs\\Compiler.targets" />
</Project>

1
uart/util Submodule

@ -0,0 +1 @@
Subproject commit 81b3ae244c9773e7ea8ee08af43193275db48514