@@ -82,10 +82,25 @@ void HardwareSerial::_tx_udr_empty_irq(void)
82
82
{
83
83
// If interrupts are enabled, there must be more data in the output
84
84
// 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;
87
85
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
+ }
89
104
90
105
// clear the TXC bit -- "can be cleared by writing a one to its bit
91
106
// location". This makes sure flush() won't return until the bytes
@@ -100,7 +115,7 @@ void HardwareSerial::_tx_udr_empty_irq(void)
100
115
101
116
// Public Methods //////////////////////////////////////////////////////////////
102
117
103
- void HardwareSerial::begin (unsigned long baud, byte config)
118
+ void HardwareSerial::begin (unsigned long baud, uint16_t config)
104
119
{
105
120
// Try u2x mode first
106
121
uint16_t baud_setting = (F_CPU / 4 / baud - 1 ) / 2 ;
@@ -127,8 +142,12 @@ void HardwareSerial::begin(unsigned long baud, byte config)
127
142
#if defined(__AVR_ATmega8__)
128
143
config |= 0x80 ; // select UCSRC register (shared with UBRRH)
129
144
#endif
130
- *_ucsrc = config;
131
-
145
+
146
+ if (config & 0x100 ) {
147
+ sbi (*_ucsrb, UCSZ02);
148
+ }
149
+ *_ucsrc = (uint8_t ) config;
150
+
132
151
sbi (*_ucsrb, RXEN0);
133
152
sbi (*_ucsrb, TXEN0);
134
153
sbi (*_ucsrb, RXCIE0);
@@ -151,15 +170,28 @@ void HardwareSerial::end()
151
170
152
171
int HardwareSerial::available (void )
153
172
{
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
+ }
155
182
}
156
183
157
184
int HardwareSerial::peek (void )
158
185
{
159
186
if (_rx_buffer_head == _rx_buffer_tail) {
160
187
return -1 ;
161
188
} 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
+ }
163
195
}
164
196
}
165
197
@@ -169,9 +201,17 @@ int HardwareSerial::read(void)
169
201
if (_rx_buffer_head == _rx_buffer_tail) {
170
202
return -1 ;
171
203
} 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
+ }
175
215
}
176
216
}
177
217
@@ -210,20 +250,35 @@ void HardwareSerial::flush()
210
250
// the hardware finished tranmission (TXC is set).
211
251
}
212
252
213
- size_t HardwareSerial::write (uint8_t c)
253
+ size_t HardwareSerial::write (uint16_t c)
214
254
{
215
255
_written = true ;
216
256
// If the buffer and the data register is empty, just write the byte
217
257
// to the data register and be done. This shortcut helps
218
258
// significantly improve the effective datarate at high (>
219
259
// 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
220
260
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;
222
270
sbi (*_ucsra, TXC0);
223
271
return 1 ;
224
272
}
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
+
227
282
// If the output buffer is full, there's nothing for it other than to
228
283
// wait for the interrupt handler to empty it a bit
229
284
while (i == _tx_buffer_tail) {
@@ -239,7 +294,13 @@ size_t HardwareSerial::write(uint8_t c)
239
294
}
240
295
}
241
296
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
+ }
243
304
_tx_buffer_head = i;
244
305
245
306
sbi (*_ucsrb, UDRIE0);
0 commit comments