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
21 changed files with 607 additions and 2785 deletions

8
.gitignore vendored
View File

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

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

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 BlackMark
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,48 +0,0 @@
#pragma once
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

View File

@@ -1,213 +0,0 @@
#pragma once
#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 {
template <class Registers, typename CtrlFlagsA, typename CtrlFlagsB, typename CtrlFlagsC, class cfg, Mode mode,
Driven driven>
class Hardware {
public:
static void init() FORCE_INLINE
{
constexpr auto baudVal = calcBaud();
*Registers::BAUD_REG_H = static_cast<uint8_t>(baudVal >> 8);
*Registers::BAUD_REG_L = 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;
*Registers::CTRL_STAT_REG_B = controlRegB;
*Registers::CTRL_STAT_REG_C = controlRegC;
}
static bool rxByteBlocking(typename cfg::data_t &byte) FORCE_INLINE
{
if (*Registers::CTRL_STAT_REG_A & (1 << CtrlFlagsA::RECEIVE_COMPLETE)) {
byte = *Registers::IO_REG;
return true;
}
return false;
}
static typename cfg::data_t rxByteInterrupt() FORCE_INLINE
{
return *Registers::IO_REG;
}
static void txByteBlocking(const typename cfg::data_t &byte) FORCE_INLINE
{
while (!(*Registers::CTRL_STAT_REG_A & (1 << CtrlFlagsA::DATA_REG_EMPTY)))
;
*Registers::IO_REG = byte;
}
static void txByteInterrupt(volatile const typename cfg::data_t &byte) FORCE_INLINE
{
*Registers::IO_REG = byte;
}
static bool peekBlocking() FORCE_INLINE
{
if (*Registers::CTRL_STAT_REG_A & (1 << CtrlFlagsA::RECEIVE_COMPLETE)) {
return true;
}
return false;
}
static void enableDataRegEmptyInt() FORCE_INLINE
{
*Registers::CTRL_STAT_REG_B |= (1 << CtrlFlagsB::DATA_REG_EMPTY_INT_ENABLE);
}
static void disableDataRegEmptyInt() FORCE_INLINE
{
*Registers::CTRL_STAT_REG_B &= ~(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::DATA_REG_EMPTY_INT_ENABLE) | (1 << CtrlFlagsB::RX_INT_ENABLE);
return interruptVal;
}
};
template <typename data_t, uint8_t Size>
struct RingBuffer {
uint8_t head;
uint8_t tail;
data_t buf[Size];
};
} // namespace detail
} // namespace uart
#undef FORCE_INLINE

View File

@@ -1,218 +0,0 @@
#pragma once
#include "config.hpp"
#include "hardware.hpp"
#define FORCE_INLINE __attribute__((always_inline))
namespace uart {
namespace detail {
#if defined(__AVR_ATmega1284P__)
struct Registers0 {
static constexpr volatile auto *IO_REG = &UDR0;
static constexpr volatile auto *CTRL_STAT_REG_A = &UCSR0A;
static constexpr volatile auto *CTRL_STAT_REG_B = &UCSR0B;
static constexpr volatile auto *CTRL_STAT_REG_C = &UCSR0C;
static constexpr volatile auto *BAUD_REG_L = &UBRR0L;
static constexpr volatile auto *BAUD_REG_H = &UBRR0H;
};
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
static void (*fnRx0IntHandler)() = nullptr;
static 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
template <Mode mode = Mode::ASYNCHRONOUS, class cfg = Config<>, Driven driven = Driven::INTERRUPT>
class Hardware0 {
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(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 &byte) FORCE_INLINE
{
static_cast<void>(byte);
static_assert(driven == Driven::BLOCKING, "Peek with data is not supported in blocking mode");
return false;
}
static bool peek() FORCE_INLINE
{
return HardwareImpl::peekBlocking();
}
private:
using HardwareImpl = detail::Hardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, mode, driven>;
};
template <Mode mode, class cfg>
class Hardware0<mode, cfg, Driven::INTERRUPT> {
public:
using data_t = typename cfg::data_t;
static constexpr auto DATA_BITS = cfg::DATA_BITS;
static void init() FORCE_INLINE
{
detail::fnRx0IntHandler = rxIntHandler;
detail::fnDataReg0EmptyIntHandler = dataRegEmptyIntHandler;
HardwareImpl::init();
}
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);
}
private:
using HardwareImpl = detail::Hardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
detail::ControlFlagsC0, cfg, mode, Driven::INTERRUPT>;
static constexpr auto TX_BUFFER_SIZE = 16;
static constexpr auto RX_BUFFER_SIZE = 16;
static volatile detail::RingBuffer<data_t, TX_BUFFER_SIZE> sm_txBuf;
static volatile detail::RingBuffer<data_t, RX_BUFFER_SIZE> sm_rxBuf;
static void rxIntHandler()
{
uint8_t tmpHead = (sm_rxBuf.head + 1) % RX_BUFFER_SIZE;
if (tmpHead != sm_rxBuf.tail) {
sm_rxBuf.head = tmpHead;
sm_rxBuf.buf[tmpHead] = HardwareImpl::rxByteInterrupt();
}
}
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();
}
};
template <Mode mode, class cfg>
volatile detail::RingBuffer<typename Hardware0<mode, cfg, Driven::INTERRUPT>::data_t,
Hardware0<mode, cfg, Driven::INTERRUPT>::TX_BUFFER_SIZE>
Hardware0<mode, cfg, Driven::INTERRUPT>::sm_txBuf = {0, 0, {0}};
template <Mode mode, class cfg>
volatile detail::RingBuffer<typename Hardware0<mode, cfg, Driven::INTERRUPT>::data_t,
Hardware0<mode, cfg, Driven::INTERRUPT>::RX_BUFFER_SIZE>
Hardware0<mode, cfg, Driven::INTERRUPT>::sm_rxBuf = {0, 0, {0}};
} // namespace uart
#undef FORCE_INLINE

View File

@@ -1,224 +0,0 @@
#pragma once
#include "config.hpp"
#include "hardware.hpp"
#define FORCE_INLINE __attribute__((always_inline))
namespace uart {
namespace detail {
#if defined(__AVR_ATmega1284P__)
struct Registers1 {
static constexpr volatile auto *IO_REG = &UDR1;
static constexpr volatile auto *CTRL_STAT_REG_A = &UCSR1A;
static constexpr volatile auto *CTRL_STAT_REG_B = &UCSR1B;
static constexpr volatile auto *CTRL_STAT_REG_C = &UCSR1C;
static constexpr volatile auto *BAUD_REG_L = &UBRR1L;
static constexpr volatile auto *BAUD_REG_H = &UBRR1H;
};
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
static void (*fnRx1IntHandler)() = nullptr;
static void (*fnDataReg1EmptyIntHandler)() = nullptr;
ISR(USART1_RX_vect)
{
if (fnRx1IntHandler)
fnRx1IntHandler();
}
ISR(USART1_UDRE_vect)
{
if (fnDataReg1EmptyIntHandler)
fnDataReg1EmptyIntHandler();
}
#define HAS_UART1
#else
#error "This chip is not supported"
#endif
} // namespace detail
#ifdef HAS_UART1
template <Mode mode = Mode::ASYNCHRONOUS, class cfg = Config<>, Driven driven = Driven::INTERRUPT>
class Hardware1 {
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 &byte) FORCE_INLINE
{
static_cast<void>(byte);
static_assert(driven != Driven::BLOCKING, "Peek with data is not supported in blocking mode");
return false;
}
static bool peek() FORCE_INLINE
{
return HardwareImpl::peekBlocking();
}
private:
using HardwareImpl = detail::Hardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, mode, driven>;
};
template <Mode mode, class cfg>
class Hardware1<mode, cfg, Driven::INTERRUPT> {
public:
using data_t = typename cfg::data_t;
static constexpr auto DATA_BITS = cfg::DATA_BITS;
static void init() FORCE_INLINE
{
detail::fnRx1IntHandler = rxIntHandler;
detail::fnDataReg1EmptyIntHandler = dataRegEmptyIntHandler;
HardwareImpl::init();
}
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);
}
private:
using HardwareImpl = detail::Hardware<detail::Registers1, detail::ControlFlagsA1, detail::ControlFlagsB1,
detail::ControlFlagsC1, cfg, mode, Driven::INTERRUPT>;
static constexpr auto TX_BUFFER_SIZE = 16;
static constexpr auto RX_BUFFER_SIZE = 16;
static volatile detail::RingBuffer<data_t, TX_BUFFER_SIZE> sm_txBuf;
static volatile detail::RingBuffer<data_t, RX_BUFFER_SIZE> sm_rxBuf;
static void rxIntHandler()
{
uint8_t tmpHead = (sm_rxBuf.head + 1) % RX_BUFFER_SIZE;
if (tmpHead != sm_rxBuf.tail) {
sm_rxBuf.head = tmpHead;
sm_rxBuf.buf[tmpHead] = HardwareImpl::rxByteInterrupt();
}
}
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();
}
};
template <Mode mode, class cfg>
volatile detail::RingBuffer<typename Hardware1<mode, cfg, Driven::INTERRUPT>::data_t,
Hardware1<mode, cfg, Driven::INTERRUPT>::TX_BUFFER_SIZE>
Hardware1<mode, cfg, Driven::INTERRUPT>::sm_txBuf = {0, 0, {0}};
template <Mode mode, class cfg>
volatile detail::RingBuffer<typename Hardware1<mode, cfg, Driven::INTERRUPT>::data_t,
Hardware1<mode, cfg, Driven::INTERRUPT>::RX_BUFFER_SIZE>
Hardware1<mode, cfg, Driven::INTERRUPT>::sm_rxBuf = {0, 0, {0}};
#endif
} // namespace uart
#undef FORCE_INLINE

View File

@@ -1,18 +0,0 @@
#pragma once
#include "config.hpp"
#include "../io/io.hpp"
namespace uart {
template <io::P rxPin, io::P txPin, class cfg = Config<>>
class Software {
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

754
uart.cpp
View File

@@ -1,754 +0,0 @@
/*************************************************************************
Title: Interrupt UART library with receive/transmit circular buffers
Author: Peter Fleury <pfleury@gmx.ch> http://tinyurl.com/peterfleury
File: $Id: uart.c,v 1.15.2.4 2015/09/05 18:33:32 peter Exp $
Software: AVR-GCC 4.x
Hardware: any AVR with built-in UART,
License: GNU General Public License
DESCRIPTION:
An interrupt is generated when the UART has finished transmitting or
receiving a byte. The interrupt handling routines use circular buffers
for buffering received and transmitted data.
The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define
the buffer size in bytes. Note that these variables must be a
power of 2.
USAGE:
Refere to the header file uart.h for a description of the routines.
See also example test_uart.c.
NOTES:
Based on Atmel Application Note AVR306
LICENSE:
Copyright (C) 2015 Peter Fleury, GNU General Public License Version 3
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*************************************************************************/
#include "uart.h"
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
/*
* constants and macros
*/
/* size of RX/TX buffers */
#define UART_RX_BUFFER_MASK (UART_RX_BUFFER_SIZE - 1)
#define UART_TX_BUFFER_MASK (UART_TX_BUFFER_SIZE - 1)
#if (UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK)
#error RX buffer size is not a power of 2
#endif
#if (UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK)
#error TX buffer size is not a power of 2
#endif
#if defined(__AVR_AT90S2313__) || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S8515__) || \
defined(__AVR_AT90S4434__) || defined(__AVR_AT90S8535__) || defined(__AVR_ATmega103__)
/* old AVR classic or ATmega103 with one UART */
#define UART0_RECEIVE_INTERRUPT UART_RX_vect
#define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect
#define UART0_STATUS USR
#define UART0_CONTROL UCR
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#define UART0_UBRRL UBRR
#define UART0_BIT_U2X U2X
#define UART0_BIT_RXCIE RXCIE
#define UART0_BIT_RXEN RXEN
#define UART0_BIT_TXEN TXEN
#elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__)
/* old AVR classic with one UART */
#define UART0_RECEIVE_INTERRUPT UART_RX_vect
#define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#define UART0_UBRRL UBRR
#define UART0_BIT_U2X U2X
#define UART0_BIT_RXCIE RXCIE
#define UART0_BIT_RXEN RXEN
#define UART0_BIT_TXEN TXEN
#elif defined(__AVR_AT90PWM216__) || defined(__AVR_AT90PWM316__)
/* AT90PWN216/316 with one USART */
#define UART0_RECEIVE_INTERRUPT USART_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_CONTROLC UCSRC
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#define UART0_UBRRL UBRRL
#define UART0_UBRRH UBRRH
#define UART0_BIT_U2X U2X
#define UART0_BIT_RXCIE RXCIE
#define UART0_BIT_RXEN RXEN
#define UART0_BIT_TXEN TXEN
#define UART0_BIT_UCSZ0 UCSZ0
#define UART0_BIT_UCSZ1 UCSZ1
#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega8A__) || defined(__AVR_ATmega16__) || \
defined(__AVR_ATmega16A__) || defined(__AVR_ATmega32__) || defined(__AVR_ATmega32A__) || \
defined(__AVR_ATmega323__)
/* ATmega with one USART */
#define UART0_RECEIVE_INTERRUPT USART_RXC_vect
#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_CONTROLC UCSRC
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#define UART0_UBRRL UBRRL
#define UART0_UBRRH UBRRH
#define UART0_BIT_U2X U2X
#define UART0_BIT_RXCIE RXCIE
#define UART0_BIT_RXEN RXEN
#define UART0_BIT_TXEN TXEN
#define UART0_BIT_UCSZ0 UCSZ0
#define UART0_BIT_UCSZ1 UCSZ1
#define UART0_BIT_URSEL URSEL
#elif defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__)
#define UART0_RECEIVE_INTERRUPT USART_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_CONTROLC UCSRC
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#define UART0_UBRRL UBRRL
#define UART0_UBRRH UBRRH
#define UART0_BIT_U2X U2X
#define UART0_BIT_RXCIE RXCIE
#define UART0_BIT_RXEN RXEN
#define UART0_BIT_TXEN TXEN
#define UART0_BIT_UCSZ0 UCSZ0
#define UART0_BIT_UCSZ1 UCSZ1
#define UART0_BIT_URSEL URSEL
#elif defined(__AVR_ATmega163__)
/* ATmega163 with one UART */
#define UART0_RECEIVE_INTERRUPT UART_RX_vect
#define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#define UART0_UBRRL UBRR
#define UART0_UBRRH UBRRHI
#define UART0_BIT_U2X U2X
#define UART0_BIT_RXCIE RXCIE
#define UART0_BIT_RXEN RXEN
#define UART0_BIT_TXEN TXEN
#elif defined(__AVR_ATmega162__)
/* ATmega with two USART */
#define ATMEGA_USART1
#define UART0_RECEIVE_INTERRUPT USART0_RXC_vect
#define UART1_RECEIVE_INTERRUPT USART1_RXC_vect
#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_CONTROLC UCSR0C
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#define UART0_UBRRL UBRR0L
#define UART0_UBRRH UBRR0H
#define UART0_BIT_URSEL URSEL0
#define UART0_BIT_U2X U2X0
#define UART0_BIT_RXCIE RXCIE0
#define UART0_BIT_RXEN RXEN0
#define UART0_BIT_TXEN TXEN0
#define UART0_BIT_UCSZ0 UCSZ00
#define UART0_BIT_UCSZ1 UCSZ01
#define UART1_STATUS UCSR1A
#define UART1_CONTROL UCSR1B
#define UART1_CONTROLC UCSR1C
#define UART1_DATA UDR1
#define UART1_UDRIE UDRIE1
#define UART1_UBRRL UBRR1L
#define UART1_UBRRH UBRR1H
#define UART1_BIT_URSEL URSEL1
#define UART1_BIT_U2X U2X1
#define UART1_BIT_RXCIE RXCIE1
#define UART1_BIT_RXEN RXEN1
#define UART1_BIT_TXEN TXEN1
#define UART1_BIT_UCSZ0 UCSZ10
#define UART1_BIT_UCSZ1 UCSZ11
#elif defined(__AVR_ATmega161__)
/* ATmega with UART */
#error "AVR ATmega161 currently not supported by this libaray !"
#elif defined(__AVR_ATmega169__)
/* ATmega with one USART */
#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_CONTROLC UCSRC
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#define UART0_UBRRL UBRRL
#define UART0_UBRRH UBRRH
#define UART0_BIT_U2X U2X
#define UART0_BIT_RXCIE RXCIE
#define UART0_BIT_RXEN RXEN
#define UART0_BIT_TXEN TXEN
#define UART0_BIT_UCSZ0 UCSZ0
#define UART0_BIT_UCSZ1 UCSZ1
#elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48P__) || \
defined(__AVR_ATmega48PA__) || defined(__AVR_ATmega48PB__) || defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega88PA__) || \
defined(__AVR_ATmega88PB__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168A__) || \
defined(__AVR_ATmega168P__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega168PB__) || \
defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega3250__) || \
defined(__AVR_ATmega3290__) || defined(__AVR_ATmega6450__) || defined(__AVR_ATmega6490__)
/* ATmega with one USART */
#define UART0_RECEIVE_INTERRUPT USART_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_CONTROLC UCSR0C
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#define UART0_UBRRL UBRR0L
#define UART0_UBRRH UBRR0H
#define UART0_BIT_U2X U2X0
#define UART0_BIT_RXCIE RXCIE0
#define UART0_BIT_RXEN RXEN0
#define UART0_BIT_TXEN TXEN0
#define UART0_BIT_UCSZ0 UCSZ00
#define UART0_BIT_UCSZ1 UCSZ01
#elif defined(__AVR_ATtiny2313__) || defined(__AVR_ATtiny2313A__) || defined(__AVR_ATtiny4313__)
/* ATtiny with one USART */
#define UART0_RECEIVE_INTERRUPT USART_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_CONTROLC UCSRC
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#define UART0_UBRRL UBRRL
#define UART0_UBRRH UBRRH
#define UART0_BIT_U2X U2X
#define UART0_BIT_RXCIE RXCIE
#define UART0_BIT_RXEN RXEN
#define UART0_BIT_TXEN TXEN
#define UART0_BIT_UCSZ0 UCSZ0
#define UART0_BIT_UCSZ1 UCSZ1
#elif defined(__AVR_ATmega329__) || defined(__AVR_ATmega649__) || defined(__AVR_ATmega3290__) || \
defined(__AVR_ATmega6490__) || defined(__AVR_ATmega169A__) || defined(__AVR_ATmega169PA__) || \
defined(__AVR_ATmega329A__) || defined(__AVR_ATmega329PA__) || defined(__AVR_ATmega3290A__) || \
defined(__AVR_ATmega3290PA__) || defined(__AVR_ATmega649A__) || defined(__AVR_ATmega649P__) || \
defined(__AVR_ATmega6490A__) || defined(__AVR_ATmega6490P__) || defined(__AVR_ATmega165__) || \
defined(__AVR_ATmega325__) || defined(__AVR_ATmega645__) || defined(__AVR_ATmega3250__) || \
defined(__AVR_ATmega6450__) || defined(__AVR_ATmega165A__) || defined(__AVR_ATmega165PA__) || \
defined(__AVR_ATmega325A__) || defined(__AVR_ATmega325PA__) || defined(__AVR_ATmega3250A__) || \
defined(__AVR_ATmega3250PA__) || defined(__AVR_ATmega645A__) || defined(__AVR_ATmega645PA__) || \
defined(__AVR_ATmega6450A__) || defined(__AVR_ATmega6450PA__) || defined(__AVR_ATmega644__)
/* ATmega with one USART */
#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_CONTROLC UCSR0C
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#define UART0_UBRRL UBRR0L
#define UART0_UBRRH UBRR0H
#define UART0_BIT_U2X U2X0
#define UART0_BIT_RXCIE RXCIE0
#define UART0_BIT_RXEN RXEN0
#define UART0_BIT_TXEN TXEN0
#define UART0_BIT_UCSZ0 UCSZ00
#define UART0_BIT_UCSZ1 UCSZ01
#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) || defined(__AVR_ATmega128A__) || \
defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || \
defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega164P__) || \
defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega164A__) || \
defined(__AVR_ATmega164PA__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) || \
defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284__) || \
defined(__AVR_ATmega1284P__) || defined(__AVR_ATtiny1634__)
/* ATmega with two USART */
#define ATMEGA_USART1
#define UART0_RECEIVE_INTERRUPT USART0_RX_vect
#define UART1_RECEIVE_INTERRUPT USART1_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect
#define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_CONTROLC UCSR0C
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#define UART0_UBRRL UBRR0L
#define UART0_UBRRH UBRR0H
#define UART0_BIT_U2X U2X0
#define UART0_BIT_RXCIE RXCIE0
#define UART0_BIT_RXEN RXEN0
#define UART0_BIT_TXEN TXEN0
#define UART0_BIT_UCSZ0 UCSZ00
#define UART0_BIT_UCSZ1 UCSZ01
#define UART1_STATUS UCSR1A
#define UART1_CONTROL UCSR1B
#define UART1_CONTROLC UCSR1C
#define UART1_DATA UDR1
#define UART1_UDRIE UDRIE1
#define UART1_UBRRL UBRR1L
#define UART1_UBRRH UBRR1H
#define UART1_BIT_U2X U2X1
#define UART1_BIT_RXCIE RXCIE1
#define UART1_BIT_RXEN RXEN1
#define UART1_BIT_TXEN TXEN1
#define UART1_BIT_UCSZ0 UCSZ10
#define UART1_BIT_UCSZ1 UCSZ11
#elif defined(__AVR_ATmega8U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || \
defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB82__) || \
defined(__AVR_AT90USB162__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || \
defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1287__)
#define UART0_RECEIVE_INTERRUPT USART1_RX_vect
#define UART0_TRANSMIT_INTERRUPT USART1_UDRE_vect
#define UART0_STATUS UCSR1A
#define UART0_CONTROL UCSR1B
#define UART0_CONTROLC UCSR1C
#define UART0_DATA UDR1
#define UART0_UDRIE UDRIE1
#define UART0_UBRRL UBRR1L
#define UART0_UBRRH UBRR1H
#define UART0_BIT_U2X U2X1
#define UART0_BIT_RXCIE RXCIE1
#define UART0_BIT_RXEN RXEN1
#define UART0_BIT_TXEN TXEN1
#define UART0_BIT_UCSZ0 UCSZ10
#define UART0_BIT_UCSZ1 UCSZ11
#else
#error "no UART definition for MCU available"
#endif
/*
* module global variables
*/
static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];
static volatile unsigned char UART_TxHead;
static volatile unsigned char UART_TxTail;
static volatile unsigned char UART_RxHead;
static volatile unsigned char UART_RxTail;
static volatile unsigned char UART_LastRxError;
#if defined(ATMEGA_USART1)
static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE];
static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE];
static volatile unsigned char UART1_TxHead;
static volatile unsigned char UART1_TxTail;
static volatile unsigned char UART1_RxHead;
static volatile unsigned char UART1_RxTail;
static volatile unsigned char UART1_LastRxError;
#endif
ISR(UART0_RECEIVE_INTERRUPT)
/*************************************************************************
Function: UART Receive Complete interrupt
Purpose: called when the UART has received a character
**************************************************************************/
{
unsigned char tmphead;
unsigned char data;
unsigned char usr;
unsigned char lastRxError;
/* read UART status register and UART data register */
usr = UART0_STATUS;
data = UART0_DATA;
/* get FEn (Frame Error) DORn (Data OverRun) UPEn (USART Parity Error) bits */
#if defined(FE) && defined(DOR) && defined(UPE)
lastRxError = usr & (_BV(FE) | _BV(DOR) | _BV(UPE));
#elif defined(FE0) && defined(DOR0) && defined(UPE0)
lastRxError = usr & (_BV(FE0) | _BV(DOR0) | _BV(UPE0));
#elif defined(FE1) && defined(DOR1) && defined(UPE1)
lastRxError = usr & (_BV(FE1) | _BV(DOR1) | _BV(UPE1));
#elif defined(FE) && defined(DOR)
lastRxError = usr & (_BV(FE) | _BV(DOR));
#endif
/* calculate buffer index */
tmphead = (UART_RxHead + 1) & UART_RX_BUFFER_MASK;
if (tmphead == UART_RxTail) {
/* error: receive buffer overflow */
lastRxError = UART_BUFFER_OVERFLOW >> 8;
} else {
/* store new index */
UART_RxHead = tmphead;
/* store received data in buffer */
UART_RxBuf[tmphead] = data;
}
UART_LastRxError |= lastRxError;
}
ISR(UART0_TRANSMIT_INTERRUPT)
/*************************************************************************
Function: UART Data Register Empty interrupt
Purpose: called when the UART is ready to transmit the next byte
**************************************************************************/
{
unsigned char tmptail;
if (UART_TxHead != UART_TxTail) {
/* calculate and store new buffer index */
tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK;
UART_TxTail = tmptail;
/* get one byte from buffer and write it to UART */
UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */
} else {
/* tx buffer empty, disable UDRE interrupt */
UART0_CONTROL &= ~_BV(UART0_UDRIE);
}
}
/*************************************************************************
Function: uart_init()
Purpose: initialize UART and set baudrate
Input: baudrate using macro UART_BAUD_SELECT()
Returns: none
**************************************************************************/
void uart_init(unsigned int baudrate)
{
UART_TxHead = 0;
UART_TxTail = 0;
UART_RxHead = 0;
UART_RxTail = 0;
#ifdef UART_TEST
#ifndef UART0_BIT_U2X
#warning "UART0_BIT_U2X not defined"
#endif
#ifndef UART0_UBRRH
#warning "UART0_UBRRH not defined"
#endif
#ifndef UART0_CONTROLC
#warning "UART0_CONTROLC not defined"
#endif
#if defined(URSEL) || defined(URSEL0)
#ifndef UART0_BIT_URSEL
#warning "UART0_BIT_URSEL not defined"
#endif
#endif
#endif
/* Set baud rate */
if (baudrate & 0x8000) {
#if UART0_BIT_U2X
UART0_STATUS = (1 << UART0_BIT_U2X); // Enable 2x speed
#endif
}
#if defined(UART0_UBRRH)
UART0_UBRRH = (unsigned char)((baudrate >> 8) & 0x80);
#endif
UART0_UBRRL = (unsigned char)(baudrate & 0x00FF);
/* Enable USART receiver and transmitter and receive complete interrupt */
UART0_CONTROL = _BV(UART0_BIT_RXCIE) | (1 << UART0_BIT_RXEN) | (1 << UART0_BIT_TXEN);
/* Set frame format: asynchronous, 8data, no parity, 1stop bit */
#ifdef UART0_CONTROLC
#ifdef UART0_BIT_URSEL
UART0_CONTROLC = (1 << UART0_BIT_URSEL) | (1 << UART0_BIT_UCSZ1) | (1 << UART0_BIT_UCSZ0);
#else
UART0_CONTROLC = (1 << UART0_BIT_UCSZ1) | (1 << UART0_BIT_UCSZ0);
#endif
#endif
} /* uart_init */
/*************************************************************************
Function: uart_getc()
Purpose: return byte from ringbuffer
Returns: lower byte: received byte from ringbuffer
higher byte: last receive error
**************************************************************************/
unsigned int uart_getc(void)
{
unsigned char tmptail;
unsigned char data;
unsigned char lastRxError;
if (UART_RxHead == UART_RxTail) {
return UART_NO_DATA; /* no data available */
}
/* calculate buffer index */
tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;
/* get data from receive buffer */
data = UART_RxBuf[tmptail];
lastRxError = UART_LastRxError;
/* store buffer index */
UART_RxTail = tmptail;
UART_LastRxError = 0;
return (lastRxError << 8) + data;
} /* uart_getc */
/*************************************************************************
Function: uart_putc()
Purpose: write byte to ringbuffer for transmitting via UART
Input: byte to be transmitted
Returns: none
**************************************************************************/
void uart_putc(unsigned char data)
{
unsigned char tmphead;
tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
while (tmphead == UART_TxTail) {
; /* wait for free space in buffer */
}
UART_TxBuf[tmphead] = data;
UART_TxHead = tmphead;
/* enable UDRE interrupt */
UART0_CONTROL |= _BV(UART0_UDRIE);
} /* uart_putc */
/*************************************************************************
Function: uart_puts()
Purpose: transmit string to UART
Input: string to be transmitted
Returns: none
**************************************************************************/
void uart_puts(const char *s)
{
while (*s)
uart_putc(*s++);
} /* uart_puts */
/*************************************************************************
Function: uart_puts_p()
Purpose: transmit string from program memory to UART
Input: program memory string to be transmitted
Returns: none
**************************************************************************/
void uart_puts_p(const char *progmem_s)
{
register char c;
while ((c = pgm_read_byte(progmem_s++)))
uart_putc(c);
} /* uart_puts_p */
/*
* these functions are only for ATmegas with two USART
*/
#if defined(ATMEGA_USART1)
ISR(UART1_RECEIVE_INTERRUPT)
/*************************************************************************
Function: UART1 Receive Complete interrupt
Purpose: called when the UART1 has received a character
**************************************************************************/
{
unsigned char tmphead;
unsigned char data;
unsigned char usr;
unsigned char lastRxError;
/* read UART status register and UART data register */
usr = UART1_STATUS;
data = UART1_DATA;
/* get FEn (Frame Error) DORn (Data OverRun) UPEn (USART Parity Error) bits */
lastRxError = usr & (_BV(FE1) | _BV(DOR1) | _BV(UPE1));
/* calculate buffer index */
tmphead = (UART1_RxHead + 1) & UART_RX_BUFFER_MASK;
if (tmphead == UART1_RxTail) {
/* error: receive buffer overflow */
lastRxError = UART_BUFFER_OVERFLOW >> 8;
} else {
/* store new index */
UART1_RxHead = tmphead;
/* store received data in buffer */
UART1_RxBuf[tmphead] = data;
}
UART1_LastRxError |= lastRxError;
}
ISR(UART1_TRANSMIT_INTERRUPT)
/*************************************************************************
Function: UART1 Data Register Empty interrupt
Purpose: called when the UART1 is ready to transmit the next byte
**************************************************************************/
{
unsigned char tmptail;
if (UART1_TxHead != UART1_TxTail) {
/* calculate and store new buffer index */
tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK;
UART1_TxTail = tmptail;
/* get one byte from buffer and write it to UART */
UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */
} else {
/* tx buffer empty, disable UDRE interrupt */
UART1_CONTROL &= ~_BV(UART1_UDRIE);
}
}
/*************************************************************************
Function: uart1_init()
Purpose: initialize UART1 and set baudrate
Input: baudrate using macro UART_BAUD_SELECT()
Returns: none
**************************************************************************/
void uart1_init(unsigned int baudrate)
{
UART1_TxHead = 0;
UART1_TxTail = 0;
UART1_RxHead = 0;
UART1_RxTail = 0;
#ifdef UART_TEST
#ifndef UART1_BIT_U2X
#warning "UART1_BIT_U2X not defined"
#endif
#ifndef UART1_UBRRH
#warning "UART1_UBRRH not defined"
#endif
#ifndef UART1_CONTROLC
#warning "UART1_CONTROLC not defined"
#endif
#if defined(URSEL) || defined(URSEL1)
#ifndef UART1_BIT_URSEL
#warning "UART1_BIT_URSEL not defined"
#endif
#endif
#endif
/* Set baud rate */
if (baudrate & 0x8000) {
#if UART1_BIT_U2X
UART1_STATUS = (1 << UART1_BIT_U2X); // Enable 2x speed
#endif
}
UART1_UBRRH = (unsigned char)((baudrate >> 8) & 0x80);
UART1_UBRRL = (unsigned char)baudrate;
/* Enable USART receiver and transmitter and receive complete interrupt */
UART1_CONTROL = _BV(UART1_BIT_RXCIE) | (1 << UART1_BIT_RXEN) | (1 << UART1_BIT_TXEN);
/* Set frame format: asynchronous, 8data, no parity, 1stop bit */
#ifdef UART1_BIT_URSEL
UART1_CONTROLC = (1 << UART1_BIT_URSEL) | (1 << UART1_BIT_UCSZ1) | (1 << UART1_BIT_UCSZ0);
#else
UART1_CONTROLC = (1 << UART1_BIT_UCSZ1) | (1 << UART1_BIT_UCSZ0);
#endif
} /* uart_init */
/*************************************************************************
Function: uart1_getc()
Purpose: return byte from ringbuffer
Returns: lower byte: received byte from ringbuffer
higher byte: last receive error
**************************************************************************/
unsigned int uart1_getc(void)
{
unsigned char tmptail;
unsigned int data;
unsigned char lastRxError;
if (UART1_RxHead == UART1_RxTail) {
return UART_NO_DATA; /* no data available */
}
/* calculate buffer index */
tmptail = (UART1_RxTail + 1) & UART_RX_BUFFER_MASK;
/* get data from receive buffer */
data = UART1_RxBuf[tmptail];
lastRxError = UART1_LastRxError;
/* store buffer index */
UART1_RxTail = tmptail;
UART1_LastRxError = 0;
return (lastRxError << 8) + data;
} /* uart1_getc */
/*************************************************************************
Function: uart1_putc()
Purpose: write byte to ringbuffer for transmitting via UART
Input: byte to be transmitted
Returns: none
**************************************************************************/
void uart1_putc(unsigned char data)
{
unsigned char tmphead;
tmphead = (UART1_TxHead + 1) & UART_TX_BUFFER_MASK;
while (tmphead == UART1_TxTail) {
; /* wait for free space in buffer */
}
UART1_TxBuf[tmphead] = data;
UART1_TxHead = tmphead;
/* enable UDRE interrupt */
UART1_CONTROL |= _BV(UART1_UDRIE);
} /* uart1_putc */
/*************************************************************************
Function: uart1_puts()
Purpose: transmit string to UART1
Input: string to be transmitted
Returns: none
**************************************************************************/
void uart1_puts(const char *s)
{
while (*s)
uart1_putc(*s++);
} /* uart1_puts */
/*************************************************************************
Function: uart1_puts_p()
Purpose: transmit string from program memory to UART1
Input: program memory string to be transmitted
Returns: none
**************************************************************************/
void uart1_puts_p(const char *progmem_s)
{
register char c;
while ((c = pgm_read_byte(progmem_s++)))
uart1_putc(c);
} /* uart1_puts_p */
#endif

196
uart.h
View File

@@ -1,196 +0,0 @@
#ifndef UART_H
#define UART_H
/************************************************************************
Title: Interrupt UART library with receive/transmit circular buffers
Author: Peter Fleury <pfleury@gmx.ch> http://tinyurl.com/peterfleury
File: $Id: uart.h,v 1.13 2015/01/11 13:53:25 peter Exp $
Software: AVR-GCC 4.x, AVR Libc 1.4 or higher
Hardware: any AVR with built-in UART/USART
Usage: see Doxygen manual
LICENSE:
Copyright (C) 2015 Peter Fleury, GNU General Public License Version 3
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
************************************************************************/
/**
* @file
* @defgroup pfleury_uart UART Library <uart.h>
* @code #include <uart.h> @endcode
*
* @brief Interrupt UART library using the built-in UART with transmit and receive circular buffers.
*
* This library can be used to transmit and receive data through the built in UART.
*
* An interrupt is generated when the UART has finished transmitting or
* receiving a byte. The interrupt handling routines use circular buffers
* for buffering received and transmitted data.
*
* The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE constants define
* the size of the circular buffers in bytes. Note that these constants must be a power of 2.
* You may need to adapt these constants to your target and your application by adding
* CDEFS += -DUART_RX_BUFFER_SIZE=nn -DUART_TX_BUFFER_SIZE=nn to your Makefile.
*
* @note Based on Atmel Application Note AVR306
* @author Peter Fleury pfleury@gmx.ch http://tinyurl.com/peterfleury
* @copyright (C) 2015 Peter Fleury, GNU General Public License Version 3
*/
#include <avr/pgmspace.h>
#if (__GNUC__ * 100 + __GNUC_MINOR__) < 405
#error "This library requires AVR-GCC 4.5 or later, update to newer AVR-GCC compiler !"
#endif
/**@{*/
/*
** constants and macros
*/
/** @brief UART Baudrate Expression
* @param xtalCpu system clock in Mhz, e.g. 4000000UL for 4Mhz
* @param baudRate baudrate in bps, e.g. 1200, 2400, 9600
*/
#define UART_BAUD_SELECT(baudRate, xtalCpu) (((xtalCpu) + 8UL * (baudRate)) / (16UL * (baudRate)) - 1UL)
/** @brief UART Baudrate Expression for ATmega double speed mode
* @param xtalCpu system clock in Mhz, e.g. 4000000UL for 4Mhz
* @param baudRate baudrate in bps, e.g. 1200, 2400, 9600
*/
#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate, xtalCpu) \
(((((xtalCpu) + 4UL * (baudRate)) / (8UL * (baudRate)) - 1UL)) | 0x8000)
/** @brief Size of the circular receive buffer, must be power of 2
*
* You may need to adapt this constant to your target and your application by adding
* CDEFS += -DUART_RX_BUFFER_SIZE=nn to your Makefile.
*/
#ifndef UART_RX_BUFFER_SIZE
#define UART_RX_BUFFER_SIZE 32
#endif
/** @brief Size of the circular transmit buffer, must be power of 2
*
* You may need to adapt this constant to your target and your application by adding
* CDEFS += -DUART_TX_BUFFER_SIZE=nn to your Makefile.
*/
#ifndef UART_TX_BUFFER_SIZE
#define UART_TX_BUFFER_SIZE 32
#endif
/* test if the size of the circular buffers fits into SRAM */
#if ((UART_RX_BUFFER_SIZE + UART_TX_BUFFER_SIZE) >= (RAMEND - 0x60))
#error "size of UART_RX_BUFFER_SIZE + UART_TX_BUFFER_SIZE larger than size of SRAM"
#endif
/*
** high byte error return code of uart_getc()
*/
#define UART_FRAME_ERROR 0x1000 /**< @brief Framing Error by UART */
#define UART_OVERRUN_ERROR 0x0800 /**< @brief Overrun condition by UART */
#define UART_PARITY_ERROR 0x0400 /**< @brief Parity Error by UART */
#define UART_BUFFER_OVERFLOW 0x0200 /**< @brief receive ringbuffer overflow */
#define UART_NO_DATA 0x0100 /**< @brief no receive data available */
/*
** function prototypes
*/
/**
@brief Initialize UART and set baudrate
@param baudrate Specify baudrate using macro UART_BAUD_SELECT()
@return none
*/
extern void uart_init(unsigned int baudrate);
/**
* @brief Get received byte from ringbuffer
*
* Returns in the lower byte the received character and in the
* higher byte the last receive error.
* UART_NO_DATA is returned when no data is available.
*
* @return lower byte: received byte from ringbuffer
* @return higher byte: last receive status
* - \b 0 successfully received data from UART
* - \b UART_NO_DATA
* <br>no receive data available
* - \b UART_BUFFER_OVERFLOW
* <br>Receive ringbuffer overflow.
* We are not reading the receive buffer fast enough,
* one or more received character have been dropped
* - \b UART_OVERRUN_ERROR
* <br>Overrun condition by UART.
* A character already present in the UART UDR register was
* not read by the interrupt handler before the next character arrived,
* one or more received characters have been dropped.
* - \b UART_FRAME_ERROR
* <br>Framing Error by UART
*/
extern unsigned int uart_getc(void);
/**
* @brief Put byte to ringbuffer for transmitting via UART
* @param data byte to be transmitted
* @return none
*/
extern void uart_putc(unsigned char data);
/**
* @brief Put string to ringbuffer for transmitting via UART
*
* The string is buffered by the uart library in a circular buffer
* and one character at a time is transmitted to the UART using interrupts.
* Blocks if it can not write the whole string into the circular buffer.
*
* @param s string to be transmitted
* @return none
*/
extern void uart_puts(const char *s);
/**
* @brief Put string from program memory to ringbuffer for transmitting via UART.
*
* The string is buffered by the uart library in a circular buffer
* and one character at a time is transmitted to the UART using interrupts.
* Blocks if it can not write the whole string into the circular buffer.
*
* @param s program memory string to be transmitted
* @return none
* @see uart_puts_P
*/
extern void uart_puts_p(const char *s);
/**
* @brief Macro to automatically put a string constant into program memory
*/
#define uart_puts_P(__s) uart_puts_p(PSTR(__s))
/** @brief Initialize USART1 (only available on selected ATmegas) @see uart_init */
extern void uart1_init(unsigned int baudrate);
/** @brief Get received byte of USART1 from ringbuffer. (only available on selected ATmega) @see uart_getc */
extern unsigned int uart1_getc(void);
/** @brief Put byte to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_putc */
extern void uart1_putc(unsigned char data);
/** @brief Put string to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts */
extern void uart1_puts(const char *s);
/** @brief Put string from program memory to ringbuffer for transmitting via USART1 (only available on selected ATmega)
* @see uart_puts_p */
extern void uart1_puts_p(const char *s);
/** @brief Macro to automatically put a string constant into program memory */
#define uart1_puts_P(__s) uart1_puts_p(PSTR(__s))
/**@}*/
#endif // UART_H

286
uart.hpp
View File

@@ -1,286 +0,0 @@
#pragma once
#include "config.hpp"
#include "hardware0.hpp"
#include "hardware1.hpp"
#include "software.hpp"
#include "../flash/flash.hpp"
#define FORCE_INLINE __attribute__((always_inline))
namespace uart {
namespace detail {
template <typename...>
struct always_false {
static constexpr auto value = false;
};
} // namespace detail
template <class Driver>
class Uart {
public:
// Initialization is done upon construction
Uart()
{
Driver::init();
}
// Moving and copying uart objects is not supported
Uart(const Uart &) = delete;
Uart(Uart &&) = delete;
Uart &operator=(const Uart &) = delete;
Uart &operator=(Uart &&) = delete;
static void txByte(const typename Driver::data_t &byte)
{
Driver::txByte(byte);
}
static bool rxByte(typename Driver::data_t &byte)
{
return Driver::rxByte(byte);
}
static bool peek(typename Driver::data_t &byte)
{
return Driver::peek(byte);
}
static bool peek()
{
return Driver::peek();
}
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);
}
//////////////////////////////////////////////////////////////////////////
// Output stream overloads
Uart &operator<<(const char *str)
{
txString(str);
return *this;
}
Uart &operator<<(const ::detail::FlashString *str)
{
txString(str);
return *this;
}
template <typename... Ts>
Uart &operator<<(char)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(unsigned char)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(short)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(unsigned short)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(int)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(unsigned int)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(long)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(unsigned long)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(long long)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(unsigned long long)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(float)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(double)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(long double)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(bool)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator<<(const void *)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
//////////////////////////////////////////////////////////////////////////
// Input stream overloads
template <typename... Ts>
Uart &operator>>(char &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned char &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(short &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned short &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(int &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned int &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(long &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned long &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(long long &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(unsigned long long &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(float &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(double &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(long double &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(bool &)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
template <typename... Ts>
Uart &operator>>(const void *&)
{
static_assert(detail::always_false<Ts...>::value, "Not implemented");
}
};
template <typename cfg = Config<>>
using Uart0 = Uart<Hardware0<Mode::ASYNCHRONOUS, cfg>>;
#ifdef HAS_UART1
template <typename cfg = Config<>>
using Uart1 = Uart<Hardware1<Mode::ASYNCHRONOUS, cfg>>;
#endif
} // namespace uart
#undef FORCE_INLINE
#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

Submodule uart/flash added at 6edb2e5a21

1
uart/io Submodule

Submodule uart/io added at 80de36ee7e

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

Submodule uart/uart added at 119de32445

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

Submodule uart/util added at 81b3ae244c

642
usart.cpp
View File

@@ -1,642 +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 );
}
//////////////////////////////////////////////////////////////////////////
uint32_t USART0::getBaudRate()
{
uint16_t ui16UBRR;
ui16UBRR = static_cast<uint16_t>( *m_vui8pUBRRH ) << 8;
ui16UBRR |= *m_vui8pUBRRL;
return F_CPU / ( static_cast<uint32_t>( 16 ) * ( ui16UBRR + 1 ) );
}
//////////////////////////////////////////////////////////////////////////
uint8_t USART0::getDataBits()
{
if( *m_vui8pUCSRB & ( 1 << UCSZ2_D ) )
{
return 9;
}
uint8_t ui8UCSRC = readUCSRC();
bool bZeroBit = ui8UCSRC & ( 1 << UCSZ0_D );
bool bOneBit = ui8UCSRC & ( 1 << UCSZ1_D );
return 5 + ( bOneBit << 1 | bZeroBit );
}
//////////////////////////////////////////////////////////////////////////
USART0::Parity USART0::getParity()
{
uint8_t ui8UCSRC = readUCSRC();
bool bZeroBit = ui8UCSRC & ( 1 << UPM0_D );
bool bOneBit = ui8UCSRC & ( 1 << UPM1_D );
if( bOneBit && !bZeroBit )
{
return Parity::EVEN;
}
if( bOneBit && bZeroBit )
{
return Parity::ODD;
}
return Parity::DISABLED;
}
//////////////////////////////////////////////////////////////////////////
USART0::StopBit USART0::getStopBits()
{
uint8_t ui8UCSRC = readUCSRC();
if( ui8UCSRC & ( 1 << USBS_D ) )
{
return StopBit::TWO;
}
return StopBit::ONE;
}
//////////////////////////////////////////////////////////////////////////
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;
}
//////////////////////////////////////////////////////////////////////////
uint8_t USART0::receiveByteBlocked()
{
uint8_t ui8Received;
while( !receiveByte( ui8Received ) );
return ui8Received;
}
//////////////////////////////////////////////////////////////////////////
uint8_t USART0::receivePeek()
{
uint8_t ui8Received;
if( !( SREG & ( 1 << SREG_I ) && m_vsizeRXBufferHead == m_vsizeRXBufferTail ) )
{
while( !( *m_vui8pUCSRA & ( 1 << RXC_D ) ) );
ui8Received = *m_vui8pUDR;
size_t sizeIndex = ( m_vsizeRXBufferHead + 1 ) % sm_sizeRXBUFFER_SIZE;
if( sizeIndex != m_vsizeRXBufferTail )
{
m_vui8aRXBuffer[m_vsizeRXBufferHead] = ui8Received;
m_vsizeRXBufferHead = sizeIndex;
}
return ui8Received;
}
while( m_vsizeRXBufferHead == m_vsizeRXBufferTail );
return m_vui8aRXBuffer[m_vsizeRXBufferTail];
}
//////////////////////////////////////////////////////////////////////////
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 ) )
{
szBuffer[sizeReceived - strlen( szLineTerminator )] = '\0';
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool USART0::receiveLine( char *szBuffer, size_t sizeBufferLength, uint16_t ui16TimeoutMS, const char *szLineTerminator /* = "\r\n" */ )
{
size_t sizeReceived = 0;
while( sizeReceived < sizeBufferLength - 1 )
{
uint8_t ui8ReceiveByte;
uint16_t ui16DelayCounter = 0;
while( !receiveByte( ui8ReceiveByte ) )
{
_delay_ms( 1 );
if( ui16DelayCounter++ > ui16TimeoutMS )
{
szBuffer[sizeReceived] = '\0';
return false;
}
}
szBuffer[sizeReceived++] = ui8ReceiveByte;
szBuffer[sizeReceived] = '\0';
if( strstr( szBuffer, szLineTerminator ) )
{
szBuffer[sizeReceived - strlen( szLineTerminator )] = '\0';
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
void USART0::flushReceive()
{
uint32_t ui32BaudRate = getBaudRate();
uint8_t ui8BitsPerSymbol = 1;
ui8BitsPerSymbol += getDataBits();
if( getParity() != Parity::DISABLED )
{
ui8BitsPerSymbol += 1;
}
if( getStopBits() == StopBit::ONE )
{
ui8BitsPerSymbol += 1;
}
else
{
ui8BitsPerSymbol += 2;
}
uint16_t ui16BaudDelayMS = static_cast<uint16_t>( ( 1000.0 * ui8BitsPerSymbol ) / ui32BaudRate ) + 1;
uint8_t ui8Received;
if( !( SREG & ( 1 << SREG_I ) ) )
{
while( true )
{
for( uint16_t i = 0; i < ui16BaudDelayMS; ++i )
{
_delay_ms( 1 );
}
if( m_vsizeRXBufferHead != m_vsizeRXBufferTail )
{
receiveByte( ui8Received );
continue;
}
if( ( *m_vui8pUCSRA & ( 1 << RXC_D ) ) )
{
ui8Received = *m_vui8pUDR;
continue;
}
break;
}
}
else
{
while( receiveByte( ui8Received, ui16BaudDelayMS ) );
}
}
//////////////////////////////////////////////////////////////////////////
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

185
usart.h
View File

@@ -1,185 +0,0 @@
/*
* Copyright (c) by BlackMark 2015-2018
* Date 12/04/2018
* Version 3.4
*/
#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__)
#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__) || (__AVR_ATmega8A__)
#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 USART_SPI
#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 );
uint32_t getBaudRate();
uint8_t getDataBits();
Parity getParity();
StopBit getStopBits();
public:
~USART0();
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 );
uint8_t receiveByteBlocked();
uint8_t receivePeek();
bool receiveLine( char *szBuffer, size_t sizeBufferLength, const char *szLineTerminator = "\r\n" );
bool receiveLine( char *szBuffer, size_t sizeBufferLength, uint16_t ui16TimeoutMS, 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