2019-08-15 18:07:11 +02:00
|
|
|
#ifndef UART_HARDWARE_0_HPP
|
|
|
|
#define UART_HARDWARE_0_HPP
|
2019-07-27 18:55:17 +02:00
|
|
|
|
2019-08-02 20:23:54 +02:00
|
|
|
#include <stdint.h>
|
|
|
|
|
2019-08-05 17:59:33 +02:00
|
|
|
#include <avr/interrupt.h>
|
2019-08-02 20:23:54 +02:00
|
|
|
#include <avr/io.h>
|
2019-08-10 14:12:10 +02:00
|
|
|
#include <avr/sfr_defs.h>
|
2019-08-02 20:23:54 +02:00
|
|
|
|
2019-07-28 12:15:19 +02:00
|
|
|
#include "config.hpp"
|
2019-08-02 09:21:47 +02:00
|
|
|
#include "hardware.hpp"
|
2019-07-27 18:55:17 +02:00
|
|
|
|
2019-07-28 17:32:51 +02:00
|
|
|
#define FORCE_INLINE __attribute__((always_inline))
|
|
|
|
|
2019-07-27 18:55:17 +02:00
|
|
|
namespace uart {
|
|
|
|
|
2019-07-28 17:32:51 +02:00
|
|
|
namespace detail {
|
|
|
|
|
2019-08-14 18:58:21 +02:00
|
|
|
#if defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega328P__)
|
2019-07-30 20:29:38 +02:00
|
|
|
|
2019-08-10 14:12:10 +02:00
|
|
|
/*
|
2019-08-15 18:49:29 +02:00
|
|
|
The following works in avr-gcc 5.4.0, but is not legal C++, because ptr's are not legal constexpr's:
|
2019-08-10 14:12:10 +02:00
|
|
|
constexpr auto *foo = ptr;
|
|
|
|
|
2019-08-15 18:49:29 +02:00
|
|
|
Workaround is to store the the address of the ptr in a uintptr_t and reinterpret_cast it at call site.
|
|
|
|
The _SFR_ADDR macro in sfr_defs.h would give the address, but it does that by taking the address of the dereferenced
|
|
|
|
pointer and casts it to uint16_t, which is still not a legal constexpr.
|
|
|
|
The workaround therefore is to disable the pointer cast and dereference macro _MMIO_BYTE temporarily.
|
2019-08-10 14:12:10 +02:00
|
|
|
*/
|
|
|
|
|
2019-08-15 18:49:29 +02:00
|
|
|
#pragma push_macro("_MMIO_BYTE")
|
|
|
|
#undef _MMIO_BYTE
|
|
|
|
#define _MMIO_BYTE
|
|
|
|
|
2019-07-30 20:29:38 +02:00
|
|
|
struct Registers0 {
|
2019-08-15 18:49:29 +02:00
|
|
|
static constexpr uintptr_t IO_REG_ADDR = UDR0;
|
|
|
|
static constexpr uintptr_t CTRL_STAT_REG_A_ADDR = UCSR0A;
|
|
|
|
static constexpr uintptr_t CTRL_STAT_REG_B_ADDR = UCSR0B;
|
|
|
|
static constexpr uintptr_t CTRL_STAT_REG_C_ADDR = UCSR0C;
|
|
|
|
static constexpr uintptr_t BAUD_REG_L_ADDR = UBRR0L;
|
|
|
|
static constexpr uintptr_t BAUD_REG_H_ADDR = UBRR0H;
|
2019-07-28 17:32:51 +02:00
|
|
|
};
|
|
|
|
|
2019-08-15 18:49:29 +02:00
|
|
|
#pragma pop_macro("_MMIO_BYTE")
|
|
|
|
|
2019-07-30 21:43:52 +02:00
|
|
|
enum class ControlFlagsA0 {
|
2019-07-30 20:56:16 +02:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2019-07-30 21:43:52 +02:00
|
|
|
enum class ControlFlagsB0 {
|
2019-07-30 20:56:16 +02:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2019-07-30 21:43:52 +02:00
|
|
|
enum class ControlFlagsC0 {
|
2019-07-30 20:56:16 +02:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2019-07-30 21:51:13 +02:00
|
|
|
// 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
|
2019-07-30 20:29:38 +02:00
|
|
|
|
2019-08-02 20:29:04 +02:00
|
|
|
extern void (*fnRx0IntHandler)();
|
|
|
|
extern void (*fnDataReg0EmptyIntHandler)();
|
2019-08-02 15:46:07 +02:00
|
|
|
|
2019-07-30 20:29:38 +02:00
|
|
|
#else
|
|
|
|
#error "This chip is not supported"
|
|
|
|
#endif
|
|
|
|
|
2019-07-30 21:43:52 +02:00
|
|
|
} // namespace detail
|
|
|
|
|
2019-08-05 20:05:59 +02:00
|
|
|
template <class cfg = Config<>, Driven driven = Driven::INTERRUPT, Mode mode = Mode::ASYNCHRONOUS>
|
2019-08-14 19:49:42 +02:00
|
|
|
class Hardware0 : public detail::BlockingHardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
|
|
|
|
detail::ControlFlagsC0, cfg, mode> {
|
|
|
|
};
|
2019-08-02 18:20:06 +02:00
|
|
|
|
2019-08-14 19:49:42 +02:00
|
|
|
template <class cfg, Mode mode>
|
|
|
|
class Hardware0<cfg, Driven::INTERRUPT, mode>
|
|
|
|
: public detail::InterruptHardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
|
|
|
|
detail::ControlFlagsC0, cfg, mode> {
|
|
|
|
using detail::InterruptHardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
|
|
|
|
detail::ControlFlagsC0, cfg, mode>::rxIntHandler;
|
2019-08-02 12:08:16 +02:00
|
|
|
|
2019-08-14 19:49:42 +02:00
|
|
|
using detail::InterruptHardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
|
|
|
|
detail::ControlFlagsC0, cfg, mode>::dataRegEmptyIntHandler;
|
2019-08-03 17:52:28 +02:00
|
|
|
|
2019-08-02 12:08:16 +02:00
|
|
|
using HardwareImpl = detail::Hardware<detail::Registers0, detail::ControlFlagsA0, detail::ControlFlagsB0,
|
2019-08-14 19:49:42 +02:00
|
|
|
detail::ControlFlagsC0, cfg, Driven::INTERRUPT, mode>;
|
2019-08-02 12:08:16 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
static void init() FORCE_INLINE
|
|
|
|
{
|
|
|
|
detail::fnRx0IntHandler = rxIntHandler;
|
2019-08-02 15:46:07 +02:00
|
|
|
detail::fnDataReg0EmptyIntHandler = dataRegEmptyIntHandler;
|
2019-08-02 12:08:16 +02:00
|
|
|
|
|
|
|
HardwareImpl::init();
|
2019-08-05 17:59:33 +02:00
|
|
|
sei();
|
2019-08-02 12:08:16 +02:00
|
|
|
}
|
2019-07-30 21:43:52 +02:00
|
|
|
};
|
|
|
|
|
2019-07-27 18:55:17 +02:00
|
|
|
} // namespace uart
|
2019-07-28 17:32:51 +02:00
|
|
|
|
|
|
|
#undef FORCE_INLINE
|
2019-08-15 18:07:11 +02:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2019-08-15 18:58:25 +02:00
|
|
|
#ifdef UART0_INT_VECTORS
|
2019-08-15 18:07:11 +02:00
|
|
|
|
|
|
|
#include <avr/interrupt.h>
|
|
|
|
|
|
|
|
namespace uart {
|
|
|
|
namespace detail {
|
|
|
|
|
|
|
|
#if defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega328P__)
|
|
|
|
|
|
|
|
#if defined(__AVR_ATmega328P__)
|
|
|
|
#define USART0_RX_vect USART_RX_vect
|
|
|
|
#define USART0_UDRE_vect USART_UDRE_vect
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void (*fnRx0IntHandler)() = nullptr;
|
|
|
|
void (*fnDataReg0EmptyIntHandler)() = nullptr;
|
|
|
|
|
|
|
|
ISR(USART0_RX_vect)
|
|
|
|
{
|
|
|
|
if (fnRx0IntHandler)
|
|
|
|
fnRx0IntHandler();
|
|
|
|
}
|
|
|
|
|
|
|
|
ISR(USART0_UDRE_vect)
|
|
|
|
{
|
|
|
|
if (fnDataReg0EmptyIntHandler)
|
|
|
|
fnDataReg0EmptyIntHandler();
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
#error "This chip is not supported"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} // namespace detail
|
|
|
|
} // namespace uart
|
|
|
|
|
2019-08-15 18:58:25 +02:00
|
|
|
#undef UART0_INT_VECTORS
|
|
|
|
|
2019-08-15 18:07:11 +02:00
|
|
|
#endif
|