Faster sampling rate possible?

I am using Arduino Due and I am using the following code to read a sampling rate from the serial monitor, and than transmit data read from ADC via serial with that transfer rate. Is there a more efficient way than the following code?

unsigned long Ts, Samp=10;
String inString = "";

void setup() {
  Serial.begin(115200);   
}

void loop() {
  while (Serial.available() > 0) {
    int inChar = Serial.read();
    if (isDigit(inChar)) {
      inString += (char)inChar;
    }
    if (inChar == '\n') {
      Samp = inString.toInt();
      inString = "";
    }
  }
  Ts=micros();                                  // Time at start
  Serial.print(analogRead(A0));                 //Send ADC
  Serial.print(',');    
  Serial.println(millis());                     // Send time spent
  unsigned int Tw=(1/(double)Samp)*1000*1000 - (micros() - Ts);

  delayMicroseconds(Tw);    
 }
 while (Serial.available() > 0) {
    int inChar = Serial.read();
    if (isDigit(inChar)) {
      inString += (char)inChar;
    }
    if (inChar == '\n') {
      Samp = inString.toInt();
      inString = "";
    }
  }

This won't work. It assumes that the whole of the what ever it is will be available. In fact it won't be. Have you run this code?

Mark

Yes, and it works. I don't understand what wouldn't? I enter i.e. 9000 in serial monitor, it receives all bytes until eol. Then converts to integer.

MartinV279:
Is there a more efficient way than the following code?

  Serial.begin(115200);

What do you mean by "more efficient way "?

At least a higher baudrate would create a faster communication:

  Serial.begin(500000);

But you'd have to use a "serial terminal emulation software" instead of the "Arduino serial monitor", as the serial monitor is limited to 115200 baud max., but neither the Arduino board nor your PC has such a low baudrate limit for Serial data. With Arduino boards you can also use 250000 or 500000 baud rate.

Well you answered my question actually. I set the prescaler as low as possible, but the serial communication was making the delay. I didn't know that I can set it up to 250k or 500k, and I will try that now. I am supposed to have a sampling rate greater than the one with my current program. I wanted to know if it is possible to do so.

I did an experiment (some eons ago) to split up the analogRead to gain time, might be worth a read

Actually I didn't find the ADC to be making a problem, it's the communication instead.
This is my output. The first line is the data I send ("AD0 input" "," "Time since start"). The thing is that I need to make it to be able to send 10k samples per second. Serial print is taking too much, and this is with 115200 baud. Any ideas?

1023,2371
AD conversion micros: 8
Serial print time : 504

So I changed the code a bit and @2 000 000 baud rate I get the speed of 1 byte per 54 us. With 16 MHz (now working on Uno) that makes it 864 clock cycles per byte. Is there a way to make this faster? I am not familiar with AVR, so that's way I am asking this.

The number of clock cycles per byte is determined by the baud rate. If the data is being sent by the USART then the clock is not at all involved in sending characters.

When I did some tests with my Uno (a while back) the actual data transfer rate seemed to match the baud rate very closely up to 500,000 baud (I can't remember if I tried it at 1,000,000. If you use a Leonardo or other Arduino with a 32U4 MCU it can send data at the full USB speed - the baud rate is effectively ignored.

I wonder are you running up against USB limitations. USB is very slow when sending single characters. It works best with full 64-byte buffers.

...R

I'm going with the basic USB COM on Arduino. You think I should try with USART? But then again, I will have to connect it with a TTL-USB module since I need to graph the data for reconstruction of signal.

MartinV279:
So I changed the code a bit and @2 000 000 baud rate I get the speed of 1 byte per 54 us. With 16 MHz (now working on Uno) that makes it 864 clock cycles per byte.

I don't know how you can create a 2 Mbit/s baud rate with an Arduino UNO.
2000000 baudrate is not possible with Arduino UNO.

With an Arduino UNO @16 MHz and a baudrate of 500000 bit/s you can send 50000 characters per second, this is 1s/50000 = 0.00002s = 0.02ms = 20µs per character.

If you are sending lines like

1023,1234567

with additional two line ending characters (CR, LF), this is 14 characters per sample.
This will take 14*20 = 280 µs per sample.
So @500000 baud you should get 1000000/280= 3571 lines (samples) per second with an UNO and "Serial" to be the bottleneck in transmission with 14 characters sent per line/sample.

Currently you are also sending much more characters for timestamp and line ending than for ADC values by design.

I mentioned the Uno because I don't have the Due currently, eventually it will be running on Due. My question was more theoretical because I will not have much time with the Due before I run the code. I guess it will work better but will not get to 10k Samples/s even with 1M baud or 2M baud.

To speed up serial comms even more send the raw ADC reading as two bytes instead of converting to an ASCII string and potentially sending 4 bytes + 2 byte end of line <CR..
To keep the raw data synchronized so you know when your reading the high/low byte of the ADC over serial you can do a bit of bit shifting before sending and reverse it at the receiving end.

ADC reading is 10 bits so highest reading can only be...
0b0000001111111111
shift 16 bits left 1
0b0000011111111110
and then send the low byte shifted right 1 (to clear the top bit)
0b01111111
and then send the high byte with the top bit set)
0b10000111
at the receiving end the high byte will always have bit 7 set and for the low byte it is never set. So if the value read from serial is > 127 then you know it's the high byte.
Just reverse the above process to reconstruct the 10 bit ADC reading in a raw form.

MartinV279:
I'm going with the basic USB COM on Arduino. You think I should try with USART?

I think there may be a big problem of technical terms here - if this comment refers to my Reply #8

The USB comms on the Uno work THROUGH the USART.

This leads me to wonder if a lot of the other content in the Thread may be confused.

Let's get back to basics...
The maximum sampling rate for an Atmega 328 is about 15kSps at full 10-bit resolution.
Suppose each sample takes 2 bytes that means 30,000 bytes per second.
It should be perfectly possible to transmit that with a baud rate of 500,000.

What is the maximum sampling rate that you want to achieve?

...R

I intend to achieve sampling rate of 10k samples per second. I should send data of type "1023,2371" 10k times in 1 second. The first slot is for the analogRead(A0) input, the second is for millis().

some thoughts:

Note at 10K samples you will have 10 samples with the same timestamp in millis. Better use micros.

instead of hard sending the value of micros(), sent the delta since last time stamp.
That would mean that instead of 6,7,8,9 digits you will mostly send 3. That is reduction of 5 digits to sent.

Same trick can be done with the ADC value.

And of course you could use RunLengthEncoding. Same values need not to be resent.

The main problem that I intended to emphasize (and with my non-technical English failed badly) is that Arduino Uno @ 2 000 000 baud rate needs approximately 54 microseconds to send one byte via Serial. In order to achieve 10k Samples/second, it should send the entire data within 100 microseconds. This leaves time for 2 bytes at most. Yes it can be done by sending the ADC infro as HIGH and LOW register, but I need the time stamps also as the receiving end is not supposed to calculate them.

I have not tried 2,000,000 baud but it should, in theory, allow you to send about 200,000 characters per second - or about 5 µsecs each. However I suspect that at that speed you are running into limitations within the Arduino. At 16MHz it can't do very much in 5µsecs. You may get much the same actual throughput at 500,000 baud.

Have you done any tests in which you just send data without any ADC or other activity? That is the only way to get an accurate indication of transmission throughput.

In any case, if you have a 2-byte ADC reading and (say) a 1-byte time delta plus a start and end character you will only need to send 5 bytes per reading - about 50,000 per second. The trick is to use Serial.write() rather than Serial.print().

And going back to my earlier comment about the USB system being a bottle-neck I think it would be worth checking whether you would get better throughput if you assemble, say 20 readings and send them as a batch. Then you have 60 data bytes and a start and end marker.

But make sure you do all of this testing without any other activity to disrupt the process.

...R

MartinV279:
The main problem that I intended to emphasize (and with my non-technical English failed badly) is that Arduino Uno @ 2 000 000 baud rate needs approximately 54 microseconds to send one byte via Serial. In order to achieve 10k Samples/second, it should send the entire data within 100 microseconds. This leaves time for 2 bytes at most. Yes it can be done by sending the ADC infro as HIGH and LOW register, but I need the time stamps also as the receiving end is not supposed to calculate them.

If your sampling at fixed time intervals then you probably only need to send the timestamp with the first sample and the receiving program can calculate the time each subsequent sample was taken.
Another trick to save time would be to reduce the number of bits sent from 8N1 to 5N1 or 6N1.

Beyond this your getting into the limits of serial. Maybe the Due (or Leonardo) with a native USB port will transfer a lot quicker.

Well I guess the best way is to decrease ADC to 8 bit precision and maybe send the time difference from sample to sample. That way it will be almost 2 bytes and the transfer will be maximized. Thanks everyone, so it was the basic performance that met the limits. I understand now, I should optimize the code.