Add SerialUART::setPollingMode() (#473)
Fixes #472 Instead of using interrupts, explicitly call the IRQ handler dueing Serial read/peek/available calls. Add to keywords.txt for syntax hilighting. Add poll calls in the SerialUART::write-like calls (write, flush, etc.) Really remove division from IRQ routines/
This commit was merged in pull request #473.
This commit is contained in:
+10
-12
@@ -114,15 +114,13 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
|
||||
}
|
||||
}
|
||||
|
||||
if ((_writer + 1) % _fifosize != _reader) {
|
||||
auto next_writer = _writer + 1;
|
||||
if (next_writer == _fifoSize) {
|
||||
next_writer = 0;
|
||||
}
|
||||
if (next_writer != _reader) {
|
||||
_queue[_writer] = val & ((1 << _bits) - 1);
|
||||
asm volatile("" ::: "memory"); // Ensure the queue is written before the written count advances
|
||||
// Avoid using division or mod because the HW divider could be in use
|
||||
auto next_writer = _writer + 1;
|
||||
if (next_writer == _fifosize) {
|
||||
next_writer = 0;
|
||||
}
|
||||
asm volatile("" ::: "memory"); // Ensure the reader value is only written once, correctly
|
||||
_writer = next_writer;
|
||||
} else {
|
||||
// TODO: Overflow
|
||||
@@ -130,11 +128,11 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
|
||||
}
|
||||
}
|
||||
|
||||
SerialPIO::SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifosize) {
|
||||
SerialPIO::SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize) {
|
||||
_tx = tx;
|
||||
_rx = rx;
|
||||
_fifosize = fifosize + 1; // Always one unused entry
|
||||
_queue = new uint8_t[_fifosize];
|
||||
_fifoSize = fifoSize + 1; // Always one unused entry
|
||||
_queue = new uint8_t[_fifoSize];
|
||||
mutex_init(&_mutex);
|
||||
}
|
||||
|
||||
@@ -278,7 +276,7 @@ int SerialPIO::read() {
|
||||
if (_writer != _reader) {
|
||||
auto ret = _queue[_reader];
|
||||
asm volatile("" ::: "memory"); // Ensure the value is read before advancing
|
||||
auto next_reader = (_reader + 1) % _fifosize;
|
||||
auto next_reader = (_reader + 1) % _fifoSize;
|
||||
asm volatile("" ::: "memory"); // Ensure the reader value is only written once, correctly
|
||||
_reader = next_reader;
|
||||
return ret;
|
||||
@@ -291,7 +289,7 @@ int SerialPIO::available() {
|
||||
if (!_running || !m || (_rx == NOPIN)) {
|
||||
return 0;
|
||||
}
|
||||
return (_writer - _reader) % _fifosize;
|
||||
return (_writer - _reader) % _fifoSize;
|
||||
}
|
||||
|
||||
int SerialPIO::availableForWrite() {
|
||||
|
||||
@@ -32,7 +32,7 @@ extern "C" typedef struct uart_inst uart_inst_t;
|
||||
class SerialPIO : public HardwareSerial {
|
||||
public:
|
||||
static const pin_size_t NOPIN = 0xff; // Use in constructor to disable RX or TX unit
|
||||
SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifosize = 32);
|
||||
SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize = 32);
|
||||
~SerialPIO();
|
||||
|
||||
void begin(unsigned long baud = 115200) override {
|
||||
@@ -73,7 +73,7 @@ private:
|
||||
int _rxBits;
|
||||
|
||||
// Lockless, IRQ-handled circular queue
|
||||
size_t _fifosize;
|
||||
size_t _fifoSize;
|
||||
uint32_t _writer;
|
||||
uint32_t _reader;
|
||||
uint8_t *_queue;
|
||||
|
||||
+52
-18
@@ -65,6 +65,14 @@ bool SerialUART::setTX(pin_size_t pin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SerialUART::setPollingMode(bool mode) {
|
||||
if (_running) {
|
||||
return false;
|
||||
}
|
||||
_polling = mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialUART::setFIFOSize(size_t size) {
|
||||
if (!size || _running) {
|
||||
return false;
|
||||
@@ -128,15 +136,19 @@ void SerialUART::begin(unsigned long baud, uint16_t config) {
|
||||
_writer = 0;
|
||||
_reader = 0;
|
||||
|
||||
if (_uart == uart0) {
|
||||
irq_set_exclusive_handler(UART0_IRQ, _uart0IRQ);
|
||||
irq_set_enabled(UART0_IRQ, true);
|
||||
if (!_polling) {
|
||||
if (_uart == uart0) {
|
||||
irq_set_exclusive_handler(UART0_IRQ, _uart0IRQ);
|
||||
irq_set_enabled(UART0_IRQ, true);
|
||||
} else {
|
||||
irq_set_exclusive_handler(UART1_IRQ, _uart1IRQ);
|
||||
irq_set_enabled(UART1_IRQ, true);
|
||||
}
|
||||
// Set the IRQ enables and FIFO level to minimum
|
||||
uart_set_irq_enables(_uart, true, false);
|
||||
} else {
|
||||
irq_set_exclusive_handler(UART1_IRQ, _uart1IRQ);
|
||||
irq_set_enabled(UART1_IRQ, true);
|
||||
// Polling mode has no IRQs used
|
||||
}
|
||||
// Set the IRQ enables and FIFO level to minimum
|
||||
uart_set_irq_enables(_uart, true, false);
|
||||
_running = true;
|
||||
}
|
||||
|
||||
@@ -144,10 +156,12 @@ void SerialUART::end() {
|
||||
if (!_running) {
|
||||
return;
|
||||
}
|
||||
if (_uart == uart0) {
|
||||
irq_set_enabled(UART0_IRQ, false);
|
||||
} else {
|
||||
irq_set_enabled(UART1_IRQ, false);
|
||||
if (!_polling) {
|
||||
if (_uart == uart0) {
|
||||
irq_set_enabled(UART0_IRQ, false);
|
||||
} else {
|
||||
irq_set_enabled(UART1_IRQ, false);
|
||||
}
|
||||
}
|
||||
uart_deinit(_uart);
|
||||
delete[] _queue;
|
||||
@@ -159,6 +173,9 @@ int SerialUART::peek() {
|
||||
if (!_running || !m) {
|
||||
return -1;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
}
|
||||
if (_writer != _reader) {
|
||||
return _queue[_reader];
|
||||
}
|
||||
@@ -170,6 +187,9 @@ int SerialUART::read() {
|
||||
if (!_running || !m) {
|
||||
return -1;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
}
|
||||
if (_writer != _reader) {
|
||||
auto ret = _queue[_reader];
|
||||
asm volatile("" ::: "memory"); // Ensure the value is read before advancing
|
||||
@@ -186,6 +206,9 @@ int SerialUART::available() {
|
||||
if (!_running || !m) {
|
||||
return 0;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
}
|
||||
return (_writer - _reader) % _fifoSize;
|
||||
}
|
||||
|
||||
@@ -194,6 +217,9 @@ int SerialUART::availableForWrite() {
|
||||
if (!_running || !m) {
|
||||
return 0;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
}
|
||||
return (uart_is_writable(_uart)) ? 1 : 0;
|
||||
}
|
||||
|
||||
@@ -202,6 +228,9 @@ void SerialUART::flush() {
|
||||
if (!_running || !m) {
|
||||
return;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
}
|
||||
uart_tx_wait_blocking(_uart);
|
||||
}
|
||||
|
||||
@@ -210,6 +239,9 @@ size_t SerialUART::write(uint8_t c) {
|
||||
if (!_running || !m) {
|
||||
return 0;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
}
|
||||
uart_putc_raw(_uart, c);
|
||||
return 1;
|
||||
}
|
||||
@@ -219,6 +251,9 @@ size_t SerialUART::write(const uint8_t *p, size_t len) {
|
||||
if (!_running || !m) {
|
||||
return 0;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
}
|
||||
size_t cnt = len;
|
||||
while (cnt) {
|
||||
uart_putc_raw(_uart, *p);
|
||||
@@ -247,21 +282,20 @@ void arduino::serialEvent2Run(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// IRQ handler, called when FIFO > 1/4 full or when it had held unread data for >32 bit times
|
||||
// IRQ handler, called when FIFO > 1/8 full or when it had held unread data for >32 bit times
|
||||
void __not_in_flash_func(SerialUART::_handleIRQ)() {
|
||||
// ICR is write-to-clear
|
||||
uart_get_hw(_uart)->icr = UART_UARTICR_RTIC_BITS | UART_UARTICR_RXIC_BITS;
|
||||
while (uart_is_readable(_uart)) {
|
||||
auto val = uart_getc(_uart);
|
||||
if ((_writer + 1) % _fifoSize != _reader) {
|
||||
auto next_writer = _writer + 1;
|
||||
if (next_writer == _fifoSize) {
|
||||
next_writer = 0;
|
||||
}
|
||||
if (next_writer != _reader) {
|
||||
_queue[_writer] = val;
|
||||
asm volatile("" ::: "memory"); // Ensure the queue is written before the written count advances
|
||||
// Avoid using division or mod because the HW divider could be in use
|
||||
auto next_writer = _writer + 1;
|
||||
if (next_writer == _fifoSize) {
|
||||
next_writer = 0;
|
||||
}
|
||||
asm volatile("" ::: "memory"); // Ensure the reader value is only written once, correctly
|
||||
_writer = next_writer;
|
||||
} else {
|
||||
// TODO: Overflow
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
return ret;
|
||||
}
|
||||
bool setFIFOSize(size_t size);
|
||||
bool setPollingMode(bool mode = true);
|
||||
|
||||
void begin(unsigned long baud = 115200) override {
|
||||
begin(baud, SERIAL_8N1);
|
||||
@@ -67,6 +68,7 @@ private:
|
||||
pin_size_t _tx, _rx;
|
||||
int _baud;
|
||||
mutex_t _mutex;
|
||||
bool _polling = false;
|
||||
|
||||
// Lockless, IRQ-handled circular queue
|
||||
uint32_t _writer;
|
||||
|
||||
@@ -31,5 +31,16 @@ using the ``setFIFOSize`` call prior to calling ``begin()``
|
||||
Serial1.setFIFOSize(128);
|
||||
Serial1.begin(baud);
|
||||
|
||||
The FIFO is normally handled via an interrupt, which reduced CPU load and
|
||||
makes it less likely to lose characters. However, the FIFO introduces up
|
||||
to 32 bit-times of delay before serial data is available to the application.
|
||||
|
||||
For applications where this is an issue (i.e. very low baud), use
|
||||
``setPollingMode(true)`` before calling ``begin()``
|
||||
|
||||
.. code:: cpp
|
||||
Serial1.setPollingMode(true);
|
||||
Serial1.begin(110)
|
||||
|
||||
For detailed information about the Serial ports, see the
|
||||
Arduino `Serial Reference <https://www.arduino.cc/reference/en/language/functions/communication/serial/>`_ .
|
||||
|
||||
@@ -35,3 +35,4 @@ PIOProgram KEYWORD2
|
||||
prepare KEYWORD2
|
||||
SerialPIO KEYWORD2
|
||||
setFIFOSize KEYWORD2
|
||||
setPollingMode KEYWORD2
|
||||
|
||||
Reference in New Issue
Block a user