Week 10 ADC and the Microphone



To avoid aliasing, the sampling frequency of an Analog-to-Digital Converter (ADC) must be at least twice the highest frequency component of the analog signal you are trying to digitize. This is known as the Nyquist theorem, and the minimum sampling rate is the Nyquist rate. In practice, it is recommended to use a sampling rate that is significantly higher than the minimum and to use a low-pass filter (anti-aliasing filter) before the ADC to remove frequencies above half the sampling rate.

If you sample a voltage through an ISR, the frequency the code gets into the ISR will be the sampling frequency.
The best practice is to use the ADC Conversion Complete ISR. When the ADC conversion is completed, it interrupts and you can process and store the data inside the ISR. This keeps the code organized in a better way.

  // Configure ADC: A0, AVCC reference, left-justified result
  ADMUX = (1 << REFS0)| (1<<ADLAR);







  // Configure ADC: Enable, Prescaler 128 (~13x slower than 16MHz)
  // ADC clock = 16MHz / 8 = 2 MHz.
  ADCSRA = (1 << ADEN) | (1 << ADPS1) | (1 << ADPS0);



  // Set to CTC mode (WGM12), no prescaler (CS10)
  TCCR1B |= (1 << WGM12) | (1 << CS10);



This time we are using TIMER1's CTC mode, which counts to the value stored in OCR1A then interrupts.



  // Set OCR1A for 25µs (16MHz * 25µs - 1 = 400 - 1 = 399)
  OCR1A = 399;

Use a test pin to measure the ADC's sampling rate. My oscilloscope shows 26 us whcih is very close to 25 us. I pressed the Run/Stop button on the scope to capture the pulses. This could be a little tricky since it happens very fast. I used the Scale knob to zoom in to the pulses to measure the distance between two rising edges.



  // Enable Timer1 compare interrupt A
  TIMSK1 |= (1 << OCIE1A);



// Timer1 Compare Match A Interrupt Service Routine
ISR(TIMER1_COMPA_vect) {
  digitalWrite(TEST_PIN, HIGH);
  // Start the ADC conversion
  ADCSRA |= (1 << ADSC);
  digitalWrite(TEST_PIN, LOW);
}



// ADC Conversion Complete Interrupt Service Routine
ISR(ADC_vect) {
  // Read the 8-bit result (we only need the high byte)
  // Read ADCL then ADCH to ensure consistency
  uint8_t low_byte = ADCL; // The Arduino ADC requires ADCL to be read first
  uint8_t high_byte = ADCH;  
  if (sample_index < NUM_SAMPLES) {
    adc_reading[sample_index] = high_byte; // Use high byte for 8-bit result
    sample_index++;
  } else {
    // We have collected all samples, so stop the timer and set flag
    TCCR1B &= 0; // Stop timer
    sampling_complete = true;
    sample_index = 0;
  }
}



Task 1 grading rubric:
1. TIMER 1 CTC mode ISR handles ADC conversion. (20 points)
2. Oscilloscope sampling rate verification - around 25 us. (20 points)
3. 64 whistling samples ploted - close to a sine wave. (20 points)