What would your general approach be to this problem?

Go To Last Post
18 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have two uC's working together: uC#1's job is to poll its GPIO ports every second or so and then communicate what it sees to uC#2 which is on another PCB about 4' away.

Anyhow, uC#1 needs to communicate 4 bytes of information - over and over again.

My goal is to make this communication as fault tolerant as possible.

I have made this work using two different scenarios:

Method #1
uC#1 sends four predetermined "key" bytes and then sends the four data bytes over the UART. This process repeats over and over. uC#2, has an interrupt-driven serial port so it always stops everything it's doing to get the latest byte when uC#1 sends it and puts it into a volatile char array of size 8 bytes. I also have a volatile char pointer that is always pointing at the next slot that the next byte will be put into. Of course, I have to check if the pointer is pointing past the 8th byte to reset it back to 1st byte of the array. uC#2 then periodically sorts the circular array to find the four keys which then leads to the location of the first data byte.

Method #2
uC#1 sends the four data bytes over the UART and then waits 500ms before sending them again. uC#2 has a timer that will overflow during the 500ms pause which triggers an interrupt to take the last four bytes and store them as the data bytes to be used elsewhere in the program. The interupt procedure also moves the pointer to the 4-char array back to the first slot and also resets the number of chars received to zero. I have the number of chars received in a volatile variable to make sure that four bytes were received since the last delay - otherwise a byte was lost or, perhaps, no bytes were sent.

Does anybody have an opinion on this? Is there some easy library that I don't know about to communicate serially with fault tolerance?

Right now I have only a transmit wire from uC1 to uC2. I could add another wire for bi-directional communication if it helps the process.

Any comments welcome.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you can easily implement the bidirectional communications, then you can echo the 4 bytes back to the micro where you are monitoring the ports. This is a good check that your communications link is error-free.

Otherwise, CRC (or at least checksum) is a good error-detection method (see postings about CRC in this forum).

Regards,
Walt

Regards,
Walt
____________________________________
"Nothing in this book is true."
-Cat's Cradle

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you can use SPI you will get all sent bytes autmatically as its nothing but a circuler buffer. However you need to send one more byte from uC1 and discard it in uC2 to get the last byte back in uC1. But i am not sure whether it will work for 4'.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The 'bit error rate' on a serial line is so small that you could transmit those 4 bytes at 430kbps for years and never get a bad character 4 feet away.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@bobgardner: I'm worried about someone disconnecting the line for a bit. I want to be able to sense that.

@waltsacuta: I'll check out the CRC idea. Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Always send a 5 byte 'packet': unique start char like 0x80, 4 data bytes (anything except start char). If line gets unplugged, you probably get a framing err on the char it gets when plugged in, throw that one out, throw out all chars until you get the start char, read 4 data bytes. Start char of 0x80 is -128. This lets you send +-127 as data.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I agree with bobgardner. The instrument I code for has over a mile of cabling and in all these years, I have yet to see a communications error that wasn't due to a power fault or the like (our protocol uses a checksum and reports the standard UART errors also). Keep it simple.

I designed a system once that monitored a bank of switches in a remote pump station and when a change was detected, dialed a modem line and reported the data to a receiver that reflected the switch state on a set of relays (I called it the 10 mile extension cable :-). Error checking was for the receiver to verify that it received a stream of 4 bytes and each pair had to match or it sent a NAK and the transmitter resent the data.
Simple and never had an error reported!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Don't forget to check the USART Rx error flags. There is lots of USART code out there that ignores these error flags. This is your first line of defense.

If UC1 can benefit from knowing UC2 has detected and error in the USART data, then bi-directional communication would be useful. If each individual data transfer is critical, two way communication allows UC1 and UC2 to synchronize or resynchronize when an error occurs, which improves your chances of getting good data transferred.

A CRC is extremely useful and highly recommended. However, if its absolutely vital that correct information is known to be transferred between the processors then you need to do some "about CRC" research. Because of the nature of the CRC there is always an undetectable error rate which is usually so incredibly tiny it doesn't matter unless you require absolute confidence.

To improve signal integrity, using RS-232 level converters would boost the serial data line signal level, improving the signal-to-noise ratio on the 4' serial data line. It also adds protection for the processor chip when who knows what happens to an unplugged cable connector. If you need higher noise margins, then use a RS-422/485 type differential driver/receiver.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here's your crc code for this...

unsigned long crc32(data)
{
 return data;
}

:lol:

Sorry, it's quite possible that I'm not actually being helpful.

I actually thought adding the line for bi-directional communication was a good idea since it allows both sides to know when the data didn't make it. May or may not be helpful now, but may become helpful if your requirements change.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My approach - Use Modbus RTU. It was primarily designed for PLC to PLC communication. You only need to implement the commands you need which in many cases is read registers and write registers. See www.modbus.org
There's free tools available to allow you to test/debug your modbus comms. Being an industry standard means other devices can talk to your device if required.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Fizgig,
I think a lot depends on the criticality of your application, and are you building one or many.
Wireless communications has the potential for lots of data errors, and more robust techniques are needed. Doing RS-232 over 4 feet is "trivial", as Bob noted above.
To optimize your link I would keep the baud rate low, say 9600, unless you have a good reason to go higher.
I would use a good quality, shielded cable.

A simple scheme to detect an unplugged cable connector, separate from the RS-232 wires, is to include two more wires in your cable. Tie one end high at uC2's end. At uC1's end, jumper the connector so the two wires are tied together. Back at uC2's end tie the wire to a resistor to ground. Monitor the voltage, (digital input), on the resistor. As long as the +5 V makes it down the wire, to the board, back up the second wire, to the board, the cable/connectors are intact. For four feet the cost for the cable is insignificant.

With lots more circuitry, (ignoring the KIS principle), you can skip the extra two wires, and superimpose a low amplitude, high frequency signal on your RS-232 transmission lines.

If you don't care about determining uC's failure mode, (power failure vs cable disconnected), the mere fact that the data doesn't arrive as expected signals an error state in the system.

If your data can take any value from 0 - 255 then a multi-byte Start of Packet, as you have implimented, is good. If the data won't encompass all of those values just sending a Start of Packet character, your data, and a check sum should be adequate.

With low data rates there is also no reason you could not send the data in triplicate, if all three copies match for a given byte, you are done. If two bytes match, you use that value, and assume you have detected a single error, (and corrected for a single error).

Many systems send a trash character or two before sending the Start of Packet. Your Receiving program just ignores them until it gets a Start of Packet character.

Lastly, it goes without stating, but I'll state it anyways:

For reliable USART communications use a crystal on both of the uCs, and additionally choose a frequency that gives 0/minimal baud rate error. Others can correct me If I'm wrong but I believe 14.7456 MHz is one such frequency.

A simple Checksum is simply the 8 bit sum of all of the preceding data bytes in the packet, ignoring any overflow from the additions.

Packet:
xxx Where x = a leading trash character or two
< = Start of Packet
B1 = Byte 1 of data, repeated
B2, B3, B4 likewise
CS = Check Sum, Sum of all the bytes after the <

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you might consider the following scheme:

1) each byte is followed by the compliment of that byte
2) there's a sync packet that identifies the start of a message. It's followed by something that isn't it's compliment, but has a regular and identified pattern:

e.g.: data1 xor data1C = 0xFF

Sync1 + Sync1C = 0x55, or 0xAA, or something other than 0xFF.

That could be implemented with simple TTL, but heck, a microprocessor is sexier....

Harvey

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Packet format that works everytime:

Byte 1: Length, or START marker if fixed packet length.
Byte 2 to Byte (Length+1): Data
Byte (Length+2): Checksum

Sender sends packet, receiver acks it with a recalculated checksum after checking if the checksum was good on the packet. If the checksum was not good, the receiver discards it and waits for a resend. The sender knows the packet was not received successfully from the ACKed checksum, and resends.

My favorite checksum is a simple LRC (longitudinal redundancy check), where you just xor all the bytes in the message together.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

We seem to be summarizing examples of simple protocols. This stuff was sort of worked out a while ago by the radio and telemetry phds. I wonder if we can gather a few rules of thumb that we agree on.... How about thruput as a function of error rate.... the higher the error rate (lower the signal to noise ratio) the lower the probability of a packet of length n getting thru. Shorter packets, higher probability. Sending the same char multiple times is the same as sending the same packet multiple times. Adding a check sum or cyclical redundancy check tells you the packet was corrupted during transmission, but doesnt help you get it back. You need some feedback from the receiver if you want him to be able to tell you 'yes I got it' or 'no I didnt'. Wireless isnt always full duplex, so some form of Forward Error Checking could be used to not only detect errors, but also correct some of them. Similar to Error Checking and Correcting ram memory that adds a parity bit for each byte in the word, plus 3 more parity bits for the parity bits. Hamming Code I think its called. Usually speed and efficiency are considerations, so the old brute force technique of 'send the message three times and if two of them get there the same, use one of those' works but is not optimally efficient. The modem protocols kick the packet size down as the retransmit count goes up to try and push the message through despite the noise.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I appreciate all the helpful comments.

I had another issue where I wanted to be able to communicate with uC #2 on another serial line which would complicate things as uC #2 would require 2 serial connections.

What I decided to do was scrap uC#1 and replace it with four octal buffers. They all share the same 8-wire bus with an enable pin for each buffer. Total wire count was 8+4+2(power) = 14 which isn't a big deal. I can use a ribbon cable.

Still learned a ton from this thread. Thanks all for your input.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

fizgig wrote:

I had another issue where I wanted to be able to communicate with uC #2 on another serial line which would complicate things as uC #2 would require 2 serial connections.

I'm still quite a n00b at avr's, but today I was feeling interested in inter-chip communications.
Anyhow, what about using a byte in the packet just for ID, so you know with whom you're communicating with (uC 1 or the other thing). Or you could look into i2c which allows communication of 128 devices over 2 wires.

edit: Even if the ID thing would work, collisions could happen. Adding a packet reply if a packet was received would help in that situation.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fizig - beware of crosstalk on the flat cable! I'd suggest you have a ground wire between each signal.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can do I2C that way, but you are limited in cable length due to cable capacitance on the branch. Even buffers do not completely solve the problem. For long length transmissions, you need to go to differential 4 wire rather than two. There's chips for that.

My I2C protocol is roughly
address (acked or nacked)
byte count (integer)
block count (integer)
command (byte)
with nack on last byte
data may follow command as needed.

Response is address (from master),
count (integer)
block count (integer)
status (integer)
app data (2 bytes)
more data may follow

Hamming code extends the idea of parity by doing parity over a combination of bits.

4 bits of data requires 3 bits of hamming code correction, and will detect and automatically fix any one bit error (parity will detect an odd number of bit errors, but will not fix any, does not detect an even number of bit errors). 4/3 hamming code (above) will detect 2 bit errors, but not fix them.

IIRC 8 bits needs 4 hamming code bits, but don't quote me on that one. 4/3 hamming code is done with each hamming code bit based on 3 bits of the 4 bit word.

The basic idea of data security in transmission just works out to redundancy, however you decide to do it.

Harvey