Need help with improving the reading speed of Arduino UNO with ADXL377 sensor

Hi, Everyone. I am currently working on a small project to measure the impact (accleration in Gs)when a dropping item hit on the ground.
The instrument I used are: Arduino UNO (with SD shield), ADXL326(it turned out exceeding its limit,didn`t use it), ADXL377. The expectation is to achieve high reading speed from sensor and high writing speed to the card so that the final data would clearly show the trending of changing acceleration during the moment. However, the real results I have got were inconsistent from each drop test and the reading and writing speed was relatively low. It was not able to capture the whole impact process.
I have no experiences of working with arduino before. Here are two sets of code I have learned from the internet and used for this project. I am looking forward to seeing at least 1000 readings per second either on the serial print or SD cards. Really hope someone here can point out the isssues or offer me some advices/recommendations. Thanks ahead of time!

Code 1
This code allow the final data (in Gs) to be printed through both Serial port and SD cards. However, the speed is extremely slow (or the amount of datas it got per second was so limited)

#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"
RTC_DS1307 rtc;
 
const int xInput = A0;
const int yInput = A1;
const int zInput = A2;
const int buttonPin = 2;
const int chipSelect = 10;
const int groundpin = 18;           
const int powerpin = 19;
File dataFile;
// Raw Ranges:
// initialize to mid-range and allow calibration to
// find the minimum and maximum for each axis
int xRawMin = 512;
int xRawMax = 512;
 
int yRawMin = 512;
int yRawMax = 512;
 
int zRawMin = 512;
int zRawMax = 512;

// Take multiple samples to reduce noise
const int sampleSize = 10;
 
void setup() {
  analogReference(EXTERNAL);
  Serial.begin(115200);
  Serial.print("Initializing SD card...");
 
  pinMode(SS, OUTPUT);
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    while (1) ;
  }
  Serial.println("card initialized.");
  dataFile = SD.open("datalog.txt", FILE_WRITE);    
  if (! dataFile) {
    Serial.println("error opening datalog.txt");
    // Wait forever since we cant write data
    while (1) ;
  }     
#ifdef AVR
  Wire.begin();
#else
  Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino Due
#endif
  rtc.begin();
  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
}
 void loop() {
  int xRaw = ReadAxis(xInput);
  int yRaw = ReadAxis(yInput);
  int zRaw = ReadAxis(zInput);
  // Read the state of the button to see if we need to calibrate.
  // This button should probably be debounced.
  if (digitalRead(buttonPin) == LOW)
  {
    AutoCalibrate(xRaw, yRaw, zRaw);
  }
  else
  {
    // Do all of the math first.
    // Convert raw values to 'milli-Gs"
    long xScaled = map(xRaw, xRawMin, xRawMax, -1000, 1000);
    long yScaled = map(yRaw, yRawMin, yRawMax, -1000, 1000);
    long zScaled = map(zRaw, zRawMin, zRawMax, -1000, 1000);
 
    // re-scale to fractional Gs
    float xAccel = xScaled / 1000.0;
    float yAccel = yScaled / 1000.0;
    float zAccel = zScaled / 1000.0;
 
    // Start the printing portion. First with serial to print to the console.
    // Note: When this code is eventually "Production Code", the printing to the 
    // serial console should be commented out to save some execution cycles. 
    Serial.print("  Raw Ranges: X: ");
    Serial.print(xRawMin);
    Serial.print("-");
    Serial.print(xRawMax);
    Serial.print(", Y: ");
    Serial.print(yRawMin);
    Serial.print("-");
    Serial.print(yRawMax);
    Serial.print(", Z:  ");
    Serial.print(zRawMin);
    Serial.print("-");
    Serial.print(zRawMax);
    Serial.print("  Raw Values: ");
    Serial.print(" X: ");
    Serial.print(xRaw);
    Serial.print(", Y: ");
    Serial.print(yRaw);
    Serial.print(", Z: ");
    Serial.print(zRaw);
    Serial.print(", ");
 
    Serial.print(" :: ");
    Serial.print(xAccel);
    //Serial.print("G, ");
    Serial.print(yAccel);
    //Serial.print("G, ");
    Serial.println(zAccel);
    //Serial.print("G     ");
 
    DateTime now = rtc.now();  
    /*Serial.print(now.year(),DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');*/
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.println(now.second(), DEC);
    //Serial.print(':');
   
    // Filter out any values of xRaw, yRaw or zRaw that are not greater than
    // the thresholds. Basically, this statement is saying print to the SD card
    // if xRaw OR yRaw OR zRaw are greater than the threshold.
    //if( abs(xAccel) > 1 || abs(yAccel) > 1 || abs(zAccel) > 1 ) {
      // Now print to the SD card.
      dataFile.print(now.year(),DEC);
      dataFile.print('/');
      dataFile.print(now.month(), DEC);
      dataFile.print('/');
      dataFile.print(now.day(), DEC);
      dataFile.print(' ');
      dataFile.print(now.hour(), DEC);
      dataFile.print(':');
      dataFile.print(now.minute(), DEC);
      dataFile.print(':');
      dataFile.print(now.second(), DEC);
      dataFile.print(",");
      dataFile.print(xAccel);
      dataFile.print(",");
      dataFile.print(yAccel);
      dataFile.print(",");
      dataFile.println(zAccel);
      dataFile.flush();
    }
  }
 
// Read "sampleSize" samples and report the average
int ReadAxis(int axisPin)
{
  long reading = 0;
  analogRead(axisPin);
  delay(1);
  for (int i = 0; i < sampleSize; i++)
  {
    reading += analogRead(axisPin);
  }
  return reading/sampleSize;
}
// Find the extreme raw readings from each axis
void AutoCalibrate(int xRaw, int yRaw, int zRaw)
{
  Serial.println("Calibrate");
  if (xRaw < xRawMin)
  {
    xRawMin = xRaw;
  }
  if (xRaw > xRawMax)
  {
    xRawMax = xRaw;
  }
 
  if (yRaw < yRawMin)
  {
    yRawMin = yRaw;
  }
  if (yRaw > yRawMax)
  {
    yRawMax = yRaw;
  }
 
  if (zRaw < zRawMin)
  {
    zRawMin = zRaw;
  }
  if (zRaw > zRawMax)
  {
    zRawMax = zRaw;
  }
}

Code 2
Based on code 1, several changes has been made by removing, simplified codes in order to improve the reading speed. For example:

  1. only allowed to print through serial with much higher baud rate (115200)
  2. removed math calculation/conversion part (to calculate Gs) since this part can be done on excel
  3. use micro seconds as time scale and print all data by using datastring
    This has dramactically increased the reading speed. Its about 600 readings but its still not fast enough. Here is the code.
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
String toprint;
const int xInput = A0;
const int yInput = A1;
const int zInput = A2;
const int buttonPin = 2;
const int chipSelect = 10;
const int groundpin = 18;           
const int powerpin = 19;
File dataFile;
// Raw Ranges:
// initialize to mid-range and allow calibration to
// find the minimum and maximum for each axis
int xRawMin = 512;
int xRawMax = 512;

int yRawMin = 512;
int yRawMax = 512;

int zRawMin = 512;
int zRawMax = 512;

// Take multiple samples to reduce noise
const int sampleSize = 10;

void setup() {
  analogReference(EXTERNAL);
  Serial.begin(115200);
  /*Serial.print("Initializing SD card...");

  pinMode(SS, OUTPUT);
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    while (1) ;
  }
  Serial.println("card initialized.");
  dataFile = SD.open("datalog.txt", FILE_WRITE);    
  if (! dataFile) {
    Serial.println("error opening datalog.txt");
    // Wait forever since we cant write data
    while (1) ;
  }*/
#ifdef AVR
  Wire.begin();
#else
  Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino Due
#endif
  /*rtc.begin();
  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }*/
}

void loop() {
  //myMillis = millis();
  int xRaw = analogRead(xInput);
  int yRaw = analogRead(yInput);
  int zRaw = analogRead(zInput);
  // Read the state of the button to see if we need to calibrate.
  // This button should probably be debounced.
  if (digitalRead(buttonPin) == LOW)
  {
    AutoCalibrate(xRaw, yRaw, zRaw);
  }
  else
  {
    // Do all of the math first.

    // Convert raw values to 'milli-Gs"
    /*long xScaled = map(xRaw, xRawMin, xRawMax, -1000, 1000);
    long yScaled = map(yRaw, yRawMin, yRawMax, -1000, 1000);
    long zScaled = map(zRaw, zRawMin, zRawMax, -1000, 1000);

    // re-scale to fractional Gs
    float xAccel = xScaled / 1000.0;
    float yAccel = yScaled / 1000.0;
    float zAccel = zScaled / 1000.0;*/
    /*DateTime now = rtc.now(); 
    Serial.print(now.second(),DEC);
    Serial.print (",");
    Serial.print(xAccel);
    Serial.print(", ");
    Serial.print(yAccel);
    Serial.print(", ");
    Serial.println(zAccel);*/
    //This is used for printing raw value of each axis into the serial print. 
     toprint  = 0;
     toprint += micros();
     //toprint +=",";
     toprint += (xRaw);
     //toprint += (", ");
     toprint +=(yRaw);
     //toprint += (", ");
     toprint +=(zRaw);
     Serial.println(toprint);
     //dataFile.println (toprint);
     //dataFile.flush();

    // Filter out any values of xRaw, yRaw or zRaw that are not greater than
    // the thresholds. Basically, this statement is saying print to the SD card
    // if xRaw OR yRaw OR zRaw are greater than the threshold.
    //if( abs(xAccel) > 1 || abs(yAccel) > 1 || abs(zAccel) > 1 ) {
    // Now print to the SD card.
    /*dataFile.print(now.second(), DEC);
    dataFile.print(",");
    dataFile.print(xAccel);
    dataFile.print(",");
    dataFile.print(yAccel);
    dataFile.print(",");
    dataFile.println(zAccel);
    dataFile.flush();*/

    //This is used for recording the raw values from each axis onto the SD card. 
    /*dataFile.print(now.second(), DEC);
     dataFile.print(",");
     dataFile.print(xRaw);
     dataFile.print(",");
     dataFile.print(yRaw);
     dataFile.print(",");
     dataFile.println(zRaw);
     dataFile.flush();*/
  }
}

// Read "sampleSize" samples and report the average
int ReadAxis(int axisPin)
{
  long reading = 0;
  analogRead(axisPin);
  delay(1);
  for (int i = 0; i < sampleSize; i++)
  {
    reading += analogRead(axisPin);
  }
  return reading/sampleSize;
}

// Find the extreme raw readings from each axis
void AutoCalibrate(int xRaw, int yRaw, int zRaw)
{
  Serial.println("Calibrate");
  if (xRaw < xRawMin)
  {
    xRawMin = xRaw;
  }
  if (xRaw > xRawMax)
  {
    xRawMax = xRaw;
  }

  if (yRaw < yRawMin)
  {
    yRawMin = yRaw;
  }
  if (yRaw > yRawMax)
  {
    yRawMax = yRaw;
  }

  if (zRaw < zRawMin)
  {
    zRawMin = zRaw;
  }
  if (zRaw > zRawMax)
  {
    zRawMax = zRaw;
  }
}

Besides coding problems I also have several questions as following:
Q1 How many readings per second I can get the most theoretically from Arduino UNO with ADXL 377 sensor ?
Q2 How to count data per second? Do I just need to count how many data shows either on serial port or SD cards with one second time frame? Or count the time difference between two sets of data then use one second to divide this. For example, here is a sets of data, the first column is time in micro-second, the next three comlumns are values of accelerations in 3-axis.
23172108 , a1,a2,a3
23172220 , a1,a2,a3
23172332 , a1,a2,a3
So, here the time between between samples is 112 microseconds. Is this mean the sample rate is 8300 [1s/(120microseconds)] ? Why the arduino did not display 8300 readings?
Q3 Will I get a fast reading speed if I switch Arduino UNO to Due?
Q4 Can I self replace the capacitors on the ADXL 377 sensors to achieve higher bandwith?or Can I order a customized accelerometer sensor from Ad fruit here?
Thanks for reading my post. Please feel free to let me know if there is anything that is unclear or confusing. Also, let me know if you have recommendations.

Q1 How many readings per second I can get the most theoretically from Arduino UNO with ADXL 377 sensor ?

That depends on what else you are doing, and how you are doing it.

Writing to an SD file each time will slow things down (especially when the buffer get full).
Serial.print() each time will slow things down.
Using the stupid String class will slow things down.

Q2 How to count data per second? Do I just need to count how many data shows either on serial port or SD cards with one second time frame? Or count the time difference between two sets of data then use one second to divide this. For example, here is a sets of data, the first column is time in micro-second, the next three comlumns are values of accelerations in 3-axis.
23172108 , a1,a2,a3
23172220 , a1,a2,a3
23172332 , a1,a2,a3
So, here the time between between samples is 120 microseconds. Is this mean the sample rate is 8300 [1s/(120microseconds)] ? Why the arduino did not display 8300 readings?

It looks like the interval is 112 microseconds, not 120.

How many did it display? Are ALL the intervals 112 microseconds? Or, are there some that are considerably longer?

Q3 Will I get a fast reading speed if I switch Arduino UNO to Due?

Probably not all that much faster. The bottlenecks appear to be your use of the String class, Serial.print(), and writing to the file. None of these is much faster on the Due.

Q4 Can I self replace the capacitors on the ADXL 377 sensors to achieve higher bandwith?

You have our permission. Reading from the sensor is probably not the issue.

Can I order a customized accelerometer sensor from Ad fruit here?

Did you see an option to do that?

you can check if the ADXL377 works with a higher I2C speed e.g. by first using the multi speed I2C scanner

warning: it might screw up the behaviour of the RTC or other I2C devices …

ADXL377 does not talk I2C - it has 3 analog outputs that an ADC must read.

ADXL377.pdf (255 KB)

Why not write a short sketch that has no code in it except the absolute minimum needed to read the sensor.
Then read and save (in an array) 100 values and see how long it takes.

One problem that may be a deal-breaker is that the Uno and Mega only have one ADC shared between all the pins and when you switch pins you need to "waste" the first reading to allow the system to settle. If you are reading 3 different inputs the max rate (at full resolution) would be something like 15,000 / 3 / 2 or 2,500 samples per second.

You may need the larger SRAM of the Mega in which to store the samples as they are taken and before they are put on an SDCard or sent to a PC.

You could probably send them to the PC as fast as they are harvested if you use a high baud rate.

...R