Skip to content

Commit 03fac84

Browse files
matthijskooijmancmaglie
authored andcommitted
Move interrupt handlers into HardwareSerial class
The actual interrupt vectors are of course defined as before, but they let new methods in the HardwareSerial class do the actual work. This greatly reduces code duplication and prepares for one of my next commits which requires the tx interrupt handler to be called from another context as well. The actual content of the interrupts handlers was pretty much identical, so that remains unchanged (except that store_char was now only needed once, so it was inlined). Now all access to the buffers are inside the HardwareSerial class, the buffer variables can be made private. One would expect a program size reduction from this change (at least with multiple UARTs), but due to the fact that the interrupt handlers now only have indirect access to a few registers (which previously were just hardcoded in the handlers) and because there is some extra function call overhead, the code size on the uno actually increases by around 70 bytes. On the mega, which has four UARTs, the code size decreases by around 70 bytes.
1 parent e40cf5b commit 03fac84

File tree

2 files changed

+50
-101
lines changed

2 files changed

+50
-101
lines changed

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

Lines changed: 45 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -84,20 +84,6 @@
8484
#error "Not all bit positions for UART3 are the same as for UART0"
8585
#endif
8686

87-
inline void store_char(unsigned char c, HardwareSerial *s)
88-
{
89-
int i = (unsigned int)(s->_rx_buffer_head + 1) % SERIAL_BUFFER_SIZE;
90-
91-
// if we should be storing the received character into the location
92-
// just before the tail (meaning that the head would advance to the
93-
// current location of the tail), we're about to overflow the buffer
94-
// and so we don't write the character or advance the head.
95-
if (i != s->_rx_buffer_tail) {
96-
s->_rx_buffer[s->_rx_buffer_head] = c;
97-
s->_rx_buffer_head = i;
98-
}
99-
}
100-
10187
#if !defined(USART0_RX_vect) && defined(USART1_RX_vect)
10288
// do nothing - on the 32u4 the first USART is USART1
10389
#else
@@ -116,23 +102,7 @@ inline void store_char(unsigned char c, HardwareSerial *s)
116102
ISR(USART_RXC_vect) // ATmega8
117103
#endif
118104
{
119-
#if defined(UDR0)
120-
if (bit_is_clear(UCSR0A, UPE0)) {
121-
unsigned char c = UDR0;
122-
store_char(c, &Serial);
123-
} else {
124-
unsigned char c = UDR0;
125-
};
126-
#elif defined(UDR)
127-
if (bit_is_clear(UCSRA, PE)) {
128-
unsigned char c = UDR;
129-
store_char(c, &Serial);
130-
} else {
131-
unsigned char c = UDR;
132-
};
133-
#else
134-
#error UDR not defined
135-
#endif
105+
Serial._rx_complete_irq();
136106
}
137107
#endif
138108
#endif
@@ -143,12 +113,7 @@ inline void store_char(unsigned char c, HardwareSerial *s)
143113
#define serialEvent1_implemented
144114
ISR(USART1_RX_vect)
145115
{
146-
if (bit_is_clear(UCSR1A, UPE1)) {
147-
unsigned char c = UDR1;
148-
store_char(c, &Serial1);
149-
} else {
150-
unsigned char c = UDR1;
151-
};
116+
Serial1._rx_complete_irq();
152117
}
153118
#endif
154119

@@ -158,12 +123,7 @@ inline void store_char(unsigned char c, HardwareSerial *s)
158123
#define serialEvent2_implemented
159124
ISR(USART2_RX_vect)
160125
{
161-
if (bit_is_clear(UCSR2A, UPE2)) {
162-
unsigned char c = UDR2;
163-
store_char(c, &Serial2);
164-
} else {
165-
unsigned char c = UDR2;
166-
};
126+
Serial2._rx_complete_irq();
167127
}
168128
#endif
169129

@@ -173,12 +133,7 @@ inline void store_char(unsigned char c, HardwareSerial *s)
173133
#define serialEvent3_implemented
174134
ISR(USART3_RX_vect)
175135
{
176-
if (bit_is_clear(UCSR3A, UPE3)) {
177-
unsigned char c = UDR3;
178-
store_char(c, &Serial3);
179-
} else {
180-
unsigned char c = UDR3;
181-
};
136+
Serial3._rx_complete_irq();
182137
}
183138
#endif
184139

@@ -215,81 +170,71 @@ ISR(USART0_UDRE_vect)
215170
ISR(USART_UDRE_vect)
216171
#endif
217172
{
218-
if (Serial._tx_buffer_head == Serial._tx_buffer_tail) {
219-
// Buffer empty, so disable interrupts
220-
#if defined(UCSR0B)
221-
cbi(UCSR0B, UDRIE0);
222-
#else
223-
cbi(UCSRB, UDRIE);
224-
#endif
225-
}
226-
else {
227-
// There is more data in the output buffer. Send the next byte
228-
unsigned char c = Serial._tx_buffer[Serial._tx_buffer_tail];
229-
Serial._tx_buffer_tail = (Serial._tx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
230-
231-
#if defined(UDR0)
232-
UDR0 = c;
233-
#elif defined(UDR)
234-
UDR = c;
235-
#else
236-
#error UDR not defined
237-
#endif
238-
}
173+
Serial._tx_udr_empty_irq();
239174
}
240175
#endif
241176
#endif
242177

243178
#ifdef USART1_UDRE_vect
244179
ISR(USART1_UDRE_vect)
245180
{
246-
if (Serial1._tx_buffer_head == Serial1._tx_buffer_tail) {
247-
// Buffer empty, so disable interrupts
248-
cbi(UCSR1B, UDRIE1);
249-
}
250-
else {
251-
// There is more data in the output buffer. Send the next byte
252-
unsigned char c = Serial1._tx_buffer[Serial1._tx_buffer_tail];
253-
Serial1._tx_buffer_tail = (Serial1._tx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
254-
255-
UDR1 = c;
256-
}
181+
Serial1._tx_udr_empty_irq();
257182
}
258183
#endif
259184

260185
#ifdef USART2_UDRE_vect
261186
ISR(USART2_UDRE_vect)
262187
{
263-
if (Serial2._tx_buffer_head == Serial2._tx_buffer_tail) {
264-
// Buffer empty, so disable interrupts
265-
cbi(UCSR2B, UDRIE2);
266-
}
267-
else {
268-
// There is more data in the output buffer. Send the next byte
269-
unsigned char c = Serial2._tx_buffer[Serial2._tx_buffer_tail];
270-
Serial2._tx_buffer_tail = (Serial2._tx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
271-
272-
UDR2 = c;
273-
}
188+
Serial2._tx_udr_empty_irq();
274189
}
275190
#endif
276191

277192
#ifdef USART3_UDRE_vect
278193
ISR(USART3_UDRE_vect)
279194
{
280-
if (Serial3._tx_buffer_head == Serial3._tx_buffer_tail) {
281-
// Buffer empty, so disable interrupts
282-
cbi(UCSR3B, UDRIE3);
195+
Serial3._tx_udr_empty_irq();
196+
}
197+
#endif
198+
199+
200+
// Actual interrupt handlers //////////////////////////////////////////////////////////////
201+
202+
void HardwareSerial::_rx_complete_irq(void)
203+
{
204+
if (bit_is_clear(*_ucsra, UPE0)) {
205+
// No Parity error, read byte and store it in the buffer if there is
206+
// room
207+
unsigned char c = *_udr;
208+
int i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_BUFFER_SIZE;
209+
210+
// if we should be storing the received character into the location
211+
// just before the tail (meaning that the head would advance to the
212+
// current location of the tail), we're about to overflow the buffer
213+
// and so we don't write the character or advance the head.
214+
if (i != _rx_buffer_tail) {
215+
_rx_buffer[_rx_buffer_head] = c;
216+
_rx_buffer_head = i;
217+
}
218+
} else {
219+
// Parity error, read byte but discard it
220+
unsigned char c = *_udr;
221+
};
222+
}
223+
224+
void HardwareSerial::_tx_udr_empty_irq(void)
225+
{
226+
if (_tx_buffer_head == _tx_buffer_tail) {
227+
// Buffer empty, so disable interrupts
228+
cbi(*_ucsrb, UDRIE0);
283229
}
284230
else {
285231
// There is more data in the output buffer. Send the next byte
286-
unsigned char c = Serial3._tx_buffer[Serial3._tx_buffer_tail];
287-
Serial3._tx_buffer_tail = (Serial3._tx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
288-
289-
UDR3 = c;
232+
unsigned char c = _tx_buffer[_tx_buffer_tail];
233+
_tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
234+
235+
*_udr = c;
290236
}
291237
}
292-
#endif
293238

294239
// Constructors ////////////////////////////////////////////////////////////////
295240

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ class HardwareSerial : public Stream
7474
volatile uint8_t *_udr;
7575
bool transmitting;
7676

77-
public:
7877
volatile uint8_t _rx_buffer_head;
7978
volatile uint8_t _rx_buffer_tail;
8079
volatile uint8_t _tx_buffer_head;
@@ -86,6 +85,7 @@ class HardwareSerial : public Stream
8685
unsigned char _rx_buffer[SERIAL_BUFFER_SIZE];
8786
unsigned char _tx_buffer[SERIAL_BUFFER_SIZE];
8887

88+
public:
8989
HardwareSerial(
9090
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
9191
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
@@ -104,6 +104,10 @@ class HardwareSerial : public Stream
104104
inline size_t write(int n) { return write((uint8_t)n); }
105105
using Print::write; // pull in write(str) and write(buf, size) from Print
106106
operator bool() { return true; }
107+
108+
// Interrupt handlers - Not intended to be called externally
109+
void _rx_complete_irq(void);
110+
void _tx_udr_empty_irq(void);
107111
};
108112

109113
#if defined(UBRRH) || defined(UBRR0H)

0 commit comments

Comments
 (0)