Baudrate - Analog Data Serial Data Tramission

Hey everyone,

I have a problem with my data acquisition with an Adafruit Metro M4 Express board.

I am trying to read the analog input at 11 kHz, since the Bandwidth of the sensor is 11kHz.

The ADC of the Metro M4 can sample at 1 MSPS and the MCU is a Cortex M4 core running at 120 MHz. It runs on the Arduino IDE.

I am using a standard script to read the analog input and print it to the serial console.

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

void loop() {
  // read the input on A0 at default resolution (10 bits) and send it out the serial connection
  analogReadResolution(16);

  int sensorValue = analogRead(A1);
  // Convert the analog reading (which goes from 0 - 65536) to a voltage (0 - 5V):
  float voltage = sensorValue * (5.0 / 65536.0) - 3.870498;  // Subtract offset 
  // print out the value you read as human-readable ASCII text followed by a carriage return character (ASCII 13, or '\r') and a newline character (ASCII 10, or '\n'):
  Serial.println(voltage, 6);

}

On the other side I used a python script and cool term to receive data and write it to .txt and .csv files. For some reasons the maximum number of readings per second that I receive is around 1800. (1.8kHz)

What seems weird is, if I change the Baudrate from 300 up to even 2000000, the sample rate of 1.8kHz of the received data doesn't significantly change.

I am trying since a few days, since I am quite new to arduino and python and can not figure out where is the bottleneck?

I am wondering, whether it is the serial.println() function. But, to conclude my questions are:

  1. Where is the bottleneck?
  2. How can I test different options? - (Already tried to eliminate the baudrate)
  3. Could it be the HW?
  4. Why does the sample rate of 1.8kHz of received data doesn't change, if I increase the Baudrate?

Any help is greatly appreciated!! :smiley:

Try the program without the float calculation - just print the value from analogRead(). If that makes no difference then it must be analogRead() that is the limiting factor.

I am not familiar with the fast Arduinos.

...R

Hi Robin,

thanks for your answer. Without the float calculation the sampling rate increased to ~2.4kHz.

Does anyone have an idea how to increase sampling rates of the analog input using arduinos or adafruit boards?

Thanks!

P

Pumpa0815:
Does anyone have an idea how to increase sampling rates of the analog input using arduinos or adafruit boards?

You will probably need to study the datasheet for your microprocessor and maybe write some code to directly access the registers that control the ADC

...R

Hi,

Please, tell me if I am wrong (no rethorical statement):

(115200 bits/sec) / (16 bits/sample) = 7200 samples / sec

This an optimistic calculation: Does not take into account the times to prepare info, receive it, ...

Regards.

Vicente.

(In fact it is even worse; it is transmitted as a float ...)

I agree, but even if I send only the analogRead() value as an int, which is supposed to be 8 bit at a baudrate of 230400, I only get a sampling rate of 2363 Hz with this Adafruit Metro M4 board. With Arduino it's supposed to give around 9600Hz.

void setup()
{
  Serial.begin(230400);
  pinMode(A0, INPUT);
}

void loop()
{
  long t0, t;

  t0 = micros();
  for(int i=0; i<1000; i++) {
    analogRead(A0);
  }
  t = micros()-t0;  // calculate elapsed time

  Serial.print("Time per sample: ");
  Serial.println((float)t/1000);
  Serial.print("Frequency: ");
  Serial.println((float)1000*1000000/t);
  Serial.println();
  delay(2000);
}

It is quite possible that a board with a Cortex MCU just ignores the baud rate and sends data at full USB speed. That is what happens on a Leonardo and Micro. Hence changing the baud rate would have no impact.

Also, USB does not have a very high throughput for small chunks of data. It may be worth capturing several readings into an array and only sending data when the array is full.

...R

Pumpa0815:
On the other side I used a python script and cool term to receive data and write it to .txt and .csv files. For some reasons the maximum number of readings per second that I receive is around 1800. (1.8kHz)

Hi,
What have you got on "the other side" (a PC)?
Regards

@ Robin

Robin,
I am a little confused: does not imply the "serial.begin" as used by the O.P. an "external" (not USB) serial connection?
Thanks
Regards

Thanks for your help!

vffgaston:
Hi,
What have you got on "the other side" (a PC)?
Regards

The python code I used to receive data, is the following:

import serial
import time
import csv

# Initialize values for Serial input
seconds = 1                     # Number of seconds to record
bandwidth = 10000               # Frequency Range of Sensor
baudrate = 115200               # Baurate must be equal to baudrate of Adafruit Metro M4
dc_offset = 0                   # Offset to adjust sensor reading to 0
port = '/dev/tty.usbmodem1411'  # set the correct COM port before run it // Can be found by ls /dev/tty.*

# Initialize Serial Connection
ser = serial.Serial(
            port = port,
            baudrate = baudrate,
            timeout = 0
                )
#ser.flushInput()
#ser.timeout = 0.1               # set read timeout

# print z1serial                # debug serial.
print(ser.is_open)              # True for opened
if ser.is_open:
    #while True:
    time_stamps = []
    data_stream = []
    for i in range(0, seconds * bandwidth):
        size = ser.inWaiting()
        if size:
            bytes = ser.readline()
            time_stamps.append(time.time())
            decoded_bytes = float(bytes[0:len(bytes)-2].decode("utf-8"))
            data_stream.append(decoded_bytes)
            data = time_stamps, data_stream
        else:
            print('no data')

else:
    print('z1serial not open')

print(len(data[0]))
with open("test_data.csv", "a") as f:
    writer = csv.writer(f, delimiter=",")
    writer.writerows(data)
print(data_stream)

On the other side with Coolterm from the speedtest:

Pumpa0815:
I agree, but even if I send only the analogRead() value as an int, which is supposed to be 8 bit at a baudrate of 230400, I only get a sampling rate of 2363 Hz with this Adafruit Metro M4 board. With Arduino it's supposed to give around 9600Hz.

void setup()

{
  Serial.begin(230400);
  pinMode(A0, INPUT);
}

void loop()
{
  long t0, t;

t0 = micros();
  for(int i=0; i<1000; i++) {
    analogRead(A0);
  }
  t = micros()-t0;  // calculate elapsed time

Serial.print("Time per sample: ");
  Serial.println((float)t/1000);
  Serial.print("Frequency: ");
  Serial.println((float)1000*1000000/t);
  Serial.println();
  delay(2000);
}

I received:

"Time per sample: 423.12
Frequency: 2363.38"

@Robin2: In this speedtest, the analog values are not printed to the serial, but only the time to sample is measured and the result is printed.

I have another question:
Would you recommend me to communicate over serial, or is there a better solution? Just to note, I do not have an SD card reader and I want to sample in real-time.

Thanks for your help!
Kind regards
P

vffgaston:
I am a little confused: does not imply the "serial.begin" as used by the O.P. an "external" (not USB) serial connection?

I have been assuming the OP is using the standard USB connection to a PC - of course I may be wrong, no doubt he will tell us.

With the standard USB connection between a Leonardo and a PC you do require a Serial.begin(bbbb) instruction but the baud rate described by bbbb is ignored.

On an Uno (for example) the baud rate is only used for communication between the Atmega328 chip and the 16U2 chip that provides the USB interface.

...R

Robin2:
I have been assuming the OP is using the standard USB connection to a PC - of course I may be wrong, no doubt he will tell us.

You are correct, I using a standard USB connection to a Mac.