chipKIT® Development Platform

Inspired by Arduino™

SoftwareSerial for UNO32...

Created Sun, 18 Dec 2011 20:01:52 +0000 by KurtE


KurtE

Sun, 18 Dec 2011 20:01:52 +0000

I have mentioned this on a few threads, that it would be nice to have a full implementation of the SoftwareSerial that is like the version that is now part of Arduino 1.0 or what was NewSoftSerial beta...

So I have been playing with it for a little bit and I think I now have parts of it limping along. I do not have all of the baud rates defined and there are still some issues with the receiving code. In particular when I do get the Pin Change notify on the Receive pin, it appears like I am properly getting the data on the receive pin. Like the Arduino code this is all done in the interrupt handler which has timed delays... During this receive it appears like maybe the Pin state of the some of the other IO pins on the Port that the receive pin get screwed up. Note sure if this is done as part of the main Serial functions, or what as the Receive side is not setting any IO pins, but only reading...

Again their is a table in the CPP file that maps the UNO32 IO pin to the corresponding Change Notify pin (if any). This table is also used to enable the PU resistor for the receive pin, unless we are in invert mode. Probably this table should be removed from here and moved to the board specific files. Also I am assuming the 80mhz...

Still need lots more testing and figure out what the IO port issue is, so this is for sure not ready for prime time. But if someone else wishes to take a look and maybe find what I am missing I have included a zip file here with my current stuff...

Kurt


KurtE

Sun, 18 Dec 2011 21:21:30 +0000

Forgot to mention, I have been using test build 1212

Kurt


KurtE

Mon, 19 Dec 2011 02:02:13 +0000

Not sure if the version I uploaded was a version I had that I screwed up the output... So thought I should refresh... I also added some hacked up code that if a baud rate is between two different baud rates, it tries to map the delays appropriately.

I also turned off the debug and removed some Serial.print...


KurtE

Mon, 19 Dec 2011 16:47:23 +0000

Background and Question:

With a bit-bang type of serial operation, there is often issues with how reliable the pulse widths, if interrupts are serviced while doing the pulses. There are two ways that different implementations I have used deal with this.

  1. Punt - If it happens, it happens. In some cases the person using these implementations can work around the issue.
  2. Disable Interrupts while outputting or inputting a byte (Arduino) - This helps to make a reasonably reliable bit-bang function, but can hurt in other ways. Like suppose you are doing a bitbang output at 300 baud. That is a long time to disable interrupts and if you have a device hooked up to a USART running at something like 115200, it could have received a whole lot of characters during that one output, and probably lost many of them as it was not able to service the interrupt to read the characters out of the usart and put into a queue. Also if your board is servicing other hardware like Servos, what happen to them while you are outputting or inputting characters with interrupts disabled?

But there is a middle ground that some implementations use, that use the System Timer (or other timer) to time the pulses. In this way it can in many cases compensate for clock ticks that happened while waiting... I used this technique awhile ago on a Basic Atom Pro where I wrote my own assembly language versions...

[color=#FF0000]So now the question[/color]: I am tempted to update my implemention here of Software Serial to time the bits by using the internal function ReadCoreTimer. It would make the bitbang a little less reliable, but it would help make other stuff run better. Like handling Servos or hardware timer interrupts... Thoughts?

Kurt


EmbeddedMan

Mon, 19 Dec 2011 16:58:34 +0000

Kurt,

That's a great idea, and exactly how I would do it.

The upside is that you'll not disable interrupts (which would be a killer for slower baud rates) and you'll get very accurate bit times (as the CoreTimer runs at a 40MHz rate).

The only downside I can see is that if you're having you main-line code check the value of CoreTimer to see when to fire the next bit, any other function in the main loop that blocks for very long (very long meaning a significant percentage of a bit time) will cause your bit times to stretch and will lead to bit errors.

The way around this would be to employ a timer, then use the timer's interrupt routine to actually send out each byte. This would work perfectly no matter what (unless somebody disabled interrupts for longer than a bit time) but then would eat a timer for each pin you want to use as an input or output. Which would be a big bummer, since we only have 5 timers to work with.

*Brian


KurtE

Mon, 19 Dec 2011 21:21:29 +0000

Thanks for the response,

Yep, I have also done it with a timer before as well. On that processor it helped for some projects we were playing with. The only issue on that processor (Renesas H8, running at 16 or 20mhz) was the overhead for the interrupts. It took like 25-30 cycles to do the interrupt switch. Each 32 bit register you used, you needed to save and restore, which took 10 clocks for the push and 10 for the pop... So it added up quickly!.

With the Arduino type libraries, I don't know of any way to ask the system for a free timer, instead I believe you simply have to grab one, which is something I hate as if I choose #2 it will turn out so did someone else. But if done correct would be great. You can do things like look ahead to see how many bits are the same and only schedule the timer for the next transition. Input will probably have to be set up, that when the start bit is detected, the pin change interrupt would be disabled and the timer scheduled. Only when the stop bit is detected would then the pin change would need to be re-enabled. Can be done, but I need to learn some more about the Pic32.

May start off with the system timer and see...

Kurt


manut

Tue, 20 Dec 2011 10:02:49 +0000

Hello, I wanted to try your Softserial lib. Do you have any example, because I'm having problems to compile my sketch with this library (maybe I misinstalled it. I'm using mpide-0022-windows-20110822). Thanks, Manu


KurtE

Tue, 20 Dec 2011 13:58:14 +0000

I have been using the latest test builds. My guess is that some of the underlying hardware definitions and/or files has changed, which is causing the issue. If I get a chance I will take a look.

Kurt


manut

Tue, 20 Dec 2011 17:06:43 +0000

Good news, I have downloaded MPIDE 0023 and now I can compile without errors. I still have issue but I think it is because I'm trying to interface a 5V module (RFID SM130) with the 3.3V Chipkit UNO32. I'll add my results whathever it works or fails. Thank you by the way for this lib.


manut

Wed, 21 Dec 2011 08:31:47 +0000

Hello, Depiste I added a logic level converter (3.3V -> 5V) on the Tx line, I still haven't any signal on the Rx line. The software uart mapping is : D7 : Rx D8 : Tx The Tx line on the D8 pin works great (with or without the level converter). Do you think the D7 pin could be incompatible with a Rx fonction? I'm still working on that, I will report my tests.


KurtE

Wed, 21 Dec 2011 14:31:14 +0000

Good to know that output is working for you. But no that IO pin will not work for input. Input needs to be done on an IO pin that has Pin Change Interrupts associated with it. The table I have currently in the code is specific to an UNO32. Should be moved into the board specific definition files. But here is the current table:

// BUGBUG:: should move to hardware board definition file...

// Map IO pins to Pin Change pin number...   Hard coded for Uno32...
const static uint8_t g_abMapArduinoPinToCNPin[] =  {
    0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,   // 0-9
      13,   10,     9,     8,     4,     6,  0xff,  0xff,  0xff,  0xff,   // 10-19
       5,     7,  0xff,  0xff,  0xff,    12,  0xff,  0xff,  0xff,  0xff,   // 20-29
    0xff,  0xff,  0xff,  0xff,    14,  0xff,    15,    16,  0xff,    17,   // 30-39
      18,     3,     2,  0xff,    11};                             // 40-44

Note: only the pins with a value not 0xff are valid...

Another way to find these pins is using the data sheet for the UNO32. If you look at the pin tables, it will be those pins that have CNn in their descriptions, like:

13 J5-11 4 SCK2/PMA5/CN8/RG6

So logical pin 13 has a change notify pin (8) and should work. Many of the pins with the notify are Analog pins. The main ones I have tested with are the high ones like 39-42

Kurt


manut

Wed, 21 Dec 2011 15:00:35 +0000

Effectively, I missed that (shame on me)... So I will modify my shield to use a CN pin -> Rx line. Thank you.


manut

Wed, 21 Dec 2011 16:43:31 +0000

I tried pin 10 (CN13) but it fails. As you said, there might might something relative to analog pins that is important.


KurtE

Wed, 21 Dec 2011 17:11:50 +0000

Also note with some IO pins like 10, what they are actually connected to depends on jumpers on the board. I believe I matched the right one for default jumpers (and what the hardware specific tables for UNO32 are set to. I don't actually see any places in their tables to handle the different jumper settings...

Kurt


manut

Thu, 22 Dec 2011 10:20:10 +0000

Finally: Pin 10 is ok. The reason why it fails does not depend on the lib. A bad wiring caused the reset pin of the rfid uart module (the one I'd like to interface) to be grounded, so it cannot send anything to the Rx line. So, I can confirm that the pin 10 can be use as Rx pin with the lib.

Thank you, it saved me lot of time to have this lib!

There might be an improvement for the start bit detection. I noticed that a fake bunch of 1's (0xFF) are in the receive buffer (see attached file). My application uses a modified RFID shield from sparkfun (based on a SM130 rfid module). The UNO32 interfaces the SM130 module with your SoftwareSerial lib with pin 10 (Rx) & 8 (Tx). The goal is to read th ID from a RFID tag and send it to the monitor. The are some bad frames (0xFF...) but it may be a consequence of my rfid uart module.


KurtE

Thu, 22 Dec 2011 14:52:30 +0000

Glad it is starting to work for you. Not sure about the FFs, that would imply that it was getting some changes in the IO line, in order to receive the pin change interrupt, but will check into it more. As I mentioned in previous post, would like to make it not hard hang with interrupts turned off, so will experiment more with that.

Hope to get back to it soon, but have been busy with other projects.

Kurt


JerryH

Sat, 28 Apr 2012 16:03:53 +0000

Semi-noob here...

I was pleased to find that someone has already done some work getting SoftSerial ported to the UNO32. I'm using this library.

However, I'm having an issue with one feature of SoftSerial: 'available'.

I'm trying to reuse some GPS code that uses SoftSerial to communicate with a GPS receiver. The code has the line:

while(uart_gps.available())

This line apparently waits until there is data in the serial port receive buffer before continuing.

I get the following compiler error:

UNO32_sketch_mar08b.cpp:84:18: error: 'class SoftwareSerial' has no member named 'available'

Is there a workaround for this? Or is there a newer version of SoftSerial for UNO32 that includes this feature?

Thanks for the help.


Ryan K

Fri, 04 May 2012 21:20:54 +0000

Hello,

Are you using KurtE test build for the SoftwareSerial, it's on page 1 of this post? The original SoftwareSerial that comes with MPIDE doesn't have a member function available in the class. You'll have to replace the SoftwareSerial in MPIDE\hardware\pic32\libraries with the test build.

Best Regards, Ryan K Digilent


kllsamui

Sat, 18 Aug 2012 00:50:22 +0000

for MAX32 could use

//UNO32
#if defined(__PIC32MX3XX__)

const static uint8_t g_abMapArduinoPinToCNPin[] =  {
    0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,   // 0-9
      13,   10,     9,     8,     4,     6,  0xff,  0xff,  0xff,  0xff,   // 10-19
       5,     7,  0xff,  0xff,  0xff,    12,  0xff,  0xff,  0xff,  0xff,   // 20-29
    0xff,  0xff,  0xff,  0xff,    14,  0xff,    15,    16,  0xff,    17,   // 30-39
      18,     3,     2,  0xff,    11};                             // 40-44 
#endif
// MAX32 (mod by KLL)
#if defined(__PIC32MX7XX__)

const static uint8_t g_abMapArduinoPinToCNPin[] =  {
    0xff,  0xff,  0xff,  0xff,     0,  0xff,  0xff,  0xff,  0xff,  0xff,   // 0-9
      13,  0xff,  0xff,  0xff,  0xff,  0xff,    18,    17,    21,   20,    // 10-19
    0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,     9,   // 20-29
    0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,    14,   // 30-39
    0xff,  0xff,  0xff,    10,  0xff,  0xff,  0xff,    15,   0xff,  0xff,  // 40-49 
       9,  0xff,     8,    11,     2,     3,     4,     5,     6,     7,   // 50-59 
    0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,   12,    // 60-69 
    0xff,  0xff,  0xff,  0xff,  0xff,     1,    19,    16,  0xff,  0xff,   // 70-79 
    0xff,  0xff,  0xff,  0xff,  0xff,  0xff };                             // 80-85 

#endif

in above lib SoftwareSerial.cpp from KurtE. Only ARDUINO Pin D10 works for MAX32 and UNO32 same as softserial RX!