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" :
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 :
//...
// 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
//...
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"
::);
#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 ?
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.