Compare commits

...

71 Commits

Author SHA1 Message Date
16c9015f43 Replaced maybe_unused with unnamed parameter 2019-08-14 19:55:06 +02:00
7c21664fe4 Refactored code to get rid of code duplication 2019-08-14 19:49:42 +02:00
e326e40b38 Fixed blocking on full rx buffer and implemented support for ATmega328P 2019-08-14 18:58:21 +02:00
8d028aa635 Changed git ignore to ignore make output 2019-08-11 10:04:15 +02:00
c4700ed824 Fixed non-compliant use of constexpr for pointers 2019-08-10 14:12:10 +02:00
1ee9bc8ca4 Removed sign from maxNumDigits, because sign is handled separately anyway 2019-08-07 19:59:48 +02:00
1c026e8eb3 Updated git ignore file 2019-08-05 21:18:36 +02:00
c4f38cbcdf Changed template parameter order 2019-08-05 20:05:59 +02:00
87e6936051 Added enabling of interrupts for interrupt driven uart 2019-08-05 17:59:33 +02:00
1d633c538e Implemented numeric limits for floating point 2019-08-05 17:56:10 +02:00
231fc0de48 Changed clock header to cpp file extension 2019-08-03 20:20:20 +02:00
6438aa81c1 Added padding and case selection to txNumber 2019-08-03 19:49:01 +02:00
8153696309 Fixed flushing not blocking correctly 2019-08-03 18:45:51 +02:00
9f9f7a8de5 Added flushing of transmit buffer 2019-08-03 17:52:28 +02:00
b6c1c3b51b Fixed conversion for bases other than 10 2019-08-03 17:32:38 +02:00
8d07e2d4db Implemented overloads for printing numbers 2019-08-03 16:52:57 +02:00
fe9e67036e Implemented stream operator for some basic types 2019-08-03 16:17:07 +02:00
9f7dc0da55 Added alias for driver dependent data size 2019-08-03 16:13:52 +02:00
2a07744575 Added static_assert for transmitting numbers 2019-08-03 16:11:21 +02:00
ecdefe40e7 Implemented integral type checking 2019-08-03 16:10:19 +02:00
53b791cb05 Implemented printing of numbers 2019-08-03 15:00:41 +02:00
50e01c480d Implemented templated numeric limits 2019-08-03 14:54:23 +02:00
7d4eddbd8b Changed interface to not initialize uart on construction 2019-08-03 11:14:01 +02:00
778f5f9754 Moved always_false template to utils 2019-08-03 10:58:32 +02:00
1ca8ea2061 Removed Peter Fleury's c uart library 2019-08-03 10:47:32 +02:00
80633998c7 Removed legacy usart library 2019-08-03 10:23:53 +02:00
2cd4069654 Moved interrupt vectors to their own translation unit to solve redefinition error 2019-08-02 20:29:04 +02:00
33c3cedb1e Fixed missing headers 2019-08-02 20:23:54 +02:00
925bb56f98 Added clang format file 2019-08-02 19:44:34 +02:00
a3d76a138d Implemented peeking with and without data for interrupt and blocking mode 2019-08-02 18:20:06 +02:00
95963295e2 Implemented blocking rx 2019-08-02 17:54:34 +02:00
0bfd303a26 Removed unneeded tx complete interrupt 2019-08-02 17:41:14 +02:00
16f4be8c6c Implemented interrupt driven rx for uart0 2019-08-02 17:38:00 +02:00
efe1446907 Implemented interrupt driven rx for uart1 2019-08-02 17:36:07 +02:00
b90da9bd9c Moved ring buffer to it's own struct 2019-08-02 17:13:53 +02:00
51a9d30c0a Implemented interrupt driven tx 2019-08-02 16:41:53 +02:00
496bb3d4d1 Removed force inlining functions that would be called often 2019-08-02 16:41:34 +02:00
5d6bc4761c Changed interrupt order to match vector numbers 2019-08-02 15:46:07 +02:00
3aeb43ee1e Added basic structure to support interrupt driven operation 2019-08-02 12:18:35 +02:00
a13a1ca9ab Fixed header includes 2019-08-02 12:18:35 +02:00
bdf4bd169e Moved hardware abstraction to separate header 2019-08-02 12:18:35 +02:00
6e45340993 Removed trailing whitespaces 2019-08-01 21:51:46 +02:00
f0a3cd6da8 Improved formatting 2019-07-30 21:51:13 +02:00
6861b8f5d1 Added force inline to reduce code size 2019-07-30 21:48:00 +02:00
aac73447b3 Implemented hardware abstraction that both hardware0 and hardware1 can use 2019-07-30 21:43:52 +02:00
fbd087808a Added enums for register bit positions 2019-07-30 20:56:16 +02:00
65bbf5e96a Refactored hardware abstraction 2019-07-30 20:29:38 +02:00
c03196493a Ran clang-format 2019-07-30 20:29:15 +02:00
470eb06345 Removed unused struct 2019-07-30 18:35:45 +02:00
099be106a7 Added C uart library by Peter Fleury as comparison 2019-07-30 18:32:00 +02:00
6ded0e1c8d Fixed rounding error in baud rate calculation 2019-07-28 19:20:03 +02:00
00cb9ad13c Added alias for first hardware uart 2019-07-28 17:58:23 +02:00
4a9cee922a Refactored class names to start with capital letter 2019-07-28 17:57:49 +02:00
8e0ba5a463 Implemented basic hardware support for transmitting 2019-07-28 17:32:51 +02:00
a71035d4b7 Specified default for hardware mode 2019-07-28 14:10:48 +02:00
fd7e8e7238 Added driving parameter 2019-07-28 14:09:09 +02:00
d9a05d0273 Fixed refactoring problem 2019-07-28 14:08:41 +02:00
2bbba0fcbd Removed unnecessary const qualifiers in template 2019-07-28 14:00:46 +02:00
29b4d85ce3 Renamed settings to config 2019-07-28 12:15:19 +02:00
ae90fdae3f Renamed choosing function 2019-07-28 10:54:47 +02:00
2364bff11f Implemented automatic type deducation depending on data bits 2019-07-28 10:49:14 +02:00
f08f607265 Fixed not implemented compiler error 2019-07-28 10:35:11 +02:00
f9c34b09ba Added basic layout for new library implementation 2019-07-27 18:55:17 +02:00
e07ba7ecd8 Fixed handling for ATmega1284P 2019-07-27 18:54:51 +02:00
81e6a9fdc0 Added support for atmega8a 2018-04-12 10:44:03 +02:00
b2a3b03867 Added git ignore and attribute files 2016-08-16 16:46:33 +02:00
88eb11cc02 Added blocking receive function and peek function 2016-05-26 20:15:21 +02:00
7fd6d8ddec Added separate receive line function with timeout and removed terminating string from received line 2016-05-25 23:38:02 +02:00
c261d7d309 Added getter functions for usart settings and fixed receive flush to work for all usart settings 2016-05-25 21:22:16 +02:00
e008cc8da1 Fixed flushing receive buffer to work independent of baud rate and with and without interrupts 2016-05-25 01:40:53 +02:00
99d09b0f0f Converted to submodule 2016-05-24 21:11:44 +02:00
19 changed files with 1304 additions and 998 deletions

13
.clang-format Normal file
View File

@@ -0,0 +1,13 @@
---
BasedOnStyle: LLVM
ColumnLimit: 120
IndentWidth: 4
TabWidth: 4
UseTab: ForIndentation
AlignEscapedNewlines: DontAlign
AllowShortFunctionsOnASingleLine: Empty
AlwaysBreakTemplateDeclarations: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: true
...

8
.gitignore vendored
View File

@@ -2,4 +2,10 @@
Release
Debug
*.componentinfo.xml
avrdude.bat
*.elf
*.o
*.hex
*.srec
*.eeprom
*.lss
*.map

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "usart/array"]
path = usart/array
url = git@blackmark.me:array.git

50
config.hpp Normal file
View File

@@ -0,0 +1,50 @@
#pragma once
#include <stdint.h>
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 = uint8_t;
};
template <>
struct choose_data_type<DataBits::NINE> {
using type = uint16_t;
};
} // namespace detail
template <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

389
hardware.hpp Normal file
View File

@@ -0,0 +1,389 @@
#pragma once
#include "../clock.hpp"
#include <stdint.h>
#include "utils.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 {
using reg_ptr_t = volatile uint8_t *;
template <uintptr_t Address>
static inline reg_ptr_t getRegPtr()
{
return reinterpret_cast<reg_ptr_t>(Address);
}
template <typename data_t, uint8_t Size>
struct RingBuffer {
uint8_t head;
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:
static void init() FORCE_INLINE
{
constexpr auto baudVal = calcBaud();
*getRegPtr<Registers::BAUD_REG_H_ADDR>() = static_cast<uint8_t>(baudVal >> 8);
*getRegPtr<Registers::BAUD_REG_L_ADDR>() = 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 auto interruptVal = calcInterrupt();
constexpr uint8_t controlRegB = dataBitsVal.regBVal | enableRx | enableTx | interruptVal;
constexpr uint8_t controlRegC = dataBitsVal.regCVal | parityVal | stopBitsVal | modeVal;
*getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() = controlRegB;
*getRegPtr<Registers::CTRL_STAT_REG_C_ADDR>() = controlRegC;
}
static bool rxByteBlocking(typename cfg::data_t &byte) FORCE_INLINE
{
if (*getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() & (1 << CtrlFlagsA::RECEIVE_COMPLETE)) {
byte = *getRegPtr<Registers::IO_REG_ADDR>();
return true;
}
return false;
}
static typename cfg::data_t rxByteInterrupt() FORCE_INLINE
{
return *getRegPtr<Registers::IO_REG_ADDR>();
}
static bool txEmpty() FORCE_INLINE
{
return *getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() & (1 << CtrlFlagsA::DATA_REG_EMPTY);
}
static bool txComplete() FORCE_INLINE
{
return *getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() & (1 << CtrlFlagsA::TRANSMIT_COMPLETE);
}
static void clearTxComplete() FORCE_INLINE
{
*getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() |= (1 << CtrlFlagsA::TRANSMIT_COMPLETE);
}
static void txByteBlocking(const typename cfg::data_t &byte) FORCE_INLINE
{
while (!txEmpty())
;
*getRegPtr<Registers::IO_REG_ADDR>() = byte;
}
static void txByteInterrupt(volatile const typename cfg::data_t &byte) FORCE_INLINE
{
*getRegPtr<Registers::IO_REG_ADDR>() = byte;
}
static bool peekBlocking() FORCE_INLINE
{
if (*getRegPtr<Registers::CTRL_STAT_REG_A_ADDR>() & (1 << CtrlFlagsA::RECEIVE_COMPLETE)) {
return true;
}
return false;
}
static void enableDataRegEmptyInt() FORCE_INLINE
{
*getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() |= (1 << CtrlFlagsB::DATA_REG_EMPTY_INT_ENABLE);
}
static void disableDataRegEmptyInt() FORCE_INLINE
{
*getRegPtr<Registers::CTRL_STAT_REG_B_ADDR>() &= ~(1 << CtrlFlagsB::DATA_REG_EMPTY_INT_ENABLE);
}
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;
}
static constexpr auto calcInterrupt()
{
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;
static void init() FORCE_INLINE
{
HardwareImpl::init();
}
static void txByte(const data_t &byte) FORCE_INLINE
{
HardwareImpl::txByteBlocking(byte);
}
static bool rxByte(data_t &byte) FORCE_INLINE
{
return HardwareImpl::rxByteBlocking(byte);
}
static bool peek(data_t &) FORCE_INLINE
{
static_assert(util::always_false_v<data_t>, "Peek with data is not supported in blocking mode");
return false;
}
static bool peek() FORCE_INLINE
{
return HardwareImpl::peekBlocking();
}
static void flushTx() FORCE_INLINE
{
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;
static void txByte(const data_t &byte) FORCE_INLINE
{
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();
}
static bool rxByte(data_t &byte) FORCE_INLINE
{
if (sm_rxBuf.head == sm_rxBuf.tail)
return false;
uint8_t tmpTail = (sm_rxBuf.tail + 1) % RX_BUFFER_SIZE;
byte = sm_rxBuf.buf[tmpTail];
sm_rxBuf.tail = tmpTail;
return true;
}
static bool peek(data_t &byte) FORCE_INLINE
{
if (sm_rxBuf.head == sm_rxBuf.tail)
return false;
uint8_t tmpTail = (sm_rxBuf.tail + 1) % RX_BUFFER_SIZE;
byte = sm_rxBuf.buf[tmpTail];
return true;
}
static bool peek() FORCE_INLINE
{
return (sm_rxBuf.head != sm_rxBuf.tail);
}
static void flushTx() FORCE_INLINE
{
while (sm_txBuf.head != sm_txBuf.tail)
;
while (!HardwareImpl::txEmpty())
;
while (!HardwareImpl::txComplete())
;
HardwareImpl::clearTxComplete();
}
protected:
static void rxIntHandler()
{
auto data = HardwareImpl::rxByteInterrupt();
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
}
}
static void dataRegEmptyIntHandler() FORCE_INLINE
{
if (sm_txBuf.head != sm_txBuf.tail) {
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
#undef FORCE_INLINE

35
hardware0.cpp Normal file
View File

@@ -0,0 +1,35 @@
#include "hardware0.hpp"
#include <avr/interrupt.h>
namespace uart {
namespace detail {
#if defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega328P__)
#if defined(__AVR_ATmega328P__)
#define USART0_RX_vect USART_RX_vect
#define USART0_UDRE_vect USART_UDRE_vect
#endif
void (*fnRx0IntHandler)() = nullptr;
void (*fnDataReg0EmptyIntHandler)() = nullptr;
ISR(USART0_RX_vect)
{
if (fnRx0IntHandler)
fnRx0IntHandler();
}
ISR(USART0_UDRE_vect)
{
if (fnDataReg0EmptyIntHandler)
fnDataReg0EmptyIntHandler();
}
#else
#error "This chip is not supported"
#endif
} // namespace detail
} // namespace uart

122
hardware0.hpp Normal file
View File

@@ -0,0 +1,122 @@
#pragma once
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include "config.hpp"
#include "hardware.hpp"
#define FORCE_INLINE __attribute__((always_inline))
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
For this to work we need to temporarily disable the _SFR_MEM8 macro so that the register macro just gives the address
*/
#undef _SFR_MEM8
#define _SFR_MEM8
struct Registers0 {
static constexpr uintptr_t IO_REG_ADDR = UDR0;
static constexpr uintptr_t CTRL_STAT_REG_A_ADDR = UCSR0A;
static constexpr uintptr_t CTRL_STAT_REG_B_ADDR = UCSR0B;
static constexpr uintptr_t CTRL_STAT_REG_C_ADDR = UCSR0C;
static constexpr uintptr_t BAUD_REG_L_ADDR = UBRR0L;
static constexpr uintptr_t BAUD_REG_H_ADDR = UBRR0H;
};
#undef _SFR_MEM8
#define _SFR_MEM8(mem_addr) _MMIO_BYTE(mem_addr)
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
extern void (*fnRx0IntHandler)();
extern void (*fnDataReg0EmptyIntHandler)();
#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> {
using detail::InterruptHardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, mode>::rxIntHandler;
using detail::InterruptHardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, mode>::dataRegEmptyIntHandler;
using HardwareImpl = detail::Hardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, Driven::INTERRUPT, mode>;
public:
static void init() FORCE_INLINE
{
detail::fnRx0IntHandler = rxIntHandler;
detail::fnDataReg0EmptyIntHandler = dataRegEmptyIntHandler;
HardwareImpl::init();
sei();
}
};
} // namespace uart
#undef FORCE_INLINE

28
hardware1.cpp Normal file
View File

@@ -0,0 +1,28 @@
#include "hardware1.hpp"
#include <avr/interrupt.h>
namespace uart {
namespace detail {
#if defined(__AVR_ATmega1284P__)
void (*fnRx1IntHandler)() = nullptr;
void (*fnDataReg1EmptyIntHandler)() = nullptr;
ISR(USART1_RX_vect)
{
if (fnRx1IntHandler)
fnRx1IntHandler();
}
ISR(USART1_UDRE_vect)
{
if (fnDataReg1EmptyIntHandler)
fnDataReg1EmptyIntHandler();
}
#endif
} // namespace detail
} // namespace uart

126
hardware1.hpp Normal file
View File

@@ -0,0 +1,126 @@
#pragma once
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include "config.hpp"
#include "hardware.hpp"
#define FORCE_INLINE __attribute__((always_inline))
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
For this to work we need to temporarily disable the _SFR_MEM8 macro so that the register macro just gives the address
*/
#undef _SFR_MEM8
#define _SFR_MEM8
struct Registers1 {
static constexpr uintptr_t IO_REG_ADDR = UDR1;
static constexpr uintptr_t CTRL_STAT_REG_A_ADDR = UCSR1A;
static constexpr uintptr_t CTRL_STAT_REG_B_ADDR = UCSR1B;
static constexpr uintptr_t CTRL_STAT_REG_C_ADDR = UCSR1C;
static constexpr uintptr_t BAUD_REG_L_ADDR = UBRR1L;
static constexpr uintptr_t BAUD_REG_H_ADDR = UBRR1H;
};
#undef _SFR_MEM8
#define _SFR_MEM8(mem_addr) _MMIO_BYTE(mem_addr)
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
extern void (*fnRx1IntHandler)();
extern void (*fnDataReg1EmptyIntHandler)();
#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> {
using detail::InterruptHardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, mode>::rxIntHandler;
using detail::InterruptHardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, mode>::dataRegEmptyIntHandler;
using HardwareImpl = detail::Hardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, Driven::INTERRUPT, mode>;
public:
static void init() FORCE_INLINE
{
detail::fnRx1IntHandler = rxIntHandler;
detail::fnDataReg1EmptyIntHandler = dataRegEmptyIntHandler;
HardwareImpl::init();
sei();
}
};
#endif
} // namespace uart
#undef FORCE_INLINE

21
software.hpp Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
#include "config.hpp"
#include "utils.hpp"
#include "../io/io.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

370
uart.hpp Normal file
View File

@@ -0,0 +1,370 @@
#pragma once
#include <stdint.h>
#include "config.hpp"
#include "hardware0.hpp"
#include "hardware1.hpp"
#include "software.hpp"
#include "utils.hpp"
#include "../flash/flash.hpp"
#define FORCE_INLINE __attribute__((always_inline))
namespace uart {
namespace detail {
template <typename T, T limit, size_t Base>
static constexpr size_t cntDigits()
{
T num = limit;
size_t cnt = 0;
do {
num /= Base;
++cnt;
} while (num > 0);
return cnt;
}
template <typename T, size_t Base>
static constexpr size_t maxNumDigits()
{
constexpr T minVal = util::NumericLimits<T>::min();
constexpr T maxVal = util::NumericLimits<T>::max();
T minDigits = cntDigits<T, minVal, Base>();
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, size_t Base = 10, size_t Padding = 0, char PadChar = '0', bool LowerCase = true>
static void txNumber(const T &val)
{
static_assert(util::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 size_t numDigits = detail::maxNumDigits<T, Base>();
data_t buffer[numDigits];
data_t *bufEnd = buffer + numDigits - 1;
T digits = val;
if (digits < 0) {
digits = -digits;
txByte('-');
}
do {
data_t lastDigit = digits % Base;
*bufEnd-- = (lastDigit < 10) ? ('0' + lastDigit) : (alphaChar + lastDigit - 10);
digits /= Base;
} while (digits > 0);
if (Padding > 0) {
size_t strLen = buffer + numDigits - (bufEnd + 1);
if (Padding > strLen) {
for (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<<(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<<(unsigned long &val)
{
txNumber(val);
return *this;
}
Uart &operator<<(long long &val)
{
txNumber(val);
return *this;
}
Uart &operator<<(unsigned long long &val)
{
txNumber(val);
return *this;
}
template <typename... Ts>
Uart &operator<<(float) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(double) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(long double) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
Uart &operator<<(const bool &val)
{
txString(val ? F("true") : F("false"));
return *this;
}
Uart &operator<<(const void *val)
{
txString(F("0x"));
txNumber<uint16_t, 16, 4, '0', false>(reinterpret_cast<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 implemented");
}
template <typename... Ts>
Uart &operator>>(double &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(long double &) const
{
static_assert(util::always_false_v<Ts...>, "Not implemented");
}
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");
}
};
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 FORCE_INLINE
#undef HAS_UART1

View File

@@ -1,22 +0,0 @@
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}") = "usart", "usart\usart.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

Submodule usart/array deleted from 634564a7bb

View File

@@ -1,14 +0,0 @@
/*
* Copyright (c) by BlackMark 2015
* Date 24/11/2015
* Version 1.1
*/
#ifndef CLOCK_H
#define CLOCK_H
#define F_CPU 8000000
#include <util/delay.h>
#endif

View File

@@ -1,92 +0,0 @@
/*
* Copyright (c) by BlackMark 2015-2016
* Date 21/05/2016
* Version 1.5
*/
#include <stdio.h>
#include "clock.h"
#include "usart.h"
#include "array/array.h"
int main()
{
sei();
USART0 &cUSART = USART0::inst();
cUSART.init();
uint32_t ui32Counter = 0;
array<char, 64> arrBuffer;
cUSART << "\r\nSizes: \r\n";
sprintf( arrBuffer.data(), "%d\r\n", sizeof( char ) );
cUSART << "sizeof( char ) = " << arrBuffer.data();
sprintf( arrBuffer.data(), "%d\r\n", sizeof( unsigned char ) );
cUSART << "sizeof( unsigned char ) = " << arrBuffer.data();
sprintf( arrBuffer.data(), "%d\r\n", sizeof( short int ) );
cUSART << "sizeof( short int ) = " << arrBuffer.data();
sprintf( arrBuffer.data(), "%d\r\n", sizeof( unsigned short int ) );
cUSART << "sizeof( unsigned short int ) = " << arrBuffer.data();
sprintf( arrBuffer.data(), "%d\r\n", sizeof( int ) );
cUSART << "sizeof( int ) = " << arrBuffer.data();
sprintf( arrBuffer.data(), "%d\r\n", sizeof( unsigned int ) );
cUSART << "sizeof( unsigned int ) = " << arrBuffer.data();
sprintf( arrBuffer.data(), "%d\r\n", sizeof( long int ) );
cUSART << "sizeof( long int ) = " << arrBuffer.data();
sprintf( arrBuffer.data(), "%d\r\n", sizeof( unsigned long int ) );
cUSART << "sizeof( unsigned long int ) = " << arrBuffer.data();
sprintf( arrBuffer.data(), "%d\r\n", sizeof( long long int ) );
cUSART << "sizeof( long long int ) = " << arrBuffer.data();
sprintf( arrBuffer.data(), "%d\r\n", sizeof( unsigned long long int ) );
cUSART << "sizeof( unsigned long long int ) = " << arrBuffer.data();
sprintf( arrBuffer.data(), "%d\r\n", sizeof( float ) );
cUSART << "sizeof( float ) = " << arrBuffer.data();
sprintf( arrBuffer.data(), "%d\r\n", sizeof( double ) );
cUSART << "sizeof( double ) = " << arrBuffer.data();
sprintf( arrBuffer.data(), "%d\r\n", sizeof( long double ) );
cUSART << "sizeof( long double ) = " << arrBuffer.data();
sprintf( arrBuffer.data(), "%d\r\n\r\n", sizeof( void* ) );
cUSART << "sizeof( void* ) = " << arrBuffer.data();
while( true )
{
sprintf( arrBuffer.data(), "%lu", ui32Counter++ );
cUSART << "This has been running for \"" << arrBuffer.data() << "\" seconds!\r\n";
if( !cUSART.receiveLine( arrBuffer.data(), arrBuffer.size(), "\r" ) )
{
cUSART << "Receive error: ";
}
else
{
cUSART << "Echo: ";
}
cUSART << arrBuffer.data() << "\r\n";
uint8_t ui8Byte;
if( cUSART.receiveByte( ui8Byte, 1000 ) )
{
cUSART.transmitByte( ui8Byte );
cUSART << "\r\n";
}
}
return 0;
}

View File

@@ -1,474 +0,0 @@
#include "usart.h"
//////////////////////////////////////////////////////////////////////////
USART0 USART0::sm_cInstance;
//////////////////////////////////////////////////////////////////////////
USART0::USART0()
{
#ifdef USART_SHAREDIO
m_vui8pUCSRA = &UCSRA;
m_vui8pUCSRB = &UCSRB;
m_vui8pUCSRC = &UCSRC;
m_vui8pUBRRH = &UBRRH;
m_vui8pUBRRL = &UBRRL;
m_vui8pUDR = &UDR;
#endif
#ifndef USART_SHAREDIO
m_vui8pUCSRA = &UCSR0A;
m_vui8pUCSRB = &UCSR0B;
m_vui8pUCSRC = &UCSR0C;
m_vui8pUBRRH = &UBRR0H;
m_vui8pUBRRL = &UBRR0L;
m_vui8pUDR = &UDR0;
#endif
m_vsizeRXBufferHead = 0;
m_vsizeRXBufferTail = 0;
m_vsizeTXBufferHead = 0;
m_vsizeTXBufferTail = 0;
}
//////////////////////////////////////////////////////////////////////////
uint8_t USART0::readUCSRC()
{
uint8_t ui8UCSRC;
#ifdef USART_SHAREDIO
ui8UCSRC = UBRRH;
ui8UCSRC = UCSRC;
#else
ui8UCSRC = *m_vui8pUCSRC;
#endif
return ui8UCSRC;
}
//////////////////////////////////////////////////////////////////////////
void USART0::setUCSRC( uint8_t ui8UCSRC )
{
#ifdef USART_SHAREDIO
*m_vui8pUCSRC = ( 1 << URSEL ) | ui8UCSRC;
#else
*m_vui8pUCSRC = ui8UCSRC;
#endif
}
//////////////////////////////////////////////////////////////////////////
void USART0::setRXState( bool bEnable )
{
if( bEnable )
{
*m_vui8pUCSRB |= ( 1 << RXEN_D );
}
else
{
*m_vui8pUCSRB &= ~( 1 << RXEN_D );
}
}
//////////////////////////////////////////////////////////////////////////
void USART0::setTXState( bool bEnable )
{
if( bEnable )
{
*m_vui8pUCSRB |= ( 1 << TXEN_D );
}
else
{
*m_vui8pUCSRB &= ~( 1 << TXEN_D );
}
}
//////////////////////////////////////////////////////////////////////////
void USART0::setRXInterrupt( bool bEnable )
{
if( bEnable )
{
*m_vui8pUCSRB |= ( 1 << RXCIE_D );
}
else
{
*m_vui8pUCSRB &= ~( 1 << RXCIE_D );
}
}
//////////////////////////////////////////////////////////////////////////
void USART0::setUDREInterrupt( bool bEnable )
{
if( bEnable )
{
*m_vui8pUCSRB |= ( 1 << UDRIE_D );
}
else
{
*m_vui8pUCSRB &= ~( 1 << UDRIE_D );
}
}
//////////////////////////////////////////////////////////////////////////
void USART0::setBaudRate( uint32_t ui32BaudRate )
{
uint16_t ui16UBRR = ( ( F_CPU / ( 16 * ui32BaudRate ) ) - 1 );
*m_vui8pUBRRH = static_cast<uint8_t>( ui16UBRR >> 8 );
*m_vui8pUBRRL = static_cast<uint8_t>( ui16UBRR );
}
//////////////////////////////////////////////////////////////////////////
void USART0::setDataBits( uint8_t ui8DataBits )
{
uint8_t ui8UCSRC = readUCSRC();
if( ui8DataBits < 5 )
{
ui8DataBits = 5;
}
else if( ui8DataBits > 9 )
{
ui8DataBits = 9;
}
if( ui8DataBits <= 8 )
{
bool bZeroBit = ( ui8DataBits - 5 ) & 1;
bool bOneBit = ( ( ui8DataBits - 5 ) >> 1 ) & 1;
if( bZeroBit )
{
ui8UCSRC |= ( 1 << UCSZ0_D );
}
else
{
ui8UCSRC &= ~( 1 << UCSZ0_D );
}
if( bOneBit )
{
ui8UCSRC |= ( 1 << UCSZ1_D );
}
else
{
ui8UCSRC &= ~( 1 << UCSZ1_D );
}
*m_vui8pUCSRB &= ~( 1 << UCSZ2_D );
}
else
{
ui8UCSRC |= ( 1 << UCSZ1_D ) | ( 1 << UCSZ0_D );
*m_vui8pUCSRB |= ( 1 << UCSZ2_D );
}
setUCSRC( ui8UCSRC );
}
//////////////////////////////////////////////////////////////////////////
void USART0::setParity( Parity enmParity )
{
uint8_t ui8UCSRC = readUCSRC();
if( enmParity == Parity::DISABLED )
{
ui8UCSRC &= ~( ( 1 << UPM1_D ) | ( 1 << UPM0_D ) );
}
else if( enmParity == Parity::ODD )
{
ui8UCSRC |= ( ( 1 << UPM1_D ) | ( 1 << UPM0_D ) );
}
else if( enmParity == Parity::EVEN )
{
ui8UCSRC &= ~( ( 1 << UPM0_D ) );
ui8UCSRC |= ( ( 1 << UPM1_D ) );
}
setUCSRC( ui8UCSRC );
}
//////////////////////////////////////////////////////////////////////////
void USART0::setStopBits( StopBit enmStopBits )
{
uint8_t ui8UCSRC = readUCSRC();
if( enmStopBits == StopBit::ONE )
{
ui8UCSRC &= ~( 1 << USBS_D );
}
else if( enmStopBits == StopBit::TWO )
{
ui8UCSRC |= ( 1 << USBS_D );
}
setUCSRC( ui8UCSRC );
}
//////////////////////////////////////////////////////////////////////////
void USART0::setMode( Mode enmMode )
{
uint8_t ui8UCSRC = readUCSRC();
#ifdef USART_SPI
if( enmMode == Mode::ASYNCHRONOUS )
{
ui8UCSRC &= ~( ( 1 << UMSEL1_D ) | ( 1 << UMSEL0_D ) );
}
else if( enmMode == Mode::SYNCHRONOUS )
{
ui8UCSRC &= ~( 1 << UMSEL1_D );
ui8UCSRC |= ( 1 << UMSEL0_D );
}
else if( enmMode == Mode::MASTERSPI )
{
ui8UCSRC |= ( ( 1 << UMSEL1_D ) | ( 1 << UMSEL0_D ) );
}
#else
if( enmMode == Mode::ASYNCHRONOUS )
{
ui8UCSRC &= ~( 1 << UMSEL_D );
}
else if( enmMode == Mode::SYNCHRONOUS )
{
ui8UCSRC |= ( 1 << UMSEL_D );
}
#endif
setUCSRC( ui8UCSRC );
}
//////////////////////////////////////////////////////////////////////////
USART0::~USART0()
{
flushTransmit();
setBaudRate( 0 );
setRXState( false );
setTXState( false );
setRXInterrupt( false );
setUDREInterrupt( false );
}
//////////////////////////////////////////////////////////////////////////
USART0& USART0::inst()
{
return sm_cInstance;
}
//////////////////////////////////////////////////////////////////////////
void USART0::init( uint32_t ui32BaudRate /* = 9600 */, uint8_t ui8DataBits /* = 8 */, Parity enmParity /* = Parity::DISABLED */, StopBit enmStopBits /* = StopBit::ONE */, Mode enmMode /* = Mode::ASYNCHRONOUS */ )
{
setBaudRate( ui32BaudRate );
setDataBits( ui8DataBits );
setParity( enmParity );
setStopBits( enmStopBits );
setMode( enmMode );
setRXState( true );
setTXState( true );
setRXInterrupt( true );
setUDREInterrupt( false );
}
//////////////////////////////////////////////////////////////////////////
bool USART0::receiveByte( uint8_t &ui8Data )
{
if( m_vsizeRXBufferHead == m_vsizeRXBufferTail && !( SREG & ( 1 << SREG_I ) ) )
{
while( !( *m_vui8pUCSRA & ( 1 << RXC_D ) ) );
ui8Data = *m_vui8pUDR;
return true;
}
else if( m_vsizeRXBufferHead == m_vsizeRXBufferTail )
{
return false;
}
ui8Data = m_vui8aRXBuffer[m_vsizeRXBufferTail];
m_vsizeRXBufferTail = ( m_vsizeRXBufferTail + 1 ) % sm_sizeRXBUFFER_SIZE;
return true;
}
//////////////////////////////////////////////////////////////////////////
bool USART0::receiveByte( uint8_t &ui8Data, uint16_t ui16TimeoutMS )
{
uint16_t ui16DelayCounter = 0;
while( !receiveByte( ui8Data ) )
{
_delay_ms( 1 );
if( ui16DelayCounter++ >= ui16TimeoutMS )
{
return false;
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool USART0::receiveLine( char *szBuffer, size_t sizeBufferLength, const char *szLineTerminator /* = "\r\n" */ )
{
size_t sizeReceived = 0;
while( sizeReceived < sizeBufferLength - 1 )
{
uint8_t ui8ReceiveByte;
while( !receiveByte( ui8ReceiveByte ) );
szBuffer[sizeReceived++] = ui8ReceiveByte;
szBuffer[sizeReceived] = '\0';
if( strstr( szBuffer, szLineTerminator ) )
{
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
void USART0::flushReceive()
{
uint8_t ui8Received;
while( m_vsizeRXBufferHead != m_vsizeRXBufferTail )
{
receiveByte( ui8Received );
}
if( !( SREG & ( 1 << SREG_I ) ) && ( *m_vui8pUCSRA & ( 1 << RXC_D ) ) )
{
ui8Received = *m_vui8pUDR;
}
}
//////////////////////////////////////////////////////////////////////////
void USART0::transmitByte( uint8_t ui8Data )
{
if( m_vsizeTXBufferHead == m_vsizeTXBufferTail && *m_vui8pUCSRA & ( 1 << UDRE_D ) )
{
*m_vui8pUDR = ui8Data;
return;
}
size_t sizeIndex = ( m_vsizeTXBufferHead + 1 ) % sm_sizeTXBUFFER_SIZE;
while( sizeIndex == m_vsizeTXBufferTail )
{
if( !( SREG & ( 1 << SREG_I ) ) && *m_vui8pUCSRA & ( 1 << UDRE_D ) )
{
transmitInterruptHandler();
}
}
m_vui8aTXBuffer[m_vsizeTXBufferHead] = ui8Data;
m_vsizeTXBufferHead = sizeIndex;
if( !( SREG & ( 1 << SREG_I ) ) )
{
while( !( *m_vui8pUCSRA & ( 1 << UDRE_D ) ) );
transmitInterruptHandler();
}
else
{
setUDREInterrupt( true );
}
}
//////////////////////////////////////////////////////////////////////////
void USART0::transmitString( const char *szString )
{
while( *szString )
{
transmitByte( *szString++ );
}
}
//////////////////////////////////////////////////////////////////////////
void USART0::flushTransmit()
{
while( m_vsizeTXBufferHead != m_vsizeTXBufferTail && !( *m_vui8pUCSRA & ( 1 << UDRE_D ) ) );
}
//////////////////////////////////////////////////////////////////////////
void USART0::receiveInterruptHandler()
{
uint8_t ui8ReceivedByte = *m_vui8pUDR;
size_t sizeIndex = ( m_vsizeRXBufferHead + 1 ) % sm_sizeRXBUFFER_SIZE;
if( sizeIndex != m_vsizeRXBufferTail )
{
m_vui8aRXBuffer[m_vsizeRXBufferHead] = ui8ReceivedByte;
m_vsizeRXBufferHead = sizeIndex;
}
}
//////////////////////////////////////////////////////////////////////////
void USART0::transmitInterruptHandler()
{
uint8_t ui8TransmitByte = m_vui8aTXBuffer[m_vsizeTXBufferTail];
m_vsizeTXBufferTail = ( m_vsizeTXBufferTail + 1 ) % sm_sizeTXBUFFER_SIZE;
*m_vui8pUDR = ui8TransmitByte;
if( m_vsizeTXBufferHead == m_vsizeTXBufferTail )
{
setUDREInterrupt( false );
}
}
//////////////////////////////////////////////////////////////////////////
ISR( USART0_RX_vect_D )
{
USART0::inst().receiveInterruptHandler();
}
//////////////////////////////////////////////////////////////////////////
ISR( USART0_UDRE_vect_D )
{
USART0::inst().transmitInterruptHandler();
}
/************************************************************************/
/************************************************************************/
#ifdef SECOND_USART
//////////////////////////////////////////////////////////////////////////
USART1 USART1::sm_cInstance;
//////////////////////////////////////////////////////////////////////////
USART1& USART1::inst()
{
return sm_cInstance;
}
//////////////////////////////////////////////////////////////////////////
USART1::USART1()
{
m_vui8pUCSRA = &UCSR1A;
m_vui8pUCSRB = &UCSR1B;
m_vui8pUCSRC = &UCSR1C;
m_vui8pUBRRH = &UBRR1H;
m_vui8pUBRRL = &UBRR1L;
m_vui8pUDR = &UDR1;
}
//////////////////////////////////////////////////////////////////////////
ISR( USART1_RX_vect_D )
{
USART1::inst().receiveInterruptHandler();
}
//////////////////////////////////////////////////////////////////////////
ISR( USART1_UDRE_vect_D )
{
USART1::inst().transmitInterruptHandler();
}
#endif

View File

@@ -1,215 +0,0 @@
<?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>ATmega328P</avrdevice>
<avrdeviceseries>none</avrdeviceseries>
<OutputType>Executable</OutputType>
<Language>CPP</Language>
<OutputFileName>$(MSBuildProjectName)</OutputFileName>
<OutputFileExtension>.elf</OutputFileExtension>
<OutputDirectory>$(MSBuildProjectDirectory)\$(Configuration)</OutputDirectory>
<AssemblyName>usart</AssemblyName>
<Name>usart</Name>
<RootNamespace>usart</RootNamespace>
<ToolchainFlavour>Native</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>
<eraseonlaunchrule>0</eraseonlaunchrule>
<AsfFrameworkConfig>
<framework-data xmlns="">
<options />
<configurations />
<files />
<documentation help="" />
<offline-documentation help="" />
<dependencies>
<content-extension eid="atmel.asf" uuidref="Atmel.ASF" version="3.31.0" />
</dependencies>
</framework-data>
</AsfFrameworkConfig>
<avrtool>com.atmel.avrdbg.tool.stk500</avrtool>
<avrtoolserialnumber />
<avrdeviceexpectedsignature>0x1E950F</avrdeviceexpectedsignature>
<com_atmel_avrdbg_tool_stk500>
<ToolOptions>
<InterfaceProperties>
<IspClock>1843200</IspClock>
</InterfaceProperties>
<InterfaceName>ISP</InterfaceName>
</ToolOptions>
<ToolType>com.atmel.avrdbg.tool.stk500</ToolType>
<ToolNumber>
</ToolNumber>
<ToolName>STK500</ToolName>
</com_atmel_avrdbg_tool_stk500>
<avrtoolinterface>ISP</avrtoolinterface>
<avrtoolinterfaceclock>1843200</avrtoolinterfaceclock>
<com_atmel_avrdbg_tool_simulator>
<ToolOptions xmlns="">
<InterfaceProperties>
</InterfaceProperties>
<InterfaceName>
</InterfaceName>
</ToolOptions>
<ToolType xmlns="">com.atmel.avrdbg.tool.simulator</ToolType>
<ToolNumber xmlns="">
</ToolNumber>
<ToolName xmlns="">Simulator</ToolName>
</com_atmel_avrdbg_tool_simulator>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<ToolchainSettings>
<AvrGccCpp>
<avrgcc.common.Device>-mmcu=atmega328p -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.0.106\gcc\dev\atmega328p"</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.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.0.106\include</Value>
</ListValues>
</avrgcc.compiler.directories.IncludePaths>
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcccpp.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.0.106\include</Value>
</ListValues>
</avrgcccpp.compiler.directories.IncludePaths>
<avrgcccpp.compiler.optimization.PackStructureMembers>True</avrgcccpp.compiler.optimization.PackStructureMembers>
<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>-Wextra -std=c++11</avrgcccpp.compiler.miscellaneous.OtherFlags>
<avrgcccpp.linker.general.UseVprintfLibrary>True</avrgcccpp.linker.general.UseVprintfLibrary>
<avrgcccpp.linker.libraries.Libraries>
<ListValues>
<Value>libm</Value>
<Value>libprintf_flt</Value>
</ListValues>
</avrgcccpp.linker.libraries.Libraries>
<avrgcccpp.assembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.0.106\include</Value>
</ListValues>
</avrgcccpp.assembler.general.IncludePaths>
<avrgcc.compiler.symbols.DefSymbols>
<ListValues>
<Value>NDEBUG</Value>
</ListValues>
</avrgcc.compiler.symbols.DefSymbols>
<avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>
<avrgcccpp.compiler.symbols.DefSymbols>
<ListValues>
<Value>NDEBUG</Value>
</ListValues>
</avrgcccpp.compiler.symbols.DefSymbols>
<avrgcccpp.compiler.optimization.level>Optimize for size (-Os)</avrgcccpp.compiler.optimization.level>
</AvrGccCpp>
</ToolchainSettings>
<PreBuildEvent>echo "C:\avrdude-6.2\avrdude.exe" -v -p$(avrdevice) %%* -Uflash:w:"$(OutputDirectory)\$(Name).hex":i &gt; "$(MSBuildProjectDirectory)\avrdude.bat"</PreBuildEvent>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<ToolchainSettings>
<AvrGccCpp>
<avrgcc.common.Device>-mmcu=atmega328p -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.0.106\gcc\dev\atmega328p"</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.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.0.106\include</Value>
</ListValues>
</avrgcc.compiler.directories.IncludePaths>
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcccpp.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.0.106\include</Value>
</ListValues>
</avrgcccpp.compiler.directories.IncludePaths>
<avrgcccpp.compiler.optimization.PackStructureMembers>True</avrgcccpp.compiler.optimization.PackStructureMembers>
<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>-Wextra -std=c++11</avrgcccpp.compiler.miscellaneous.OtherFlags>
<avrgcccpp.linker.general.UseVprintfLibrary>True</avrgcccpp.linker.general.UseVprintfLibrary>
<avrgcccpp.linker.libraries.Libraries>
<ListValues>
<Value>libm</Value>
<Value>libprintf_flt</Value>
</ListValues>
</avrgcccpp.linker.libraries.Libraries>
<avrgcccpp.assembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.0.106\include</Value>
</ListValues>
</avrgcccpp.assembler.general.IncludePaths>
<avrgcc.compiler.symbols.DefSymbols>
<ListValues>
<Value>DEBUG</Value>
</ListValues>
</avrgcc.compiler.symbols.DefSymbols>
<avrgcc.compiler.optimization.level>Optimize (-O1)</avrgcc.compiler.optimization.level>
<avrgcc.compiler.optimization.DebugLevel>Default (-g2)</avrgcc.compiler.optimization.DebugLevel>
<avrgcccpp.compiler.symbols.DefSymbols>
<ListValues>
<Value>DEBUG</Value>
</ListValues>
</avrgcccpp.compiler.symbols.DefSymbols>
<avrgcccpp.compiler.optimization.level>Optimize (-O1)</avrgcccpp.compiler.optimization.level>
<avrgcccpp.compiler.optimization.DebugLevel>Default (-g2)</avrgcccpp.compiler.optimization.DebugLevel>
<avrgcccpp.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcccpp.assembler.debugging.DebugLevel>
</AvrGccCpp>
</ToolchainSettings>
<PreBuildEvent>echo "C:\avrdude-6.2\avrdude.exe" -v -p$(avrdevice) %%* -Uflash:w:"$(OutputDirectory)\$(Name).hex":i &gt; "$(MSBuildProjectDirectory)\avrdude.bat"</PreBuildEvent>
</PropertyGroup>
<ItemGroup>
<Compile Include="array\array.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="clock.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="main.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="usart.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="usart.h">
<SubType>compile</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="array" />
</ItemGroup>
<Import Project="$(AVRSTUDIO_EXE_PATH)\\Vs\\Compiler.targets" />
</Project>

View File

@@ -1,176 +0,0 @@
/*
* Copyright (c) by BlackMark 2015-2016
* Date 24/05/2016
* Version 2.9
*/
#ifndef USART_H
#define USART_H
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <string.h>
#include "clock.h"
#if defined (__AVR_ATmega168A__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega1284P__)
#define USART_SPI
#define USART0_RX_vect_D USART_RX_vect
#define USART0_UDRE_vect_D USART_UDRE_vect
#endif
#if defined (__AVR_ATmega32A__) || (__AVR_ATmega8__)
#define USART_SHAREDIO
#define USART0_RX_vect_D USART_RXC_vect
#define USART0_UDRE_vect_D USART_UDRE_vect
#endif
#if defined (__AVR_ATmega1284P__)
#define SECOND_USART
#define USART0_RX_vect_D USART0_RX_vect
#define USART1_RX_vect_D USART1_RX_vect
#define USART0_UDRE_vect_D USART0_UDRE_vect
#define USART1_UDRE_vect_D USART1_UDRE_vect
#endif
#ifdef USART_SHAREDIO
#define RXEN_D RXEN
#define TXEN_D TXEN
#define RXCIE_D RXCIE
#define UDRIE_D UDRIE
#define UCSZ0_D UCSZ0
#define UCSZ1_D UCSZ1
#define UCSZ2_D UCSZ2
#define UPM0_D UPM0
#define UPM1_D UPM1
#define USBS_D USBS
#define RXC_D RXC
#define UDRE_D UDRE
#else
#define RXEN_D RXEN0
#define TXEN_D TXEN0
#define RXCIE_D RXCIE0
#define UDRIE_D UDRIE0
#define UCSZ0_D UCSZ00
#define UCSZ1_D UCSZ01
#define UCSZ2_D UCSZ02
#define UPM0_D UPM00
#define UPM1_D UPM01
#define USBS_D USBS0
#define RXC_D RXC0
#define UDRE_D UDRE0
#endif
#ifdef USART_SPI
#define UMSEL0_D UMSEL00
#define UMSEL1_D UMSEL01
#else
#define UMSEL_D UMSEL
#endif
class USART0
{
public:
enum class Mode
{
ASYNCHRONOUS = 0,
SYNCHRONOUS = 1,
#ifdef USART_SPI
MASTERSPI = 2
#endif
};
enum class Parity
{
DISABLED = 0,
ODD = 1,
EVEN = 2
};
enum class StopBit
{
ONE = 1,
TWO = 2
};
static constexpr size_t sm_sizeRXBUFFER_SIZE = 16;
static constexpr size_t sm_sizeTXBUFFER_SIZE = 16;
protected:
volatile uint8_t *m_vui8pUCSRA;
volatile uint8_t *m_vui8pUCSRB;
volatile uint8_t *m_vui8pUCSRC;
volatile uint8_t *m_vui8pUBRRH;
volatile uint8_t *m_vui8pUBRRL;
volatile uint8_t *m_vui8pUDR;
volatile size_t m_vsizeRXBufferHead;
volatile size_t m_vsizeRXBufferTail;
volatile size_t m_vsizeTXBufferHead;
volatile size_t m_vsizeTXBufferTail;
volatile uint8_t m_vui8aRXBuffer[sm_sizeRXBUFFER_SIZE];
volatile uint8_t m_vui8aTXBuffer[sm_sizeTXBUFFER_SIZE];
USART0();
private:
static USART0 sm_cInstance;
uint8_t readUCSRC();
void setUCSRC( uint8_t ui8UCSRC );
void setRXState( bool bEnable );
void setTXState( bool bEnable );
void setRXInterrupt( bool bEnable );
void setUDREInterrupt( bool bEnable );
void setBaudRate( uint32_t ui32BaudRate );
void setDataBits( uint8_t ui8DataBits );
void setParity( Parity enmParity );
void setStopBits( StopBit enmStopBits );
void setMode( Mode enmMode );
~USART0();
public:
static USART0& inst();
USART0( const USART0& ) = delete;
void operator=( const USART0& ) = delete;
void init( uint32_t ui32BaudRate = 9600, uint8_t ui8DataBits = 8, Parity enmParity = Parity::DISABLED, StopBit enmStopBits = StopBit::ONE, Mode enmMode = Mode::ASYNCHRONOUS );
bool receiveByte( uint8_t &ui8Data );
bool receiveByte( uint8_t &ui8Data, uint16_t ui16TimeoutMS );
bool receiveLine( char *szBuffer, size_t sizeBufferLength, const char *szLineTerminator = "\r\n" );
void flushReceive();
void transmitByte( uint8_t ui8Data );
void transmitString( const char *szString );
void flushTransmit();
void receiveInterruptHandler();
void transmitInterruptHandler();
inline USART0& operator<<( const char *szString )
{
transmitString( szString );
return *this;
}
};
#ifdef SECOND_USART
class USART1 : public USART0
{
public:
static USART1& inst();
USART1( const USART1& ) = delete;
void operator=( const USART1& ) = delete;
private:
static USART1 sm_cInstance;
USART1();
};
#endif
#endif

143
utils.hpp Normal file
View File

@@ -0,0 +1,143 @@
#pragma once
// Fix for limits.h not exposing LLONG_MIN, LLONG_MIN, and ULLONG_MAX to C++ context
#ifdef __cplusplus
#define __STDC_VERSION__ 201112L
#endif
#include <float.h>
#include <limits.h>
namespace uart {
namespace util {
// clang-format off
template <bool Val> struct set_bool { static constexpr auto value = Val; };
struct true_type : set_bool<true> {};
struct false_type : set_bool<false> {};
template <typename...> struct always_false : false_type {};
template <typename... Ts> static constexpr auto always_false_v = always_false<Ts...>::value;
template <typename T> struct is_integral : false_type {};
template <> struct is_integral<bool> : true_type {};
template <> struct is_integral<char> : true_type {};
template <> struct is_integral<signed char> : true_type {};
template <> struct is_integral<unsigned char> : true_type {};
template <> struct is_integral<short> : true_type {};
template <> struct is_integral<int> : true_type {};
template <> struct is_integral<long int> : true_type {};
template <> struct is_integral<long long int> : true_type {};
template <> struct is_integral<unsigned short> : true_type {};
template <> struct is_integral<unsigned int> : true_type {};
template <> struct is_integral<unsigned long int> : true_type {};
template <> struct is_integral<unsigned long long int> : true_type {};
template <typename T> static constexpr auto is_integral_v = is_integral<T>::value;
template <typename T, typename U> struct is_same : false_type {};
template <typename T> struct is_same<T, T> : true_type {};
template <typename T, typename U> static constexpr auto is_same_v = is_same<T, U>::value;
template <typename T>
struct NumericLimits {
static constexpr T min() { return T(); }
static constexpr T max() { return T(); }
};
template <>
struct NumericLimits<bool> {
static constexpr bool min() { return false; }
static constexpr bool max() { return true; }
};
template <>
struct NumericLimits<char> {
static constexpr char min() { return CHAR_MIN; }
static constexpr char max() { return CHAR_MAX; }
};
template <>
struct NumericLimits<signed char> {
static constexpr signed char min() { return SCHAR_MIN; }
static constexpr signed char max() { return SCHAR_MAX; }
};
template <>
struct NumericLimits<unsigned char> {
static constexpr unsigned char min() { return 0; }
static constexpr unsigned char max() { return UCHAR_MAX; }
};
template <>
struct NumericLimits<short> {
static constexpr short min() { return SHRT_MIN; }
static constexpr short max() { return SHRT_MAX; }
};
template <>
struct NumericLimits<int> {
static constexpr int min() { return INT_MIN; }
static constexpr int max() { return INT_MAX; }
};
template <>
struct NumericLimits<long> {
static constexpr long int min() { return LONG_MIN; }
static constexpr long int max() { return LONG_MAX; }
};
template <>
struct NumericLimits<long long int> {
static constexpr long long int min() { return LLONG_MIN; }
static constexpr long long int max() { return LLONG_MAX; }
};
template <>
struct NumericLimits<unsigned short> {
static constexpr unsigned short min() { return 0; }
static constexpr unsigned short max() { return USHRT_MAX; }
};
template <>
struct NumericLimits<unsigned int> {
static constexpr unsigned int min() { return 0; }
static constexpr unsigned int max() { return UINT_MAX; }
};
template <>
struct NumericLimits<unsigned long int> {
static constexpr unsigned long int min() { return 0; }
static constexpr unsigned long int max() { return ULONG_MAX; }
};
template <>
struct NumericLimits<unsigned long long int> {
static constexpr unsigned long long int min() { return 0; }
static constexpr unsigned long long int max() { return ULLONG_MAX; }
};
template <>
struct NumericLimits<float> {
template <typename... Ts> static constexpr float min() { return FLT_MIN; }
template <typename... Ts> static constexpr float max() { return FLT_MAX; }
};
template <>
struct NumericLimits<double> {
template <typename... Ts> static constexpr double min() { return DBL_MIN; }
template <typename... Ts> static constexpr double max() { return DBL_MAX; }
};
template <>
struct NumericLimits<long double> {
template <typename... Ts> static constexpr long double min() { return LDBL_MIN; }
template <typename... Ts> static constexpr long double max() { return LDBL_MAX; }
};
// clang-format on
} // namespace util
} // namespace uart