Pages: [1]   Go Down
Author Topic: SoftwareSerial 8-o-1 problem  (Read 1239 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi!

I'm trying to use Arduino's SoftwareSerial to communicate with a RS-422 device.
I use SN75179BP to convert 422 to TTL.

The device is 8bit - odd parity - 1 stop bit.
I've tried to mod the softwareserial library using:
http://arduino.cc/forum/index.php/topic,108097.0.html

Changed the parity bit calculation in the write function to odd instead of even.

Couple of problems:
First, if I use the exact mod suggested by pylon [the 4th comment] on the recv function, while trying to upload the sketch I get:

Code:
/var/folders/st/vmhkh5t57592ln_zhkyfq2q80000gn/T//cct5EjNP.s: Assembler messages:
/var/folders/st/vmhkh5t57592ln_zhkyfq2q80000gn/T//cct5EjNP.s:243: Error: register r24, r26, r28 or r30 required
/var/folders/st/vmhkh5t57592ln_zhkyfq2q80000gn/T//cct5EjNP.s:263: Error: register r24, r26, r28 or r30 required

Have no idea why.
but if I leave the function as is, and only changing this:

Code:
 // skip the parity bit
    tunedDelay(_rx_delay_stopbit);
    DebugPulse(_DEBUG_PIN2, 1);

    // skip the stop bit
    tunedDelay(_rx_delay_stopbit);
    DebugPulse(_DEBUG_PIN2, 1);
    

to this:

Code:
// skip the 2 stop bits
    tunedDelay(_rx_delay_stopbit*2);
    DebugPulse(_DEBUG_PIN2, 1);

I can upload the sketch and even start receiving true and correct data on my serial.

The second problem, is that no matter what I do - I can't get the write function to work.
The device doesn't respond to any input except that in the second I try to send something to that device over the serial, I stop getting nice and clean data on my recieve channel, instead I get clutter...

[BTW, in that situation - if send some "new line" 0D, it brings back the normal data on the recieve channel...]

*-I'm using Arduino 1.0.1


EDIT: I don't know if it's important or not, but I'm using inverse_logic for the receive function to work.



Any ideas will be more than welcomed,
Liad.
« Last Edit: September 10, 2012, 03:26:47 pm by Liad » Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5144
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Changed the parity bit calculation in the write function to odd instead of even.

Show us your changed code to check the implementation.

Quote
First, if I use the exact mod suggested by pylon [the 4th comment] on the recv function, while trying to upload the sketch I get:

For what board type are you compiling this?

Quote
but if I leave the function as is, and only changing this:

Your change is just skipping the parity bit and the stop bit. This works for the receiving part but it's clear that the transmitting part is not working that way.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Show us your changed code to check the implementation.

Just changed
Code:
 uint8_t p = 0;

to
Code:
 uint8_t p = 1;


Quote
For what board type are you compiling this?
Arduino UNO.


Quote
Your change is just skipping the parity bit and the stop bit. This works for the receiving part but it's clear that the transmitting part is not working that way.
Yea, I know...I just wanted the receiving part to work to see if my device will show any changes while playing with the write function.
« Last Edit: September 11, 2012, 09:32:52 am by Liad » Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5144
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's the code for the 8o1 variant.

Code:
//
// The receive routine called by the interrupt handler
//
void SoftwareSerial::recv()
{

#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 

  uint8_t d = 0;

  // If RX line is high, then we don't see any start bit
  // so interrupt is probably not for us
  if (_inverse_logic ? rx_pin_read() : !rx_pin_read())
  {
    // Wait approximately 1/2 of a bit width to "center" the sample
    tunedDelay(_rx_delay_centering);
    DebugPulse(_DEBUG_PIN2, 1);

    // Read each of the 8 bits
    for (uint8_t i=0x1; i; i <<= 1)
    {
      tunedDelay(_rx_delay_intrabit);
      DebugPulse(_DEBUG_PIN2, 1);
      uint8_t noti = ~i;
      if (rx_pin_read())
        d |= i;
      else // else clause added to ensure function timing is ~balanced
        d &= noti;
    }
    // skip the parity bit
    tunedDelay(_rx_delay_stopbit);
    DebugPulse(_DEBUG_PIN2, 1);

    // skip the 2 stop bits
    tunedDelay(_rx_delay_stopbit);
    DebugPulse(_DEBUG_PIN2, 1);

    if (_inverse_logic)
      d = ~d;

    // if buffer full, set the overflow flag and return
    if ((_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF != _receive_buffer_head)
    {
      // save new data in buffer: tail points to where byte goes
      _receive_buffer[_receive_buffer_tail] = d; // save new byte
      _receive_buffer_tail = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF;
    }
    else
    {
#if _DEBUG // for scope: pulse pin as overflow indictator
      DebugPulse(_DEBUG_PIN1, 1);
#endif
      _buffer_overflow = true;
    }
  }

#if GCC_VERSION < 40302
// Work-around for avr-gcc 4.3.0 OSX version bug
// Restore the registers that the compiler misses
  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"
    ::);
#endif
}

and the write part:

Code:
size_t SoftwareSerial::write(uint8_t b)
{
  if (_tx_delay == 0) {
    setWriteError();
    return 0;
  }

  uint8_t oldSREG = SREG;
  cli();  // turn off interrupts for a clean txmit

  // Write the start bit
  tx_pin_write(_inverse_logic ? HIGH : LOW);
  tunedDelay(_tx_delay + XMIT_START_ADJUSTMENT);
  uint8_t p = 0;
  uint8_t t;
  for (t = 0x80; t; t >>= 1)
    if (b & t) p++;
 

  // Write each of the 8 bits
  if (_inverse_logic)
  {
    for (byte mask = 0x01; mask; mask <<= 1)
    {
      if (b & mask) // choose bit
        tx_pin_write(LOW); // send 1
      else
        tx_pin_write(HIGH); // send 0
   
      tunedDelay(_tx_delay);
    }
    // parity
    if (p & 0x01)
      tx_pin_write(LOW); // send 1
    else
      tx_pin_write(HIGH); // send 0
    tunedDelay(_tx_delay);

    tx_pin_write(LOW); // restore pin to natural state
  }
  else
  {
    for (byte mask = 0x01; mask; mask <<= 1)
    {
      if (b & mask) // choose bit
        tx_pin_write(HIGH); // send 1
      else
        tx_pin_write(LOW); // send 0
   
      tunedDelay(_tx_delay);
    }
    // parity
    if (p & 0x01)
      tx_pin_write(HIGH); // send 1
    else
      tx_pin_write(LOW); // send 0
    tunedDelay(_tx_delay);

    tx_pin_write(HIGH); // restore pin to natural state
  }

  SREG = oldSREG; // turn interrupts back on
  tunedDelay(_tx_delay);
 
  return 1;
}

The compiler errors you get indicate that you're working with MacOS X as the compilation machine. Correct?

I got the compilation error away on my machine by changing the following code too:

Code:
inline void SoftwareSerial8o1::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 inserted volatile statements to keep the compiler from optimizing the variables away.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey,

Thank you for your quick response.
I compiled it with the new code but I still can't transmit normally.

The device is constantly sending data. [ASCII formated messegs] I can read it clearly.
Whey I send 1 character using the serial terminal. I stop getting normal data from the device and it doesn't do what it suppose to do if he got the correct data from me.

I took an oscilloscope to check the arduino's output and it outputs exactly what it should [I think]
For example, sending 0x01 - I get 1011111110 [inverse logic]

is it possible that there is a problem with the timing? bit size?

Thanks,
Liad.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 21
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey,

Problem solved!

I don't completely get it, but the minute I've changed the write function to non-inverse logic [With of course setting up the parity+stop bit correctly] - everything started working...

I'll keep investigate it to see exactly what's going on but it's nice to see it working.

Pylon, thanks a lot for that OSx workaround!

Liad.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello,

I'm not sure that my problems with SoftwareSerial has anything to do with this thread, but it sounds likely. I'm using MacOS 10.6.8 with Arduino 1.0.1.

When I make a bluetooth connection to my Sparkfun Bluetooth Mate Gold I can query the device correctly, and both sending commands and receiving chars works fine. However, when I try to make a small echo sketch the chars come back garbled.

Question and code is here: http://electronics.stackexchange.com/questions/40408/making-an-echo-sketch-using-softwareserial-and-bluetooth.

Help is needed!

Thanks.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 610
Posts: 48993
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I'm not sure that my problems with SoftwareSerial has anything to do with this thread, but it sounds likely
No to me, it doesn't. Stick to your own thread.
Logged

Pages: [1]   Go Up
Jump to: