Go Down

Topic: how to know buffered serially received data? (Read 3761 times) previous topic - next topic

ironbot

Hi,
My Arduino in receiving Serial data from another device. Well I learned to check the arrival of data with Serial.available(), but is there any way to know actually how many bytes are currently buffered "in" my Arduino Atmega168 chip? What is the real mechanism? if the buffer of Arduino is full, the device sending data will be wait right? I hope so :D

nospam2000

Hi ironbot,

the ATMega168/328 only has a one byte buffer for the received serial data, therefore there needs to be a software buffer which is implemented in HardwareSerial. This software buffer has a size of 128 bytes.

There is no hardware handshake (CTS/RTS) or software handshake (Xon/Xoff) implemented in the Arduino libraries because it would make hardware and software more complicated. The other side of the cable will never know if your Arduino sketch can process the sent data in time.

 MikeT

ironbot

Thanks!

>implemented in HardwareSerial. This software buffer has a size of 128 bytes.

I still can't understand one thing: what happens when this 128-byte buffer is full? next byte of data being sent is losti f there is not handshaking?

I am completing my sketch so that Arduino receives a command and perform it. So, if my guesses are right, I just program my sketch so that read 128 byte, then after analyzing them send a confirming message so that the device sends next data. I.e. a soft-hand shaking, right? (or there is a better/ready to use mechanism of existed libs I may use?).


nospam2000

Hi ironbot,


From HardwareSerial.cpp:
Code: [Select]
inline void store_char(unsigned char c, ring_buffer *rx_buffer)
{
 int i = (rx_buffer->head + 1) % RX_BUFFER_SIZE;

 // if we should be storing the received character into the location
 // just before the tail (meaning that the head would advance to the
 // current location of the tail), we're about to overflow the buffer
 // and so we don't write the character or advance the head.
 if (i != rx_buffer->tail) {
   rx_buffer->buffer[rx_buffer->head] = c;
   rx_buffer->head = i;
 }
}


You can see, that any received character is dropped, when the receive buffer is full.

How long are your commands / telegrams? You should start analyzing the received characters as soon as possible and not wait until the buffer is almost full. Use short commands.

A handshake doesn't solve the problem, it just moves the responsibility of buffering to the other side of the cable.

 MikeT

ironbot

#4
Mar 28, 2010, 11:05 am Last Edit: Mar 28, 2010, 11:09 am by ironbot Reason: 1
Hi Mike,

I have some sensors and servo motrs connected to my Arduino and the router must be able to read sensors, write value (h/l) to digital pins and turn servos on/off. I plan for this set of commands:
Code: [Select]

@ma180               //motor #1 pulse to: 180 (motors a-z)
@rd12             //read digital pin 12
@ra12             //read analog pin 12
@wd12h            //write to digital pin 12 value high
@wa051023      //write to analog pin 12 value 1023

the '@' I thought is necessary so that I may use strstok() to separate commands. Commands may be accumulated:
"@ma110 mb50 mc100 md80"

The code I have has this at hear (I didn't copy the whole sketch as it is long and yet not very human readable, I'm editing it toward that):
Code: [Select]

void loop()
{
 if(Serial.available()>0)
 {
   
   while( Serial.available() && c != '\n' && sriBufCounter < MAXCMDLEN)  //MAXCMDLEN 128
   {
      c = Serial.read();
      cmdbuf[sriBufCounter++] = c;
   }
   
   analyzeCommand(cmdbuf, sriBufCounter);
   if(sriBufCounter >= sriBufCounter)
       sriBufCounter = 0;
 }
}

void analyzeCommand(char* cmdbut, int sriBufCounter)
{
 if(strcmp(cmdbuf, "this is a test")==0)
   Serial.println("done!");
}


I chose MAXCMDLEN=128 after your kind explanation. I removed all the processing to the router in a Master-Slave style. The analyzeCommand() must:
1. extract the command between '@' and '\n' characters.
2. perform it.
3. return to check if Serial.available().

I still don't fully understand the serial mechanism of Arduino, I need to read the code where you pointed, but for now if possible please let me know your idea: how can I make this code more safe so that to add the guarantee that Arduino won't lose the commands? Am I on the right direction or you see mistakes in coding style?

Thank you!

PaulS

One issue that I'd like to point out is the difference between arrays of characters and strings.

Your serial read code is populating an array of characters. The strcmp function (and strtok and all other strXXX functions) take a string as an argument.

The difference between an array of characters and a string is that a string is a NULL terminated array of characters.

You are not NULL terminating the array of characters, so it is not a string. Eventually, this will bite you.

nospam2000

Hi ironbot,

it's a good idea to have a well defined frame beginning (@) and frame end (\n), so you can always synchronize when losing a character.

The buffer length of your cmdbuf is independent of the serial receive buffer. The cmdbuf must be long enough to hold a complete frame, so when you make your maximum command length very short, e.g. "@wa65535\n" as longest command, you only need only 10 bytes for the command buffer.

I would not allow to concatenate commands. Every single command should start with "@" and be terminated with "\n" because this makes parsing easier and requires a shorter cmdbuf. The serial receive buffer can contain more than one command at a time.

As long as the baudrate is not too high and you don't have too much code, you will be able to keep up with the received commands. I wouldn't use a baudrate above 57600.

With 57600 bps, you have 5760 chars/second which means at least 576 commands/second and therefore a maximum time of 2 milliseconds per command. When your processing for a command needs more than this time, you might lose serial characters.

  MikeT

ironbot

#7
Mar 28, 2010, 11:29 pm Last Edit: Mar 28, 2010, 11:32 pm by ironbot Reason: 1
PaulS
[glow]>Eventually, this will bite you. [/glow]
Thanks! Ok then I will add a '\n' to my character array to avoid being bite ;)

Mike T
[glow]>I would not allow to concatenate commands.[/glow]
The right idea. I just thought about the concatenation for 2 of motors: those who run the navigation. Well if I want to tell the robot to move forward, then I have to try to command both motors (nearly) at the same time. Then a command like:
@ma80 mb100
will be processed right in one function jump. If no concatenation, then @ma80 makes a jump to the processing function and only after putting one motor to work, it is back to wait for the command to come from serial port, i.e. @mb100. Now if for some reason the Linux box delays for sending the next command, the robot is turning when being said to move forward!
May be I'm wrong with this logic?


[glow]>The serial receive buffer can contain more than one command at a time.[/glow]
Could you please explain what do you mean by this, in coding? If I was in Linux only, then I put serial activities in one process, and in the other the command processing and made a pipe between these two processes. Here in Arduino I don't have processes and I won't use interrupt on the serial arival, as it already is on an interrupt. When I receive a command of say 10 byte, then I jump to processing it in another function and I am not there, where the updating of serial data takes place, then how could I have more than one command at a time? I can't understad :(

[glow]>As long as the baudrate is not too high and you don't have too much code[/glow]
Thank you! These ideas for calculations on commands are very clear and helpful. I didn't know them. Before I thought that a high baudrate is necessary to get sensor reading fast! :)

Go Up