Software Serial Revisited

RonC
Tue Jan 19, 2016 9:29 pm
Hi folks,

I’ve had a couple of projects where I needed more than three serial ports. Sometimes it’s just one but I needed 3 additional transmit only ports for one project. Choices are typical – use a “V” part with it’s 5 ports, add external UART hardware for a total hardware solution, add external shift registers for some hardware assist, or… software only.

Given cost and complexity concerns I’ve opted for a software serial solution. I started out with a relatively simple hack of the delay based Arduino AVR software serial. Works ok for some applications but for others I need full duplex and/or simultaneous receive and transmit on other ports so I wrote a new, interrupt driven software serial from scratch using timers and exint allowing the use of nearly any pins for TX/RX. However, because of the inefficient way STM32 shares interrupts and the way ST32Duino libraries handle them I found it difficult to get full-duplex operations to work reliably. It’s also somewhat sensitive to interrupt latency but it has the advantage of being able to use nearly any GPIO pin. So, in an effort to improve tolerance for higher interrupt latencies, I took a hint from the Teensy software serial library and wrote a version that get’s additional hardware assist by using timer capture and compare capability.

Each library has it’s own set of unique benefits and considerations so they are not replacements for each other. Rather, the one with the best fit for your application should be used.

So, here they are. Below is a brief and incomplete description of each. There’s more info in the code files and, of course, looking at the code itself. I hope others can benefit and maybe improve them.

1. Delay based software serial library. SoftwareSerialSTM32
https://github.com/wingspinner/SoftwareSerialSTM32
This is a hack of the AVR Arduino library with conditionals so the same library can be used for either AVR or STM32Duino. It has all the benefits and restrictions of the original library including:

Benefits:
– Simple to use because no worries about interrupt latency (interrupts disabled) and can use nearly any GPIO pin for RX/TX.

Restrictions/Considerations
– Requires that all interrupts be disabled during transmit and receive making it incompatible with any other interrupt
driven peripheral.
– Cannot receive or transmit simultaneously
– Supports multiple instantiations but only one can be active at a time.
– TX not buffered. System must wait until TX complete. This has a huge impact on system performance especially at lower
baud rates.

2. Interrupt Driven software serial library. SoftSerialIntAP
https://github.com/wingspinner/SoftSerialIntAP
This is fully buffered for both tx and rx and can use nearly any GPIO pin for tx or rx as well as any timer. It’s currently set to use any of the first four timers but that can be easily modified if you are using a part with more timers and wish to use other than the first four. One timer is required per port and you can instantiate multiple independent ports.

Benefits:
– Interrupt driven so system performance impact is negligible even at low baud rates.
– Can use nearly any GPIO pin for tx or rx
– Fully buffered tx/rx
– Highly accurate timing using system timers
– Multiple, simultaneous instantiations
– Compatible member functions with Arduino Software Serial Library
– Tx and RX can be independently enabled/disabled (instead of the entire port).

Restrictions/Considerations
– Somewhat sensitive to interrupt latencies since bit timing depends on servicing timer interrupts. I would estimate it can tolerate approximately 0.5 bit time of interrupt latency.
– Currently does not support inverted serial signal.
– Currently only supports 8 bits, no parity

3 Interrupt Driven using Capture/Compare software serial library. SoftSerialIntCC
https://github.com/wingspinner/SoftSerialIntCC
This is based on my SoftSerialIntAP library but modified to use timer capture/compare capability. It it a bit more tolerant to other interrupt activity and appears to be able to do full duplex up to about 57,600 baud (YMMV!). It has lower processor overhead because it only interrupts on bit changes (versus every bit time). As with SoftSerialIntAP, SoftSerialIntCC can use any of the first four timers but that can be easily modified if you are using a part with more timers and wish to use other than the first four. One timer is required per port and you can instantiate multiple independent ports.

Benefits:
– Interrupt driven using timer capture/compar so system performance impact is negligible even at low baud rates.
– Fully buffered tx/rx
– Highly accurate timing using system timers
– Multiple, simultaneous instantiations
– Compatible member functions with Arduino Software Serial Library
– Tx and RX can be independently enabled/disabled (instead of the entire port).
– Less sensitive to interrupt latencies due to capture/compare hardware. Estimate 1 bit time of latency can be tolerated.

Restrictions/Considerations
– Can only use capture/compare pins assigned to the timer in use for RX and TX.
– Pin selections are not automatic. You must specify the correct pins for the timer you specify when instantiating.
– Currently does not support inverted serial signal.
– Currently only supports 8 bits, no parity

As you may imagine, it’s a lot of work to test all this stuff so my testing has been mostly limited to that which I need for my applications. Therefore, make sure you do adequate testing in your environment and configuration. As well, dealing with ISRs in C++ and especially allowing for multiple, independent instantiations required jumping through some hoops. There may be better ways than I came up with. Perhaps someone can contribute to improvements.

Ron Curry


martinayotte
Wed Jan 20, 2016 1:59 am
Thanks for your contributions, Ron !
Of course, “time is still the missing ingredient”, so I won’t have time to try it out, although I’ve downloaded them.

weiming
Wed Jan 20, 2016 2:03 am
that’s great, i have test on stm32f103r8t6, but SoftSerialIntAP it can not rx, only tx.

RonC
Thu Jan 21, 2016 6:39 pm
weiming wrote:that’s great, i have test on stm32f103r8t6, but SoftSerialIntAP it can not rx, only tx.

RogerClark
Thu Jan 21, 2016 7:50 pm
I found a Software Serial for ESP8266 Arduino the other day… which seems to work.

So you could take a look at that and see if it just uses API calls and may therefore work on the STM32 without modification.


mrburnette
Thu Jan 21, 2016 10:30 pm
RogerClark wrote:I found a Software Serial for ESP8266 Arduino the other day… which seems to work.

So you could take a look at that and see if it just uses API calls and may therefore work on the STM32 without modification.


RogerClark
Thu Jan 21, 2016 10:39 pm
mrburnette wrote:

Nick Gammon also has a “sendonly” & a “receiveonly” implementation.

Ray


RonC
Fri Jan 22, 2016 12:53 am
RogerClark wrote:I found a Software Serial for ESP8266 Arduino the other day… which seems to work.

So you could take a look at that and see if it just uses API calls and may therefore work on the STM32 without modification.


RogerClark
Fri Jan 22, 2016 1:03 am
I’m pretty sure it was this one

https://github.com/plieningerweb/esp8266-software-uart


RonC
Fri Jan 22, 2016 3:16 am
RogerClark wrote:I’m pretty sure it was this one

https://github.com/plieningerweb/esp8266-software-uart


weiming
Fri Jan 22, 2016 12:23 pm
SoftSerialIntAP mySerial(PB15, PB14, 1); //rx tx timer

void setup()
{
mySerial.begin(9600);
mySerial.println(“Hello, world?”);
}

void loop() // run over and over
{
mySerial.println(“Hello, world?”);
delay(1000);
}

this is my code , i do not receive the string, i do not know why?


RonC
Fri Jan 22, 2016 6:23 pm
weiming wrote:SoftSerialIntAP mySerial(PB15, PB14, 1); //rx tx timer

void setup()
{
mySerial.begin(9600);
mySerial.println(“Hello, world?”);
}

void loop() // run over and over
{
mySerial.println(“Hello, world?”);
delay(1000);
}

this is my code , i do not receive the string, i do not know why?


weiming
Sat Jan 23, 2016 3:24 am
this works well, everything is ok.
SoftSerialSTM32 mySerial(PB15, PB14); // RX, TX
———————————————————————————————–
SoftSerialIntAP mySerial(PB15, PB14, 1); //rx tx timer rx is ok, tx is something wrong
but this mySerial.println(“Hello, world?”); do not work , anything wrong?
//if (mySerial.available())
//Serial.write(mySerial.read()); // this line is work well

DavidJ
Sun Jul 24, 2016 9:27 am
I can’t get these libraries to work either on a STM32F103C8T6 on 72Mhz.
I use a bare sketch. Tried several boards, ports and baudrates (9600 and 57600).
SoftSerialSTM32 sends corrupted data.
SoftSerialIntAP does nothing.
SoftSerialIntCC only produces repeated spaces.
Everything is hooked up correctly. Hardware Serial/Serial1 work fine.

Has anyone figured out how to use these libraries?


Leave a Reply

Your email address will not be published. Required fields are marked *