3838SoftwareSerial *ap3_active_softwareserial_handle = 0 ;
3939
4040// Uncomment to enable debug pulses and Serial.prints
41- // #define DEBUG
41+ #define DEBUG
4242
4343#ifdef DEBUG
4444#define SS_DEBUG_PIN 9
@@ -105,14 +105,15 @@ bool SoftwareSerial::isListening()
105105
106106void SoftwareSerial::begin (uint32_t baudRate, HardwareSerial_Config_e SSconfig)
107107{
108- pinMode (_txPin, OUTPUT);
109108 digitalWrite (_txPin, _invertLogic ? LOW : HIGH);
109+ pinMode (_txPin, OUTPUT);
110110
111111 pinMode (_rxPin, INPUT);
112112 if (_invertLogic == false )
113113 pinMode (_rxPin, INPUT_PULLUP); // Enable external pullup if using normal logic
114114
115115#ifdef DEBUG
116+ am_hal_gpio_output_clear (debugPad);
116117 pinMode (SS_DEBUG_PIN, OUTPUT);
117118#endif
118119
@@ -126,13 +127,18 @@ void SoftwareSerial::begin(uint32_t baudRate, HardwareSerial_Config_e SSconfig)
126127 // Set variables data bits, stop bits and parity based on config
127128 softwareserialSetConfig (SSconfig);
128129
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
130132
131- sysTicksPerByte = (TIMER_FREQ / baudRate) * (_dataBits + _parityBits + _stopBits);
133+ rxSysTicksPerByte = (TIMER_FREQ / baudRate) * (_dataBits + _parityBits + _stopBits);
132134
133135 // During RX, if leftover systicks is more than a fraction of a bit, we will call it a bit
134136 // 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);
136142
137143 // Clear pin change interrupt
138144 am_hal_gpio_interrupt_clear (AM_HAL_GPIO_BIT (_rxPad));
@@ -179,14 +185,99 @@ int SoftwareSerial::peek()
179185// Clears flag when called
180186bool SoftwareSerial::overflow ()
181187{
182- if (_rxBufferOverflow)
188+ if (_rxBufferOverflow || _txBufferOverflow )
183189 {
184190 _rxBufferOverflow = false ;
191+ _txBufferOverflow = false ;
185192 return (true );
186193 }
187194 return (false );
188195}
189196
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+
190281ap3_err_t SoftwareSerial::softwareserialSetConfig (HardwareSerial_Config_e SSconfig)
191282{
192283 ap3_err_t retval = AP3_OK;
@@ -338,29 +429,28 @@ void SoftwareSerial::rxBit(void)
338429 bitCounter = 0 ;
339430 lastBitTime = bitTime;
340431 bitType = false ;
432+ rxInUse = true ; // Indicate we are now in process of receiving a byte
341433
342434 // 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
345437
346438 // Enable the timer interrupt in the NVIC.
347439 NVIC_EnableIRQ (STIMER_CMPR7_IRQn);
348440 }
349441 else
350442 {
351443 // 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;
355445
356446 if (bitCounter == 0 )
357447 {
358448 // Catch any partial bits
359449 // For very high bauds (115200) the final interrupt spills over into the
360450 // start bit of the next byte. This catches the partial systicks and correctly
361451 // 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 )
364454 {
365455#ifdef DEBUG
366456 Serial.println (" Partial!" );
@@ -384,7 +474,7 @@ void SoftwareSerial::rxBit(void)
384474 }
385475 }
386476
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
388478 {
389479 incomingByte >>= 1 ;
390480 if (bitType == true )
@@ -400,7 +490,7 @@ void SoftwareSerial::rxBit(void)
400490#endif
401491}
402492
403- void SoftwareSerial::endOfByte ()
493+ void SoftwareSerial::rxEndOfByte ()
404494{
405495 // Finish out bytes that are less than 8 bits
406496#ifdef DEBUG
@@ -459,12 +549,105 @@ void SoftwareSerial::endOfByte()
459549
460550 lastBitTime = 0 ; // Reset for next byte
461551
462- rxInUse = false ;
552+ rxInUse = false ; // Release so that we can TX if needed
463553
464554 // Disable the timer interrupt in the NVIC.
465555 NVIC_DisableIRQ (STIMER_CMPR7_IRQn);
466556}
467557
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+
468651// Called at the completion of bytes
469652extern " C" void am_stimer_cmpr7_isr (void )
470653{
@@ -477,7 +660,14 @@ extern "C" void am_stimer_cmpr7_isr(void)
477660 {
478661 am_hal_stimer_int_clear (AM_HAL_STIMER_INT_COMPAREH);
479662
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+ }
481671 }
482672
483673#ifdef DEBUG
0 commit comments