Tuesday, January 31, 2023

Analog data logging using Arduino

For fast analog data acquisition on an Arduino UNO, you can utilize the analogRead() function, but to optimize it for speed, we can:

1. Use Direct Register Manipulation to bypass the overhead of the `analogRead()` function.
2. Disable ADC interrupts if you're not using them.
3. Set the ADC prescaler to a value that allows faster conversions.

Here’s a code example that shows how to configure the Arduino UNO to acquire analog data very fast:

Fast Analog Data Acquisition Code


const int analogPin = A0;  // Analog input pin
const int numSamples = 1000; // Number of samples to acquire

// Variables to hold ADC results
volatile uint16_t analogData[numSamples];
volatile unsigned long lastMicros = 0;
volatile int sampleIndex = 0;

void setup() {
  Serial.begin(115200);  // Initialize Serial for output
  // Configure the ADC for fast conversion
  ADMUX = (1 << MUX0);    // Select A0 pin (MUX0 = 1)
  ADCSRA |= (1 << ADEN);  // Enable ADC
  ADCSRA &= ~(1 << ADIF); // Clear ADC interrupt flag
  ADCSRA |= (1 << ADATE); // Enable Auto Trigger
  ADCSRA |= (1 << ADPS2) | (1 << ADPS1);  // Set prescaler to 64 (fastest)
  ADCSRA |= (1 << ADSC);  // Start the conversion
  ADCSRA |= (1 << ADIE);  // Enable ADC interrupt

  // Configure the ADC to be in free-running mode
  ADCSRA |= (1 << ADATE); // Enable auto-triggering mode (free running)
  ADCSRB = 0;             // Free running mode

  sei();  // Enable global interrupts
}

void loop() {
  // We acquire data until numSamples is filled
  if (sampleIndex >= numSamples) {
    // Send the data to Serial when done
    for (int i = 0; i < numSamples; i++) {
      Serial.println(analogData[i]);
    }
    sampleIndex = 0;  // Reset for the next acquisition
  }
}

// ADC Conversion Complete ISR
ISR(ADC_vect) {
  if (sampleIndex < numSamples) {
    analogData[sampleIndex++] = ADC;  // Store the ADC result
  }
}


Key Optimizations:

1. Direct Register Manipulation:
   - Instead of using `analogRead()`, this code reads directly from the ADC register (`ADC`).
   - It sets the ADC prescaler to 64 for faster conversion, and uses `ADCSRA` for controlling ADC features.

2. Auto-trigger (Free Running Mode):
   - The ADC is set to continuous conversion mode, so it automatically triggers a new conversion after each one. This eliminates the need for manual triggering.

3. Interrupts for Fast Acquisition:
   - The `ADC_vect` interrupt is triggered every time an analog-to-digital conversion is complete, enabling fast acquisition without delay.

Prescaler Settings for ADC Clock:
The ADC clock in an Arduino UNO can be controlled using the prescaler, which divides the 16 MHz system clock to give the ADC a lower clock frequency. The prescaler is set in the `ADCSRA` register:

- Prescaler of 16 (default): 1 MHz
- Prescaler of 64: 250 kHz (faster, but higher noise)
- Prescaler of 128: 125 kHz (useful for higher precision but slower)

In the example, we used a prescaler of 64, which provides a balance between speed and accuracy.

Data Output:
- The `analogData` array will store all the ADC readings, and once the acquisition of the desired number of samples (`numSamples`) is complete, it sends the data over serial to the PC for analysis.

Notes:
- The code is designed for fast analog data acquisition. You can adjust the `numSamples` for longer or shorter acquisition.
- The resolution of the analog readings will be 10 bits (0-1023) as provided by the standard ADC in Arduino UNO.
- If you need higher speeds, consider moving to a more advanced board, such as Arduino Due or Teensy, which support faster ADCs.


Difference between Active and Passive Transducer

  Feature Active Transducers Passive Transducers Power Supply Requires an external power source to operate...