38
38
SoftwareSerial *ap3_active_softwareserial_handle = 0 ;
39
39
40
40
// Uncomment to enable debug pulses and Serial.prints
41
- // #define DEBUG
41
+ #define DEBUG
42
42
43
43
#ifdef DEBUG
44
44
#define SS_DEBUG_PIN 9
@@ -105,14 +105,15 @@ bool SoftwareSerial::isListening()
105
105
106
106
void SoftwareSerial::begin (uint32_t baudRate, HardwareSerial_Config_e SSconfig)
107
107
{
108
- pinMode (_txPin, OUTPUT);
109
108
digitalWrite (_txPin, _invertLogic ? LOW : HIGH);
109
+ pinMode (_txPin, OUTPUT);
110
110
111
111
pinMode (_rxPin, INPUT);
112
112
if (_invertLogic == false )
113
113
pinMode (_rxPin, INPUT_PULLUP); // Enable external pullup if using normal logic
114
114
115
115
#ifdef DEBUG
116
+ am_hal_gpio_output_clear (debugPad);
116
117
pinMode (SS_DEBUG_PIN, OUTPUT);
117
118
#endif
118
119
@@ -126,13 +127,18 @@ void SoftwareSerial::begin(uint32_t baudRate, HardwareSerial_Config_e SSconfig)
126
127
// Set variables data bits, stop bits and parity based on config
127
128
softwareserialSetConfig (SSconfig);
128
129
129
- sysTicksPerBit = (TIMER_FREQ / baudRate) * 0.98 ; // Short the number of sysTicks a small amount because we are doing a mod operation
130
+ rxSysTicksPerBit = (TIMER_FREQ / baudRate) * 0.98 ; // Shorten the number of sysTicks a small amount because we are doing a mod operation
131
+ txSysTicksPerBit = (TIMER_FREQ / baudRate) - 6 ; // Shorten the txSysTicksPerBit by the number of ticks needed to run the txHandler ISR
130
132
131
- sysTicksPerByte = (TIMER_FREQ / baudRate) * (_dataBits + _parityBits + _stopBits);
133
+ rxSysTicksPerByte = (TIMER_FREQ / baudRate) * (_dataBits + _parityBits + _stopBits);
132
134
133
135
// During RX, if leftover systicks is more than a fraction of a bit, we will call it a bit
134
136
// This is needed during 115200 when cmpr ISR extends into the start bit of the following byte
135
- sysTicksPartialBit = sysTicksPerBit / 4 ;
137
+ rxSysTicksPartialBit = rxSysTicksPerBit / 4 ;
138
+
139
+ txSysTicksPerStopBit = txSysTicksPerBit * _stopBits;
140
+
141
+ Serial.printf (" sysTicksPerBit: %d\n " , txSysTicksPerBit);
136
142
137
143
// Clear pin change interrupt
138
144
am_hal_gpio_interrupt_clear (AM_HAL_GPIO_BIT (_rxPad));
@@ -179,14 +185,99 @@ int SoftwareSerial::peek()
179
185
// Clears flag when called
180
186
bool SoftwareSerial::overflow ()
181
187
{
182
- if (_rxBufferOverflow)
188
+ if (_rxBufferOverflow || _txBufferOverflow )
183
189
{
184
190
_rxBufferOverflow = false ;
191
+ _txBufferOverflow = false ;
185
192
return (true );
186
193
}
187
194
return (false );
188
195
}
189
196
197
+ void SoftwareSerial::write (uint8_t toSend)
198
+ {
199
+ // See if we are going to overflow buffer
200
+ uint8_t nextSpot = (txBufferHead + 1 ) % AP3_SS_BUFFER_SIZE;
201
+ if (nextSpot != txBufferTail)
202
+ {
203
+ // Add this byte into the circular buffer
204
+ txBuffer[nextSpot] = toSend;
205
+ txBufferHead = nextSpot;
206
+ }
207
+ else
208
+ {
209
+ _txBufferOverflow = true ;
210
+ }
211
+
212
+ // See if hardware is available
213
+ if (txInUse == false )
214
+ {
215
+ txInUse = true ;
216
+
217
+ // Start sending this byte immediately
218
+ txBufferTail = (txBufferTail + 1 ) % AP3_SS_BUFFER_SIZE;
219
+ outgoingByte = txBuffer[txBufferTail];
220
+
221
+ // Calc parity
222
+ calcParityBit ();
223
+
224
+ beginTX ();
225
+ }
226
+ }
227
+
228
+ // Starts the transmission of the next available byte from the buffer
229
+ void SoftwareSerial::beginTX ()
230
+ {
231
+ bitCounter = 0 ;
232
+
233
+ am_hal_gpio_output_set (debugPad);
234
+
235
+ // Initiate start bit
236
+ if (_invertLogic == false )
237
+ {
238
+ am_hal_gpio_output_clear (_txPad); // Normal logic, low is start bit
239
+ }
240
+ else
241
+ {
242
+ am_hal_gpio_output_set (_txPad);
243
+ }
244
+
245
+ // Setup ISR to trigger when we are in middle of start bit
246
+ // am_hal_stimer_compare_delta_set(7, txSsysTicksPerBit);
247
+ AM_REGVAL (AM_REG_STIMER_COMPARE (0 , 7 )) = txSysTicksPerBit; // Direct reg write to decrease execution time
248
+
249
+ // Enable the timer interrupt in the NVIC.
250
+ NVIC_EnableIRQ (STIMER_CMPR7_IRQn);
251
+
252
+ am_hal_gpio_output_clear (debugPad);
253
+ }
254
+
255
+ // Assumes the global variables have been set: _parity, _dataBits, outgoingByte
256
+ // Sets global variable _parityBit
257
+ void SoftwareSerial::calcParityBit ()
258
+ {
259
+ if (_parity == 0 )
260
+ return ; // No parity
261
+
262
+ uint8_t ones = 0 ;
263
+ for (uint8_t x = 0 ; x < _dataBits; x++)
264
+ {
265
+ if (outgoingByte & (0x01 << x))
266
+ {
267
+ ones++;
268
+ }
269
+ }
270
+
271
+ if (_parity == 1 ) // Odd
272
+ {
273
+ _parityForByte = !(ones % 2 );
274
+ }
275
+ else // Even
276
+ {
277
+ _parityForByte = (ones % 2 );
278
+ }
279
+ }
280
+
190
281
ap3_err_t SoftwareSerial::softwareserialSetConfig (HardwareSerial_Config_e SSconfig)
191
282
{
192
283
ap3_err_t retval = AP3_OK;
@@ -338,29 +429,28 @@ void SoftwareSerial::rxBit(void)
338
429
bitCounter = 0 ;
339
430
lastBitTime = bitTime;
340
431
bitType = false ;
432
+ rxInUse = true ; // Indicate we are now in process of receiving a byte
341
433
342
434
// Setup cmpr7 interrupt to handle overall timeout
343
- // am_hal_stimer_compare_delta_set(7, sysTicksPerByte );
344
- AM_REGVAL (AM_REG_STIMER_COMPARE (0 , 7 )) = sysTicksPerByte ; // Direct reg write to decrease execution time
435
+ // am_hal_stimer_compare_delta_set(7, rxSysTicksPerByte );
436
+ AM_REGVAL (AM_REG_STIMER_COMPARE (0 , 7 )) = rxSysTicksPerByte ; // Direct reg write to decrease execution time
345
437
346
438
// Enable the timer interrupt in the NVIC.
347
439
NVIC_EnableIRQ (STIMER_CMPR7_IRQn);
348
440
}
349
441
else
350
442
{
351
443
// Calculate the number of bits that have occured since last PCI
352
- // Then add those bits of the current bitType (either 1 or 0) to
353
- // the byte
354
- uint8_t numberOfBits = (bitTime - lastBitTime) / sysTicksPerBit;
444
+ uint8_t numberOfBits = (bitTime - lastBitTime) / rxSysTicksPerBit;
355
445
356
446
if (bitCounter == 0 )
357
447
{
358
448
// Catch any partial bits
359
449
// For very high bauds (115200) the final interrupt spills over into the
360
450
// start bit of the next byte. This catches the partial systicks and correctly
361
451
// identifies the start bit as such.
362
- uint16_t partialBits = (bitTime - lastBitTime) % sysTicksPerBit ;
363
- if (partialBits > sysTicksPartialBit )
452
+ uint16_t partialBits = (bitTime - lastBitTime) % rxSysTicksPerBit ;
453
+ if (partialBits > rxSysTicksPartialBit )
364
454
{
365
455
#ifdef DEBUG
366
456
Serial.println (" Partial!" );
@@ -384,7 +474,7 @@ void SoftwareSerial::rxBit(void)
384
474
}
385
475
}
386
476
387
- for (uint8_t y = 0 ; y < numberOfBits; y++) // Number of bits in this chunk of time
477
+ for (uint8_t y = 0 ; y < numberOfBits; y++) // Add bits of the current bitType (either 1 or 0) to our byte
388
478
{
389
479
incomingByte >>= 1 ;
390
480
if (bitType == true )
@@ -400,7 +490,7 @@ void SoftwareSerial::rxBit(void)
400
490
#endif
401
491
}
402
492
403
- void SoftwareSerial::endOfByte ()
493
+ void SoftwareSerial::rxEndOfByte ()
404
494
{
405
495
// Finish out bytes that are less than 8 bits
406
496
#ifdef DEBUG
@@ -459,12 +549,105 @@ void SoftwareSerial::endOfByte()
459
549
460
550
lastBitTime = 0 ; // Reset for next byte
461
551
462
- rxInUse = false ;
552
+ rxInUse = false ; // Release so that we can TX if needed
463
553
464
554
// Disable the timer interrupt in the NVIC.
465
555
NVIC_DisableIRQ (STIMER_CMPR7_IRQn);
466
556
}
467
557
558
+ // Called from cmprX ISR
559
+ // Sends out a bit with each cmprX ISR trigger
560
+ void SoftwareSerial::txHandler ()
561
+ {
562
+ if (bitCounter < _dataBits) // Data bits 0 to 7
563
+ {
564
+ AM_REGVAL (AM_REG_STIMER_COMPARE (0 , 7 )) = txSysTicksPerBit; // Direct reg write to decrease execution time
565
+ if (outgoingByte & 0x01 )
566
+ {
567
+ am_hal_gpio_output_set (_txPad);
568
+ }
569
+ else
570
+ {
571
+ am_hal_gpio_output_clear (_txPad);
572
+ }
573
+ outgoingByte >>= 1 ;
574
+ bitCounter++;
575
+ }
576
+ else if (bitCounter == _dataBits) // Send parity bit or stop bit(s)
577
+ {
578
+ if (_parity)
579
+ {
580
+ // Send parity bit
581
+ AM_REGVAL (AM_REG_STIMER_COMPARE (0 , 7 )) = txSysTicksPerBit; // Direct reg write to decrease execution time
582
+ if (_parityForByte)
583
+ {
584
+ am_hal_gpio_output_set (_txPad);
585
+ }
586
+ else
587
+ {
588
+ am_hal_gpio_output_clear (_txPad);
589
+ }
590
+ }
591
+ else
592
+ {
593
+ // Send stop bit
594
+ AM_REGVAL (AM_REG_STIMER_COMPARE (0 , 7 )) = txSysTicksPerStopBit; // Direct reg write to decrease execution time
595
+ am_hal_gpio_output_set (_txPad);
596
+ }
597
+ bitCounter++;
598
+ }
599
+ else if (bitCounter == (_dataBits + 1 )) // Send stop bit or begin next byte
600
+ {
601
+ if (_parity)
602
+ {
603
+ // Send stop bit
604
+ AM_REGVAL (AM_REG_STIMER_COMPARE (0 , 7 )) = txSysTicksPerStopBit; // Direct reg write to decrease execution time
605
+ am_hal_gpio_output_set (_txPad);
606
+ bitCounter++;
607
+ }
608
+ else
609
+ {
610
+ // Start next byte
611
+ if (txBufferTail == txBufferHead)
612
+ {
613
+ // Disable the timer interrupt in the NVIC.
614
+ NVIC_DisableIRQ (STIMER_CMPR7_IRQn);
615
+
616
+ // All done!
617
+ txInUse = false ;
618
+ }
619
+ else
620
+ {
621
+ // Send next byte in buffer
622
+ txBufferTail = (txBufferTail + 1 ) % AP3_SS_BUFFER_SIZE;
623
+ outgoingByte = txBuffer[txBufferTail];
624
+ calcParityBit ();
625
+ beginTX ();
626
+ }
627
+ }
628
+ }
629
+ else if (bitCounter == (_dataBits + 2 )) // Begin next byte
630
+ {
631
+ // Start next byte
632
+ if (txBufferTail == txBufferHead)
633
+ {
634
+ // Disable the timer interrupt in the NVIC.
635
+ NVIC_DisableIRQ (STIMER_CMPR7_IRQn);
636
+
637
+ // All done!
638
+ txInUse = false ;
639
+ }
640
+ else
641
+ {
642
+ // Send next byte in buffer
643
+ txBufferTail = (txBufferTail + 1 ) % AP3_SS_BUFFER_SIZE;
644
+ outgoingByte = txBuffer[txBufferTail];
645
+ calcParityBit ();
646
+ beginTX ();
647
+ }
648
+ }
649
+ }
650
+
468
651
// Called at the completion of bytes
469
652
extern " C" void am_stimer_cmpr7_isr (void )
470
653
{
@@ -477,7 +660,14 @@ extern "C" void am_stimer_cmpr7_isr(void)
477
660
{
478
661
am_hal_stimer_int_clear (AM_HAL_STIMER_INT_COMPAREH);
479
662
480
- ap3_active_softwareserial_handle->endOfByte ();
663
+ if (ap3_active_softwareserial_handle->rxInUse == true )
664
+ {
665
+ ap3_active_softwareserial_handle->rxEndOfByte ();
666
+ }
667
+ else if (ap3_active_softwareserial_handle->txInUse == true )
668
+ {
669
+ ap3_active_softwareserial_handle->txHandler ();
670
+ }
481
671
}
482
672
483
673
#ifdef DEBUG
0 commit comments