Go Down

Topic: NewSoftSerial Library: An AFSoftSerial update (Read 43881 times) previous topic - next topic


Note also that the inline assembly work-around for the OSX 0013 interrupt bug that I provided *may* not work with the 328.  I don't know if the compiler will generate the same register code as for a 168 (and I don't have any 328's to test with).

That being said, I suspect it will work because I can't see any way that the buggy 4.3.0 version of the compiler would know about the 328 and have specific optimizations.


Feb 20, 2009, 10:29 pm Last Edit: Feb 20, 2009, 10:37 pm by mikalhart Reason: 1
-however- the interrupt bug in v13 is not resolved so there may be freaky experiences.

Oh, sorry, I thought you said in your previous post that you had tested NSS5 with etracer's workaround on the 328p... ?  

otherwise, works very nicely with 1 GPS module under v13 ide on windows and mac osx tested with 168 and 328p

Is this not correct?



Feb 21, 2009, 10:34 pm Last Edit: Feb 21, 2009, 11:00 pm by ladyada Reason: 1
the 'hack' etracer added will resolve it as long as those are the registers used. the compiler can pick nearly any registers so in some cases it will still break.

the bug in v13 really needs to be fixed for NSS (and nearly any arduino code with interrupts) to work perfectly all the time
ive poked dmellis about it but hes probably quite busy & i didn't get a date for when it will be fixed :(


Since this OSX avr-gcc interrupt bug is killing me on a number of projects, I got impatient and hacked in avr-gcc 4.3.2 into my OSX Arduino-0013 install. I can report that the new version fixes the interrupt bug.  One minor thing I noticed is that my small test program was a little larger with avr-gcc 4.3.2. Overall it was 130 bytes larger or about 3%. This may not be significant as I'm not sure my hacked install has all of the same compile options as the "official" Arduino version will.

Also note that the corrected interrupt vector names that ladyada fixed in the latest version are critical for avr-gcc 4.3.2. With the old vector names the code would compile, but the chip would reset whenever an interrupt occurred. So there's nothing to fix as code is now correct, but it's just something to be aware of.

@mikalhart: I added some conditional compiling based on avr-gcc version so that the inline assembly hacks would only be included if needed (for 4.3.0). I'll PM you with a link, but here's the gist of the changes:

In NewSoftSerial.h, define GCC_VERSION

Code: [Select]

#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)

For avr-gcc 4.3.0, GCC_VERSION will be 40300 (40302 for 4.3.2, etc.)

In NewSoftSerial.cpp, put conditional compilation around the inline assembly so that it's only included for version 4.3.0 (the only version to be included with the IDE that has the bug). I also updated the comment to indicate 4.3.0 instead of only 4.3.

Code: [Select]

// Work-around for avr-gcc 4.3.0 OSX version bug
// Preserve the registers that the compiler misses
// (courtesy of Arduino forum user *etracer*)
#if (GCC_VERSION == 40300)
 asm volatile(
     "push r18 \n\t"
     "push r19 \n\t"
     "push r20 \n\t"
     "push r21 \n\t"
     "push r22 \n\t"
     "push r23 \n\t"
     "push r26 \n\t"
     "push r27 \n\t"


Code: [Select]

// Work-around for avr-gcc 4.3.0 OSX version bug
// Restore the registers that the compiler misses
#if (GCC_VERSION == 40300)
 asm volatile(
     "pop r27 \n\t"
     "pop r26 \n\t"
     "pop r23 \n\t"
     "pop r22 \n\t"
     "pop r21 \n\t"
     "pop r20 \n\t"
     "pop r19 \n\t"
     "pop r18 \n\t"

On a non-interrupt-bug note...

I might suggest changing your versioning scheme. It's kind of confusing to have NewSoftSerial1, NewSoftSerial2, etc. This scheme implies a major version change that added new features or fuctionality. The common versioning scheme is to use a major version number (probably 1 in this case), a minor revision (maybe 1 or 2?), and a patch level (maybe 5 or 6?).

Lastly, it would be helpful to change how you package each version. Having the directory named "NewSoftSerial6" will cause confusion for new users that are unaware that they should remove the 6 before putting it in their library directory. Then when NewSoftSerial7 comes along and they copy that, they'll get all kinds of compile errors due to the duplicate source files.

I would suggest something like this:

-- NewSoftSerial
---- Examples
---- NewSoftSerial.cpp
---- NewSoftSerial.h

Then when the users expand NewSoftSerial-1_2_3.zip they can directly copy the enclosed NewSoftSerial directory to their libraries.



Thanks for testing with 4.3.2.  I had already implemented the conditional compilation of the workaround, using __GNUC_PATCHLEVEL__ etc., but was just waiting for confirmation that the new compiler actually *did* fix the problem before rolling it out.

Your point about the organization of the ZIP file is a good one.  I should have thought of that.  I'll certainly release the next version of NSS in that format.  I probably will stick with the single-digit versioning, though.  I don't think that NewSoftSerial is a big enough project to warrant an x.y.z versioning scheme, and I would have to change the NewSoftSerial::library_version() interface to support it.

Thanks much!  Nice work as always.



Again, thank you all (especially mikalhart) for the great work on this.  I'd love to replace the existing SoftwareSerial with this library.

Is there a chance that someone can add support for 8 MHz processors?  

Also, what's the best option for people using the ATmega8?  Should we just conditionally revert to the current SoftwareSerial library?



I've got an Arduino Pro here, and if I can get some time, it is at the top of my priority stack to add support for 8MHz (and possibly 20MHz) processors.  What would be supporting the ATmega8 entail?


I tested the binary you sent (compiled under OSX with the 4.3.2 compiler and the new conditional #ifdef workaround) and it passed my baud rate test bench with flying colors.  I should be posting a new version of the library shortly.  Thanks!



Awesome library.  I can't wait to use it.  Will it support odd baud rates like 976 and 7812?  I am pulling data from devices that are rather antiquated.



Is it fairly easy to update the compiler for arduino-0013? Do you have to build it, or is there a binary distribution you can just untar in the right place?


Feb 26, 2009, 09:54 pm Last Edit: Feb 27, 2009, 02:23 am by etracer Reason: 1
Is it fairly easy to update the compiler for arduino-0013? Do you have to build it, or is there a binary distribution you can just untar in the right place?

Here's how I did it for OSX (this will probably work for Linux as well but I don't know where to get a precompiled binary)...  These instructions assume you have arduino-0013 installed inside your Applications folder.

1. Download AVRMacPack-20081213.dmg
2. Run the installer
3. Open up Terminal
4. cd /usr/local/AVRMacPack
5. Select GCC4: ./bin/avr-gcc-select 4
6. TAR up the entire directory tree: tar cvf /tmp/avr-gcc432.tar .
7. Inside your Arduino-0013 folder go to hardware/tools
8. Rename the current avr folder avr_old and create a new empty avr folder
9. In terminal: cd to /Applications/arduino-0013/hardware/tools/avr
10. Un-tar the new version in the empty avr directory: tar xvf /tmp/avr-gcc432.tar
11. You need to "rescue" the avrdude program from the avr_old folder as the Arduino version is custom and the one included with the AVRMacPack won't work.  Copy avr_old/bin/avrdude to avr/bin/avrdude and avr_old/etc/avrdude.conf to avr/etc/avrdude.conf

Note that I used tar because I wanted to make sure that permissions and symbolic links would be preserved.  Doing a Finder copy might work - but I don't know.

You also want to make sure that all of the libraries get recompiled.  The simplest way to do this is to change the board type in the IDE (and then change it back).

Since this installation method uses the pre-build compiler from AVRMacPack, the paths to the components are embedded in the various executables.  In this case they point to the installation directory for AVRMacPack under /usr/local.  So this means you must leave AVRMacPack installed for the IDE to work and be able to compile sketches.  Copying the modified arduino-0013 directory to another computer will not work unless you also install AVRMacPack on that computer.

EDIT: Corrected step 11 by adding avrdude.conf and added the caveat warning.


I just posted NewSoftSerial 7, which makes etracer's workaround conditional upon the avr-gcc compiler version.  Thanks again, etracer.


@Frank: No, NewSoftSerial does not support a continuous range of baud rates, and the two you mention below are not among the discrete set.  However, you should be able to patch your copy of the library to work at those speeds by adding a couple of cases for them in the begin() method.  I would guess that for 976, you'd set _bitDelay to something like 2284, and for 7812, you might try 281.  These will probably require tweaking, but it's a start.



etracer, can you post up a .sit or .dmg of your patched v13? if so, i can host it on ladyada.net...let me know, otherwise i will put it on my todo list :)


Feb 27, 2009, 12:06 am Last Edit: Feb 27, 2009, 12:43 am by etracer Reason: 1
Now not to open up a can of worms, but...

One thing that's been bugging me is how the library is writing the serial output.  Particularly how the code is blocked during the output bit timing.  As noted in the documentation, at slow baud rates this means the code is spending most of its time in the output timing loops and not leaving much time for any other processing.  It just seems counterintuitive that the slower speeds would be more processing cycle intensive.

Since all the write is doing (in abstract) is cycling through the bits, setting the output high or low and waiting for the bit delay (and wasting a bunch of cycles), I wanted to think about an alternate way to eliminate the synchronous delay loops.

Maybe I'm gone off the deep end, but what if we made use of one of the timers and transitioned the output bits on the interrupt?  This probably wouldn't work at higher baud rates because you couldn't get enough precision from the timer interrupts.  But at high baud rates you don't need this anyway as the timing loops are short.  At low speeds the timer interrupt could eliminate the long bit delay loops (with some small fudging with the tunedDelay()).

As an example, at 2400 baud the bit delay is approximately 416.67us.  With a 16MHz clock and prescaler at 256, you get 16us per counter value.  So setting the count at 26 gives you 416us per interrupt.  So with creative tuning of the prescaler and counter it should be possible to get pretty close to the needed delays.

Now that being said, I'm not in any way an expert on using timers so I might be completely off in lala land.  I just thought it would be an interesting tangent.


Feb 27, 2009, 12:28 am Last Edit: Feb 27, 2009, 02:30 am by etracer Reason: 1

I'll work on it later tonight and send you a PM with a link.  I have to redo a clean version without all of my libraries installed.


Sorry, I'm not going to be able to provide a self contained version with the updated compiler.  The reason is that the pre-built AVRMacPack was compiled with an absolute directory path of /usr/local/AVRMacPack-YYYYMMDD

This means the modified arduino-0013 version will only work on machines that have already had AVRMacPack installed.

I've updated my install instructions above accordingly.


Hah. I actually wrote a version that uses Timer1 and Timer2 to do that, when I was having some problems with NewSoftSerial. Turns out those were all interrupt related, so I didn't do anything with it. It has some problems at higher baud rates, but I've run it at 19200 with no problems. You're welcome to take a look if you like: http://idisk.mac.com/jinschoi-Public?view=web

The code is based on an earlier version of NewSoftSerial, version 2 or 3. It also contains code for RTS/CTS flow control, which I found I needed for my project.

Go Up