esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
15.96k stars 13.34k forks source link

Reference: clarify Serial.setRxBufferSize description #7484

Closed wolfbert closed 4 years ago

wolfbert commented 4 years ago

Basic Infos

Platform

Problem Description

https://arduino-esp8266.readthedocs.io/en/latest/reference.html#serial

Serial has additional 256-byte TX and RX buffers.

Looking at uart.cpp, I can only find support for the RX buffer.

The method Serial.setRxBufferSize(size_t size) allows to define the receiving buffer depth. The default value is 256.

While this reflects the code, it is by no means the whole story. The RX buffer shadows the hardware FIFO. If the RX buffer size is set to 0, UART initialization will fail. After every 16 (or more) received (unread) characters, FIFO content will be moved to the RX buffer which wraps around. So you can buffer at most RX buffer size + 15 (possibly up to 128) characters. Therefore, any change in the buffer size must be carefully considered. In case the buffer is resized smaller after UART initialization, unread data may get truncated (and the overrun flag remains unchanged).

As an aside, if the 128 byte hardware FIFO buffer is sufficient for the application, the RX buffer wouldn't be needed (but that requires a change in the code, i.e. don't allocate RX buffer unless requested size > 128).

Edit: fixed link to documentation.

d-a-v commented 4 years ago

To summarize, do you wish to clarify doc with the following statements ?

wolfbert commented 4 years ago

Let me suggest:

"Serial object works much the same way as on a regular Arduino. Apart from hardware FIFO (128 bytes for TX and RX) Serial has additional 256-byte TX and RX buffers a customizable RX buffer (default size 256 bytes) in RAM. Both transmit and receive is interrupt-driven. Write and read functions only block the sketch execution when the respective FIFO/buffers are full/empty. Note that the length of additional 256-bit buffer can be customized."

"The method Serial.setRxBufferSize(size_t size) allows to define the receiving buffer depth. It must be at least the size of the largest block of data you may need to buffer before reading. The default value size is 256. For transmit-only operation, the buffer can be switched off by passing mode SERIAL_TX_ONLY to Serial.begin()."

Edit: rephrased minimum size.

Tech-TX commented 4 years ago

There is indeed some sort of TX buffer; I saw it in action when I was playing with the Low Power Demo in December/January. I don't know if it's managed by the core or SDK, nor how large it is. I had to do Serial.flush() or the CPU wouldn't sleep in a couple of places. Backtrack the flush should show you the buffer. It may be a hardware buffer in the UART.

wolfbert commented 4 years ago

@Tech-TX

There is indeed some sort of TX buffer; [...] Backtrack the flush should show you the buffer. It may be a hardware buffer in the UART.

It is indeed the hardware buffer.

Edit: removed incorrect comment about flush().

TD-er commented 4 years ago

I always thought (not sure where I got it from) the hardware buffer was only 128 bytes in size, both for reading and writing.

wolfbert commented 4 years ago

@TD-er It is, 128 bytes each for input and output, for each UART.

According to Esspressifs Technical Reference, Chapter 11, page 79:

Both UART0 and UART1 have a length of 128 Byte hardware, read and write FIFO operations are at the same address.

In the rest of the chapter, receive and transmit buffers are described separately (e.g. buffer full and empty interrupt triggers can be set in the range of 0-127). Also, issues #1683 and #2237 refer to the implementation of the serial buffer for ESP8266.

d-a-v commented 4 years ago

@wolfbert here's an update:

"Serial object works much the same way as on a regular Arduino. Apart from hardware FIFO (128 bytes for TX and RX) Serial has a customizable RX buffer (default size 256 bytes, can be customized) in RAM. Both transmit and receive is interrupt-driven. ::write() and ::readBytes() functions only block the sketch execution when the respective FIFO/buffers are full/empty, but ::read(buffer, size) does not block and returns the number of bytes read. ::flush() will block until all output bytes are effectively sent and has no effect on input buffer."

"The method Serial.setRxBufferSize(size_t size) allows to define the receiving buffer depth. It must be at least the size of the largest block of data you may need to buffer before reading. The default value size is 256. For transmit-only operation, the buffer can be switched off by passing mode SERIAL_TX_ONLY to Serial.begin(). Other modes are SERIAL_RX_ONLY and SERIAL_FULL (the default). Default configuration mode is SERIAL_8N1. Possibilities are SERIAL_[5678][NEO][12]."

wolfbert commented 4 years ago

@d-a-v Thanks, fine with me, just a minor copy issue:

The default value size is 256.

Note that the two paragraphs are separated by a number of lines in the documentation.

devyte commented 4 years ago

Both transmit and receive is interrupt-driven

Transmit is not interrupt driven, it is blocking due to polling busy-wait, ref here.

The Arduino AVR reference seems to be interrupt-driven, ref there.

Rx is interrupt-driven, i.e.: there is a sw buffer that has a default size of 256 bytes, that gets filled when there are bytes incoming. If I remember correctly, the ISR is triggered under 2 conditions:

So that part is wrong in both current and proposed doc: Only Rx is interrupt driven.

Serial object works much the same way as on a regular Arduino

However, both are blocking, so the behavior from the user's POV is pretty much the same as for Arduino, i.e.: it makes no difference that our implementation for Tx isn't interrupt driven.

::write() and ::readBytes() functions only block the sketch execution when the respective FIFO/buffers are full/empty, but ::read(buffer, size) does not block and returns the number of bytes read.

Transmit, i.e.: write(), blocks when the Tx hw FIFO is full. Receive:

Serial has a customizable RX buffer (default size 256 bytes, can be customized) in RAM

To reduce redundancy, I suggest along the lines of: "Serial has a software RX buffer in RAM. The default size 256 bytes, but it can be customized as needed."

Possibilities are SERIAL_[5678][NEO][12]

I suggest adding an example, e.g.: "For example, SERIAL_8N1 means 8 No parity 1 end bit."