Changing Prescaler Affecting Timing

Wanting to perform 128-point FHT with sampling rate of 38.4kHz, which requires changing the AVR prescaler to 32. However, believe this will also change how millis() and delay() behave, and I assume will change the bit timing of DMXsimple writes.

Does this sound correct and does this mean I'm limited to the default 9.6kHz sample rate for timing functions to behave normally? There are some utilities that correct millis() and delay() for changes in the prescaler but don't know if they would apply to DMXsimple.

Timer 0 has a prescaler. Timer 1 has a prescaler. Timer 2 has a prescaler. The analog-to-digital converter has a prescaler. The USART has a prescaler. The SPI peripheral has a prescaler. The CPU has a prescaler. So, when you say "the AVR prescaler" no one can possibly know which.

From the context I would guess you mean the CPU. But that does not make sense. Slowing the CPU by that much is going to make processing samples at that rate very difficult.

FFT ?
You mean you want to set up a timer with a frequency of 38.4 KHz and do something in the timer interrupt routine ?
Something like How to create a 38 Khz pulse with arduino using timer or PWM? - Programming Questions - Arduino Forum

If you are changing the system clock prescaler, have a look at this thread Is there a simple way to reduce clock speed on an UNO? - Microcontrollers - Arduino Forum

Believe it's the "System Clock Prescaler" that is altered to change the ADC sample rate from its default 9kHz to 38.4kHz.
Unfortunately...

You can use the clock prescaler, but a lot in the sketch will go wrong : millis(), Serial, and others.

There may be other ways to accomplish this without things going "wrong" though.

You want the analog-to-digital (ADC) prescaler. You will be sacrificing quality for speed.

(32/16000000)131000000 = 26 μs per sample or ~38461 samples per second (after the first sample; no changing channels; no changing reference)

So the ADC prescaler values are "ADPS0..2" and only affect the ADC, no effect on millis() and digital timing?

The prescaler is set to "101" using these...

sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
sbi(ADCSRA,ADPS0) ;

for the ADPS2,1,0 where "sbi" is "set bit" and "cbi" is "clear bit"?

You will be sacrificing quality for speed.

What is meant by this... quality of samples vs. sample speed?

rickso234:
So the ADC prescaler values are "ADPS0..2" and only affect the ADC, no effect on millis() and digital timing?

Correct.

The prescaler is set to "101" using these... for the ADPS2,1,0 where "sbi" is "set bit" and "cbi" is "clear bit"?

Correct.

What is meant by this... quality of samples vs. sample speed?

From the datasheet...

By default, the successive approximation circuitry requires an input clock frequency between 50kHz and 200kHz to get maximum resolution. If a lower resolution than 10 bits is needed, the input clock frequency to the ADC can be higher than 200kHz to get a higher sample rate.

You get an ideal maximum of 10 bits of resolution. As you speed up the clock you drop bits of resolution.

For a good tutorial on ADC conversion on the Arduino see Gammon Forum : Electronics : Microprocessors : ADC conversion on the Arduino (analogRead)

There is data presented which shows no accuracy problems at prescaler 32.

The DMXsimple library uses Timer2 which will be unaffected by the ADC clock.

Great tutorial by Grumpy Mike!
So looks like I’m on the right track except… this FHT code doesn’t seem to do what I expect.

/*
fht_adc_serial.pde
guest openmusiclabs.com 7.7.14
example sketch for testing the fht library.
it takes in data on ADC0 (Analog0) and processes them
with the fht. the data is sent out over the serial
port at 115.2kb.
*/

#define LOG_OUT 1 // use the log output function
#define FHT_N 128 // set to 128 point fht (gives 64 freq bins)
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

#include <FHT.h> // include the library

unsigned long StartTime = 0;
unsigned long EndTime = 0;

void setup() {
// set prescaler to 32 for a sample rate of 38.4kHz (BW = 19.2kHz)
   sbi(ADCSRA,ADPS2);
   cbi(ADCSRA,ADPS1);
   sbi(ADCSRA,ADPS0);

/*
Prescale  ADPS2,1,0  Clock MHz)  Sampling rate (KHz)
  2 	  0 0 1 	8 	  615
  4 	  0 1 0 	4 	  307
  8 	  0 1 1 	2 	  153
  16 	  1 0 0 	1 	  76.8
  32 	  1 0 1 	0.5 	  38.4 <
  64 	  1 1 0 	0.25 	  19.2
  128 	  1 1 1 	0.125 	  9.6 (default)
*/

/*
// Define various ADC prescaler a different way...
const unsigned char PS_16 = (1 << ADPS2);
const unsigned char PS_32 = (1 << ADPS2) | (1 << ADPS0);
const unsigned char PS_64 = (1 << ADPS2) | (1 << ADPS1);
const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
  // set up the ADC
  ADCSRA &= ~PS_128;  // remove bits set by Arduino library
  // you can choose a prescaler from above.
  // PS_16, PS_32, PS_64 or PS_128
  ADCSRA |= PS_32;    // set our own prescaler to 32 
*/
  
  Serial.begin(9600); // use the serial port
  TIMSK0 = 0; // turn off timer0 for lower jitter
  ADCSRA = 0xe5; // set the adc to free running mode
  ADMUX = 0x40; // use adc0
  DIDR0 = 0x01; // turn off the digital input for adc0
} // end Setup

void loop() {
  while(1) { // reduces jitter
//StartTime = micros();
    cli();  // UDRE interrupt slows this way down on arduino1.0
    for (int i = 0 ; i < FHT_N ; i++) { // save 256 samples
      while(!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA = 0xf5; // restart adc
      byte m = ADCL; // fetch adc data
      byte j = ADCH;
      int k = (j << 8) | m; // form into an int
      k -= 0x0200; // form into a signed int
      k <<= 6; // form into a 16b signed int
      fht_input[i] = k; // put real data into bins
    }
    fht_window(); // window the data for better frequency response
    fht_reorder(); // reorder the data before doing the fht
    fht_run(); // process the data in the fht
    fht_mag_log(); // take the output of the fht

    sei();
//EndTime = micros();    
    
    Serial.print("Start:  ");
    for (byte i = 0 ; i < FHT_N/2 ; i++) {
      Serial.print(fht_log_out[i]); // send out the data
      Serial.print(" ");
    }
//     Serial.print("ET (us) = "); 
//     Serial.print(EndTime - StartTime);

     Serial.println();
     Serial.flush();
  }
}

Tried setting the prescaler = 32 a couple different ways, and this appears to also set the bits to “101”…

Using the Adafruit mic module (MAX4466) with output to A0.
Getting 64 values but they don’t change when I whistle or clap into the mic. With a scope, can see signals on mic output.
With A0 grounded, get all “0”, except for first bin.
SHouldn’t I see activity in the bins with sound at the mic?

rickso234:
Great tutorial by Grumpy Mike!

  • ? -

Sorry, got my names mixed up... written by Nick Gammon