Assembler error, SoftwareSerial, add even parity bit

Using serial communication on a Mega2560 board, I need to talk to devices with which “even” parity is required (no way to select “no” parity on those devices).
Then, when sending data, I have to add one bit (“0” if not inverted, because I have 8 data bits) between data bits and stop bit, and when receiving data, I have to read one bit between data bits and stop bit.
I created “ParitySoftwareSerial” library, based on “SoftwareSerial”.
If I just modify function “write” by adding :

  if (_inverse_logic)
    for (byte mask = 0x01; mask; mask <<= 1)
    // write the even parity bit : we sent 8 bits, so we send "1" :
    for (byte mask = 0x01; mask; mask <<= 1)
    // write the even parity bit : we sent 8 bits, so we send "0" :

…when I recompile my sketch using the libray, it works.

But when I modify “recv” by adding :

    // Read each of the 8 bits
    for (uint8_t i=0x1; i; i <<= 1)
    // skip the parity bit
    tunedDelay(_rx_delay_stopbit); // I use delay defined for stop bit...
    DebugPulse(_DEBUG_PIN2, 1);
    // skip the stop bit

I receive a compiler error :

Assembler messages:
C:\Users\Alytech\AppData\Local\Temp/cczbUxov.s:227: Error: register r24, r26, r28 or r30 required

And if I just commentthe two added lines (by adding “//” in front of them), compiling is ok.

Does anyone have an idea or can show me where to search to get an answer to my problem ?

Thank you very much in advance !

Well recv() has a workaround for certain versions of avr-gcc (saving some registers on the stack in assembler) - there is a compiler issue under OSX with some versions of avr-gcc - perhaps this is hitting you too?

I could see effectively that, at the beginning and end of function “recv”, there are some “push/pop” for registers under certain circumstances :

#if GCC_VERSION < 40302
// Work-around for avr-gcc 4.3.0 OSX version bug
// Preserve the registers that the compiler misses
// (courtesy of Arduino forum user *etracer*)
  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"

But I am running MS-Windows 7 Pro (not Mac OSX). Are they some known bugs in such a situation too ?
Anywya, I don’t care, I just want things to work. How can I solve this ?

Thank You in advance for Your precious help !

Have you tried wrapping the stop bit handling in a two iteration for loop?

I don't know the details, but its a bug triggered when an interrupt routine calls another routine. If interrupt routine does all the work itself rather than calling a subroutine, I suspect that might cure things - so you'd need to re-write a copy of SoftwareSerial to do things this way.

The underlying problem is probably that the calling convention used in avr-gcc is not the same as that used by the hardware interrupt-handling.

It might be worth investigating which version of avr-gcc you have and what the current version is - try upgrading to that (but be prepared to back-out again!). I know my (elderly) ubuntu install is using v. 4.3.5, if you post the complete SoftwareSerial mod you have some of us could test if it compiles on their installs.

It doesn't look related but change tunedDelay() the following routine:

/* static */ 
inline void SoftwareSerial7e1::tunedDelay(volatile uint16_t delay) { 
  volatile uint8_t tmp=0;
  asm volatile("sbiw    %0, 0x01 \n\t"
    "ldi %1, 0xFF \n\t"
    "cpi %A0, 0xFF \n\t"
    "cpc %B0, %1 \n\t"
    "brne .-10 \n\t"
    : "+r" (delay), "+a" (tmp)
    : "0" (delay)

Note the added volatile statements. For me it compiles so.