Problem with impedance matching(?) for ATM16 ADC..

Go To Last Post
14 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello someone clever!

I am trying to control an ADC input on an Atmega16 with a potentiometer (I need 4 all in all). The problem is that the taper is extremely un-linear (and only) when connected to the input eg. PA0. Have tried with different potentiometers (from 500k down to 10k). Now I have made a simple buffer circuit with a TL074 op amp. When I plug it out of PA0 it is totally smooth but when connected to and ADC input the op amp can't pull it up or down very much (depends of the settings in the ATM, have tried various configurations from not defining the port in/out to setting it to input/output).

Has anyone experience with how to make a working/matching buffer circuit for the ADC input? Would it be better to make it with transistors instead?

Here is the relevant code (don't know if that could have an influence) and a sketch attached.


void ADC_init(void)	
{
	ADMUX=(1<<REFS0);
	ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADIE);	
}

unsigned int ADC_read(unsigned char ch)
{
	ch = ch & 0b00000111;	
	ADMUX |= ch;			
	ADCSRA|=(1<<ADSC);			// start conversion	
	return 0;
	
}

ISR(ADC_vect){
	
	ADCSRA|=(1<<ADIF);		
	ledWrite(ADC);
	//ADCSRA|=(1<<ADSC);
}

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The ADC input impedance is very high.
But I thought that a signal to it should be less than 10k, for the ADC to work properly. So a 20k pot or less should be fine.

You don't need a buffer at all.
To test it, the 100k should be just fine.

I don't know how you set up the I/O-pins and I'm not sure your ADC code is right.
Do you check the linearity with a PWM to a led ? That looks very unlinear, because of the human eye.
The ledWrite function is called from an ISR, are you sure that is okay?
You start a conversion, right after setting the MUX. I know I read something about that, check the datasheet.

Did you connect AVcc to 5V ? Some analog inputs don't use the normal +5V, but use the AVcc. For best result a LC-filter should be used, but just for testing you could tie AVcc to +5V.

Last Edited: Mon. Mar 5, 2012 - 10:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

ADMUX |= ch;

You are losing your reference selection after the first channel read. This can cause erratic results, and if fighting reference signals can damage the chip.

As said,

Quote:

You don't need a buffer at all.
To test it, the 100k should be just fine.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

STOP

Don't use your buffer circuit, or you could damage the uC.

You have powered the op-amp with +12/-5 V. Pots are noisy devices, the wipers bounce a bit. If there is a bad spot on the pot or much noise there is transiently no wiper connection, and your input is floating. It can then swing the output from rail to rail, i.e. +12 V out to -5 V out.

If one powers the op-amp from +5/Gnd then a full swing is within spec for the ADC input. If you use a bi-polar power supply for the op-amp, and/or have V+ > 5V, then you need to be sure that the output can not exceed 5V. You haven't done this.

The ADC inputs on AVRs don't accept a negative input voltage at all, and the positive input should not be greater than the micro's V+, (+5 V usually).

Although it is common to use an op-amp to pre-process an analog signal for an ADC this isn't necessary for a simple POT input.

So: Remove your op-amp from the circuit. Reconnect just the wiper to the ADC input pin.

Add a small cap, perhaps 0.1 uF, from the ADC input to ground. This filters out noise on the POT, makes the input a form of LPF, and lowers in impedance of your source providing the signal to the ADC.

Pots come in linear, log, and other configurations. Once you can correctly read the ADC input voltage you can correct for any non-linearity in software, if needed, but that discussion can be held later.

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
...to setting it to input/output).

STOP, (Again).
An ADC is an INPUT. If you define it as an OUTUT then the micro tries to drive the pin at either a High level (near V+), or a Low level, (near ground).

This fights with the pot which is trying to set it somewhere else.

If the pot is turned to the end where it provides 5 V, and the micro's pin is an output, driven low, then you essentially have a SHORT CIRCUIT to ground, which can damage the micro's pin. (Similarly with the micro's output High, and the pot at the ground end).

You need to ENABLE the ADC module on the micro and use the pin as an ADC input.

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your adc_read() returns a ZERO, EVERY TIME !

YOu don't select a new channel correctly . Example, previous channel = 7 and now you want channel = 1...1 | with 7 is still 7 . See the adc tutorials about that .

You shouldn't mess with ISR version until regular code's working .

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kun.io wrote:
The ADC input impedance is very high.
But I thought that a signal to it should be less than 10k, for the ADC to work properly. So a 20k pot or less should be fine.

You don't need a buffer at all.
To test it, the 100k should be just fine.

I don't know how you set up the I/O-pins and I'm not sure your ADC code is right.
Do you check the linearity with a PWM to a led ? That looks very unlinear, because of the human eye.
The ledWrite function is called from an ISR, are you sure that is okay?
You start a conversion, right after setting the MUX. I know I read something about that, check the datasheet.

Did you connect AVcc to 5V ? Some analog inputs don't use the normal +5V, but use the AVcc. For best result a LC-filter should be used, but just for testing you could tie AVcc to +5V.

Thanks for the answer!
I am testing the ADC with a multimeter at the input PA0. Already here the taper of the potmeter is screwed when it's connected to the input. If it's not, the taper is just fine. I have also hooked up a led display with 8 leds, it works as it should and I can write out the values.

> The ledWrite function is called from an ISR, are you sure that is okay? <

I thinks so. Anyway, the problem seems to occur no matter if I sample or not. It's the same if I use polling instead.

> Did you connect AVcc to 5V ? <

It's connected to VCC through a 0.1uF capacitor.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DocJC wrote:
STOP

Don't use your buffer circuit, or you could damage the uC.

You have powered the op-amp with +12/-5 V. Pots are noisy devices, the wipers bounce a bit. If there is a bad spot on the pot or much noise there is transiently no wiper connection, and your input is floating. It can then swing the output from rail to rail, i.e. +12 V out to -5 V out.

If one powers the op-amp from +5/Gnd then a full swing is within spec for the ADC input. If you use a bi-polar power supply for the op-amp, and/or have V+ > 5V, then you need to be sure that the output can not exceed 5V. You haven't done this.

The ADC inputs on AVRs don't accept a negative input voltage at all, and the positive input should not be greater than the micro's V+, (+5 V usually).

Although it is common to use an op-amp to pre-process an analog signal for an ADC this isn't necessary for a simple POT input.

So: Remove your op-amp from the circuit. Reconnect just the wiper to the ADC input pin.

Add a small cap, perhaps 0.1 uF, from the ADC input to ground. This filters out noise on the POT, makes the input a form of LPF, and lowers in impedance of your source providing the signal to the ADC.

Pots come in linear, log, and other configurations. Once you can correctly read the ADC input voltage you can correct for any non-linearity in software, if needed, but that discussion can be held later.

JC

> Add a small cap, perhaps 0.1 uF, from the ADC input to ground. This filters out noise on the POT, makes the input a form of LPF, and lowers in impedance of your source providing the signal to the ADC. <

ok will try!

> Pots come in linear, log, and other configurations. Once you can correctly read the ADC input voltage you can correct for any non-linearity in software, if needed, but that discussion can be held later. <

I know. have tried both logarithmic and linear. But as long as the pot moves 90% of the way on the first 10'th of the turn it will be to unstable to correct it in software.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:
Your adc_read() returns a ZERO, EVERY TIME !

YOu don't select a new channel correctly . Example, previous channel = 7 and now you want channel = 1...1 | with 7 is still 7 . See the adc tutorials about that .

You shouldn't mess with ISR version until regular code's working .

Thanks! But for now I am just measuring the input with a voltmeter to check the taper. Have no trouble of getting the ADC to work. I am not changing the channel (just got that part of the code from a tutorial in here, but thanks for noticing! Haven't payed attention to that part yet).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

oleoleo2 wrote:
indianajones11 wrote:
Your adc_read() returns a ZERO, EVERY TIME !

YOu don't select a new channel correctly . Example, previous channel = 7 and now you want channel = 1...1 | with 7 is still 7 . See the adc tutorials about that .

You shouldn't mess with ISR version until regular code's working .


Thanks! But for now I am just measuring the input with a voltmeter to check the taper. Have no trouble of getting the ADC to work. I am not changing the channel (just got that part of the code from a tutorial in here, but thanks for noticing! Haven't payed attention to that part yet).

> Your adc_read() returns a ZERO, EVERY TIME ! <

I know. This is not where I check the value. Have just simplified the code trying to fix the error.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

oleoleo2 wrote:
> Did you connect AVcc to 5V ? <
It's connected to VCC through a 0.1uF capacitor.

I'm not sure what you mean by this. Connect AVcc to +5V and you may add an extra 100nF to the ground.

Because something went wrong, you might already have damaged the ATmega16.
If you show us the schematics and initialization code, we could be more specific.

To make small steps, you could set a program in the ATmega16 that doesn't initialize anything (just a program loop). All I/O-pins are inputs and you could measure the voltage of the potmeter.
If that is already wrong, your hardware is wrong. If it's okay, make the next small step. Initialize the ADC.
And so on.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I'm not sure what you mean by this. Connect AVcc to +5V and you may add an extra 100nF to the ground.

Done. Same result.

Quote:
To make small steps, you could set a program in the ATmega16 that doesn't initialize anything (just a program loop). All I/O-pins are inputs and you could measure the voltage of the potmeter.
If that is already wrong, your hardware is wrong. If it's okay, make the next small step. Initialize the ADC.
And so on.

Done! The result is the same though.

(I have connected the pot directly to the ADC again). It works better with a 10K pot, maybe I should get a 4k7 pot?

Isn't the taper supposed to be smooth? or is it supposed to feel rather un-linear?

Quote:
If you show us the schematics and initialization code, we could be more specific.

There is no schematic yet. Here is the initialization code:

void ini(void){

	//ports
	DDRA = 0x00;
	DDRC = 0x1F;
	DDRB |= 0xF0;
	DDRD |= 0x0E;
	
	//debug 
	i2c_init();
	
	//UART:
	unsigned char ubrr_val;
	ubrr_val = ((F_CPU/(MIDI_BAUD*16.0)) - 1);
	UBRRH = (unsigned char) (ubrr_val>>8);
	UBRRL = (unsigned char)  ubrr_val;
	UCSRB = (1<<RXEN) | (1<<RXCIE) | (1<<TXCIE);
    UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0); 	// 8 bit data, asynchonous, 1 stop bit, no parity
	
	//timer
	TCCR0 = (1<<CS02) | (1<<CS00); //prescaler 1024 = 15625cps
	TIFR = (1<<TOV0); //clear pending interrupts
	TIMSK  = (1<<TOIE0); //Enable timer 0 overflow
	//ADC
	ADC_init();
	CLEARBIT(PINA,PA0);

	//Machine ready
	CLEARBIT(DAC_PORT, DAC_DA); //low
	CLEARBIT(DAC_PORT, DAC_CLK); //low
	SETBIT(DAC_PORT, DAC_CS); //low
	CLEARBIT(LED_PORT, LED_SCK); //low
	CLEARBIT(LED_PORT, LED_SDA); //low
	decodeSwitch(OFF);
	ledWrite(0); 
	sei(); //global interrupt enable

void ADC_init(void)	
{
	ADMUX=(1<<REFS0);	// AVcc with external capacitor at AREF
	ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADIE);	
}
	
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You shouldn't try to get that code working.
Make very small steps and test everything seperately.

For example, you do: CLEARBIT(PINA,PA0).
But PINA is an input register.

Start with new code for the ADC only, and see if changing the potmeter has the same effect connected and unconnected.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
You shouldn't try to get that code working.
Make very small steps and test everything seperately.

Thanks! Now it's working!

Found the error! (it was a stupid one..). I had an I2C debug module that was setup to use PA0 and PA1.

The taper is nice and smooth now, pew!