Skip to content

Commit 9120f2e

Browse files
Bounifacchinm
authored andcommitted
Add 9bit support to HardwareSerial
Squash and rebase of arduino/Arduino#2291 Supersedes arduino/Arduino#1221
1 parent 6c861d8 commit 9120f2e

File tree

3 files changed

+149
-52
lines changed

3 files changed

+149
-52
lines changed

cores/arduino/HardwareSerial.cpp

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,25 @@ void HardwareSerial::_tx_udr_empty_irq(void)
8282
{
8383
// If interrupts are enabled, there must be more data in the output
8484
// buffer. Send the next byte
85-
unsigned char c = _tx_buffer[_tx_buffer_tail];
86-
_tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_TX_BUFFER_SIZE;
8785

88-
*_udr = c;
86+
if(bit_is_set(*_ucsrb, UCSZ02)) {
87+
// If Uart is configured for 9 bit mode
88+
unsigned char mb = _tx_buffer[_tx_buffer_tail];
89+
unsigned char c = _tx_buffer[_tx_buffer_tail + 1];
90+
_tx_buffer_tail = (_tx_buffer_tail + 2) % SERIAL_TX_BUFFER_SIZE;
91+
if(mb & 0x01) {
92+
sbi(*_ucsrb, TXB80);
93+
} else {
94+
cbi(*_ucsrb, TXB80);
95+
}
96+
*_udr = c;
97+
} else {
98+
// UART is configured for 5 to 8 bit modes
99+
unsigned char c = _tx_buffer[_tx_buffer_tail];
100+
_tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_TX_BUFFER_SIZE;
101+
102+
*_udr = c;
103+
}
89104

90105
// clear the TXC bit -- "can be cleared by writing a one to its bit
91106
// location". This makes sure flush() won't return until the bytes
@@ -100,7 +115,7 @@ void HardwareSerial::_tx_udr_empty_irq(void)
100115

101116
// Public Methods //////////////////////////////////////////////////////////////
102117

103-
void HardwareSerial::begin(unsigned long baud, byte config)
118+
void HardwareSerial::begin(unsigned long baud, uint16_t config)
104119
{
105120
// Try u2x mode first
106121
uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2;
@@ -127,8 +142,12 @@ void HardwareSerial::begin(unsigned long baud, byte config)
127142
#if defined(__AVR_ATmega8__)
128143
config |= 0x80; // select UCSRC register (shared with UBRRH)
129144
#endif
130-
*_ucsrc = config;
131-
145+
146+
if(config & 0x100) {
147+
sbi(*_ucsrb, UCSZ02);
148+
}
149+
*_ucsrc = (uint8_t) config;
150+
132151
sbi(*_ucsrb, RXEN0);
133152
sbi(*_ucsrb, TXEN0);
134153
sbi(*_ucsrb, RXCIE0);
@@ -151,15 +170,28 @@ void HardwareSerial::end()
151170

152171
int HardwareSerial::available(void)
153172
{
154-
return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;
173+
unsigned int a = (unsigned int) (SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail) % SERIAL_RX_BUFFER_SIZE;
174+
if(bit_is_set(*_ucsrb, UCSZ02)) {
175+
// If Uart is in 9 bit mode return only the half, because we use two bytes per 9 bit "byte".
176+
return a / 2;
177+
}
178+
else {
179+
// For 5 - 8 bit modes simply return the number
180+
return a;
181+
}
155182
}
156183

157184
int HardwareSerial::peek(void)
158185
{
159186
if (_rx_buffer_head == _rx_buffer_tail) {
160187
return -1;
161188
} else {
162-
return _rx_buffer[_rx_buffer_tail];
189+
if(bit_is_set(*_ucsrb, UCSZ02)) {
190+
// If Uart is in 9 bit mode read two bytes and merge them
191+
return (_rx_buffer[_rx_buffer_tail] << 8) | _rx_buffer[_rx_buffer_tail + 1 % SERIAL_RX_BUFFER_SIZE];
192+
} else {
193+
return _rx_buffer[_rx_buffer_tail];
194+
}
163195
}
164196
}
165197

@@ -169,9 +201,17 @@ int HardwareSerial::read(void)
169201
if (_rx_buffer_head == _rx_buffer_tail) {
170202
return -1;
171203
} else {
172-
unsigned char c = _rx_buffer[_rx_buffer_tail];
173-
_rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
174-
return c;
204+
if(bit_is_set(*_ucsrb, UCSZ02)) {
205+
// If Uart is in 9 bit mode read two bytes and merge them
206+
unsigned char mb = _rx_buffer[_rx_buffer_tail];
207+
unsigned char c = _rx_buffer[_rx_buffer_tail + 1];
208+
_rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 2) % SERIAL_RX_BUFFER_SIZE;
209+
return ((mb << 8) | c);
210+
} else {
211+
unsigned char c = _rx_buffer[_rx_buffer_tail];
212+
_rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
213+
return c;
214+
}
175215
}
176216
}
177217

@@ -210,20 +250,35 @@ void HardwareSerial::flush()
210250
// the hardware finished tranmission (TXC is set).
211251
}
212252

213-
size_t HardwareSerial::write(uint8_t c)
253+
size_t HardwareSerial::write(uint16_t c)
214254
{
215255
_written = true;
216256
// If the buffer and the data register is empty, just write the byte
217257
// to the data register and be done. This shortcut helps
218258
// significantly improve the effective datarate at high (>
219259
// 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
220260
if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) {
221-
*_udr = c;
261+
if(bit_is_set(*_ucsrb, UCSZ02)) {
262+
// in 9 bit mode set TXB8 bit if necessary
263+
if(c & 0x100) {
264+
sbi(*_ucsrb, TXB80);
265+
} else {
266+
cbi(*_ucsrb, TXB80);
267+
}
268+
}
269+
*_udr = (uint8_t) c;
222270
sbi(*_ucsra, TXC0);
223271
return 1;
224272
}
225-
tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE;
226-
273+
274+
tx_buffer_index_t i;
275+
276+
if(bit_is_set(*_ucsrb, UCSZ02)) {
277+
i = ((_tx_buffer_head + 2) % SERIAL_TX_BUFFER_SIZE);
278+
} else {
279+
i = ((_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE);
280+
}
281+
227282
// If the output buffer is full, there's nothing for it other than to
228283
// wait for the interrupt handler to empty it a bit
229284
while (i == _tx_buffer_tail) {
@@ -239,7 +294,13 @@ size_t HardwareSerial::write(uint8_t c)
239294
}
240295
}
241296

242-
_tx_buffer[_tx_buffer_head] = c;
297+
298+
if(bit_is_set(*_ucsrb, UCSZ02)) {
299+
_tx_buffer[_tx_buffer_head] = (uint8_t) (c >> 8) & 0x01;
300+
_tx_buffer[_tx_buffer_head + 1] = (uint8_t) c;
301+
} else {
302+
_tx_buffer[_tx_buffer_head] = (uint8_t) c;
303+
}
243304
_tx_buffer_head = i;
244305

245306
sbi(*_ucsrb, UDRIE0);

cores/arduino/HardwareSerial.h

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -65,30 +65,41 @@ typedef uint8_t rx_buffer_index_t;
6565
#endif
6666

6767
// Define config for Serial.begin(baud, config);
68-
#define SERIAL_5N1 0x00
69-
#define SERIAL_6N1 0x02
70-
#define SERIAL_7N1 0x04
71-
#define SERIAL_8N1 0x06
72-
#define SERIAL_5N2 0x08
73-
#define SERIAL_6N2 0x0A
74-
#define SERIAL_7N2 0x0C
75-
#define SERIAL_8N2 0x0E
76-
#define SERIAL_5E1 0x20
77-
#define SERIAL_6E1 0x22
78-
#define SERIAL_7E1 0x24
79-
#define SERIAL_8E1 0x26
80-
#define SERIAL_5E2 0x28
81-
#define SERIAL_6E2 0x2A
82-
#define SERIAL_7E2 0x2C
83-
#define SERIAL_8E2 0x2E
84-
#define SERIAL_5O1 0x30
85-
#define SERIAL_6O1 0x32
86-
#define SERIAL_7O1 0x34
87-
#define SERIAL_8O1 0x36
88-
#define SERIAL_5O2 0x38
89-
#define SERIAL_6O2 0x3A
90-
#define SERIAL_7O2 0x3C
91-
#define SERIAL_8O2 0x3E
68+
#define SERIAL_5N1 0x000 //0b000000000
69+
#define SERIAL_6N1 0x002 //0b000000010
70+
#define SERIAL_7N1 0x004 //0b000000100
71+
#define SERIAL_8N1 0x006 //0b000000110
72+
#define SERIAL_9N1 0x106 //0b100000110
73+
74+
#define SERIAL_5N2 0x008 //0b000001000
75+
#define SERIAL_6N2 0x00A //0b000001010
76+
#define SERIAL_7N2 0x00C //0b000001100
77+
#define SERIAL_8N2 0x00E //0b000001110
78+
#define SERIAL_9N2 0x10E //0b100001110
79+
80+
#define SERIAL_5E1 0x020 //0b000100000
81+
#define SERIAL_6E1 0x022 //0b000100010
82+
#define SERIAL_7E1 0x024 //0b000100100
83+
#define SERIAL_8E1 0x026 //0b000100110
84+
#define SERIAL_9E1 0x126 //0b100100110
85+
86+
#define SERIAL_5E2 0x028 //0b000101000
87+
#define SERIAL_6E2 0x02A //0b000101010
88+
#define SERIAL_7E2 0x02C //0b000101100
89+
#define SERIAL_8E2 0x02E //0b000101110
90+
#define SERIAL_9E2 0x12E //0b100101110
91+
92+
#define SERIAL_5O1 0x030 //0b000110000
93+
#define SERIAL_6O1 0x032 //0b000110010
94+
#define SERIAL_7O1 0x034 //0b000110100
95+
#define SERIAL_8O1 0x036 //0b000110110
96+
#define SERIAL_9O1 0x136 //0b100110110
97+
98+
#define SERIAL_5O2 0x038 //0b000111000
99+
#define SERIAL_6O2 0x03A //0b000111010
100+
#define SERIAL_7O2 0x03C //0b000111100
101+
#define SERIAL_8O2 0x03E //0b000111110
102+
#define SERIAL_9O2 0x13E //0b100111110
92103

93104
class HardwareSerial : public Stream
94105
{
@@ -119,18 +130,18 @@ class HardwareSerial : public Stream
119130
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
120131
volatile uint8_t *ucsrc, volatile uint8_t *udr);
121132
void begin(unsigned long baud) { begin(baud, SERIAL_8N1); }
122-
void begin(unsigned long, uint8_t);
133+
void begin(unsigned long, uint16_t);
123134
void end();
124135
virtual int available(void);
125136
virtual int peek(void);
126137
virtual int read(void);
127138
virtual int availableForWrite(void);
128139
virtual void flush(void);
129-
virtual size_t write(uint8_t);
130-
inline size_t write(unsigned long n) { return write((uint8_t)n); }
131-
inline size_t write(long n) { return write((uint8_t)n); }
132-
inline size_t write(unsigned int n) { return write((uint8_t)n); }
133-
inline size_t write(int n) { return write((uint8_t)n); }
140+
virtual size_t write(uint16_t);
141+
inline size_t write(unsigned long n) { return write((uint16_t)n); }
142+
inline size_t write(long n) { return write((uint16_t)n); }
143+
inline size_t write(unsigned int n) { return write((uint16_t)n); }
144+
inline size_t write(int n) { return write((uint16_t)n); }
134145
using Print::write; // pull in write(str) and write(buf, size) from Print
135146
operator bool() { return true; }
136147

cores/arduino/HardwareSerial_private.h

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
#define U2X0 U2X
4949
#define UPE0 UPE
5050
#define UDRE0 UDRE
51+
#define UCSZ02 UCSZ2
52+
#define TXB80 TXB8
53+
#define RXB80 RXB8
5154
#elif defined(TXC1)
5255
// Some devices have uart1 but no uart0
5356
#define TXC0 TXC1
@@ -58,6 +61,9 @@
5861
#define U2X0 U2X1
5962
#define UPE0 UPE1
6063
#define UDRE0 UDRE1
64+
#define UCSZ02 UCSZ12
65+
#define TXB80 TXB81
66+
#define RXB80 RXB81
6167
#else
6268
#error No UART found in HardwareSerial.cpp
6369
#endif
@@ -68,17 +74,17 @@
6874
// changed for future hardware.
6975
#if defined(TXC1) && (TXC1 != TXC0 || RXEN1 != RXEN0 || RXCIE1 != RXCIE0 || \
7076
UDRIE1 != UDRIE0 || U2X1 != U2X0 || UPE1 != UPE0 || \
71-
UDRE1 != UDRE0)
77+
UDRE1 != UDRE0 || UCSZ12 != UCSZ02 || TXB81 != TXB80 || RXB81 != RXB80)
7278
#error "Not all bit positions for UART1 are the same as for UART0"
7379
#endif
7480
#if defined(TXC2) && (TXC2 != TXC0 || RXEN2 != RXEN0 || RXCIE2 != RXCIE0 || \
7581
UDRIE2 != UDRIE0 || U2X2 != U2X0 || UPE2 != UPE0 || \
76-
UDRE2 != UDRE0)
82+
UDRE2 != UDRE0 || UCSZ22 != UCSZ02 || TXB82 != TXB80 || RXB82 != RXB80)
7783
#error "Not all bit positions for UART2 are the same as for UART0"
7884
#endif
7985
#if defined(TXC3) && (TXC3 != TXC0 || RXEN3 != RXEN0 || RXCIE3 != RXCIE0 || \
8086
UDRIE3 != UDRIE0 || U3X3 != U3X0 || UPE3 != UPE0 || \
81-
UDRE3 != UDRE0)
87+
UDRE3 != UDRE0 || UCSZ32 != UCSZ02 || TXB83 != TXB80 || TXB83 != TXB80)
8288
#error "Not all bit positions for UART3 are the same as for UART0"
8389
#endif
8490

@@ -103,15 +109,34 @@ void HardwareSerial::_rx_complete_irq(void)
103109
if (bit_is_clear(*_ucsra, UPE0)) {
104110
// No Parity error, read byte and store it in the buffer if there is
105111
// room
106-
unsigned char c = *_udr;
107-
rx_buffer_index_t i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE;
112+
rx_buffer_index_t i;
113+
unsigned char mb;
114+
unsigned char c;
115+
116+
if(bit_is_set(*_ucsrb, UCSZ02)) {
117+
// If Uart is configured for 9 bit mode
118+
i = (unsigned int)(_rx_buffer_head + 2) % SERIAL_RX_BUFFER_SIZE;
119+
mb = (*_ucsrb >> RXB80) & 0x01;
120+
c = *_udr;
121+
} else {
122+
// UART is configured for 5 to 8 bit modes
123+
i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE;
124+
c = *_udr;
125+
}
108126

109127
// if we should be storing the received character into the location
110128
// just before the tail (meaning that the head would advance to the
111129
// current location of the tail), we're about to overflow the buffer
112130
// and so we don't write the character or advance the head.
113131
if (i != _rx_buffer_tail) {
114-
_rx_buffer[_rx_buffer_head] = c;
132+
if(bit_is_set(*_ucsrb, UCSZ02)) {
133+
// If Uart is configured for 9 bit mode
134+
_rx_buffer[_rx_buffer_head] = mb;
135+
_rx_buffer[_rx_buffer_head + 1] = c;
136+
} else {
137+
// UART is configured for 5 to 8 bit modes
138+
_rx_buffer[_rx_buffer_head] = c;
139+
}
115140
_rx_buffer_head = i;
116141
}
117142
} else {

0 commit comments

Comments
 (0)