From 38992c2a9ebce581fd2591ad7684c555022c36f7 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 9 Oct 2015 15:25:45 -0400 Subject: [PATCH 1/8] Add availableForStore method to RingBuffer --- cores/arduino/RingBuffer.cpp | 8 ++++++++ cores/arduino/RingBuffer.h | 1 + 2 files changed, 9 insertions(+) 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(); From 57c432e688edbbc4deaf3eb052ab953d5b7c128d Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 9 Oct 2015 15:40:45 -0400 Subject: [PATCH 2/8] Add enable and disable data register interrupt APIs for UART --- cores/arduino/SERCOM.cpp | 10 ++++++++++ cores/arduino/SERCOM.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp index 71986c1f9..ae58e5a32 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.bit.DRE = 1; +} + +void SERCOM::disableDataRegisterEmptyInterruptUART() +{ + sercom->USART.INTENSET.bit.DRE = 0; +} + /* ========================= * ===== 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) ; From b24c9e5b6851ba70bc4bfa6b454f3a999d50262c Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 9 Oct 2015 15:58:13 -0400 Subject: [PATCH 3/8] TX buffering for UART using RingBuffer --- cores/arduino/Uart.cpp | 24 ++++++++++++++++++++++-- cores/arduino/Uart.h | 1 + 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/cores/arduino/Uart.cpp b/cores/arduino/Uart.cpp index 37b6e6903..94b430061 100644 --- a/cores/arduino/Uart.cpp +++ b/cores/arduino/Uart.cpp @@ -50,6 +50,7 @@ void Uart::end() { sercom->resetUART(); rxBuffer.clear(); + txBuffer.clear(); } void Uart::flush() @@ -59,6 +60,16 @@ void Uart::flush() void Uart::IrqHandler() { + if (sercom->isDataRegisterEmptyUART()) { + if (txBuffer.available()) { + uint8_t data = txBuffer.read_char(); + + sercom->writeDataUART(data); + } else { + sercom->disableDataRegisterEmptyInterruptUART(); + } + } + if (sercom->availableDataUART()) { rxBuffer.store_char(sercom->readDataUART()); } @@ -79,7 +90,7 @@ int Uart::available() int Uart::availableForWrite() { - return (sercom->isDataRegisterEmptyUART() ? 1 : 0); + return txBuffer.availableForStore(); } int Uart::peek() @@ -94,7 +105,16 @@ int Uart::read() size_t Uart::write(const uint8_t data) { - sercom->writeDataUART(data); + if (sercom->isDataRegisterEmptyUART()) { + 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; From 158df98d0c6925571e9970e777e3f9e070862b27 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 9 Oct 2015 16:42:47 -0400 Subject: [PATCH 4/8] Correct disableDataRegisterEmptyInterruptUART to use INTENCLR instead of INTENSET --- cores/arduino/SERCOM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp index ae58e5a32..192db3ad5 100644 --- a/cores/arduino/SERCOM.cpp +++ b/cores/arduino/SERCOM.cpp @@ -180,7 +180,7 @@ void SERCOM::enableDataRegisterEmptyInterruptUART() void SERCOM::disableDataRegisterEmptyInterruptUART() { - sercom->USART.INTENSET.bit.DRE = 0; + sercom->USART.INTENCLR.bit.DRE = 1; } /* ========================= From aa400fd4342a614b0d67365680f10a9a9e59f29e Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 9 Oct 2015 16:43:11 -0400 Subject: [PATCH 5/8] Update flush to also wait for TX buffer to empty --- cores/arduino/Uart.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cores/arduino/Uart.cpp b/cores/arduino/Uart.cpp index 94b430061..7b4276d4d 100644 --- a/cores/arduino/Uart.cpp +++ b/cores/arduino/Uart.cpp @@ -55,6 +55,8 @@ void Uart::end() void Uart::flush() { + while(txBuffer.available()); // wait until TX buffer is empty + sercom->flushUART(); } From 12b3774c3f757d8619c99a2ba78fbf6cace18076 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 23 Oct 2015 09:08:46 -0400 Subject: [PATCH 6/8] Use reg instead of bit to enable/disable the DRE interrupt The RXC interrupt was being disabled when using bit to disable the DRE interrupt. --- cores/arduino/SERCOM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp index 192db3ad5..42c46d015 100644 --- a/cores/arduino/SERCOM.cpp +++ b/cores/arduino/SERCOM.cpp @@ -175,12 +175,12 @@ int SERCOM::writeDataUART(uint8_t data) void SERCOM::enableDataRegisterEmptyInterruptUART() { - sercom->USART.INTENSET.bit.DRE = 1; + sercom->USART.INTENSET.reg |= SERCOM_USART_INTENSET_DRE; } void SERCOM::disableDataRegisterEmptyInterruptUART() { - sercom->USART.INTENCLR.bit.DRE = 1; + sercom->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_DRE; } /* ========================= From 610d4a8b8b10b40e976297861f69586ac8f049dd Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Thu, 29 Oct 2015 09:26:05 -0400 Subject: [PATCH 7/8] Also check if TX buffer is empty before writing to data to UART reg directly --- cores/arduino/Uart.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/arduino/Uart.cpp b/cores/arduino/Uart.cpp index 7b4276d4d..7277ed078 100644 --- a/cores/arduino/Uart.cpp +++ b/cores/arduino/Uart.cpp @@ -107,7 +107,7 @@ int Uart::read() size_t Uart::write(const uint8_t data) { - if (sercom->isDataRegisterEmptyUART()) { + if (sercom->isDataRegisterEmptyUART() && txBuffer.available() == 0) { sercom->writeDataUART(data); } else { while(txBuffer.isFull()); // spin lock until a spot opens up in the buffer From 46653a61e18f5d0d0be95981eddf4ed7c0bc1c84 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Thu, 29 Oct 2015 09:31:52 -0400 Subject: [PATCH 8/8] Change IRQ handler to check if data is available before check for DRE --- cores/arduino/Uart.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cores/arduino/Uart.cpp b/cores/arduino/Uart.cpp index 7277ed078..adc73146f 100644 --- a/cores/arduino/Uart.cpp +++ b/cores/arduino/Uart.cpp @@ -62,6 +62,10 @@ void Uart::flush() void Uart::IrqHandler() { + if (sercom->availableDataUART()) { + rxBuffer.store_char(sercom->readDataUART()); + } + if (sercom->isDataRegisterEmptyUART()) { if (txBuffer.available()) { uint8_t data = txBuffer.read_char(); @@ -72,10 +76,6 @@ void Uart::IrqHandler() } } - if (sercom->availableDataUART()) { - rxBuffer.store_char(sercom->readDataUART()); - } - if (sercom->isUARTError()) { sercom->acknowledgeUARTError(); // TODO: if (sercom->isBufferOverflowErrorUART()) ....