Speed up this sampling rate

Hi Everyone,

I am trying to sample some sinousidl signals of range 1Hz to 1KHz. With the current code i am not getting good samples. Can someone suggest me a way to increase the sampling rate so that i can sample the higher frequency with more resolution. I know the fact that analogRead takes about 0.1ms and digital write takes about 2us for complete execution. I tried to time my whole loop and it takes about 1ms for the whole loop to complete which is pretty slow. May be someone can suggest me a method to increase this sampling speed so that my loop;loops faster.

const int numReadings = 4;
int readings[numReadings];      // the readings from the analog input
int index = 0;// the index of the current reading
int total = 0;                  // the running total
int average = 0;   // the average
int average_new=0;
int average_final=0;
int inputPin = A0;
unsigned long time; 
void setup()
{
pinMode(1, OUTPUT); 
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);

  // initialize serial communication with computer:
  Serial.begin(9600);                   
  // initialize all the readings to 0: 
  //initialise the array here. 
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings[thisReading] = 0;          
}

void loop() {
  time=micros();
  // subtract the last reading:
  total= total - readings[index];         
  // read from the sensor:  
  
  //first time to the loop, we set the index value of zero to the reading. 
  readings[index] = analogRead(inputPin); 
  // add the reading to the total:
  total= total + readings[index];       
  // advance to the next position in the array:  
  index = index + 1;                    

  // if we're at the end of the array...
  if (index >= numReadings)              
    // ...wrap around to the beginning: 
    index = 0;       
// so that we stay in the array    
average = total / numReadings; 
 
int myMaxValue = readings[index];
int size=numReadings;

for (int i=0; i<size; i++) { 
 
myMaxValue= max (myMaxValue, readings[i]);

} 

 {  
if (average <0  ) 
 digitalWrite(1, HIGH);
else 
 digitalWrite(1, LOW);
  }
 {  
if (average <200 && average >1)
digitalWrite(2, HIGH);
else
digitalWrite(2, LOW);
 } 
  {  
if (average <300 && average >200  ) 
digitalWrite(3, HIGH);
else
digitalWrite(3, LOW);
 } 
 {  
if (average <400  && average >300 ) 
digitalWrite(4, HIGH);
else
digitalWrite(4, LOW);
 } 
  {  
if (average <500  && average >400 ) 
digitalWrite(5, HIGH);
else
digitalWrite(5, LOW);
 } 
  {  
if (average <600  && average >500 ) 
digitalWrite(6, HIGH);
else
digitalWrite(6, LOW);
 } 
  {  
if (average <700  && average >600 ) 
digitalWrite(7, HIGH);
else
digitalWrite(7, LOW);
 } 
  {  
if (average <800  && average >700 ) 
digitalWrite(8, HIGH);
else
digitalWrite(8, LOW);
 } 
  {  
if (average <900  && average >800 ) 
digitalWrite(9, HIGH);
else
digitalWrite(9, LOW);
 } 
  {  
if (average <1023  && average >900 ) 
digitalWrite(10, HIGH);
else
digitalWrite(10, LOW);
 } 

  Serial.print (readings[index]);
  Serial.print("\t");
  Serial.print(average); 
  Serial.print("\t");
  Serial.print(myMaxValue); 
  Serial.print ("\t");
  Serial.print(time);
  Serial.println();

      
}

I know the fact that analogRead takes about 0.1ms

Most of which time is a busy wait, with the processor twiddling its thumbs - time which could be used for other things.
If you look at the source of "analogRead", you'll see it consists of the following steps:

  1. Setup the input mux
  2. start the conversion
  3. wait for the conversion to complete
  4. read the result and return the reading.

By far the biggest chunk is 3), so if you split this function, you can do useful work in the time that the ADC is doing its stuff.

As your code stands all the time is taken in Serial.print - is the 1ms timing you mention free from Serial overhead?

You sliding average of 4 samples serves to reduce the effective sampling rate by 4, which is not what you want - use
every sample and it should go quicker (the calculation of an average is what reduces your throughput by 4, lose this
and output the "total" variable on every sample?). An RC hardware low-pass-filter on the analog pin itself would be
a possibly better way to reduce out-of-band noise.

If you do filter in software there are sites that can generate you a proper digital filter to a given specification.

When sampling you need a regular clock to sample on, not a great strategy to rely on the execution time of your
code, better to actually wait for the next sample time with a polling loop on micros(), or perhaps set up a timer
to interrupt at the desired rate. Again the blink-without-delay advice applies (except with micros() rather than millis()).

And finally there are ways to speed up the ADC (at a slight reduction of accuracy), or as has been mentioned to pipeline
the operation of the ADC in parallel with your code (although this can increase analog noise).

Change the Serial.print speed - make it 115200

Replace the digitalWrites with direct port manipulations:

digitalWrite(2, HIGH);
becomes
PORTD = PORTD | B00000100; // set bit 2 high

digitalWrite(2, LOW);
becomes
PORTD = PORTD & B11111011; // clear bit 2

Not a speed thing, but need to fix your boundary tests:
if (average <600 && average >500 )
What happens when it equals 500 or 600? Need to cover those cases with <=, or >=

Can this occur?
if (average <0 )
Isn't the available range 0 to 1023?