@@ -116,12 +116,6 @@ void UartClass::_tx_data_empty_irq(void) {
116
116
if (_tx_buffer_head == _tx_buffer_tail) {
117
117
// Buffer empty, so disable "data register empty" interrupt
118
118
(*_hwserial_module).CTRLA &= (~USART_DREIE_bm);
119
-
120
- // Take the DRE interrupt back no normal priority level if it has been elevated
121
- // if (_hwserial_dre_interrupt_elevated) {
122
- // CPUINT.LVL1VEC = _prev_lvl1_interrupt_vect;
123
- // _hwserial_dre_interrupt_elevated = 0;
124
- // }
125
119
}
126
120
}
127
121
@@ -196,10 +190,12 @@ void UartClass::begin(unsigned long baud, uint16_t config) {
196
190
if (baud>=(38400 *(F_CPU/1000000 ))) {
197
191
rxmode = USART_RXMODE_CLK2X_gc;
198
192
baud=baud>>1 ;
193
+ } /*
194
+ since this is the default, we don't need to set this, saving a bit of flash.
195
+ else {
196
+ rxmode = USART_RXMODE_NORMAL_gc;
199
197
}
200
- // else {
201
- // rxmode = USART_RXMODE_NORMAL_gc;
202
- // }
198
+ */
203
199
#else
204
200
// if clocked at 1 or 2 MHz, always use CLK2X mode and save a bit of space, we correct for not shifting the baud value below, as it saves a bit of flash
205
201
rxmode = USART_RXMODE_CLK2X_gc;
@@ -210,42 +206,42 @@ void UartClass::begin(unsigned long baud, uint16_t config) {
210
206
211
207
212
208
// See #131 for more info on this
213
- #if (CLOCK_SOURCE==0 && PROGMEM_SIZE> 4096 && (defined(UARTBAUD3V)|| UARTBAUD5V))
214
- // if the flash is 2k or 4k, we really can't spare the flash for the baud rate correction...
215
- // it's close enough to work under normal circumstances anyway.
216
- #if (F_CPU==20000000UL || F_CPU==10000000UL || F_CPU==5000000UL) // this means we are on the 20MHz oscillator
217
- #ifdef UARTBAUD3V
218
- int8_t sigrow_val = SIGROW.OSC20ERR3V ;
219
- #else
220
- int8_t sigrow_val = SIGROW.OSC20ERR5V ;
221
- #endif
222
- #else // we are on 16MHz one
223
- #ifdef UARTBAUD3V
224
- int8_t sigrow_val = SIGROW.OSC16ERR3V ;
225
- #else
226
- int8_t sigrow_val = SIGROW.OSC16ERR5V ;
227
- #endif
228
- #endif
229
- #if (F_CPU > 2000000)
230
- // if we are above 2 MHz, baud was corrected above if CLK2X used.
231
- baud_setting = ((8 * F_CPU) / baud);
232
- #else
233
- // if clocked at 1 or 2 MHz, always use CLK2X mode and save a bit of flash...
234
- baud_setting = ((16 * F_CPU) / baud);
235
- #endif
236
- baud_setting *= (1024 + sigrow_val);
237
- baud_setting /= 2048 ;
238
- if (baud_setting>65535 ){
239
- baud_setting=65535 ;
240
- }
241
- #else
242
- #if (F_CPU > 2000000)
243
- // if we are above 2 MHz, baud was corrected above if CLK2X used.
244
- baud_setting = (((4 * F_CPU) / baud));
245
- #else
246
- // if clocked at 1 or 2 MHz, always use CLK2X mode and save a bit of flash...
247
- baud_setting = (((8 * F_CPU) / baud));
248
- #endif
209
+ #if (CLOCK_SOURCE==0 && PROGMEM_SIZE > 4096 && (defined(UARTBAUD3V) || defined( UARTBAUD5V) ))
210
+ // if the flash is 2k or 4k, we really can't spare the flash for the baud rate correction...
211
+ // it's close enough to work under normal circumstances anyway.
212
+ #if (F_CPU==20000000UL || F_CPU==10000000UL || F_CPU==5000000UL) // this means we are on the 20MHz oscillator
213
+ #ifdef UARTBAUD3V
214
+ int8_t sigrow_val = SIGROW.OSC20ERR3V ;
215
+ #else
216
+ int8_t sigrow_val = SIGROW.OSC20ERR5V ;
217
+ #endif
218
+ #else // we are on 16MHz one
219
+ #ifdef UARTBAUD3V
220
+ int8_t sigrow_val = SIGROW.OSC16ERR3V ;
221
+ #else
222
+ int8_t sigrow_val = SIGROW.OSC16ERR5V ;
223
+ #endif
224
+ #endif
225
+ #if (F_CPU > 2000000)
226
+ // if we are above 2 MHz, baud was corrected above if CLK2X used.
227
+ baud_setting = ((8 * F_CPU) / baud);
228
+ #else
229
+ // if clocked at 1 or 2 MHz, always use CLK2X mode and save a bit of flash...
230
+ baud_setting = ((16 * F_CPU) / baud);
231
+ #endif
232
+ baud_setting *= (1024 + sigrow_val);
233
+ baud_setting /= 2048 ;
234
+ if (baud_setting>65535 ){
235
+ baud_setting=65535 ;
236
+ }
237
+ #else
238
+ #if (F_CPU > 2000000)
239
+ // if we are above 2 MHz, baud was corrected above if CLK2X used.
240
+ baud_setting = (((4 * F_CPU) / baud));
241
+ #else
242
+ // if clocked at 1 or 2 MHz, always use CLK2X mode and save a bit of flash...
243
+ baud_setting = (((8 * F_CPU) / baud));
244
+ #endif
249
245
#endif
250
246
251
247
// Make sure global interrupts are disabled during initialization
@@ -266,9 +262,9 @@ void UartClass::begin(unsigned long baud, uint16_t config) {
266
262
267
263
// Let PORTMUX point to alternative UART pins as requested
268
264
#ifdef PORTMUX_CTRLB
269
- PORTMUX.CTRLB = set->mux | (PORTMUX.CTRLB & ~_hw_set[1 ].mux );
265
+ PORTMUX.CTRLB = set->mux | (PORTMUX.CTRLB & ~_hw_set[1 ].mux );
270
266
#else
271
- PORTMUX.USARTROUTEA = set->mux | (PORTMUX.USARTROUTEA & ~_hw_set[1 ].mux );
267
+ PORTMUX.USARTROUTEA = set->mux | (PORTMUX.USARTROUTEA & ~_hw_set[1 ].mux );
272
268
#endif
273
269
274
270
// Set pin state for swapped UART pins
@@ -341,7 +337,7 @@ void UartClass::flush() {
341
337
return ;
342
338
}
343
339
344
- // Check if we are inside an ISR already (e.g. connected to a different peripheral then UART), in which case the UART ISRs will not be called.
340
+ // Check if we are inside an ISR already (e.g. connected to a different peripheral then UART), in which case the UART ISRs will not be called.
345
341
// Spence 10/23/20: Changed _poll_tx_data_empty() to instead call the ISR directly in this case too
346
342
// Why elevate the interrupt if we're going to go into a busywait loop checking if the interrupt is disabled and if so, check for the bit and
347
343
// manually call the ISR if the bit is set... *anyway*? Plus, in write(), this mode will be enabled upon a write of a single character from an ISR
@@ -350,16 +346,6 @@ void UartClass::flush() {
350
346
// it's appropriate to use for applications where it has only very small benefits, and significant risk of surprising the user and causing
351
347
// breakage of code that would otherwise work. Finally, the previous implementation didn't check if it was called from the current lvl1 ISR
352
348
// and in that case flush(), and write() with full buffer would just straight up hang...
353
- //
354
- // Temporarily elevate the DRE interrupt to allow it to run.
355
- // if (CPUINT.STATUS & CPUINT_LVL0EX_bm) {
356
- // Elevate the priority level of the Data Register Empty Interrupt vector
357
- // and copy whatever vector number that might be in the register already.
358
- // _prev_lvl1_interrupt_vect = CPUINT.LVL1VEC;
359
- // CPUINT.LVL1VEC = _hwserial_dre_interrupt_vect_num;
360
-
361
- // _hwserial_dre_interrupt_elevated = 1;
362
- // }
363
349
364
350
// Spin until the data-register-empty-interrupt is disabled and TX complete interrupt flag is raised
365
351
while (((*_hwserial_module).CTRLA & USART_DREIE_bm) || (!((*_hwserial_module).STATUS & USART_TXCIF_bm))) {
@@ -368,10 +354,45 @@ void UartClass::flush() {
368
354
// poll the "data register empty" interrupt flag to prevent deadlock
369
355
_poll_tx_data_empty ();
370
356
}
371
- // If we get here, nothing is queued anymore (DREIE is disabled) and
357
+ // When we get here, nothing is queued anymore (DREIE is disabled) and
372
358
// the hardware finished transmission (TXCIF is set).
373
359
}
374
360
361
+ size_t UartClass::write (uint8_t c) {
362
+ _written = true ;
363
+
364
+ // If the buffer and the data register is empty, just write the byte
365
+ // to the data register and be done. This shortcut helps
366
+ // significantly improve the effective data rate at high (>
367
+ // 500kbit/s) bit rates, where interrupt overhead becomes a slowdown.
368
+ if ((_tx_buffer_head == _tx_buffer_tail) && ((*_hwserial_module).STATUS & USART_DREIF_bm)) {
369
+ (*_hwserial_module).TXDATAL = c;
370
+ (*_hwserial_module).STATUS = USART_TXCIF_bm;
371
+
372
+ // Make sure data register empty interrupt is disabled to avoid
373
+ // that the interrupt handler is called in this situation
374
+ (*_hwserial_module).CTRLA &= (~USART_DREIE_bm);
375
+
376
+ return 1 ;
377
+ }
378
+
379
+ tx_buffer_index_t i = (_tx_buffer_head + 1 ) & (SERIAL_TX_BUFFER_SIZE-1 ); // % SERIAL_TX_BUFFER_SIZE;
380
+
381
+ // If the output buffer is full, there's nothing for it other than to
382
+ // wait for the interrupt handler to empty it a bit (or emulate interrupts)
383
+ while (i == _tx_buffer_tail) {
384
+ _poll_tx_data_empty ();
385
+ }
386
+
387
+ _tx_buffer[_tx_buffer_head] = c;
388
+ _tx_buffer_head = i;
389
+
390
+ // Enable data "register empty interrupt"
391
+ (*_hwserial_module).CTRLA |= USART_DREIE_bm;
392
+
393
+ return 1 ;
394
+ }
395
+
375
396
void UartClass::printHex (const uint8_t b) {
376
397
char x=(b>>4 )|' 0' ;
377
398
if (x > ' 9' )
@@ -425,51 +446,5 @@ uint16_t * UartClass::printHex(uint16_t* p, uint8_t len, char sep, bool swaporde
425
446
}
426
447
return p;
427
448
}
428
- size_t UartClass::write (uint8_t c) {
429
- _written = true ;
430
-
431
- // If the buffer and the data register is empty, just write the byte
432
- // to the data register and be done. This shortcut helps
433
- // significantly improve the effective data rate at high (>
434
- // 500kbit/s) bit rates, where interrupt overhead becomes a slowdown.
435
- if ((_tx_buffer_head == _tx_buffer_tail) && ((*_hwserial_module).STATUS & USART_DREIF_bm)) {
436
- (*_hwserial_module).TXDATAL = c;
437
- (*_hwserial_module).STATUS = USART_TXCIF_bm;
438
-
439
- // Make sure data register empty interrupt is disabled to avoid
440
- // that the interrupt handler is called in this situation
441
- (*_hwserial_module).CTRLA &= (~USART_DREIE_bm);
442
449
443
- return 1 ;
444
- }
445
- // See above for reasoning for disabling this functionality and moving the check
446
- // to _poll_tx_data_empty()
447
- // Check if we are inside an ISR already (could be from by a source other than UART),
448
- // in which case the UART ISRs will be blocked.
449
- // if (CPUINT.STATUS & CPUINT_LVL0EX_bm) {
450
- // Elevate the priority level of the Data Register Empty Interrupt vector
451
- // and copy whatever vector number that might be in the register already.
452
- // _prev_lvl1_interrupt_vect = CPUINT.LVL1VEC;
453
- // CPUINT.LVL1VEC = _hwserial_dre_interrupt_vect_num;
454
-
455
- // _hwserial_dre_interrupt_elevated = 1;
456
- // }
457
-
458
- tx_buffer_index_t i = (_tx_buffer_head + 1 ) & (SERIAL_TX_BUFFER_SIZE-1 ); // % SERIAL_TX_BUFFER_SIZE;
459
-
460
- // If the output buffer is full, there's nothing for it other than to
461
- // wait for the interrupt handler to empty it a bit (or emulate interrupts)
462
- while (i == _tx_buffer_tail) {
463
- _poll_tx_data_empty ();
464
- }
465
-
466
- _tx_buffer[_tx_buffer_head] = c;
467
- _tx_buffer_head = i;
468
-
469
- // Enable data "register empty interrupt"
470
- (*_hwserial_module).CTRLA |= USART_DREIE_bm;
471
-
472
- return 1 ;
473
- }
474
-
475
- #endif // whole file
450
+ #endif
0 commit comments