1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-15 00:02:49 +03:00

uart: BW improvements (#4620)

* uart fixes and BW improvements

* uart: read_char straightly use hw buffer

* +attributes for functions called by ISR

* uart: BW improvements
read_char straightly use hw buffer (+ ~10%bw)
read by block (+ ~190%bw) (instead of generic Stream::readBytes)
attributes for functions called by ISR
remove overrun message
remove some ISR flags which were not honoured

* fix merge

* fix buffer overflow

* serial stress test sketch

* astyle

* serial stress example: interactive keyboard, stop reading, overrun

* serial device test: bandwidth & overrun

* update + HardwareSerial::hasError()

* interactive overrun in example

* astyle

* Test using @plerup's SoftwareSerial as submodule (tag 3.4.1)

* update upstream ref (fix warning)

* host mock uart/read(buf,size)

* reset style changes in submodules before style diff

* update build_boards_manager_package.sh for submodules

* trigger CI (removing space)

* cannot reproduce locally the CI issue, setting bash -x option to get live trace

* remove previously added (in this PR) 'set -e' in package builder (passes local tests, not real CI)
script-comment new recipe.hooks.core.prebuild.3 (along with already commented .1 and .2)
moved CI package test to be first on the test list
remove 'set -x', wish me luck
This commit is contained in:
david gauchard
2018-12-10 14:35:11 +01:00
committed by Develo
parent 8a8848829c
commit 4c8d8f1e8a
11 changed files with 545 additions and 44 deletions

View File

@ -88,6 +88,10 @@ public:
void end();
size_t setRxBufferSize(size_t size);
size_t getRxBufferSize()
{
return uart_get_rx_buffer_size(_uart);
}
void swap()
{
@ -120,14 +124,22 @@ public:
int peek(void) override
{
// this may return -1, but that's okay
// return -1 when data is unvailable (arduino api)
return uart_peek_char(_uart);
}
int read(void) override
{
// this may return -1, but that's okay
// return -1 when data is unvailable (arduino api)
return uart_read_char(_uart);
}
size_t readBytes(char* buffer, size_t size) override
{
return uart_read(_uart, buffer, size);
}
size_t readBytes(uint8_t* buffer, size_t size) override
{
return uart_read(_uart, (char*)buffer, size);
}
int availableForWrite(void)
{
return static_cast<int>(uart_tx_free(_uart));
@ -184,6 +196,11 @@ public:
return uart_has_overrun(_uart);
}
bool hasRxError(void)
{
return uart_has_rx_error(_uart);
}
void startDetectBaudrate();
unsigned long testBaudrate();

View File

@ -47,11 +47,11 @@
#include "user_interface.h"
#include "uart_register.h"
const char overrun_str [] PROGMEM STORE_ATTR = "uart input full!\r\n";
//const char overrun_str [] PROGMEM STORE_ATTR = "uart input full!\r\n";
static int s_uart_debug_nr = UART0;
struct uart_rx_buffer_
struct uart_rx_buffer_
{
size_t size;
size_t rpos;
@ -65,7 +65,8 @@ struct uart_
int baud_rate;
bool rx_enabled;
bool tx_enabled;
bool overrun;
bool rx_overrun;
bool rx_error;
uint8_t rx_pin;
uint8_t tx_pin;
struct uart_rx_buffer_ * rx_buffer;
@ -85,7 +86,8 @@ struct uart_
inline size_t
// called by ISR
inline size_t ICACHE_RAM_ATTR
uart_rx_fifo_available(const int uart_nr)
{
return (USS(uart_nr) >> USRXC) & 0xFF;
@ -110,11 +112,11 @@ uart_rx_available_unsafe(uart_t* uart)
return uart_rx_buffer_available_unsafe(uart->rx_buffer) + uart_rx_fifo_available(uart->uart_nr);
}
//#define UART_DISCARD_NEWEST
// Copy all the rx fifo bytes that fit into the rx buffer
inline void
// called by ISR
inline void ICACHE_RAM_ATTR
uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart)
{
struct uart_rx_buffer_ *rx_buffer = uart->rx_buffer;
@ -124,11 +126,10 @@ uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart)
size_t nextPos = (rx_buffer->wpos + 1) % rx_buffer->size;
if(nextPos == rx_buffer->rpos)
{
if (!uart->overrun)
if (!uart->rx_overrun)
{
uart->overrun = true;
os_printf_plus(overrun_str);
uart->rx_overrun = true;
//os_printf_plus(overrun_str);
}
// a choice has to be made here,
@ -158,25 +159,27 @@ uart_peek_char_unsafe(uart_t* uart)
//without the following if statement and body, there is a good chance of a fifo overrun
if (uart_rx_buffer_available_unsafe(uart->rx_buffer) == 0)
// hw fifo can't be peeked, data need to be copied to sw
uart_rx_copy_fifo_to_buffer_unsafe(uart);
return uart->rx_buffer->buffer[uart->rx_buffer->rpos];
}
inline int
// taking data straight from hw fifo: loopback-test BW jumps by 19%
inline int
uart_read_char_unsafe(uart_t* uart)
{
int data = uart_peek_char_unsafe(uart);
if(data != -1)
if (uart_rx_buffer_available_unsafe(uart->rx_buffer))
{
// take oldest sw data
int ret = uart->rx_buffer->buffer[uart->rx_buffer->rpos];
uart->rx_buffer->rpos = (uart->rx_buffer->rpos + 1) % uart->rx_buffer->size;
return data;
return ret;
}
// unavailable
return -1;
}
/**********************************************************/
size_t
uart_rx_available(uart_t* uart)
{
@ -204,14 +207,47 @@ uart_peek_char(uart_t* uart)
int
uart_read_char(uart_t* uart)
{
uint8_t ret;
return uart_read(uart, (char*)&ret, 1)? ret: -1;
}
// loopback-test BW jumps by 190%
size_t
uart_read(uart_t* uart, char* userbuffer, size_t usersize)
{
if(uart == NULL || !uart->rx_enabled)
return -1;
return 0;
size_t ret = 0;
ETS_UART_INTR_DISABLE();
int data = uart_read_char_unsafe(uart);
while (ret < usersize && uart_rx_available_unsafe(uart))
{
if (!uart_rx_buffer_available_unsafe(uart->rx_buffer))
{
// no more data in sw buffer, take them from hw fifo
while (ret < usersize && uart_rx_fifo_available(uart->uart_nr))
userbuffer[ret++] = USF(uart->uart_nr);
// no more sw/hw data available
break;
}
// pour sw buffer to user's buffer
// get largest linear length from sw buffer
size_t chunk = uart->rx_buffer->rpos < uart->rx_buffer->wpos?
uart->rx_buffer->wpos - uart->rx_buffer->rpos:
uart->rx_buffer->size - uart->rx_buffer->rpos;
if (ret + chunk > usersize)
chunk = usersize - ret;
memcpy(userbuffer + ret, uart->rx_buffer->buffer + uart->rx_buffer->rpos, chunk);
uart->rx_buffer->rpos = (uart->rx_buffer->rpos + chunk) % uart->rx_buffer->size;
ret += chunk;
}
ETS_UART_INTR_ENABLE();
return data;
return ret;
}
size_t
@ -231,6 +267,8 @@ uart_resize_rx_buffer(uart_t* uart, size_t new_size)
ETS_UART_INTR_DISABLE();
while(uart_rx_available_unsafe(uart) && new_wpos < new_size)
new_buf[new_wpos++] = uart_read_char_unsafe(uart); //if uart_rx_available_unsafe() returns non-0, uart_read_char_unsafe() can't return -1
if (new_wpos == new_size)
new_wpos = 0;
uint8_t * old_buf = uart->rx_buffer->buffer;
uart->rx_buffer->rpos = 0;
@ -242,22 +280,39 @@ uart_resize_rx_buffer(uart_t* uart, size_t new_size)
return uart->rx_buffer->size;
}
size_t
uart_get_rx_buffer_size(uart_t* uart)
{
return uart && uart->rx_enabled? uart->rx_buffer->size: 0;
}
void ICACHE_RAM_ATTR
uart_isr(void * arg)
{
uart_t* uart = (uart_t*)arg;
uint32_t usis = USIS(uart->uart_nr);
if(uart == NULL || !uart->rx_enabled)
{
USIC(uart->uart_nr) = USIS(uart->uart_nr);
USIC(uart->uart_nr) = usis;
ETS_UART_INTR_DISABLE();
return;
}
if(USIS(uart->uart_nr) & ((1 << UIFF) | (1 << UITO)))
if(usis & (1 << UIFF))
uart_rx_copy_fifo_to_buffer_unsafe(uart);
if((usis & (1 << UIOF)) && !uart->rx_overrun)
{
uart->rx_overrun = true;
//os_printf_plus(overrun_str);
}
USIC(uart->uart_nr) = USIS(uart->uart_nr);
if (usis & ((1 << UIFR) | (1 << UIPE) | (1 << UITO)))
uart->rx_error = true;
USIC(uart->uart_nr) = usis;
}
static void
@ -270,9 +325,22 @@ uart_start_isr(uart_t* uart)
// triggers the IRS very often. A value of 127 would not leave much time
// for ISR to clear fifo before the next byte is dropped. So pick a value
// in the middle.
USC1(uart->uart_nr) = (100 << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE );
// update: loopback test @ 3Mbauds/8n1 (=2343Kibits/s):
// - 4..120 give > 2300Kibits/s
// - 1, 2, 3 are below
// was 100, use 16 to stay away from overrun
#define INTRIGG 16
//was:USC1(uart->uart_nr) = (INTRIGG << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE);
USC1(uart->uart_nr) = (INTRIGG << UCFFT);
USIC(uart->uart_nr) = 0xffff;
USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIFR) | (1 << UITO);
//was: USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIFR) | (1 << UITO);
// UIFF: rx fifo full
// UIOF: rx fifo overflow (=overrun)
// UIFR: frame error
// UIPE: parity error
// UITO: rx fifo timeout
USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIOF) | (1 << UIFR) | (1 << UIPE) | (1 << UITO);
ETS_UART_INTR_ATTACH(uart_isr, (void *)uart);
ETS_UART_INTR_ENABLE();
}
@ -415,7 +483,8 @@ uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx
return NULL;
uart->uart_nr = uart_nr;
uart->overrun = false;
uart->rx_overrun = false;
uart->rx_error = false;
switch(uart->uart_nr)
{
@ -678,11 +747,22 @@ uart_rx_enabled(uart_t* uart)
bool
uart_has_overrun (uart_t* uart)
{
if (uart == NULL || !uart->overrun)
if (uart == NULL || !uart->rx_overrun)
return false;
// clear flag
uart->overrun = false;
uart->rx_overrun = false;
return true;
}
bool
uart_has_rx_error (uart_t* uart)
{
if (uart == NULL || !uart->rx_error)
return false;
// clear flag
uart->rx_error = false;
return true;
}

View File

@ -126,17 +126,20 @@ void uart_set_baudrate(uart_t* uart, int baud_rate);
int uart_get_baudrate(uart_t* uart);
size_t uart_resize_rx_buffer(uart_t* uart, size_t new_size);
size_t uart_get_rx_buffer_size(uart_t* uart);
size_t uart_write_char(uart_t* uart, char c);
size_t uart_write(uart_t* uart, const char* buf, size_t size);
int uart_read_char(uart_t* uart);
int uart_peek_char(uart_t* uart);
size_t uart_read(uart_t* uart, char* buffer, size_t size);
size_t uart_rx_available(uart_t* uart);
size_t uart_tx_free(uart_t* uart);
void uart_wait_tx_empty(uart_t* uart);
void uart_flush(uart_t* uart);
bool uart_has_overrun (uart_t* uart); // returns then clear overrun flag
bool uart_has_rx_error (uart_t* uart); // returns then clear rxerror flag
void uart_set_debug(int uart_nr);
int uart_get_debug();