Hardware components | ||||||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
Software apps and online services | ||||||
![]() |
|
- Dropping Characters/Receiving Garbage
- Serial Monitor not Working
- Really Slow
- Can't use Both Hardware UARTS at the same time
- Need 9-bit Support
UART issues were reported by our customers, when using the Arduino UNO R4 with the IO Expander. When the Serial Monitor was enabled for debugging, the UART communications to the IO Expander started failing. What was going on? Surely a big company like Arduino would not release a faulty product? To help our customers we investigated the issue and discovered that the issue was with the Arduino UNO R4 UART driver and released this fix to help everyone else with these same issues.
Upon examination of the UART::write(uint8_t) function we can clearly see the while (!tx_done), waiting for tx_done to be set by the Transmit End Interrupt. This function is blocking and will not return until the transmit is complete. What a waste of CPU!
/* -------------------------------------------------------------------------- */
size_t UART::write(uint8_t c) {
/* -------------------------------------------------------------------------- */
if(init_ok) {
tx_done = false;
R_SCI_UART_Write(&uart_ctrl, &c, 1);
while (!tx_done) {}
return 1;
}
else {
return 0;
}
}
Transmit Ring Buffer not UsedThe class UART defines a txBuffer but is never used by the UART::write(uint8_t) function. What a waste of Memory!
class UART : public arduino::HardwareSerial {
...
private:
...
arduino::SafeRingBufferN<SERIAL_BUFFER_SIZE> txBuffer;
...
};
Ring Buffer is not Interrupt SafeWhen you get a Receive Interrupt the function RingBufferN::store_char(uint8_t) is called which updates the _numElems variable. In your application when you call the Serial.read() function it calls the RingBufferN::read_char() which also updates the very same _numElems variable. This is not interrupt safe and can result in the _numElems not updating properly or even becoming corrupted.
/* -------------------------------------------------------------------------- */
void UART::WrapperCallback(uart_callback_args_t *p_args) {
/* -------------------------------------------------------------------------- */
...
case UART_EVENT_RX_CHAR:
{
if (uart_ptr->rxBuffer.availableForStore())
uart_ptr->rxBuffer.store_char(p_args->data);
break;
}
...
}
void RingBufferN::store_char( uint8_t c )
{
/* if we should be storing the received character into the location
just before the tail (meaning that the head would advance to the
current location of the tail), we're about to overflow the buffer
and so we don't write the character or advance the head. */
if (!isFull())
{
_aucBuffer[_iHead] = c ;
_iHead = nextIndex(_iHead);
_numElems = _numElems + 1;
}
}
/* -------------------------------------------------------------------------- */
int UART::read() {
/* -------------------------------------------------------------------------- */
return rxBuffer.read_char();
}
int RingBufferN::read_char()
{
if (isEmpty())
return -1;
uint8_t value = _aucBuffer[_iTail];
_iTail = nextIndex(_iTail);
_numElems = _numElems - 1;
return value;
}
USB Communications Blocks UART InterruptsUSB Communications has the same Interrupt Priority as UART communications, but the USB interrupt can consume too much time not allowing a UART interrupt, causing a Receive Interrupt Overrun at higher speed communications like 115k. No communication device should block others from getting their critical CPU time.
9-bit SupportTo help support the IO Expander 9-bit mode, the UART class has also been modified to support 9-bit communications as well.
Download FilesPlease make a backup of the files you are going to replace first, or you can reinstall the Arduino UNO R4 board package.
Download and replace the following files in the Arduino15\packages\arduino\hardware\renesas_uno\1.2.0\Cores\Arduino folder.
Windows: C:\Users\{username}\AppData\Local\Arduino15
macOS: /Users/{username}/Library/Arduino15
Linux: /home/{username}/.arduino15
serial.h
serial.cpp
IRQManager.cpp
api\HardwareSerial.h
Note: Fix is for Arduino UNO R4 v1.2.0 Board Package.
This fix 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.
serial.h
C/C++Windows: C:\Users\{username}\AppData\Local\Arduino15
macOS: /Users/{username}/Library/Arduino15
Linux: /home/{username}/.arduino15
/*
Serial.h - Hardware serial library for Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 28 September 2010 by Mark Sproul
Modified 14 August 2012 by Alarus
Modified 3 December 2013 by Matthijs Kooijman
*/
/*
Modifications for v1.2.0 Arduino UNO R4 Board package to fix:
1. Ring Buffer not thread safe.
2. Added Tx buffer.
3. Removed TEIE.
4. Both Hardware UARTS can be used at the same time.
Modified 1 November 2024 by Christian Huygen
www.zevendevelopment.com
*/
#define _TIMEVAL_DEFINED
#define _SYS_SELECT_H
#include "Arduino.h"
#include "api/HardwareSerial.h"
#ifdef __cplusplus
#ifndef __ARDUINO_UART_IMPLEMENTATION__
#define __ARDUINO_UART_IMPLEMENTATION__
#include "r_sci_uart.h"
#include "r_uart_api.h"
#include "SafeRingBuffer.h"
#undef SERIAL_BUFFER_SIZE
//#define SERIAL_BUFFER_SIZE 512
// Need to add one because the SerialRingBuffer no longer uses _numItems
// This will make the Serial Ring Buffer Interrupt Safe.
// _numElems gets updated when a character is received in the Interrupt and also when you UART::read() *** CORRUPTION OF SafeRingBufferN ***
// The SerialRingBuffer updates the _head when a character is received in the Interrupt, but updates the _tail when you UART::read().
#define SERIAL_BUFFER_SIZE 64+1
#define MAX_UARTS 10
typedef enum {
TX_STARTED,
TX_STOPPED
} TxStatus_t;
namespace arduino {
template <int N>
class SerialRingBuffer
{
public:
SerialRingBuffer() { clear(); }
inline void clear() { _head = _tail = 0; }
inline bool isEmpty() { return (_head == _tail); }
inline bool isFull()
{
int i = (_head + 1) % N;
return (i == _tail);
}
bool store_char(uint8_t c)
{
int i = (_head + 1) % N;
if (i == _tail) return false;
_buffer[_head] = c;
_head = i;
return true;
}
int read_char()
{
if (isEmpty()) return -1;
uint8_t c = _buffer[_tail];
_tail = (_tail + 1) % N;
return c;
}
int available() { return (N + _head - _tail) % N; }
int peek()
{
if (isEmpty()) return -1;
return _buffer[_tail];
}
private:
volatile int _head, _tail;
uint8_t _buffer[N];
};
}
class UART : public arduino::HardwareSerial {
public:
static UART *g_uarts[MAX_UARTS];
static void WrapperCallback(uart_callback_args_t *p_args);
UART(int _pin_tx, int _pin_rx, int pin_rts = -1, int pin_cts = -1);
void begin(unsigned long);
void begin(unsigned long, uint16_t config);
void end();
int available(void);
int peek(void);
int read(void);
void flush(void);
size_t write(uint8_t c);
size_t write(uint8_t* c, size_t len);
size_t write_raw(uint8_t* c, size_t len);
void address(uint8_t c);
using Print::write;
operator bool(); // { return true; }
private:
int tx_pin;
int rx_pin;
int rts_pin = -1;
int cts_pin = -1;
bool cfg_pins(int max_index);
int channel;
//arduino::SafeRingBufferN<SERIAL_BUFFER_SIZE> rxBuffer;
//arduino::SafeRingBufferN<SERIAL_BUFFER_SIZE> txBuffer;
arduino::SerialRingBuffer<SERIAL_BUFFER_SIZE> rxBuffer;
arduino::SerialRingBuffer<SERIAL_BUFFER_SIZE> txBuffer;
//volatile bool tx_done;
sci_uart_instance_ctrl_t uart_ctrl;
uart_cfg_t uart_cfg;
baud_setting_t uart_baud;
sci_uart_extended_cfg_t uart_cfg_extend;
uart_ctrl_t* get_ctrl() { return &uart_ctrl; }
bool setUpUartIrqs(uart_cfg_t &cfg);
protected:
bool init_ok;
};
extern UART _UART1_;
extern UART _UART2_;
extern UART _UART3_;
extern UART _UART4_;
extern UART _UART5_;
#endif
#endif
serial.cpp
C/C++Windows: C:\Users\{username}\AppData\Local\Arduino15
macOS: /Users/{username}/Library/Arduino15
Linux: /home/{username}/.arduino15
/*
Serial.cpp - wrapper over mbed RawSerial
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2018-2019 Arduino SA
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
/*
Modifications for v1.2.0 Arduino UNO R4 Board package to fix:
1. Transmit is Blocking.
2. Transmit Ring Buffer not Used.
3. Ring Buffer is not Interrupt Safe.
4. Both Hardware UARTS can be used at the same time.
5. 9-bit Support.
Modified 6 July 2024 by Christian Huygen
www.zevendevelopment.com
*/
#include "Arduino.h"
#include "Serial.h"
#include "IRQManager.h"
#ifdef Serial
#undef Serial
#endif
UART * UART::g_uarts[MAX_UARTS] = {nullptr};
void uart_callback(uart_callback_args_t __attribute((unused)) *p_args)
{
/* This callback function is not used but it is referenced into
FSP configuration so that (for the moment it is necessary to keep it) */
}
/* -------------------------------------------------------------------------- */
void UART::WrapperCallback(uart_callback_args_t *p_args) {
/* -------------------------------------------------------------------------- */
uint32_t channel = p_args->channel;
UART *uart_ptr = UART::g_uarts[channel];
if(uart_ptr == nullptr) {
return;
}
switch (p_args->event){
case UART_EVENT_ERR_PARITY:
case UART_EVENT_ERR_FRAMING:
case UART_EVENT_ERR_OVERFLOW:
case UART_EVENT_RX_COMPLETE: // This is called when all the "expected" data are received
{
break;
}
case UART_EVENT_TX_COMPLETE:
{
break;
}
case UART_EVENT_TX_DATA_EMPTY:
{
//uint8_t to_enqueue = uart_ptr->txBuffer.available() < uart_ptr->uart_ctrl.fifo_depth ? uart_ptr->txBuffer.available() : uart_ptr->uart_ctrl.fifo_depth;
//while (to_enqueue) {
//uart_ptr->tx_done = true;
if (!uart_ptr->txBuffer.isEmpty())
uart_ptr->uart_ctrl.p_reg->TDR = uart_ptr->txBuffer.read_char();
uart_ptr->uart_ctrl.p_reg->SCR_b.TIE = 1;
// Disable TEIE
// DTC and DMAC activation is not possible with TEIE enabled.
// See Table 28.25 of RA4M1 documentation
// Left alone for possible I2C communications requirements
//uart_ptr->uart_ctrl.p_reg->SCR_b.TEIE = 0;
break;
}
case UART_EVENT_RX_CHAR:
{
//if (uart_ptr->rxBuffer.availableForStore()) {
if (!uart_ptr->rxBuffer.isFull()) {
uart_ptr->rxBuffer.store_char(p_args->data);
}
break;
}
case UART_EVENT_BREAK_DETECT:
{
break;
}
}
}
UART::UART(int _pin_tx, int _pin_rx, int _pin_rts, int _pin_cts):
tx_pin(_pin_tx),
rx_pin(_pin_rx),
rts_pin(_pin_rts),
cts_pin(_pin_cts),
init_ok(false) {
/* -------------------------------------------------------------------------- */
uart_cfg.txi_irq = FSP_INVALID_VECTOR;
uart_cfg.tei_irq = FSP_INVALID_VECTOR;
uart_cfg.rxi_irq = FSP_INVALID_VECTOR;
uart_cfg.eri_irq = FSP_INVALID_VECTOR;
}
/* -------------------------------------------------------------------------- */
bool UART::setUpUartIrqs(uart_cfg_t &cfg) {
/* -------------------------------------------------------------------------- */
bool rv = false;
rv = IRQManager::getInstance().addPeripheral(IRQ_SCI_UART,&cfg);
return rv;
}
/* -------------------------------------------------------------------------- */
size_t UART::write(uint8_t c) {
/* -------------------------------------------------------------------------- */
if(init_ok) {
// Interrupts are disabled because a Transmit Interrupt could have occured with one
// char in the buffer, and it is removed before we can store it, resulting in a missed
// TDR and there will be no more TIE interrupts.
noInterrupts();
if (txBuffer.isEmpty() && uart_ctrl.p_reg->SSR_b.TDRE == 1) {
interrupts();
uart_ctrl.p_reg->SCR_b.TIE = 1;
if (uart_cfg.data_bits == UART_DATA_BITS_9) uart_ctrl.p_reg->TDRHL = c;
else uart_ctrl.p_reg->TDR = c;
return 1;
}
if (txBuffer.isFull()) {
interrupts();
while(txBuffer.isFull());
}
txBuffer.store_char(c);
interrupts();
/*
tx_done = false;
R_SCI_UART_Write(&uart_ctrl, &c, 1);
while (!tx_done) {} */
return 1;
}
else {
return 0;
}
}
size_t UART::write(uint8_t* c, size_t len) {
size_t i = 0;
if(init_ok) {
while (i < len) {
write(*(c+i));
i++;
}
/* tx_done = false;
R_SCI_UART_Write(&uart_ctrl, c, len);
while (!tx_done) {} */
return len;
}
else {
return 0;
}
}
/* -------------------------------------------------------------------------- */
UART::operator bool() {
/* -------------------------------------------------------------------------- */
return true;
}
/* -------------------------------------------------------------------------- */
bool UART::cfg_pins(int max_index) {
/* -------------------------------------------------------------------------- */
/* verify index are good */
if(tx_pin < 0 || rx_pin < 0 || tx_pin >= max_index || rx_pin >= max_index) {
return false;
}
/* getting configuration from table */
auto cfgs_tx = getPinCfgs(tx_pin, PIN_CFG_REQ_UART_TX);
auto cfgs_rx = getPinCfgs(rx_pin, PIN_CFG_REQ_UART_RX);
uint16_t cfg_tx = 0;
uint16_t cfg_rx = 0;
/* Find the best combination */
for (size_t i = 0; i < cfgs_tx.size(); i++) {
for (size_t j = 0; j < cfgs_rx.size(); j++) {
if (cfgs_tx[i] && cfgs_rx[i] && GET_CHANNEL(cfgs_tx[i]) == GET_CHANNEL(cfgs_rx[j])) {
cfg_tx = cfgs_tx[i];
cfg_rx = cfgs_rx[j];
channel = GET_CHANNEL(cfg_tx);
goto done;
}
}
}
done:
/* verify configuration are good */
if(cfg_tx == 0 || cfg_rx == 0 ) {
return false;
}
/* verify channel does not exceed max possible uart channels */
if(channel >= MAX_UARTS) {
return false;
}
/* setting channel */
channel = GET_CHANNEL(cfg_tx);
/* actually configuring PIN function */
ioport_peripheral_t ioport_tx = USE_SCI_EVEN_CFG(cfg_tx) ? IOPORT_PERIPHERAL_SCI0_2_4_6_8 : IOPORT_PERIPHERAL_SCI1_3_5_7_9;
ioport_peripheral_t ioport_rx = USE_SCI_EVEN_CFG(cfg_rx) ? IOPORT_PERIPHERAL_SCI0_2_4_6_8 : IOPORT_PERIPHERAL_SCI1_3_5_7_9;
R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[tx_pin].pin, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | ioport_tx));
R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[rx_pin].pin, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | ioport_rx));
if (rts_pin != -1 && cts_pin != -1) {
// hopefully people using flow control have read the datasheet so let's avoid the double check
R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[rts_pin].pin, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | ioport_rx));
R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[cts_pin].pin, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | ioport_rx));
}
return true;
}
/* -------------------------------------------------------------------------- */
void UART::begin(unsigned long baudrate, uint16_t config) {
/* -------------------------------------------------------------------------- */
int max_index = PINS_COUNT;
init_ok = cfg_pins(max_index);
if(init_ok) {
UART::g_uarts[channel] = this;
uart_baud.semr_baudrate_bits_b.abcse = 0;
uart_baud.semr_baudrate_bits_b.abcs = 0;
uart_baud.semr_baudrate_bits_b.bgdm = 1;
uart_baud.cks = 0;
uart_baud.brr = 25;
uart_baud.mddr = (uint8_t) 256;
uart_baud.semr_baudrate_bits_b.brme = false;
uart_cfg_extend.clock = SCI_UART_CLOCK_INT;
uart_cfg_extend.rx_edge_start = SCI_UART_START_BIT_FALLING_EDGE;
uart_cfg_extend.noise_cancel = SCI_UART_NOISE_CANCELLATION_DISABLE;
uart_cfg_extend.rx_fifo_trigger = SCI_UART_RX_FIFO_TRIGGER_MAX;
uart_cfg_extend.p_baud_setting = &uart_baud;
uart_cfg_extend.flow_control = SCI_UART_FLOW_CONTROL_RTS;
uart_cfg_extend.flow_control_pin = (bsp_io_port_pin_t) UINT16_MAX;
if (rts_pin != -1 && cts_pin != -1) {
uart_cfg_extend.flow_control = SCI_UART_FLOW_CONTROL_HARDWARE_CTSRTS;
}
uart_cfg_extend.rs485_setting.enable = SCI_UART_RS485_DISABLE;
uart_cfg_extend.rs485_setting.polarity = SCI_UART_RS485_DE_POLARITY_HIGH;
uart_cfg_extend.rs485_setting.de_control_pin = (bsp_io_port_pin_t) UINT16_MAX;
uart_cfg.channel = channel;
uart_cfg.p_context = NULL;
uart_cfg.p_extend = &uart_cfg_extend;
uart_cfg.p_transfer_tx = NULL;
uart_cfg.p_transfer_rx = NULL;
switch(config){
case SERIAL_8N1:
uart_cfg.data_bits = UART_DATA_BITS_8;
uart_cfg.parity = UART_PARITY_OFF;
uart_cfg.stop_bits = UART_STOP_BITS_1;
break;
case SERIAL_8N2:
uart_cfg.data_bits = UART_DATA_BITS_8;
uart_cfg.parity = UART_PARITY_OFF;
uart_cfg.stop_bits = UART_STOP_BITS_2;
break;
case SERIAL_8E1:
uart_cfg.data_bits = UART_DATA_BITS_8;
uart_cfg.parity = UART_PARITY_EVEN;
uart_cfg.stop_bits = UART_STOP_BITS_1;
break;
case SERIAL_8E2:
uart_cfg.data_bits = UART_DATA_BITS_8;
uart_cfg.parity = UART_PARITY_EVEN;
uart_cfg.stop_bits = UART_STOP_BITS_2;
break;
case SERIAL_8O1:
uart_cfg.data_bits = UART_DATA_BITS_8;
uart_cfg.parity = UART_PARITY_ODD;
uart_cfg.stop_bits = UART_STOP_BITS_1;
break;
case SERIAL_8O2:
uart_cfg.data_bits = UART_DATA_BITS_8;
uart_cfg.parity = UART_PARITY_ODD;
uart_cfg.stop_bits = UART_STOP_BITS_2;
break;
// add 7 bit support
case SERIAL_7N1:
uart_cfg.data_bits = UART_DATA_BITS_7;
uart_cfg.parity = UART_PARITY_OFF;
uart_cfg.stop_bits = UART_STOP_BITS_1;
break;
case SERIAL_7N2:
uart_cfg.data_bits = UART_DATA_BITS_7;
uart_cfg.parity = UART_PARITY_OFF;
uart_cfg.stop_bits = UART_STOP_BITS_2;
break;
case SERIAL_7E1:
uart_cfg.data_bits = UART_DATA_BITS_7;
uart_cfg.parity = UART_PARITY_EVEN;
uart_cfg.stop_bits = UART_STOP_BITS_1;
break;
case SERIAL_7E2:
uart_cfg.data_bits = UART_DATA_BITS_7;
uart_cfg.parity = UART_PARITY_EVEN;
uart_cfg.stop_bits = UART_STOP_BITS_2;
break;
case SERIAL_7O1:
uart_cfg.data_bits = UART_DATA_BITS_7;
uart_cfg.parity = UART_PARITY_ODD;
uart_cfg.stop_bits = UART_STOP_BITS_1;
break;
case SERIAL_7O2:
uart_cfg.data_bits = UART_DATA_BITS_7;
uart_cfg.parity = UART_PARITY_ODD;
uart_cfg.stop_bits = UART_STOP_BITS_2;
break;
// add 9 bit support 9N1
case SERIAL_9N1:
uart_cfg.data_bits = UART_DATA_BITS_9;
uart_cfg.parity = UART_PARITY_OFF;
uart_cfg.stop_bits = UART_STOP_BITS_1;
break;
}
uart_cfg.p_callback = UART::WrapperCallback;
}
else {
return;
}
init_ok &= setUpUartIrqs(uart_cfg);
fsp_err_t err;
const bool bit_mod = true;
const uint32_t err_rate = 3000; //means 3%
err = R_SCI_UART_BaudCalculate(baudrate, bit_mod, err_rate, &uart_baud);
if (uart_baud.mddr == 0) {
err = R_SCI_UART_BaudCalculate(baudrate, false, err_rate, &uart_baud);
}
err = R_SCI_UART_Open (&uart_ctrl, &uart_cfg);
if(err != FSP_SUCCESS) while(1);
err = R_SCI_UART_BaudSet(&uart_ctrl, (void *) &uart_baud);
if(err != FSP_SUCCESS) while(1);
rxBuffer.clear();
txBuffer.clear();
}
/* -------------------------------------------------------------------------- */
void UART::begin(unsigned long baudrate) {
/* -------------------------------------------------------------------------- */
begin(baudrate, SERIAL_8N1);
}
/* -------------------------------------------------------------------------- */
void UART::end() {
/* -------------------------------------------------------------------------- */
rxBuffer.clear();
txBuffer.clear();
R_SCI_UART_Close (&uart_ctrl);
}
/* -------------------------------------------------------------------------- */
int UART::available() {
/* -------------------------------------------------------------------------- */
return rxBuffer.available();
}
/* -------------------------------------------------------------------------- */
int UART::peek() {
/* -------------------------------------------------------------------------- */
return rxBuffer.peek();
}
/* -------------------------------------------------------------------------- */
int UART::read() {
/* -------------------------------------------------------------------------- */
return rxBuffer.read_char();
}
/* -------------------------------------------------------------------------- */
void UART::flush() {
/* -------------------------------------------------------------------------- */
//while(txBuffer.available());
// Wait for queue to empty and TDR to be sent to RSR
while (!txBuffer.isEmpty() && uart_ctrl.p_reg->SSR_b.TDRE == 0);
}
/* -------------------------------------------------------------------------- */
size_t UART::write_raw(uint8_t* c, size_t len) {
/* -------------------------------------------------------------------------- */
size_t i = 0;
while (i < len) {
uart_ctrl.p_reg->TDR = *(c+i);
while (uart_ctrl.p_reg->SSR_b.TEND == 0) {}
i++;
}
return len;
}
/* -------------------------------------------------------------------------- */
void UART::address(uint8_t c) {
/* -------------------------------------------------------------------------- */
// 9-bit set for address
flush();
uart_ctrl.p_reg->TDRHL = 0x100 + c;
// Wait for address to be sent so next write will clear out the address bit
while (uart_ctrl.p_reg->SSR_b.TDRE == 0);
}
IRQManager.cpp
C/C++Windows: C:\Users\{username}\AppData\Local\Arduino15
macOS: /Users/{username}/Library/Arduino15
Linux: /home/{username}/.arduino15
/*
Modifications for v1.2.0 Arduino UNO R4 Board package to fix:
1. Ring Buffer not thread safe.
2. Added Tx buffer.
3. Removed TEIE.
4. Both Hardware UARTS can be used at the same time.
Modified 6 July 2024 by Christian Huygen
www.zevendevelopment.com
*/
#include "IRQManager.h"
#include "bsp_api.h"
#define FIXED_IRQ_NUM 16
#define PROG_IRQ_NUM BSP_ICU_VECTOR_MAX_ENTRIES //32
#define ETHERNET_PRIORITY 12
#define SDCARD_ACCESS_PRIORITY 10
#define SDCARD_DMA_REQ_PRIORITY 10
#define SDCARD_CARD_PRIORITY 12
#define EXTERNAL_PIN_PRIORITY 12
// UART Priority needs to be lower than USB so you can run both Serial and Serial1 at the same time
#define UART_SCI_PRIORITY 10 // 12
#define USB_PRIORITY 12
#define AGT_PRIORITY 14
#define RTC_PRIORITY 12
#define I2C_MASTER_PRIORITY 12
#define I2C_SLAVE_PRIORITY 12
#define SPI_MASTER_PRIORITY 6
#define DMA_PRIORITY 12
#define TIMER_PRIORITY 8
#define ADC_PRIORITY 12
#define CAN_PRIORITY 12
#define CANFD_PRIORITY 12
#define I2S_PRIORITY 12
#define FIRST_INT_SLOT_FREE 0
IRQManager::IRQManager() : last_interrupt_index{0} {
}
IRQManager::~IRQManager() {
}
IRQManager& IRQManager::getInstance() {
static IRQManager instance;
return instance;
}
bool IRQManager::addGenericInterrupt(GenericIrqCfg_t &cfg, Irq_f fnc /*= nullptr*/){
/* getting the address of the current location of the irq vector table */
volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
/* set the displacement to the "programmable" part of the table */
irq_ptr += FIXED_IRQ_NUM;
bool rv = false;
if((cfg.irq == FSP_INVALID_VECTOR) && (last_interrupt_index < PROG_IRQ_NUM)) {
if(fnc != nullptr){
R_ICU->IELSR[last_interrupt_index] = cfg.event;
*(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
NVIC_SetPriority((IRQn_Type)last_interrupt_index, cfg.ipl);
R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
cfg.irq = (IRQn_Type)last_interrupt_index;
last_interrupt_index++;
rv = true;
}
}
return rv;
}
bool IRQManager::addADCScanEnd(ADC_Container *adc, Irq_f fnc /*= nullptr*/) {
/* getting the address of the current location of the irq vector table */
volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
/* set the displacement to the "programmable" part of the table */
irq_ptr += FIXED_IRQ_NUM;
bool rv = true;
if (last_interrupt_index >= PROG_IRQ_NUM){
rv = false;
}
else if (adc->cfg.scan_end_irq == FSP_INVALID_VECTOR) {
if(set_adc_end_link_event(last_interrupt_index, adc->cfg.unit)) {
adc->cfg.scan_end_ipl = TIMER_PRIORITY;
adc->cfg.scan_end_irq = (IRQn_Type)last_interrupt_index;
if(fnc == nullptr) {
*(irq_ptr + last_interrupt_index) = (uint32_t)adc_scan_end_isr;
}
else {
*(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
}
last_interrupt_index++;
}
}
else {
if(adc->cfg.scan_end_irq == FSP_INVALID_VECTOR) {
rv = false;
}
else {
rv = true;
}
}
return rv;
}
bool IRQManager::addADCScanEndB(ADC_Container *adc, Irq_f fnc /*= nullptr*/) {
/* getting the address of the current location of the irq vector table */
volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
/* set the displacement to the "programmable" part of the table */
irq_ptr += FIXED_IRQ_NUM;
bool rv = true;
if (last_interrupt_index >= PROG_IRQ_NUM){
rv = false;
}
else if (adc->cfg.scan_end_b_irq == FSP_INVALID_VECTOR) {
if(set_adc_end_b_link_event(last_interrupt_index, adc->cfg.unit)) {
adc->cfg.scan_end_b_ipl = TIMER_PRIORITY;
adc->cfg.scan_end_b_irq = (IRQn_Type)last_interrupt_index;
if(fnc == nullptr) {
*(irq_ptr + last_interrupt_index) = (uint32_t)adc_scan_end_b_isr;
}
else {
*(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
}
last_interrupt_index++;
}
}
return rv;
}
bool IRQManager::addADCWinCmpA(ADC_Container *adc, Irq_f fnc /*= nullptr*/) {
/* getting the address of the current location of the irq vector table */
volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
/* set the displacement to the "programmable" part of the table */
irq_ptr += FIXED_IRQ_NUM;
bool rv = true;
if (last_interrupt_index >= PROG_IRQ_NUM){
rv = false;
}
else if( ((adc_extended_cfg_t *)(adc->cfg.p_extend))->window_a_irq == FSP_INVALID_VECTOR) {
if(set_adc_win_a_link_event(last_interrupt_index, adc->cfg.unit)) {
((adc_extended_cfg_t *)(adc->cfg.p_extend))->window_a_ipl = TIMER_PRIORITY;
((adc_extended_cfg_t *)(adc->cfg.p_extend))->window_a_irq = (IRQn_Type)last_interrupt_index;
if(fnc == nullptr) {
*(irq_ptr + last_interrupt_index) = (uint32_t)adc_window_compare_isr;
}
else {
*(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
}
last_interrupt_index++;
}
}
return rv;
}
bool IRQManager::addADCWinCmpB(ADC_Container *adc, Irq_f fnc /*= nullptr*/) {
/* getting the address of the current location of the irq vector table */
volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
/* set the displacement to the "programmable" part of the table */
irq_ptr += FIXED_IRQ_NUM;
bool rv = true;
if (last_interrupt_index >= PROG_IRQ_NUM){
rv = false;
}
else if (((adc_extended_cfg_t *)(adc->cfg.p_extend))->window_b_irq == FSP_INVALID_VECTOR) {
if(set_adc_win_b_link_event(last_interrupt_index, adc->cfg.unit)) {
((adc_extended_cfg_t *)(adc->cfg.p_extend))->window_b_ipl = TIMER_PRIORITY;
((adc_extended_cfg_t *)(adc->cfg.p_extend))->window_b_irq = (IRQn_Type)last_interrupt_index;
if(fnc == nullptr) {
*(irq_ptr + last_interrupt_index) = (uint32_t)adc_window_compare_isr;
}
else {
*(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
}
last_interrupt_index++;
}
}
return rv;
}
/* -------------------------------------------------------------------------- */
bool IRQManager::addTimerOverflow(TimerIrqCfg_t &cfg, Irq_f fnc /* = nullptr */) {
/* -------------------------------------------------------------------------- */
/* getting the address of the current location of the irq vector table */
volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
/* set the displacement to the "programmable" part of the table */
irq_ptr += FIXED_IRQ_NUM;
bool rv = true;
if (last_interrupt_index >= PROG_IRQ_NUM){
rv = false;
}
else if (cfg.base_cfg->cycle_end_irq == FSP_INVALID_VECTOR) {
if(cfg.gpt_ext_cfg != nullptr) {
if(set_gpt_over_link_event(last_interrupt_index, cfg.base_cfg->channel)) {
cfg.base_cfg->cycle_end_ipl = TIMER_PRIORITY;
cfg.base_cfg->cycle_end_irq = (IRQn_Type)last_interrupt_index;
/* that is a GPT timer */
if(fnc == nullptr) {
*(irq_ptr + last_interrupt_index) = (uint32_t)gpt_counter_overflow_isr;
}
else {
*(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
}
last_interrupt_index++;
}
}
else if(cfg.agt_ext_cfg != nullptr) {
/* DOUBT: is EVENT_AGT0_INT Overflow?? */
if(set_agt_link_event(last_interrupt_index, cfg.base_cfg->channel)) {
cfg.base_cfg->cycle_end_ipl = TIMER_PRIORITY;
cfg.base_cfg->cycle_end_irq = (IRQn_Type)last_interrupt_index;
/* that is a AGT timer */
if(fnc == nullptr) {
*(irq_ptr + last_interrupt_index) = (uint32_t)agt_int_isr;
}
else {
*(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
}
last_interrupt_index++;
}
}
else {
rv = false;
}
}
return rv;
}
/* -------------------------------------------------------------------------- */
bool IRQManager::addTimerUnderflow(TimerIrqCfg_t &cfg, Irq_f fnc /*= nullptr*/) {
/* -------------------------------------------------------------------------- */
/* getting the address of the current location of the irq vector table */
volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
/* set the displacement to the "programmable" part of the table */
irq_ptr += FIXED_IRQ_NUM;
bool rv = true;
if((cfg.agt_ext_cfg != nullptr) || (last_interrupt_index >= PROG_IRQ_NUM)) {
/* not supported for AGT */
rv = false;
}
else if(cfg.gpt_ext_cfg != nullptr && cfg.gpt_ext_cfg->p_pwm_cfg != nullptr) {
if (cfg.gpt_ext_cfg->p_pwm_cfg->trough_irq == FSP_INVALID_VECTOR) {
if(set_gpt_under_link_event(last_interrupt_index, cfg.base_cfg->channel)){
((gpt_extended_pwm_cfg_t *)(cfg.gpt_ext_cfg->p_pwm_cfg))->trough_ipl = TIMER_PRIORITY;
((gpt_extended_pwm_cfg_t *)(cfg.gpt_ext_cfg->p_pwm_cfg))->trough_irq = (IRQn_Type)last_interrupt_index;
if(fnc == nullptr) {
*(irq_ptr + last_interrupt_index) = (uint32_t)gpt_counter_underflow_isr;
}
else {
*(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
}
last_interrupt_index++;
}
}
}
else {
rv = false;
}
return rv;
}
/* -------------------------------------------------------------------------- */
bool IRQManager::addTimerCompareCaptureA(TimerIrqCfg_t &cfg, Irq_f fnc /*= nullptr*/) {
/* -------------------------------------------------------------------------- */
/* getting the address of the current location of the irq vector table */
volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
/* set the displacement to the "programmable" part of the table */
irq_ptr += FIXED_IRQ_NUM;
bool rv = true;
if((cfg.agt_ext_cfg != nullptr) || (last_interrupt_index >= PROG_IRQ_NUM)) {
/* not supported for AGT */
rv = false;
}
else if(cfg.gpt_ext_cfg != nullptr ) {
if (cfg.gpt_ext_cfg->capture_a_irq == FSP_INVALID_VECTOR) {
if(set_gpt_compare_capture_A_link_event(last_interrupt_index, cfg.base_cfg->channel)){
cfg.gpt_ext_cfg->capture_a_ipl = TIMER_PRIORITY;
cfg.gpt_ext_cfg->capture_a_irq = (IRQn_Type)last_interrupt_index;
if(fnc == nullptr) {
*(irq_ptr + last_interrupt_index) = (uint32_t)gpt_capture_a_isr;
}
else {
*(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
}
last_interrupt_index++;
}
}
}
else {
rv = false;
}
return rv;
}
/* -------------------------------------------------------------------------- */
bool IRQManager::addTimerCompareCaptureB(TimerIrqCfg_t &cfg, Irq_f fnc /*= nullptr*/) {
/* -------------------------------------------------------------------------- */
/* getting the address of the current location of the irq vector table */
volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
/* set the displacement to the "programmable" part of the table */
irq_ptr += FIXED_IRQ_NUM;
bool rv = true;
if((cfg.agt_ext_cfg != nullptr) || (last_interrupt_index >= PROG_IRQ_NUM)) {
/* not supported for AGT */
rv = false;
}
else if(cfg.gpt_ext_cfg != nullptr ) {
if (cfg.gpt_ext_cfg->capture_b_irq == FSP_INVALID_VECTOR) {
if(set_gpt_compare_capture_B_link_event(last_interrupt_index, cfg.base_cfg->channel)){
cfg.gpt_ext_cfg->capture_b_ipl = TIMER_PRIORITY;
cfg.gpt_ext_cfg->capture_b_irq = (IRQn_Type)last_interrupt_index;
if(fnc == nullptr) {
*(irq_ptr + last_interrupt_index) = (uint32_t)gpt_capture_b_isr;
}
else {
*(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
}
last_interrupt_index++;
}
}
}
else {
rv = false;
}
return rv;
}
#ifdef HAS_DMAC
/* -------------------------------------------------------------------------- */
bool IRQManager::addDMA(dmac_extended_cfg_t &cfg, Irq_f fnc /* = nullptr */) {
/* -------------------------------------------------------------------------- */
/* getting the address of the current location of the irq vector table */
volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
/* set the displacement to the "programmable" part of the table */
irq_ptr += FIXED_IRQ_NUM;
bool rv = true;
if (last_interrupt_index >= PROG_IRQ_NUM){
rv = false;
}
else if (cfg.irq == FSP_INVALID_VECTOR) {
/* to check correctness of the channel */
if(set_dma_link_event(last_interrupt_index, cfg.channel)) {
cfg.ipl = DMA_PRIORITY;
cfg.irq = (IRQn_Type)last_interrupt_index;
if(fnc == nullptr) {
*(irq_ptr + last_interrupt_index) = (uint32_t)dmac_int_isr;
}
else {
*(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
}
last_interrupt_index++;
}
else {
rv = false;
}
}
return rv;
}
#endif
/* -------------------------------------------------------------------------- */
bool IRQManager::addPeripheral(Peripheral_t p, void *cfg) {
/* -------------------------------------------------------------------------- */
/* getting the address of the current location of the irq vector table */
volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
/* set the displacement to the "programmable" part of the table */
irq_ptr += FIXED_IRQ_NUM;
bool rv = true;
if(last_interrupt_index >= PROG_IRQ_NUM){
rv = false;
goto end_config;
}
__disable_irq();
/* **********************************************************************
USB
********************************************************************** */
if(p == IRQ_USB && cfg != NULL) {
USBIrqCfg_t *irqcfg = (USBIrqCfg_t *)cfg;
if (irqcfg->first_irq_number != FSP_INVALID_VECTOR) {
// already configured, return
goto end_config;
}
/* configuring USB interrupts */
/* in case of USB which does not use any FSP API the cfg contains the
only interrupt handler function used */
if( (last_interrupt_index + irqcfg->num_of_irqs_required ) < PROG_IRQ_NUM ) {
#ifdef ELC_EVENT_USBFS_INT
/* USBFS INT (USBFS interrupt) */
*(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBFS_INT);
R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
irqcfg->first_irq_number = last_interrupt_index;
last_interrupt_index++;
#endif
#ifdef ELC_EVENT_USBFS_RESUME
/* USBFS RESUME (USBFS resume interrupt) */
*(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBFS_RESUME);
R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
last_interrupt_index++;
#endif
#ifdef ELC_EVENT_USBFS_FIFO_0
/* USBFS FIFO 0 (DMA transfer request 0) */
*(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBFS_FIFO_0);
R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
last_interrupt_index++;
#endif
#ifdef ELC_EVENT_USBFS_FIFO_1
/* USBFS FIFO 1 (DMA transfer request 1) */
*(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBFS_FIFO_1);
R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
last_interrupt_index++;
#endif
}
else {
rv = false;
}
}
else if(p == IRQ_USB_HS && cfg != NULL) {
USBIrqCfg_t *irqcfg = (USBIrqCfg_t *)cfg;
if (irqcfg->first_irq_number != FSP_INVALID_VECTOR) {
// already configured, return
goto end_config;
}
/* configuring USB interrupts */
/* in case of USB which does not use any FSP API the cfg contains the
only interrupt handler function used */
if( (last_interrupt_index + irqcfg->num_of_irqs_required ) < PROG_IRQ_NUM ) {
#ifdef ELC_EVENT_USBHS_USB_INT_RESUME
/* USBHS INT (USBFS interrupt) */
*(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBHS_USB_INT_RESUME);
R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
irqcfg->first_irq_number = last_interrupt_index;
last_interrupt_index++;
#endif
#ifdef ELC_EVENT_USBHS_FIFO_0
/* USBFS FIFO 0 (DMA transfer request 0) */
*(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBHS_FIFO_0);
R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
last_interrupt_index++;
#endif
#ifdef ELC_EVENT_USBHS_FIFO_1
/* USBFS FIFO 1 (DMA transfer request 1) */
*(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBHS_FIFO_1);
R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
last_interrupt_index++;
#endif
} else {
rv = false;
}
}
/* **********************************************************************
AGT
********************************************************************** */
else if(p == IRQ_AGT && cfg != NULL) {
timer_cfg_t *p_cfg = (timer_cfg_t *)cfg;
if (p_cfg->cycle_end_irq == FSP_INVALID_VECTOR) {
p_cfg->cycle_end_ipl = AGT_PRIORITY;
p_cfg->cycle_end_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)agt_int_isr;
set_agt_link_event(last_interrupt_index, p_cfg->channel);
last_interrupt_index++;
}
}
/* **********************************************************************
UART
********************************************************************** */
else if(p == IRQ_SCI_UART && cfg != NULL) {
uart_cfg_t *p_cfg = (uart_cfg_t *)cfg;
if (p_cfg->txi_irq == FSP_INVALID_VECTOR) {
if (last_interrupt_index + UART_INTERRUPT_COUNT > PROG_IRQ_NUM){
rv = false;
goto end_config;
}
/* TX interrupt */
p_cfg->txi_ipl = UART_SCI_PRIORITY;
p_cfg->txi_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)sci_uart_txi_isr;
set_sci_tx_link_event(last_interrupt_index, p_cfg->channel);
last_interrupt_index++;
/* TX-ERROR interrupt */
p_cfg->tei_ipl = UART_SCI_PRIORITY;
p_cfg->tei_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)sci_uart_tei_isr;
set_sci_tei_link_event(last_interrupt_index, p_cfg->channel);
last_interrupt_index++;
/* RX interrupt */
p_cfg->rxi_ipl = UART_SCI_PRIORITY;
p_cfg->rxi_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)sci_uart_rxi_isr;
set_sci_rx_link_event(last_interrupt_index, p_cfg->channel);
last_interrupt_index++;
/* RX-ERROR interrupt */
p_cfg->eri_ipl = UART_SCI_PRIORITY;
p_cfg->eri_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)sci_uart_eri_isr;
set_sci_eri_link_event(last_interrupt_index, p_cfg->channel);
last_interrupt_index++;
}
R_BSP_IrqEnable (p_cfg->txi_irq);
R_BSP_IrqEnable (p_cfg->tei_irq);
R_BSP_IrqEnable (p_cfg->rxi_irq);
R_BSP_IrqEnable (p_cfg->eri_irq);
}
/* **********************************************************************
RTC
********************************************************************** */
#if RTC_HOWMANY > 0
else if(p == IRQ_RTC && cfg != NULL) {
RTCIrqCfg_t *p_cfg = (RTCIrqCfg_t *)cfg;
/* rtc interrupts are added once a time and not all three together */
if(p_cfg->req == RTC_ALARM) {
if (p_cfg->cfg->alarm_irq == FSP_INVALID_VECTOR) {
p_cfg->cfg->alarm_ipl = RTC_PRIORITY;
p_cfg->cfg->alarm_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)rtc_alarm_periodic_isr;
R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_RTC_ALARM);
R_BSP_IrqCfg(p_cfg->cfg->alarm_irq, p_cfg->cfg->alarm_ipl, p_cfg->ctrl);
last_interrupt_index++;
}
R_BSP_IrqEnable (p_cfg->cfg->alarm_irq);
}
else if(p_cfg->req == RTC_PERIODIC) {
if (p_cfg->cfg->periodic_irq == FSP_INVALID_VECTOR) {
p_cfg->cfg->periodic_ipl = RTC_PRIORITY;
p_cfg->cfg->periodic_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)rtc_alarm_periodic_isr;
R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_RTC_PERIOD);
R_BSP_IrqCfg(p_cfg->cfg->periodic_irq, p_cfg->cfg->periodic_ipl, p_cfg->ctrl);
last_interrupt_index++;
}
R_BSP_IrqEnable (p_cfg->cfg->periodic_irq);
}
else if(p_cfg->req == RTC_CARRY) {
if (p_cfg->cfg->carry_irq == FSP_INVALID_VECTOR) {
p_cfg->cfg->carry_ipl = RTC_PRIORITY;
p_cfg->cfg->carry_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)rtc_carry_isr;
R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_RTC_CARRY);
R_BSP_IrqCfg(p_cfg->cfg->carry_irq, p_cfg->cfg->carry_ipl, p_cfg->ctrl);
last_interrupt_index++;
}
R_BSP_IrqEnable (p_cfg->cfg->carry_irq);
}
else {
rv = false;
}
}
#endif
#if WIRE_HOWMANY > 0
/* I2C true NOT SCI */
else if(p == IRQ_I2C_MASTER && cfg != NULL) {
I2CIrqReq_t *p_cfg = (I2CIrqReq_t *)cfg;
i2c_master_cfg_t *mcfg = (i2c_master_cfg_t *)p_cfg->mcfg;
i2c_slave_cfg_t *scfg = (i2c_slave_cfg_t *)p_cfg->scfg;
mcfg->ipl = I2C_MASTER_PRIORITY;
if (mcfg->txi_irq == FSP_INVALID_VECTOR) {
if (last_interrupt_index + WIRE_MASTER_INTERRUPT_COUNT > PROG_IRQ_NUM){
rv = false;
goto end_config;
}
/* TX interrupt */
mcfg->txi_irq = (IRQn_Type)last_interrupt_index;
scfg->txi_irq = (IRQn_Type)last_interrupt_index;
set_iic_tx_link_event(last_interrupt_index, p_cfg->mcfg->channel);
R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
last_interrupt_index++;
/* RX interrupt */
mcfg->rxi_irq = (IRQn_Type)last_interrupt_index;
scfg->rxi_irq = (IRQn_Type)last_interrupt_index;
set_iic_rx_link_event(last_interrupt_index, p_cfg->mcfg->channel);
R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
last_interrupt_index++;
/* TX ERROR interrupt */
mcfg->tei_irq = (IRQn_Type)last_interrupt_index;
scfg->tei_irq = (IRQn_Type)last_interrupt_index;
set_iic_tei_link_event(last_interrupt_index, p_cfg->mcfg->channel);
R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
last_interrupt_index++;
/* RX ERROR interrupt */
mcfg->eri_irq = (IRQn_Type)last_interrupt_index;
scfg->eri_irq = (IRQn_Type)last_interrupt_index;
set_iic_eri_link_event(last_interrupt_index, p_cfg->mcfg->channel);
R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
last_interrupt_index++;
}
*(irq_ptr + mcfg->txi_irq) = (uint32_t)iic_master_txi_isr;
*(irq_ptr + mcfg->rxi_irq) = (uint32_t)iic_master_rxi_isr;
*(irq_ptr + mcfg->tei_irq) = (uint32_t)iic_master_tei_isr;
*(irq_ptr + mcfg->eri_irq) = (uint32_t)iic_master_eri_isr;
R_BSP_IrqEnable (mcfg->txi_irq);
R_BSP_IrqEnable (mcfg->rxi_irq);
R_BSP_IrqEnable (mcfg->tei_irq);
R_BSP_IrqEnable (mcfg->eri_irq);
}
/* I2C SCI MASTER (only) */
else if(p == IRQ_SCI_I2C_MASTER && cfg != NULL) {
I2CIrqReq_t *p_cfg = (I2CIrqReq_t *)cfg;
i2c_master_cfg_t *mcfg = (i2c_master_cfg_t *)p_cfg->mcfg;
mcfg->ipl = I2C_MASTER_PRIORITY;
if (mcfg->txi_irq == FSP_INVALID_VECTOR) {
if (last_interrupt_index + WIRE_SCI_MASTER_INTERRUPT_COUNT > PROG_IRQ_NUM) {
rv = false;
goto end_config;
}
/* TX interrupt */
mcfg->txi_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)sci_i2c_txi_isr;
set_sci_tx_link_event(last_interrupt_index, p_cfg->mcfg->channel);
R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
last_interrupt_index++;
/* RX interrupt */
mcfg->rxi_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)sci_i2c_rxi_isr;
set_sci_rx_link_event(last_interrupt_index, p_cfg->mcfg->channel);
R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
last_interrupt_index++;
/* TX ERROR interrupt */
mcfg->tei_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)sci_i2c_tei_isr;
set_sci_tei_link_event(last_interrupt_index, p_cfg->mcfg->channel);
R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
last_interrupt_index++;
/* RX ERROR interrupt */
#if 0
mcfg->eri_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)sci_i2c_eri_isr;
set_sci_eri_link_event(last_interrupt_index, p_cfg->mcfg->channel);
R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
last_interrupt_index++;
#endif
}
R_BSP_IrqEnable (mcfg->txi_irq);
R_BSP_IrqEnable (mcfg->rxi_irq);
R_BSP_IrqEnable (mcfg->tei_irq);
#if 0
R_BSP_IrqEnable (mcfg->eri_irq);
#endif
}
else if(p == IRQ_I2C_SLAVE && cfg != NULL) {
I2CIrqReq_t *p_cfg = (I2CIrqReq_t *)cfg;
i2c_master_cfg_t *mcfg = (i2c_master_cfg_t *)p_cfg->mcfg;
i2c_slave_cfg_t *scfg = (i2c_slave_cfg_t *)p_cfg->scfg;
scfg->ipl = I2C_SLAVE_PRIORITY;
scfg->eri_ipl = I2C_SLAVE_PRIORITY;
if (scfg->txi_irq == FSP_INVALID_VECTOR) {
if (last_interrupt_index + WIRE_SLAVE_INTERRUPT_COUNT > PROG_IRQ_NUM) {
rv = false;
goto end_config;
}
/* TX interrupt */
mcfg->txi_irq = (IRQn_Type)last_interrupt_index;
scfg->txi_irq = (IRQn_Type)last_interrupt_index;
set_iic_tx_link_event(last_interrupt_index, scfg->channel);
last_interrupt_index++;
/* RX interrupt */
scfg->rxi_irq = (IRQn_Type)last_interrupt_index;
mcfg->rxi_irq = (IRQn_Type)last_interrupt_index;
set_iic_rx_link_event(last_interrupt_index, scfg->channel);
last_interrupt_index++;
/* TEI interrupt */
scfg->tei_irq = (IRQn_Type)last_interrupt_index;
mcfg->tei_irq = (IRQn_Type)last_interrupt_index;
set_iic_tei_link_event(last_interrupt_index, scfg->channel);
last_interrupt_index++;
/* ERI interrupt */
scfg->eri_irq = (IRQn_Type)last_interrupt_index;
mcfg->eri_irq = (IRQn_Type)last_interrupt_index;
set_iic_eri_link_event(last_interrupt_index, scfg->channel);
last_interrupt_index++;
}
*(irq_ptr + scfg->txi_irq) = (uint32_t)iic_slave_txi_isr;
*(irq_ptr + scfg->rxi_irq) = (uint32_t)iic_slave_rxi_isr;
*(irq_ptr + scfg->tei_irq) = (uint32_t)iic_slave_tei_isr;
*(irq_ptr + scfg->eri_irq) = (uint32_t)iic_slave_eri_isr;
R_BSP_IrqEnable (scfg->txi_irq);
R_BSP_IrqEnable (scfg->rxi_irq);
R_BSP_IrqEnable (scfg->tei_irq);
R_BSP_IrqEnable (scfg->eri_irq);
}
#endif
#if EXT_INTERRUPTS_HOWMANY > 0
/* **********************************************************************
PIN EXTERNAL INTERRUPT
********************************************************************** */
else if(p == IRQ_EXTERNAL_PIN && cfg != NULL) {
external_irq_cfg_t *p_cfg = (external_irq_cfg_t *)cfg;
if (p_cfg->irq == FSP_INVALID_VECTOR) {
p_cfg->ipl = EXTERNAL_PIN_PRIORITY;
p_cfg->irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)r_icu_isr;
set_ext_link_event(last_interrupt_index, p_cfg->channel);
last_interrupt_index++;
}
}
#endif
#if SPI_HOWMANY > 0
/* **********************************************************************
SPI MASTER
********************************************************************** */
else if(p == IRQ_SPI_MASTER && cfg != NULL) {
spi_instance_ctrl_t * p_ctrl = reinterpret_cast<SpiMasterIrqReq_t *>(cfg)->ctrl;
spi_cfg_t * p_cfg = reinterpret_cast<SpiMasterIrqReq_t *>(cfg)->cfg;
uint8_t const hw_channel = reinterpret_cast<SpiMasterIrqReq_t *>(cfg)->hw_channel;
if (p_cfg->txi_irq == FSP_INVALID_VECTOR) {
if (last_interrupt_index + SPI_INTERRUPT_COUNT > PROG_IRQ_NUM) {
rv = false;
goto end_config;
}
/* TX interrupt */
p_cfg->txi_irq = (IRQn_Type)last_interrupt_index;
p_cfg->txi_ipl = SPI_MASTER_PRIORITY;
*(irq_ptr + last_interrupt_index) = (uint32_t)spi_txi_isr;
set_spi_tx_link_event(last_interrupt_index, hw_channel);
R_BSP_IrqCfg(p_cfg->txi_irq, p_cfg->txi_ipl, p_ctrl);
last_interrupt_index++;
/* RX interrupt */
p_cfg->rxi_irq = (IRQn_Type)last_interrupt_index;
p_cfg->rxi_ipl = SPI_MASTER_PRIORITY;
*(irq_ptr + last_interrupt_index) = (uint32_t)spi_rxi_isr;
set_spi_rx_link_event(last_interrupt_index, hw_channel);
R_BSP_IrqCfg(p_cfg->rxi_irq, p_cfg->rxi_ipl, p_ctrl);
last_interrupt_index++;
/* Error interrupt */
p_cfg->eri_irq = (IRQn_Type)last_interrupt_index;
p_cfg->eri_ipl = SPI_MASTER_PRIORITY;
*(irq_ptr + last_interrupt_index) = (uint32_t)spi_eri_isr;
set_spi_eri_link_event(last_interrupt_index, hw_channel);
R_BSP_IrqCfg(p_cfg->eri_irq, p_cfg->eri_ipl, p_ctrl);
last_interrupt_index++;
/* TX register empty interrupt */
p_cfg->tei_irq = (IRQn_Type)last_interrupt_index;
p_cfg->tei_ipl = SPI_MASTER_PRIORITY;
*(irq_ptr + last_interrupt_index) = (uint32_t)spi_tei_isr;
set_spi_tei_link_event(last_interrupt_index, hw_channel);
R_BSP_IrqCfg(p_cfg->tei_irq, p_cfg->tei_ipl, p_ctrl);
last_interrupt_index++;
}
R_BSP_IrqEnable (p_cfg->txi_irq);
R_BSP_IrqEnable (p_cfg->rxi_irq);
R_BSP_IrqEnable (p_cfg->eri_irq);
/* Note tei_irq is not enabled until the last data frame is transfered. */
// R_BSP_IrqEnable (p_cfg->tei_irq);
}
/* **********************************************************************
SCI SPI MASTER
********************************************************************** */
else if(p == IRQ_SCI_SPI_MASTER && cfg != NULL) {
sci_spi_instance_ctrl_t * p_ctrl = reinterpret_cast<SciSpiMasterIrqReq_t *>(cfg)->ctrl;
spi_cfg_t * p_cfg = reinterpret_cast<SciSpiMasterIrqReq_t *>(cfg)->cfg;
uint8_t const hw_channel = reinterpret_cast<SciSpiMasterIrqReq_t *>(cfg)->hw_channel;
if (p_cfg->txi_irq == FSP_INVALID_VECTOR) {
if (last_interrupt_index + SPI_INTERRUPT_COUNT > PROG_IRQ_NUM) {
rv = false;
goto end_config;
}
/* TX interrupt */
p_cfg->txi_irq = (IRQn_Type)last_interrupt_index;
p_cfg->txi_ipl = SPI_MASTER_PRIORITY;
*(irq_ptr + last_interrupt_index) = (uint32_t)sci_spi_txi_isr;
set_sci_tx_link_event(last_interrupt_index, hw_channel);
R_BSP_IrqCfg(p_cfg->txi_irq, p_cfg->txi_ipl, p_ctrl);
last_interrupt_index++;
/* RX interrupt */
p_cfg->rxi_irq = (IRQn_Type)last_interrupt_index;
p_cfg->rxi_ipl = SPI_MASTER_PRIORITY;
*(irq_ptr + last_interrupt_index) = (uint32_t)sci_spi_rxi_isr;
set_sci_rx_link_event(last_interrupt_index, hw_channel);
R_BSP_IrqCfg(p_cfg->rxi_irq, p_cfg->rxi_ipl, p_ctrl);
last_interrupt_index++;
/* Error interrupt */
p_cfg->eri_irq = (IRQn_Type)last_interrupt_index;
p_cfg->eri_ipl = SPI_MASTER_PRIORITY;
*(irq_ptr + last_interrupt_index) = (uint32_t)sci_spi_eri_isr;
set_sci_eri_link_event(last_interrupt_index, hw_channel);
R_BSP_IrqCfg(p_cfg->eri_irq, p_cfg->eri_ipl, p_ctrl);
last_interrupt_index++;
/* TX register empty interrupt */
p_cfg->tei_irq = (IRQn_Type)last_interrupt_index;
p_cfg->tei_ipl = SPI_MASTER_PRIORITY;
*(irq_ptr + last_interrupt_index) = (uint32_t)sci_spi_tei_isr;
set_sci_tei_link_event(last_interrupt_index, hw_channel);
R_BSP_IrqCfg(p_cfg->tei_irq, p_cfg->tei_ipl, p_ctrl);
last_interrupt_index++;
}
R_BSP_IrqEnable (p_cfg->txi_irq);
R_BSP_IrqEnable (p_cfg->rxi_irq);
R_BSP_IrqEnable (p_cfg->eri_irq);
R_BSP_IrqEnable (p_cfg->tei_irq);
}
#endif
#if CAN_HOWMANY > 0
/* **********************************************************************
CAN
********************************************************************** */
else if(p == IRQ_CAN && cfg != NULL) {
can_instance_ctrl_t * p_ctrl = reinterpret_cast<CanIrqReq_t *>(cfg)->ctrl;
can_cfg_t * p_cfg = reinterpret_cast<CanIrqReq_t *>(cfg)->cfg;
p_cfg->ipl = CAN_PRIORITY; /* All interrupts share the same priority. */
if (p_cfg->error_irq == FSP_INVALID_VECTOR) {
if (last_interrupt_index + CAN_INTERRUPT_COUNT > PROG_IRQ_NUM) {
rv = false;
goto end_config;
}
/* Error interrupt */
p_cfg->error_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)can_error_isr;
set_can_error_link_event(last_interrupt_index, p_cfg->channel);
R_BSP_IrqCfg(p_cfg->error_irq, p_cfg->ipl, p_ctrl);
last_interrupt_index++;
/* Receive interrupt */
p_cfg->rx_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)can_rx_isr;
set_can_rx_link_event(last_interrupt_index, p_cfg->channel);
R_BSP_IrqCfg(p_cfg->rx_irq, p_cfg->ipl, p_ctrl);
last_interrupt_index++;
/* Transmit interrupt */
p_cfg->tx_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)can_tx_isr;
set_can_tx_link_event(last_interrupt_index, p_cfg->channel);
R_BSP_IrqCfg(p_cfg->tx_irq, p_cfg->ipl, p_ctrl);
last_interrupt_index++;
}
R_BSP_IrqEnable (p_cfg->error_irq);
R_BSP_IrqEnable (p_cfg->rx_irq);
R_BSP_IrqEnable (p_cfg->tx_irq);
}
#endif /* CAN_HOWMANY > 0 */
#if ETHERNET_HOWMANY > 0
/* **********************************************************************
ETHERNET
********************************************************************** */
else if(p == IRQ_ETHERNET && cfg != NULL) {
ether_cfg_t *eth = (ether_cfg_t *)cfg;
if (eth->irq == FSP_INVALID_VECTOR) {
eth->irq = (IRQn_Type)last_interrupt_index;
eth->interrupt_priority = ETHERNET_PRIORITY;
*(irq_ptr + last_interrupt_index) = (uint32_t)ether_eint_isr;
R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_EDMAC0_EINT);
last_interrupt_index++;
}
}
#endif
#if CANFD_HOWMANY > 0
/* **********************************************************************
CANFD
********************************************************************** */
else if(p == IRQ_CANFD && cfg != NULL) {
canfd_instance_ctrl_t * p_ctrl = reinterpret_cast<CanFdIrqReq_t *>(cfg)->ctrl;
can_cfg_t * p_cfg = reinterpret_cast<CanFdIrqReq_t *>(cfg)->cfg;
p_cfg->ipl = CAN_PRIORITY; /* All interrupts share the same priority. */
if (p_cfg->error_irq == FSP_INVALID_VECTOR) {
if (last_interrupt_index + CANFD_INTERRUPT_COUNT > PROG_IRQ_NUM) {
rv = false;
goto end_config;
}
/* Error interrupt */
p_cfg->error_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)canfd_error_isr;
set_canfd_error_link_event(last_interrupt_index, p_cfg->channel);
R_BSP_IrqCfg(p_cfg->error_irq, p_cfg->ipl, p_ctrl);
last_interrupt_index++;
/* Receive interrupt */
p_cfg->rx_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)canfd_rx_fifo_isr;
set_canfd_rx_link_event(last_interrupt_index, p_cfg->channel);
R_BSP_IrqCfg(p_cfg->rx_irq, p_cfg->ipl, p_ctrl);
last_interrupt_index++;
/* Transmit interrupt */
p_cfg->tx_irq = (IRQn_Type)last_interrupt_index;
*(irq_ptr + last_interrupt_index) = (uint32_t)canfd_channel_tx_isr;
set_canfd_tx_link_event(last_interrupt_index, p_cfg->channel);
R_BSP_IrqCfg(p_cfg->tx_irq, p_cfg->ipl, p_ctrl);
last_interrupt_index++;
}
R_BSP_IrqEnable (p_cfg->error_irq);
R_BSP_IrqEnable (p_cfg->rx_irq);
R_BSP_IrqEnable (p_cfg->tx_irq);
}
#endif /* CANFD_HOWMANY > 0 */
#if SDCARD_HOWMANY > 0
/* **********************************************************************
SDCARD
********************************************************************** */
else if(p == IRQ_SDCARD && cfg != NULL) {
sdmmc_cfg_t *sd_cfg = (sdmmc_cfg_t *)cfg;
/* SDCARD_ACCESS */
if(sd_cfg->access_irq == FSP_INVALID_VECTOR) {
if (last_interrupt_index + SD_INTERRUPT_COUNT > PROG_IRQ_NUM){
rv = false;
goto end_config;
}
sd_cfg->access_irq = (IRQn_Type)last_interrupt_index;
sd_cfg->access_ipl = SDCARD_ACCESS_PRIORITY;
*(irq_ptr + last_interrupt_index) = (uint32_t)sdhimmc_accs_isr;
R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_SDHIMMC0_ACCS);
last_interrupt_index++;
...
This file has been truncated, please download it to see its full contents.
api\HardwareSerial.h
C/C++Windows: C:\Users\{username}\AppData\Local\Arduino15
macOS: /Users/{username}/Library/Arduino15
Linux: /home/{username}/.arduino15
/*
Copyright (c) 2016 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
Modifications for v1.2.0 Arduino UNO R4 Board package to fix:
1. Ring Buffer not interrupt safe.
2. Added Tx buffer.
3. Removed TEIE.
4. Both Hardware UARTS can be used at the same time.
Modified 6 July 2024 by Christian Huygen
www.zevendevelopment.com
*/
#pragma once
#include <inttypes.h>
#include "Stream.h"
namespace arduino {
// XXX: Those constants should be defined as const int / enums?
// XXX: shall we use namespaces too?
#define SERIAL_PARITY_EVEN (0x1ul)
#define SERIAL_PARITY_ODD (0x2ul)
#define SERIAL_PARITY_NONE (0x3ul)
#define SERIAL_PARITY_MARK (0x4ul)
#define SERIAL_PARITY_SPACE (0x5ul)
#define SERIAL_PARITY_MASK (0xFul)
#define SERIAL_STOP_BIT_1 (0x10ul)
#define SERIAL_STOP_BIT_1_5 (0x20ul)
#define SERIAL_STOP_BIT_2 (0x30ul)
#define SERIAL_STOP_BIT_MASK (0xF0ul)
#define SERIAL_DATA_5 (0x100ul)
#define SERIAL_DATA_6 (0x200ul)
#define SERIAL_DATA_7 (0x300ul)
#define SERIAL_DATA_8 (0x400ul)
#define SERIAL_DATA_9 (0x500ul)
#define SERIAL_DATA_MASK (0xF00ul)
#define SERIAL_5N1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE | SERIAL_DATA_5)
#define SERIAL_6N1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE | SERIAL_DATA_6)
#define SERIAL_7N1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE | SERIAL_DATA_7)
#define SERIAL_8N1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE | SERIAL_DATA_8)
#define SERIAL_5N2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE | SERIAL_DATA_5)
#define SERIAL_6N2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE | SERIAL_DATA_6)
#define SERIAL_7N2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE | SERIAL_DATA_7)
#define SERIAL_8N2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE | SERIAL_DATA_8)
#define SERIAL_5E1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN | SERIAL_DATA_5)
#define SERIAL_6E1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN | SERIAL_DATA_6)
#define SERIAL_7E1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN | SERIAL_DATA_7)
#define SERIAL_8E1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN | SERIAL_DATA_8)
#define SERIAL_5E2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN | SERIAL_DATA_5)
#define SERIAL_6E2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN | SERIAL_DATA_6)
#define SERIAL_7E2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN | SERIAL_DATA_7)
#define SERIAL_8E2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN | SERIAL_DATA_8)
#define SERIAL_5O1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD | SERIAL_DATA_5)
#define SERIAL_6O1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD | SERIAL_DATA_6)
#define SERIAL_7O1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD | SERIAL_DATA_7)
#define SERIAL_8O1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD | SERIAL_DATA_8)
#define SERIAL_5O2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD | SERIAL_DATA_5)
#define SERIAL_6O2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD | SERIAL_DATA_6)
#define SERIAL_7O2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD | SERIAL_DATA_7)
#define SERIAL_8O2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD | SERIAL_DATA_8)
#define SERIAL_5M1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK | SERIAL_DATA_5)
#define SERIAL_6M1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK | SERIAL_DATA_6)
#define SERIAL_7M1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK | SERIAL_DATA_7)
#define SERIAL_8M1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK | SERIAL_DATA_8)
#define SERIAL_5M2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK | SERIAL_DATA_5)
#define SERIAL_6M2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK | SERIAL_DATA_6)
#define SERIAL_7M2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK | SERIAL_DATA_7)
#define SERIAL_8M2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK | SERIAL_DATA_8)
#define SERIAL_5S1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_5)
#define SERIAL_6S1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_6)
#define SERIAL_7S1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_7)
#define SERIAL_8S1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_8)
#define SERIAL_5S2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_5)
#define SERIAL_6S2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_6)
#define SERIAL_7S2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_7)
#define SERIAL_8S2 (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_8)
#define SERIAL_9N1 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE | SERIAL_DATA_9)
class HardwareSerial : public Stream
{
public:
virtual void begin(unsigned long) = 0;
virtual void begin(unsigned long baudrate, uint16_t config) = 0;
virtual void end() = 0;
virtual int available(void) = 0;
virtual int peek(void) = 0;
virtual int read(void) = 0;
virtual void flush(void) = 0;
virtual size_t write(uint8_t) = 0;
using Print::write; // pull in write(str) and write(buf, size) from Print
virtual operator bool() = 0;
};
// XXX: Are we keeping the serialEvent API?
extern void serialEventRun(void) __attribute__((weak));
}
Comments
Please log in or sign up to comment.