2
\$\begingroup\$

I want to receive and send packets via UART. The problem is that I don't want to immediately react on a received byte but on a certain sequence. That sequence consists of 4 UART bytes and shall only be evaluated when its completely received.

What's the best way to do that? Creating just an array that fits the 4 bytes and once I received 4 bytes just check if its correct or would a larger ring buffer be better, where all receiving bytes are stored sequentially? (not sure how to implement that)

Example of a transmission:

-PC sends out zeros as long as it doesn't get any response

-a little microcontroller board is connected and receives the bytes

-if 4 bytes of zero are received by the micro, it shall transmit its 4 bytes to the PC

-the PC sees the data on its TXD and stops sending the zeros and does what was requested by the micro. When it's done the PC sends 4 bytes back to the micro to acknowledge its request and tell it that everything is ready.

What's the best way to implement something like this?

\$\endgroup\$
  • 1
    \$\begingroup\$ What (in the bigger picture) are you trying to achieve? \$\endgroup\$ – Andy aka Nov 22 '15 at 22:40
  • 1
    \$\begingroup\$ Ring buffering and pulling at convenience to assemble into packets which are processed when complete is workable and conceptually simple. Buffering which triggers processing on completion of a packet is possibly more tuned to a specific application, but not necessarily worth the trouble unless there is an issue with the first approach. \$\endgroup\$ – Chris Stratton Nov 22 '15 at 22:43
  • \$\begingroup\$ @Andy aka i want to calibrate a device (or better various types of devices). The PC sets up a requested voltage. Every device knows it's type and requests that specific voltage it needs. When the PC is ready, it should tell the controller that it can start the measurement with the ADC. \$\endgroup\$ – JavaForStarters Nov 22 '15 at 23:03
  • \$\begingroup\$ @canbus The internal design of the hardware buffer associated with a UART varies from one microcontroller family to another. Do you have a specific microcontroller in mind? \$\endgroup\$ – Nick Alexeev Nov 22 '15 at 23:04
  • \$\begingroup\$ @Chris Stratton in a ring buffer arrangement, I would need to count the incoming bytes and increment two pointers, one for the data position and one for the last read data, am I correct? \$\endgroup\$ – JavaForStarters Nov 22 '15 at 23:06
3
\$\begingroup\$

First I recommend a protocol, a frame structure, ideally a start pattern that is not found in the data or if found wont be repetative, or have a start pattern and a checksum. In any case you have to do your system engineering/design to make sure that you are not operating on the wrong bytes or bytes in the wrong position.

Second, do your system engineering, what is your data rate what is the processing and execution rates. If for example you can process the four bytes worth of data within one byte transmission time with enough time to spare, then that would make for a simpler solution. You obviously have to store the 4 bytes of information somewhere be it in the uart if the uart has a fifo deep enough or outside the uart if not.

Well, actually does the host have to be constantly transmitting something or is it, or can the protocol be one burst of a packet to you then you burst an answer back? The question for your system design is do I have to be handling new bytes coming in while I am processing an existing request?

If you have to be handing data while processing other, and it takes more than one byte time to process a packet, even if so it is probably better to plan for a circular buffer, the size you likely have to tune because you probably dont have enough resources to make it big enough to not care. Also you have to plan to insure that while processing the current data you are collecting the new data (if the protocol requires you to handle more than one at a time). Interrupts may come into play here, but are tricky to get working, interrupts are not a required solution, but often how folks choose to do it.

if you go with a packet/frame approach, then you definitely need a fifo that is collecting at least a packets worth of data, each new byte that comes in shifts the data through a window (or better use a circular buffer and shift your head and tail pointers around) once you have a start pattern and at least the right number of bytes for the packet, then checksum it if that is how you choose to implement, and if passes process it, if not dont toss the whole thing just move the head pointer around to the next start pattern if there is any in the accumulated data, otherwise match it to the tail and wait for more.

if you are sending data back, same deal what is the protocol for that, frame/data format? Assumed to be the same baud rate, so if as you mention you accept four and send four back, it takes the same time in each direction, even if it takes a small number of mcu clock cycles to process the data, it still takes a lot of clock cycles to send it back out at that baud rate, if the hardware does not have a tx fifo and you protocol is not half duplex then you will need to be handling waiting for a tx slot to open, moving the next byte in there from some buffer/ring. the waiting can be polling or interrupts, same answer a above, doesnt HAVE to be either kind, can be what you are comfortable with and what works, for TX it is a lot easier unless the protocol has a timeout, as you cannot lose bytes on the way out, if your code isnt fast enough you simply add gaps. On the RX side if the world you can lose bytes if you are not fast enough.

All of this is very basic stuff and hopefully not stuff you already knew and had figured out. Start simple, send one blob of data from the pc, somehow indicate from the mcu to your debug solution (for me it is printing stuff out a uart or blinking an led) that you have the data. Either then develop the response with bogus data, or develop the processing step next. Basically do your system engineering, break the problem down into bite sized chunks, define the interfaces between the chunks, and develop each chunk and then glue them together, the boundaries between the chunks are opportunities if needed to place test code/instrumentation to test that chunk. Some of these chunks might be able to be developed on a host computer using a common programming language (C is a good one) with a test fixture around the code, that would only be for generic processing of course, if you have any mcu/board hardware specific resources required then you would either have to simulate that on a host (more code to develop and test to wrap around the code under test). That doesnt necessarily mean a simulator for that environment but finding/developing one might be useful. It all depends on how hard the problem becomes.

Performance, when I said a bytes worth of time, understand that simply adding or removing a line of code can change the performance of the code by a noticeable amount 10% 20% or more. Even the same code with its alignment changed (more or fewer instructions in the bootstrap) can and sometimes will change the performance of the code as much as 10% or 20% or more. Simply clocking the mcu up by a factor of N to get more performance does not make the same code run N times faster, esp if the flash is slower than the max speed of the mcu clock and you have to put additional wait states as you increase the mcu speed to try to compensate for processing requirements. Consider running from sram if you have enough if you run into this but there are no guarantees that the ram or memory interface was designed to run without wait states for higher clock speeds either. Likewise the cpu clock might be able to go one rate, but that doesnt mean the peripheral busses are on that clock. the only way through this is to test and measure (Michael Abrash Zen of Assembly language, look past the x86 nature of that book at the core concepts of finding cycle stealers, can be found free on github afaik)

very short answer, do your system engineering, does the hardware have a buffer, what other resources do you have. how much storage do you need for the communications in order to not lose data or get behind. Obviously you have to store up some number of bytes before you can do the processing so you need at least that much storage. How much beyond that is up to your protocol and analyzing how long it should take to do things. Or design the protocol to be a half duplex handshake and take as much time as you want.

\$\endgroup\$
3
\$\begingroup\$

If the data reads have to be generic, for example you are parsing multiple text strings, then indeed you'll have to implement a FIFO ring buffer (which is rather trivial, should be plenty of code for that on the internet).

If the data is not generic, but rather just one single constant sequence, such as a synch word, then you don't need a buffer. Simply read character by character.

Conceptual pseudo code:

#define LENGTH 4

void read_uart (void)
{
  static const char sync [LENGTH] = "WORD";
  static uint8_t counter = 0;

  char ch;

  uart_err_t error = uart_receive(&ch);

  if(!error && ch == sync[counter])
  {
    counter++;
  }
  else
  {
    counter=0; // reset

    if(error)
    {
      // handle errors, frame/overrun error etc etc
    }
  }

  if(counter == LENGTH)
  {
    // whole sync word found, everything ok
  }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.