Skip to content

Commit 0bd6a2d

Browse files
matthijskooijmancmaglie
authored andcommitted
Move buffers into HardwareSerial
This removes the need for doing an extra pointer dereference on every access to the buffers, shrinking the code by around 100 bytes. The members for these buffers must be public for now, since the interrupt handlers also need to access them. These can later be made private again. Furthermore, the struct ring_buffer was removed. This allows the all head and tail pointers to be put into the HardwareSerial struct before the actual buffers, so the pointers all end up in the first 32 bytes of the struct that can be accessed using a single instruction (ldd). References: arduino#947
1 parent e0a9a76 commit 0bd6a2d

File tree

2 files changed

+63
-88
lines changed

2 files changed

+63
-88
lines changed

hardware/arduino/avr/cores/arduino/HardwareSerial.cpp

Lines changed: 41 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -49,59 +49,17 @@
4949
#endif
5050
#endif
5151

52-
// Define constants and variables for buffering incoming serial data. We're
53-
// using a ring buffer (I think), in which head is the index of the location
54-
// to which to write the next incoming character and tail is the index of the
55-
// location from which to read.
56-
#if (RAMEND < 1000)
57-
#define SERIAL_BUFFER_SIZE 16
58-
#else
59-
#define SERIAL_BUFFER_SIZE 64
60-
#endif
61-
62-
struct ring_buffer
63-
{
64-
unsigned char buffer[SERIAL_BUFFER_SIZE];
65-
volatile uint8_t head;
66-
volatile uint8_t tail;
67-
};
68-
69-
#if SERIAL_BUFFER_SIZE > 256
70-
#error Serial buffer size too big for head and tail pointers
71-
#endif
72-
73-
#if defined(USBCON)
74-
ring_buffer rx_buffer = { { 0 }, 0, 0};
75-
ring_buffer tx_buffer = { { 0 }, 0, 0};
76-
#endif
77-
#if defined(UBRRH) || defined(UBRR0H)
78-
ring_buffer rx_buffer = { { 0 }, 0, 0 };
79-
ring_buffer tx_buffer = { { 0 }, 0, 0 };
80-
#endif
81-
#if defined(UBRR1H)
82-
ring_buffer rx_buffer1 = { { 0 }, 0, 0 };
83-
ring_buffer tx_buffer1 = { { 0 }, 0, 0 };
84-
#endif
85-
#if defined(UBRR2H)
86-
ring_buffer rx_buffer2 = { { 0 }, 0, 0 };
87-
ring_buffer tx_buffer2 = { { 0 }, 0, 0 };
88-
#endif
89-
#if defined(UBRR3H)
90-
ring_buffer rx_buffer3 = { { 0 }, 0, 0 };
91-
ring_buffer tx_buffer3 = { { 0 }, 0, 0 };
92-
#endif
93-
94-
inline void store_char(unsigned char c, ring_buffer *buffer)
52+
inline void store_char(unsigned char c, HardwareSerial *s)
9553
{
96-
int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;
54+
int i = (unsigned int)(s->_rx_buffer_head + 1) % SERIAL_BUFFER_SIZE;
9755

9856
// if we should be storing the received character into the location
9957
// just before the tail (meaning that the head would advance to the
10058
// current location of the tail), we're about to overflow the buffer
10159
// and so we don't write the character or advance the head.
102-
if (i != buffer->tail) {
103-
buffer->buffer[buffer->head] = c;
104-
buffer->head = i;
60+
if (i != s->_rx_buffer_tail) {
61+
s->_rx_buffer[s->_rx_buffer_head] = c;
62+
s->_rx_buffer_head = i;
10563
}
10664
}
10765

@@ -126,7 +84,7 @@ inline void store_char(unsigned char c, ring_buffer *buffer)
12684
#if defined(UDR0)
12785
if (bit_is_clear(UCSR0A, UPE0)) {
12886
unsigned char c = UDR0;
129-
store_char(c, &rx_buffer);
87+
store_char(c, &Serial);
13088
} else {
13189
unsigned char c = UDR0;
13290
};
@@ -152,7 +110,7 @@ inline void store_char(unsigned char c, ring_buffer *buffer)
152110
{
153111
if (bit_is_clear(UCSR1A, UPE1)) {
154112
unsigned char c = UDR1;
155-
store_char(c, &rx_buffer1);
113+
store_char(c, &Serial1);
156114
} else {
157115
unsigned char c = UDR1;
158116
};
@@ -167,7 +125,7 @@ inline void store_char(unsigned char c, ring_buffer *buffer)
167125
{
168126
if (bit_is_clear(UCSR2A, UPE2)) {
169127
unsigned char c = UDR2;
170-
store_char(c, &rx_buffer2);
128+
store_char(c, &Serial2);
171129
} else {
172130
unsigned char c = UDR2;
173131
};
@@ -182,7 +140,7 @@ inline void store_char(unsigned char c, ring_buffer *buffer)
182140
{
183141
if (bit_is_clear(UCSR3A, UPE3)) {
184142
unsigned char c = UDR3;
185-
store_char(c, &rx_buffer3);
143+
store_char(c, &Serial3);
186144
} else {
187145
unsigned char c = UDR3;
188146
};
@@ -222,7 +180,7 @@ ISR(USART0_UDRE_vect)
222180
ISR(USART_UDRE_vect)
223181
#endif
224182
{
225-
if (tx_buffer.head == tx_buffer.tail) {
183+
if (Serial._tx_buffer_head == Serial._tx_buffer_tail) {
226184
// Buffer empty, so disable interrupts
227185
#if defined(UCSR0B)
228186
cbi(UCSR0B, UDRIE0);
@@ -232,8 +190,8 @@ ISR(USART_UDRE_vect)
232190
}
233191
else {
234192
// There is more data in the output buffer. Send the next byte
235-
unsigned char c = tx_buffer.buffer[tx_buffer.tail];
236-
tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE;
193+
unsigned char c = Serial._tx_buffer[Serial._tx_buffer_tail];
194+
Serial._tx_buffer_tail = (Serial._tx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
237195

238196
#if defined(UDR0)
239197
UDR0 = c;
@@ -250,14 +208,14 @@ ISR(USART_UDRE_vect)
250208
#ifdef USART1_UDRE_vect
251209
ISR(USART1_UDRE_vect)
252210
{
253-
if (tx_buffer1.head == tx_buffer1.tail) {
211+
if (Serial1._tx_buffer_head == Serial1._tx_buffer_tail) {
254212
// Buffer empty, so disable interrupts
255213
cbi(UCSR1B, UDRIE1);
256214
}
257215
else {
258216
// There is more data in the output buffer. Send the next byte
259-
unsigned char c = tx_buffer1.buffer[tx_buffer1.tail];
260-
tx_buffer1.tail = (tx_buffer1.tail + 1) % SERIAL_BUFFER_SIZE;
217+
unsigned char c = Serial1._tx_buffer[Serial1._tx_buffer_tail];
218+
Serial1._tx_buffer_tail = (Serial1._tx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
261219

262220
UDR1 = c;
263221
}
@@ -267,14 +225,14 @@ ISR(USART1_UDRE_vect)
267225
#ifdef USART2_UDRE_vect
268226
ISR(USART2_UDRE_vect)
269227
{
270-
if (tx_buffer2.head == tx_buffer2.tail) {
228+
if (Serial2._tx_buffer_head == Serial2._tx_buffer_tail) {
271229
// Buffer empty, so disable interrupts
272230
cbi(UCSR2B, UDRIE2);
273231
}
274232
else {
275233
// There is more data in the output buffer. Send the next byte
276-
unsigned char c = tx_buffer2.buffer[tx_buffer2.tail];
277-
tx_buffer2.tail = (tx_buffer2.tail + 1) % SERIAL_BUFFER_SIZE;
234+
unsigned char c = Serial2._tx_buffer[Serial2._tx_buffer_tail];
235+
Serial2._tx_buffer_tail = (Serial2._tx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
278236

279237
UDR2 = c;
280238
}
@@ -284,31 +242,30 @@ ISR(USART2_UDRE_vect)
284242
#ifdef USART3_UDRE_vect
285243
ISR(USART3_UDRE_vect)
286244
{
287-
if (tx_buffer3.head == tx_buffer3.tail) {
245+
if (Serial3._tx_buffer_head == Serial3._tx_buffer_tail) {
288246
// Buffer empty, so disable interrupts
289247
cbi(UCSR3B, UDRIE3);
290248
}
291249
else {
292250
// There is more data in the output buffer. Send the next byte
293-
unsigned char c = tx_buffer3.buffer[tx_buffer3.tail];
294-
tx_buffer3.tail = (tx_buffer3.tail + 1) % SERIAL_BUFFER_SIZE;
251+
unsigned char c = Serial3._tx_buffer[Serial3._tx_buffer_tail];
252+
Serial3._tx_buffer_tail = (Serial3._tx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
295253

296254
UDR3 = c;
297255
}
298256
}
299257
#endif
300258

301-
302259
// Constructors ////////////////////////////////////////////////////////////////
303260

304-
HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer,
261+
HardwareSerial::HardwareSerial(
305262
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
306263
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
307264
volatile uint8_t *ucsrc, volatile uint8_t *udr,
308265
uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x)
309266
{
310-
_rx_buffer = rx_buffer;
311-
_tx_buffer = tx_buffer;
267+
_tx_buffer_head = _tx_buffer_tail = 0;
268+
_rx_buffer_head = _rx_buffer_tail = 0;
312269
_ubrrh = ubrrh;
313270
_ubrrl = ubrrl;
314271
_ucsra = ucsra;
@@ -416,7 +373,7 @@ void HardwareSerial::begin(unsigned long baud, byte config)
416373
void HardwareSerial::end()
417374
{
418375
// wait for transmission of outgoing data
419-
while (_tx_buffer->head != _tx_buffer->tail)
376+
while (_tx_buffer_head != _tx_buffer_tail)
420377
;
421378

422379
cbi(*_ucsrb, _rxen);
@@ -425,31 +382,31 @@ void HardwareSerial::end()
425382
cbi(*_ucsrb, _udrie);
426383

427384
// clear any received data
428-
_rx_buffer->head = _rx_buffer->tail;
385+
_rx_buffer_head = _rx_buffer_tail;
429386
}
430387

431388
int HardwareSerial::available(void)
432389
{
433-
return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE;
390+
return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail) % SERIAL_BUFFER_SIZE;
434391
}
435392

436393
int HardwareSerial::peek(void)
437394
{
438-
if (_rx_buffer->head == _rx_buffer->tail) {
395+
if (_rx_buffer_head == _rx_buffer_tail) {
439396
return -1;
440397
} else {
441-
return _rx_buffer->buffer[_rx_buffer->tail];
398+
return _rx_buffer[_rx_buffer_tail];
442399
}
443400
}
444401

445402
int HardwareSerial::read(void)
446403
{
447404
// if the head isn't ahead of the tail, we don't have any characters
448-
if (_rx_buffer->head == _rx_buffer->tail) {
405+
if (_rx_buffer_head == _rx_buffer_tail) {
449406
return -1;
450407
} else {
451-
unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
452-
_rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE;
408+
unsigned char c = _rx_buffer[_rx_buffer_tail];
409+
_rx_buffer_tail = (unsigned int)(_rx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
453410
return c;
454411
}
455412
}
@@ -463,16 +420,16 @@ void HardwareSerial::flush()
463420

464421
size_t HardwareSerial::write(uint8_t c)
465422
{
466-
int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE;
423+
int i = (_tx_buffer_head + 1) % SERIAL_BUFFER_SIZE;
467424

468425
// If the output buffer is full, there's nothing for it other than to
469426
// wait for the interrupt handler to empty it a bit
470427
// ???: return 0 here instead?
471-
while (i == _tx_buffer->tail)
428+
while (i == _tx_buffer_tail)
472429
;
473430

474-
_tx_buffer->buffer[_tx_buffer->head] = c;
475-
_tx_buffer->head = i;
431+
_tx_buffer[_tx_buffer_head] = c;
432+
_tx_buffer_head = i;
476433

477434
sbi(*_ucsrb, _udrie);
478435
// clear the TXC bit -- "can be cleared by writing a one to its bit location"
@@ -489,23 +446,23 @@ HardwareSerial::operator bool() {
489446
// Preinstantiate Objects //////////////////////////////////////////////////////
490447

491448
#if defined(UBRRH) && defined(UBRRL)
492-
HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR, RXEN, TXEN, RXCIE, UDRIE, U2X);
449+
HardwareSerial Serial(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR, RXEN, TXEN, RXCIE, UDRIE, U2X);
493450
#elif defined(UBRR0H) && defined(UBRR0L)
494-
HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UCSR0C, &UDR0, RXEN0, TXEN0, RXCIE0, UDRIE0, U2X0);
451+
HardwareSerial Serial(&UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UCSR0C, &UDR0, RXEN0, TXEN0, RXCIE0, UDRIE0, U2X0);
495452
#elif defined(USBCON)
496453
// do nothing - Serial object and buffers are initialized in CDC code
497454
#else
498455
#error no serial port defined (port 0)
499456
#endif
500457

501458
#if defined(UBRR1H)
502-
HardwareSerial Serial1(&rx_buffer1, &tx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1, RXEN1, TXEN1, RXCIE1, UDRIE1, U2X1);
459+
HardwareSerial Serial1(&UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1, RXEN1, TXEN1, RXCIE1, UDRIE1, U2X1);
503460
#endif
504461
#if defined(UBRR2H)
505-
HardwareSerial Serial2(&rx_buffer2, &tx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2, RXEN2, TXEN2, RXCIE2, UDRIE2, U2X2);
462+
HardwareSerial Serial2(&UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2, RXEN2, TXEN2, RXCIE2, UDRIE2, U2X2);
506463
#endif
507464
#if defined(UBRR3H)
508-
HardwareSerial Serial3(&rx_buffer3, &tx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3, RXEN3, TXEN3, RXCIE3, UDRIE3, U2X3);
465+
HardwareSerial Serial3(&UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3, RXEN3, TXEN3, RXCIE3, UDRIE3, U2X3);
509466
#endif
510467

511468
#endif // whole file

hardware/arduino/avr/cores/arduino/HardwareSerial.h

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,19 @@
2727

2828
#include "Stream.h"
2929

30-
struct ring_buffer;
30+
// Define constants and variables for buffering incoming serial data. We're
31+
// using a ring buffer (I think), in which head is the index of the location
32+
// to which to write the next incoming character and tail is the index of the
33+
// location from which to read.
34+
#if (RAMEND < 1000)
35+
#define SERIAL_BUFFER_SIZE 16
36+
#else
37+
#define SERIAL_BUFFER_SIZE 64
38+
#endif
3139

3240
class HardwareSerial : public Stream
3341
{
3442
private:
35-
ring_buffer *_rx_buffer;
36-
ring_buffer *_tx_buffer;
3743
volatile uint8_t *_ubrrh;
3844
volatile uint8_t *_ubrrl;
3945
volatile uint8_t *_ucsra;
@@ -46,8 +52,20 @@ class HardwareSerial : public Stream
4652
uint8_t _udrie;
4753
uint8_t _u2x;
4854
bool transmitting;
55+
4956
public:
50-
HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer,
57+
volatile uint8_t _rx_buffer_head;
58+
volatile uint8_t _rx_buffer_tail;
59+
volatile uint8_t _tx_buffer_head;
60+
volatile uint8_t _tx_buffer_tail;
61+
62+
// Don't put any members after these buffers, since only the first
63+
// 32 bytes of this struct can be accessed quickly using the ldd
64+
// instruction.
65+
unsigned char _rx_buffer[SERIAL_BUFFER_SIZE];
66+
unsigned char _tx_buffer[SERIAL_BUFFER_SIZE];
67+
68+
HardwareSerial(
5169
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
5270
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
5371
volatile uint8_t *ucsrc, volatile uint8_t *udr,

0 commit comments

Comments
 (0)