Jump to content
Rickta59

[Energia Library] sw_serial_t template based UART code

Recommended Posts

Yet another software only serial class implementation? What makes this one different? C++ template based with asm routines to implement read and write. Works with any pin and port combination. You can mix and match, put read on P2.0 and write on P1.2. Small size even with Energia. Multiple instances allowed. Each instance uses about 12 bytes so you are only limited by the number of pins and memory on your chip. Big plus, doesn't use the timer. Read on if this piques your interest.

This code implements a C++ template based software only blocking serial UART class. It doesn't use the timer peripheral so it can be used with other code that might want to monopolize the timer(s). The read/write routines are based on oPossum's CCS msp430 asm based cycle counting serial routines. They have been generalized for use with Energia, C++ templates, msp430-gas abi asm, modified to support any port and pin combination, and will allow for multiple serial instances.

The code does use some instance data (~12 bytes) but you can have multiple sw_serial_t class instances. You might find this useful if you have have to interact with more than one serial device. This isn't a library so much as a header file you include in your project. The code weighs in at about 1200 bytes for a typical ASCII table print. A serial.print("Hello World\n") is only about 560 bytes. Useful things can even be done on the MSP430G2231 chip using this code.

I've successfully tested output to 230400 baud running the DCO clock at 16MHz. You won't be able to achieve that baud rate running at 1MHz. Note: I did calibrate my DCO clock to be to 16.00MHz before trying to run that fast.

I've not stressed the input side so I can't say what the limits are for input. Needless to say, it will all depend on the input and how you attempt to process the input data.

You might want to snag a couple of those $3 pl2303x usb modules from ebay. That is what I used to test at high speed.

The sw_serial_t template class inherits from the Stream base class. That means that all the normal print() methods are available for use as you would do with any other Serial class implementation. In addition, I've included the Streaming class from http://arduiniana.org/libraries/streaming/ This allows C++-style output with the "<<" operator.

See the example '.ino' files for information on how to actually instance the sw_serial_t template.

Some caveats:

1.) This code uses cycle counting. That means when you use the write() or read() methods, they disable the watchdog timer. Disabling the watchdog in Energia means the millis() count is going to be wrong. I guess an improvement would be to update the millis counter based on the baud rate but I haven't done that. You have been warned!

2.) This code implements blocking routines. If you do a read() it will block until a character arrives. If you do a write() it will block until the bits have been shifted out. I take care of disabling the watchdog timer. However, if you have timer interrupt routines they will break this code. You will have to make sure you disable the timer interrupts while doing serial IO or pick a time when the timer code isn't running.

3.) This code doesn't use a ring buffer. So, expect it to to drop characters if you receive a long stream of characters and you try to do too much in between the read() calls. If you need to do something with a stream of characters, receive each byte and put it in your own buffer then process the buffer when you detect a new line. Some simple solutions to dealing with blocking reads: a.) use a slower host BAUD rate. b.) add extra stop bits from the host side to give yourself more time between received bytes. c.) preface the stream of bytes with a length so your firmware will know how many bytes to receive before it tries to process them.

4.) The more features of the Print class you use the larger your code will grow. If you really only want multiple serial instances then just use the read() and write() methods for the smallest code. Avoid the print() methods and you will acheive the smallest implementation.

This code is implemented as templates and doesn't use the Arduino style pin number table runtime lookups. Pin information must be available at compile time so the asm routines can do the right thing. However, using templates reduces the size of this code and makes it more flexible. Look at the ssgpio.h for more information about the pin configuration. It is only setup for P1 and P2. I'm assuming people who want to use this are probably going to use it on the G series DIP chips. You will have to add entries for anything other than that.

-rick

hosted on github https://gist.github.com/RickKimball/4758580

Share this post


Link to post
Share on other sites

Rick, I really like some of that there, and in particular the streaming.h stuff. Is that stand alone or does it require arduino.h  / Energia.h ? It seems like it could be, but I have not dug deep yet.

Share this post


Link to post
Share on other sites

The streaming.h stuff works hand in hand with the Print class of Energia. You could implement the same thing in non-energia code by providing print functions for all the different data types you use. Look at the implementation of Print.h in Eneregia for an example of what it does. You could also just provide your own '<<' operator implementation in classes you want to use this feature.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×