Serial communication is still an important part of our embedded world. Typically we use a 3 wire setup (RX TX and GROUND) and hope that everything goes according to plan. Though this works for most experimenters, sometimes its not the most ideal situation. This is where [simmonmt’s] handiwork comes in adding hardware handshaking to a AVR.
The hardware setup is pretty typical, an Atmega644 sits on one end of the connection, passes through a SP3232EB level shifter and out to a PC. 5 lines are used, again one for RX, TX and GROUND, but also RTS and CTS. When the PC is ready to transmit data it inverts the line (normally held high), the micro controller notices this it pulls CTS low and transmission can commence whenever it darn well feels like it. Handy!
What most of you need to learn is RS485. Want to send serial data 800 feet? Rs485. Want to send it 1200feet through a lot of electrical interference generating rooms? Rs485. rs485 can be full duplex and half duplex. It’s a wonderful thing.
Coupled with checksum bytes and you dont need handshaking.
@fartface
Another important thing: because RS485 is differential, it doesn’t mean that two wires are enough. The third one, ground, is also important. All the advantages of RS485 go down the drain when common-mode voltage limits are exceeded.
As a 40+ year user of RS-232 (and MIL-188), I find it both sad and promising that serial port handshaking (even) rises to rate a HackADay mention. I am always astounded when I see a new design which ignores (or, worse yet, makes *no* provision for) RTS/CTS flow control (and to a lesser degree, DSR/DTR), particularly when the baud rates go so high, (non-deterministic) multi-tasking operating systems (can anyone say “Windows”?), and busy little microcontrollers are involved. I’m always happy to see a leap “back to basics”!
@SpeedBall: It makes me sad to see a multi-tasking operating system with huge amounts of memory for buffers, interrupts and DMA cannot keep up with a busy little microcontroller on RS232 speeds.
We’re running linux on a 40Mhz PowerPC (PPC860) which is equiped with 5 serial lines, and no flow control, but we never have flow control issues.
@SpeedBall:
“particularly when the baud rates go so high, (non-deterministic) multi-tasking operating systems (can anyone say “Windows”?), and busy little microcontrollers are involved.”
I think we have hardware FIFO’s since longtime, and the baud rates are not high, compared to processor speed.
And Arduino uses 9600 bps as default, but even 115200 bps is nothing for a processor of today.
@SpeedBall @Daid Well from the post the author is far more worried about over flowing the MCU buffers and not the PC.
It all comes down to what you are doing with the data coming in and the baud rate. But I like to fallow a simple rule. Make it always work. If you add handshaking it will never over flow the buffer so why not use it if you can?
It makes me sad to see people still using serial ports. Maybe we should go back to carrier pigeons?
(full sarcasm here)
@ dext3r – true that. For most of my MCU projects, if it’s PCMCU communication I need, I use USB. If it’s MCUOther IC communication, I use I2C bus. Super robust with built in error checking/ACK, I2C can be very fast (up to 1 mb/s)
@lwatcdr: Yes, that’s what I’m worried about — the PC overflowing the MCU. I really want to write my code as getchar, do something with it, including writing stuff back to the pc, repeat until sun burns out. if i did that without flow control, and without any silly sleeps on the PC, incoming commands which arrived during the “do stuff” phase would routinely get dropped or corrupted. RTS/CTS seemed like the obvious fix for that.
@dext3r: I used serial because it’s easy to understand, and easy to implement. As I’m still getting my toes wet in this embedded world, I wanted something that I could make work, reliably, without a need to learn a USB framework (which would’ve isolated me from the bit-banging details I wanted to learn in the first place). I’m sure I’ll have plenty of time/desire to play with raw USB at some point in the future — just not now.
@Matt
Note: Nothing against hardware handshaking.. I’m thinking of doing this once I find a CP2102 board that breaks out the signals (I’m cheeeeeap).
>>overflowing the MCU.
Not sure about the AVR, havent used one in ages.. but the UARTs on the ARM board I have been playing around with recently have interrupts that trigger on various levels.. so the FIFO is 16 deep, interrupt triggers on 14 bytes in buffer. So you have enough head room to jump into an ISR and move the data out into a bigger buffer (I’m moving TCP/IP over SLIP and feeding it into a ring buffer and processing when there are enough bytes for a packet, it works pretty well). You could trigger sooner if you a really worried. The only issue is if the sender refuses to stop sending data so you are forever in the ISR..
>>I really want to write my code as getchar,
>>do something with it, including writing
>> stuff back to the pc,
Unless your protocol is really simple that a command can fit into a byte you should be letting the FIFO do it’s job and collect the data only when there is something worth processing..
>>repeat until sun burns out.
Hardware handshaking doesnt stop data corruption.. you need some sort of transport that insures the data is correct before it gets to your business code.. having that would also work around any bytes that get lost from an overflowing FIFO as long as you don’t overflow all the time.
>>if i did that without flow control,
>>and without any silly sleeps on the PC
You can implement handshaking in software..
I.e. have your MCU send back “ok, send me more” every fifo full or something.
RTS/CTS are not request/acknowledge signals.
RTS is used to meter the flow of data from the DCE (the AVR) to the DTE (the PC).
CTS is used to meter the flow of data from the DTE (the PC) to the DCE (the AVR).
In the example above, the PC is always ready to accept data, so RTS is always asserted. But the AVR is not always ready to accept data, so CTS will tell the PC to hold off sending data until the AVR is ready.
@cantido: I dream of buffers that large. IIRC, the ATMega buffer is one byte. Maybe two. There’s also a lot to be said for not having to write ISRs, and for not having to deal with the interaction between said ISRs and normal code. That’s not to say that the approach you’re suggesting isn’t appropriate in some situations — it certainly is. It’s just that my application is simple enough that I don’t think I need that added complication.
As to corruption, I wasn’t talking about a 1 turning into a 0 as it flies across the wire. I’m talking about what happens when you miss a few bytes due to the overflow, and end up with a command that looks sane but is actually the concatenation of bits of two separate commands.
The disconnect here may be in that you’re talking about applications which are orders of magnitude more complicated than what I’m going to use this for. I’m doing simple question/response stuff. Rather than “implement TCP/IP”, think “turn on pin 3” or “is pin 7 high”. The code running on the MCU can be ridiculously simple if I don’t have to worry about buffering the input. Hardware handshaking frees me from that worry.
@Ag Primatic: It looks like RTS/CTS can be used as request/ack or, as you described, for bidirectional metering. See
http://en.wikipedia.org/wiki/RS-232#RTS.2FCTS_handshaking
I’ll add an addendum to the post.
@Matt
>>IIRC, the ATMega buffer is one byte.
USART0 seems to have a one byte for the incoming byte and one for a waiting byte.. that’s to give you enough time to move the waiting byte out of the way (into a bigger buffer in RAM). What I would do is 1: Wait for an interrupt to fire from the UART, 2: collect all the bytes coming in up to some byte/time limit, 3: set a flag that there is data waiting, 4: let the main loop come and get it. 3a would be check the checksum attached to the end of the “packet” to make sure I have all the bytes I’m meant to.
>>said for not having to write ISRs,
I’m not sure if USART0 interrupts can wake up the AVR (I’m not even sure how sleep works on the AVR). But if you are always polling stuff you are never sleeping or doing stuff you could otherwise be.. like blinking an LED.
>>command that looks sane but
You could miss bytes even with handshaking.. if getting bad data might cause something bad to happen you should check it.. if your proto is only a byte per command parity is good enough I suppose.
>> Rather than “implement TCP/IP”,
I think the concerns are the same (the amounts of data are different, but I have 16bytes of FIFO and 75Mhz of processing power so it works out even I think).. you want your commands to get delivered to your MCU without data getting lost so you really want some sort of resend request and acking ability.. once you have that as long as you don’t drop bytes all the time you wouldn’t hardware handshaking. (Though its always nice to have).
@fartface
I don’t know dude, if you don’t know what you are doing (with a good amount of experience) chances are RS485 would be really hard. I tried a 200Ft communication with RS485 and spend 2 days (around 18 hours) working on the thing.Even by the end of 2 days the thing was not 100% Okey. Don’t know where the problem was, but most probably it was the chip(mas458)
@matt your doing fine. I ran into the same problem years ago but it was with PCs. The PC was reading data dumped from a program that ran on an old CTOS machine. To get the data out we had to use the print function and the program didn’t offer anyway to set the flow control. So we had to take the data at 9600 baud. The problem was that the program needed to do a lot of processing with the data so a 40mhz 386 couldn’t keep up. And yes that was a fast machine at that time. We had to capture the data to the disk first and then process it after the dump was done.
You can ack nak commands if you want but I think your solution is just fine.
@matt–now you have me wondering how to tell a PC which mode to use.
In all the times I’ve used a PC serial port, it just has a setting for Hardware Flow Control. Not a choice for request/ack mode or bidirectional metering mode.
XON/XOFF should be enough unless the line is so bad that characters become XON/OFF when not intended.
@Ag: A bidi host talking to a request/ack peripheral is just a degenerate case of bidi/bidi. That is, when the request/ack peripheral waits for RTS from the host before it uses CTS to signal that it is ready to receive data, it’s taking actions that are legal under the bidi regime. That is, waiting for RTS from the host won’t mess up the bidi scheme — it’s just unnecessary. So if you have a bidi host (which I assume most/all are these days), you’ll magically work with both bidi and req/ack peripherals. Things seem like they’d get dicey if you had a request/ack host and a bidi peripheral, but I’m guessing that that’s pretty rare.
RS232 is a very widely violated specification. The use of RTS/CTS is a particular area of messiness. Originally, and per specification, the CTS/RTS handshake is about “turning around” half-duplex modems. The local DTE (eg computer) would indicate to the modem that it had data to send by asserting RTS. The DCE (modem) would (though a mechanism dependent on the type of modem, not included in the rs232 specification) negotiate with the remote modem to do whatever was necessary to switch the data direction, and then it would assert CTS to tell the DTE that it was OK to actually send the data.
You’ll note that half-duplex modems have been pretty rare since, say, the mid 1970s. Meanwhile, the use of rs232 for local data connections increased. And that half-duplex was rarely an issue for local communications.
So someone at some point decided that RTS/CTS could be used for “flow control” instead of modem switching. It’s a natural enough thought; if CTS untrue means “don’t transmit”, it shouldn’t really matter to equipment whether that’s “don’t transmit because the modem is doing magic” or “don’t transmit because my buffers are getting full.” The handling of RTS is different, though. For a local connection using flow control, RTS is (or can be) exactly symmetric with CTS – it gets connected to the other side’s CTS, and you assert RTS if you can receive data, and listen to CTS to see if you can send data. (which is different than the “assert RTS when you HAVE data to send” of the original spec.) (since the original devices that needed “hardware flow control” were things like printers where the reverse direction was not used, the original behavior of RTS was probably a bit … unspecified.)
The implementation here is an interesting exercise, but I think it’s somewhat confused as to whether it is following the older rs232 (modem oriented) specifications or the more modern and common (and never “standardized”, AFAIK) flow-control behavior.
@dext3r: try using USB over distances longer than 5 meters … And do USB at 100 meters = I owe you 20 bucks. RS232 has no problem even at several hundred meters, with reduced data rate.
Also, implementing USB communication in many lower cost MCUs is a pain.
@WestW: Thank you for the concise summary of the two different RTS/CTS methods.
From Matt’s pointer to the Wikipedia entry on RS-232, it does say that the bidirectional flow control behavior was standardized in ANSI/EIA/TIA-232-E. From the Wikipedia references, here’s a usenet post from 1990 describing it: http://groups.google.com/group/comp.dcom.modems/msg/39042605325cc765?dmode=source