diff --git a/cores/arduino/RingBuffer.cpp b/cores/arduino/RingBuffer.cpp index d877a6e30..11a32ebd7 100644 --- a/cores/arduino/RingBuffer.cpp +++ b/cores/arduino/RingBuffer.cpp @@ -67,6 +67,14 @@ int RingBuffer::available() return delta; } +int RingBuffer::availableForStore() +{ + if (_iHead >= _iTail) + return SERIAL_BUFFER_SIZE - 1 - _iHead + _iTail; + else + return _iTail - _iHead - 1; +} + int RingBuffer::peek() { if(_iTail == _iHead) diff --git a/cores/arduino/RingBuffer.h b/cores/arduino/RingBuffer.h index e212e6b60..c2ad3664a 100644 --- a/cores/arduino/RingBuffer.h +++ b/cores/arduino/RingBuffer.h @@ -40,6 +40,7 @@ class RingBuffer void clear(); int read_char(); int available(); + int availableForStore(); int peek(); bool isFull(); diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp index 71986c1f9..42c46d015 100644 --- a/cores/arduino/SERCOM.cpp +++ b/cores/arduino/SERCOM.cpp @@ -173,6 +173,16 @@ int SERCOM::writeDataUART(uint8_t data) return 1; } +void SERCOM::enableDataRegisterEmptyInterruptUART() +{ + sercom->USART.INTENSET.reg |= SERCOM_USART_INTENSET_DRE; +} + +void SERCOM::disableDataRegisterEmptyInterruptUART() +{ + sercom->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_DRE; +} + /* ========================= * ===== Sercom SPI * ========================= diff --git a/cores/arduino/SERCOM.h b/cores/arduino/SERCOM.h index 79249011d..6b7c703a7 100644 --- a/cores/arduino/SERCOM.h +++ b/cores/arduino/SERCOM.h @@ -163,6 +163,8 @@ class SERCOM int writeDataUART(uint8_t data) ; bool isUARTError() ; void acknowledgeUARTError() ; + void enableDataRegisterEmptyInterruptUART(); + void disableDataRegisterEmptyInterruptUART(); /* ========== SPI ========== */ void initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder) ; diff --git a/cores/arduino/Uart.cpp b/cores/arduino/Uart.cpp index 37b6e6903..adc73146f 100644 --- a/cores/arduino/Uart.cpp +++ b/cores/arduino/Uart.cpp @@ -50,10 +50,13 @@ void Uart::end() { sercom->resetUART(); rxBuffer.clear(); + txBuffer.clear(); } void Uart::flush() { + while(txBuffer.available()); // wait until TX buffer is empty + sercom->flushUART(); } @@ -63,6 +66,16 @@ void Uart::IrqHandler() rxBuffer.store_char(sercom->readDataUART()); } + if (sercom->isDataRegisterEmptyUART()) { + if (txBuffer.available()) { + uint8_t data = txBuffer.read_char(); + + sercom->writeDataUART(data); + } else { + sercom->disableDataRegisterEmptyInterruptUART(); + } + } + if (sercom->isUARTError()) { sercom->acknowledgeUARTError(); // TODO: if (sercom->isBufferOverflowErrorUART()) .... @@ -79,7 +92,7 @@ int Uart::available() int Uart::availableForWrite() { - return (sercom->isDataRegisterEmptyUART() ? 1 : 0); + return txBuffer.availableForStore(); } int Uart::peek() @@ -94,7 +107,16 @@ int Uart::read() size_t Uart::write(const uint8_t data) { - sercom->writeDataUART(data); + if (sercom->isDataRegisterEmptyUART() && txBuffer.available() == 0) { + sercom->writeDataUART(data); + } else { + while(txBuffer.isFull()); // spin lock until a spot opens up in the buffer + + txBuffer.store_char(data); + + sercom->enableDataRegisterEmptyInterruptUART(); + } + return 1; } diff --git a/cores/arduino/Uart.h b/cores/arduino/Uart.h index 02d30bd45..4b0aa04d9 100644 --- a/cores/arduino/Uart.h +++ b/cores/arduino/Uart.h @@ -46,6 +46,7 @@ class Uart : public HardwareSerial private: SERCOM *sercom; RingBuffer rxBuffer; + RingBuffer txBuffer; uint8_t uc_pinRX; uint8_t uc_pinTX;