Go Down

Topic: Assembler error, SoftwareSerial, add even parity bit (Read 1 time) previous topic - next topic

AlyTech

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 :
Code: [Select]

  //...
  if (_inverse_logic)
  {
    for (byte mask = 0x01; mask; mask <<= 1)
    {
        //...
    }
    // write the even parity bit : we sent 8 bits, so we send "1" :
    tx_pin_write(HIGH);
    tunedDelay(_tx_delay);
    //...
  }
  else
  {
    for (byte mask = 0x01; mask; mask <<= 1)
    {
        //...
    }
    // write the even parity bit : we sent 8 bits, so we send "0" :
    tx_pin_write(LOW);
    tunedDelay(_tx_delay);
    //...
  }
  //...

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

But when I modify "recv" by adding :
Code: [Select]

    //...
    // 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 :
Code: [Select]

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 !

MarkT

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 won't respond to messages, use the forum please ]

AlyTech

I could see effectively that, at the beginning and end of function "recv", there are some "push/pop" for registers under certain circumstances :
Code: [Select]

#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"
    ::);
#endif 


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 !

AWOL

Have you tried wrapping the stop bit handling in a two iteration for loop?
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

MarkT

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.
[ I won't respond to messages, use the forum please ]

pylon

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

Code: [Select]
/* 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.

Go Up