Audio input via ADC + potentiometer

Hi,
I have successfully managed to loop audio through my Arduino Uno via the method outlined in numerous examples. The system diagram is basically:

Opamp to convert audio level to 0-5V -> Analogue input 0 of Arduino -> PWM output of Arduino -> Low pass filter -> Opamp to convert 0-5v to audio level

I am using the ADC_vect in free-running mode, to get the fastest read time possible.

This is all working great, but I also want to read potentiometers on the other inputs. I have added a 10k pot on Analogue input 1 of Arduino. My interrupt code looks like this:

volatile unsigned char master_output; 
volatile float process; 
volatile byte curInput;


void setup() {
  Init_Register();
}

void loop() {

}

//Interrupt loop.  Sets PWM output (i.e. generates the audio)
ISR(TIMER1_COMPA_vect) {    
  master_output = (char)process + 128;
  OCR2B = master_output;              //sets sample value
} 

ISR(ADC_vect) {//when new ADC value ready
  byte a;
  a = ADCH;
  switch (curInput){
    case 0:
        process = (float)a - 128;
      break;
    case 1:
     //do stuff with pot here
      break;
  }

  
  curInput++;
  if (curInput>1){
    curInput = 0;
  }
  ADMUX = B00100000 | curInput;
}

I'm now getting very strange behaviour.

  • If I connect the potentiometer, the audio stops being read completely.
  • If I move the audio to analogue input 1 (pot unconnected) I still hear the audio, even though code doesn't use input 1 at present.
  • If I move the audio to analogue input 2 (pot still unconnected) I still hear a little bit of audio. Code doesn't even read input 2!!

It's though I am getting some kind of cross talk between inputs. And why connecting the pot stops the audio being read is beyond me! I have checked the pot with the demo analogue read sketch and it's fine.

I believe that there's a capacitor that has to discharge when changing inputs. Is this part of the problem? If so, is there no way to scan all the inputs very fast? I was eventually hoping to scan them in the order 0,1,0,2,0,3,0,4,0,5 etc, because the audio needs updating at a fast rate, but the pots don't.

Any help would be appreciated! :wink:
Paul

Code for Init_register below:

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

void Init_Register() {

  // Set up Timer 2 to do pulse width modulation on the speaker
  // pin.
  pinMode(3, OUTPUT);

  //use internal clock
  cbi(ASSR,EXCLK);    //disable external clock
  cbi(ASSR,AS2);      //clock timers from internal clock

  //Fast PWM mode  
  sbi(TCCR2A,WGM20);  //TOV flag set on max
  sbi(TCCR2A,WGM21);  //Update OCRx at bottom
  cbi(TCCR2B,WGM22);  //Top = 0xFF

  //Set non-inverting PWM on OC2B pin
  cbi(TCCR2A,COM2B0);
  sbi(TCCR2A,COM2B1);
  //set normal operation on OC2A pin
  cbi(TCCR2A,COM2A0);
  cbi(TCCR2A,COM2A1);
  
  //no prescaler
  sbi(TCCR2B,CS20);
  cbi(TCCR2B,CS21);
  cbi(TCCR2B,CS22);
  
  // Set Timer 1 to update sample on interrupt

  cli();      //pause interrupts

  // Set CTC mode (Clear timer on compare match)
  cbi(TCCR1A,WGM10);
  cbi(TCCR1A,WGM11);
  sbi(TCCR1B,WGM12);
  cbi(TCCR1B,WGM13);

  //No prescaler
  sbi(TCCR1B,CS10);
  cbi(TCCR1B,CS11);
  cbi(TCCR1B,CS12);  

  // Set the compare register (OCR1A) initial value
  OCR1A = master_ocr1;
  
  // Timer 1, output compare A match interrupt enable
  sbi(TIMSK1,OCIE1A);

  
  //clear ADCSRA and ADCSRB registers
  ADCSRA = 0;
  ADCSRB = 0;
  
  cbi(ADMUX,REFS0);  //use ref voltage
  cbi(ADMUX,REFS1);
  sbi(ADMUX, ADLAR);  //left align to read highest 8 bits only
  
  sbi(ADCSRA,ADPS0);  //set ADC clock with 32 prescaler- 16mHz/32=500kHz
  cbi(ADCSRA,ADPS1);
  sbi(ADCSRA,ADPS2);   
  
  sbi(ADCSRA,ADATE); //enable auto trigger
  sbi(ADCSRA,ADIE); //enable interrupt
  sbi(ADCSRA,ADEN); //enable ADC
  sbi(ADCSRA,ADSC); //start ADC   

  sei();    //start interrupts

}

I believe that there's a capacitor that has to discharge when changing inputs. Is this part of the problem?

Yes, that cap is part of the uCs sample & hold circiut.

If so, is there no way to scan all the inputs very fast?

Usual solution is to take 2 readings, and only use the 2nd one, lets the cap charge to correct levels.

Better solution is to use a fast external ADC, such as MCP3208.

Ah - interesting. I did suspect that an external ADC may be the best way to get audio in and use pots.

I'll try the taking multiple samples idea too.

The problem seems to be less bad when using a 1k pot (rather than the 10k pot). Is there any logic to this or is this just chance? The opamps output impedance is very low too.

cheers
Paul

1K pot lets more current flow so cap can charge quicker.

Ah right. Well I guess it would be a good idea to keep it as low as possible. Any ideas how low you can go before it starts to draw too much current?

paulsoulsby:
Ah right. Well I guess it would be a good idea to keep it as low as possible. Any ideas how low you can go before it starts to draw too much current?

Too much is defined by the pot. Look at the power rating of the pot and do not exceed that. Power is volts times amps, so if you have 5V across the pot and a 100R pot you will have 5 / 100 = 0.05 A thus the power will be 0.05 * 5 = 0.25 W which is the ratings of a typical pot. But see your pot to make sure.

Great thanks! I'll give 100?/¼W a try + double reading each pin. If that's still no good, I'll have to branch out into using an external ADC.