views:

351

answers:

7

I am sending data from a linux application through serial port to an embedded device.

In the current implementation a byte circular buffer is used in the firmware. (Nothing but an array with a read and write pointer) As the bytes come in, it is written to the circular bufffer.

Now the PC application appears to be sending the data too fast for the firmware to handle. Bytes are missed resulting in the firmware returning WRONG_INPUT too mant times.

I think baud rate (115200) is not the issue. A more efficient data structure at the firmware side might help. Any suggestions on choice of data structure?

+1  A: 

There is nothing better than a circular buffer.

You could use a slower baud rate or speed up the application in the firmware so that it can handle data coming at full speed.

If the output of the PC is in bursts it may help to make the buffer big enough to handle one burst.

The last option is to implement some form of flow control.

starblue
A: 

You could implement something like IP datagram which contains data length, id, and checksum.

Edit: Then you could hard-code some fixed length for the packets, for example 1024 byte or whatever that makes sense for the device. PC side would then check if the queue is full at the device every time it writes in a packet. Firmware side would run checksum to see if all data is valid, and read up till the data length.

eed3si9n
What? How does this answer the question?
Matthew Flaschen
+12  A: 

A circular buffer is the best answer. It is the easiest way to model a hardware FIFO in pure software.

The real issue is likely to be either the way you are collecting bytes from the UART to put in the buffer, or overflow of that buffer.

At 115200 baud with the usual 1 start bit, 1 stop bit and 8 data bits, you can see as many as 11520 bytes per second arrive at that port. That gives you an average of just about 86.8 µs per byte to work with. In a PC, that will seem like a lot of time, but in a small microprocessor, it might not be all that many total instructions or in some cases very many I/O register accesses. If you overfill your buffer because bytes are arriving on average faster than you can consume them, then you will have errors.

Some general advice:

  • Don't do polled I/O.
  • Do use a Rx Ready interrupt.
  • Enable the receive FIFO, if available.
  • Empty the FIFO completely in the interrupt handler.
  • Make the ring buffer large enough.
  • Consider flow control.

Sizing your ring buffer large enough to hold a complete message is important. If your protocol has known limits on the message size, then you can use the higher levels of your protocol to do flow control and survive without the pains of getting XON/XOFF flow to work right in all of the edge cases, or RTS/CTS to work as expected in both ends of the wire which can be nearly as hairy.

If you can't make the ring buffer that large, then you will need some kind of flow control.

RBerteig
I am not sure doing IRQ driven recpetion is always : - available - desirable
shodanex
IMHO, polled IO is troublesome because it requires that the code be able to check for the next character in time. On a really small processor, it might be your only option, however. On larger processors, polling can be significantly less efficient than using interrupts or DMA.
RBerteig
+1  A: 

What do you mean by embedded device ? I think most of current DSP and processor can easily handle this kind of load. The problem is not with the circular buffer, but how do you collect bytes from the serial port.

Does your UART have a hardware fifo ? If yes, then you should enable it. If you have an interrupt per byte, you can quickly get into trouble, especially if you are working with an OS or with virtual memory, where the IRQ cost can be quit high.

If your receiving firmware is very simple (no multitasking), and you don't have an hardware fifo, polled mode can be a better solution than interrupt driven, because then your processor is doing only UART data reception, and you have no interrupt overhead.

Another problem might be with the transfer protocol. For example if you have long packet of data that you have to checksum, and you do the whole checksum at the end of the packet, then all the processing time of the packet is at the end of it, and that is why you may miss the beginning of the next packet.

So circular buffer is fine and you have to way to improve : - The way you interact with the hardware - The protocol (packet length, acknoledgment etc ...)

shodanex
yes, before replacing the underlying data structure, first make sure that this really is the bottleneck you are seeing
none
+1  A: 

Before trying to solve the problem, first you need to establish what the problem really is. Otherwise you might waste time trying to fix something that isn't actually broken.

Without knowing more about your set-up it's hard to give more specific advice. But you should investigate further to establish what exactly the hardware and software is currently doing when the bytes come in, and then what is the weak point where they're going missing.

Craig McQueen
I agree. I've wasted too many hours with embedded applications trying to fix something where the actual problem was somewhere else.
guzelo
A: 

A circular buffer with Interrupt driven IO will work on the smallest and slowest of embedded targets.

First try it at the lowest baud rate and only then try at high speeds.

Gerhard
A: 

Using a circular buffer in conjunction with IRQ is an excellent suggestion. If your processor generates an interrupt each time a byte is received take that byte and store it in the buffer. How you decide to empty that buffer depends on if you are processing a stream of data or data packets. If you are processing a stream simply have your background process remove the bytes from the buffer and process them first-in-first-out. If you are processing packets then just keep filing the buffer until you have a complete packet. I've used the packet method successfully many times in the past. I would implement some type of flow control as well to signal to the PC if something went wrong like a full buffer or if packet-processing time is long to indicate to the PC when it is ready for the next packet.

mjh2007