Wrong value reading ADC

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

Hello all.

I am using the ATmega644P and 5 ADC inputs for reading several analog voltages. When I read 100mV if I convert the the analog reading into volts again I have a difference of 30mV, reading only 70mV. If I read 2,5 volts the difference is only 10mV. As we go up in the voltage read the difference is smaller. I used a potentiometer to make a voltage divider and if we read voltages of 50mV the ADC reading is equivalent to 25mV.

The AVCC voltage pin is 5V and I have a low pass filter with 100uH choke and a 4.7uF tantalum capacitor and a .1uF. Connected to the AREF pin I have a 0.1uF capacitor.

The ADC setup is the following:

// ADC Enable
			ADCSRA |=(1<<ADEN);
			ADCSRA |=(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
			ADMUX  |=(1<<REFS0);
			DIDR0 =0b00011111;

The function call and the ADC reading routine is the following:


 adc_value = Read_ADC(0+64);  // +64 is the  REFS= bit, AVCC with external capacitor at AREF pin  



/****************************************************************
* This routine is to read the ADC. The ADC is going to read the 
* motor battery voltage, receiver battery voltage, temperature and
* air speed.
*/
 uint16_t Read_ADC(uint8_t adc_adr)
{
		uint16_t adc_value =0;
	
		ADMUX = (adc_adr);

		ADCSRA |=(1<<ADSC);

			while(ADCSRA & (1<<ADSC)); {}
	
				adc_value=ADCW;
							
				return adc_value;
			 
}		

Do you see any thing wrong in the code? Can you please help me on solve the problem.

Regards,
Manuel

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

Quote:
ADMUX = (adc_adr);

With this you clear the reference setting (REFS0).

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

Quote:

With this you clear the reference setting (REFS0).

No - look again at the function invocation and the +64 in particular.

(though I agree it's a horrendous way to do it!)

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

Clawson,

Thanks. Can you please advise a better way to do it. Is there any thing wrong in the code that can generate the problem I have?

Thanks and regards,
Manuel

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

Quote:

Can you please advise a better way to do it.

adc_value = Read_ADC(0);

and

 uint16_t Read_ADC(uint8_t adc_adr)
{
      uint16_t adc_value =0;
   
      ADMUX = (adc_adr) | (1<<REFS0);

As for the inaccuracy - is it a constant 30mV across the range or does the inaccuracy get worse with higher voltage?

If the former I'd suggest your reference might simply be off by that amount (voltage sag because of high current load perhaps?).

If the latter I'd suspect the calculation you use to convert ADC reading back to absolute voltage.

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

Clawson,

Thanks, the code you suggest is nicer and more clear.

I measure the AVCC voltage and is less 0.001V that the VCC because of the choke I use, Vcc=5.005 AVCC=5.004V.

The calculation I do is the following:

read voltage= (AVCC/1024)* ADC read

The inaccuracy is decreasing as the voltage read is higher.

Thanks
Manuel

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

Hello all,

After better analyzing the problem, the ADC conversion doesn't give any result until the voltage in the ADC pin is >= 0.030V.

This is the reason I see only differences on lower values.

Any clue of what can be the problem.

Thanks.
Manuel

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

This may or may not be related to your issue, but I always make it a point to set the ADC mux to the next channel immediately after finishing a read, rather than just before starting the next read. This gives the ADC mux path the longest possible time to settle down, since each new channel has to pass through the RC network of the source voltage, the mux and the ADC circuitry. I can attest that there are cases where this extra settling time makes quite a difference (but I wouldn't claim that it is required in every case).

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

The ADC, itself, has no inherent nonlinearities near zero. So, I would check, very carefully, where you are measuring.

1. Do you have the analog ground (the one between AVcc and ARef) grounded?

2. Where do you connect the ground lead of your meter?

3. What does your meter read when you connect the two measuring leads together?

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

kk6gm,

Thanks for your inputs. I put a delay and didn't' solve the problem. Also I did what you advise, before come out of the function I change the ADMUX for the next channel, but it doesn't work.

Thanks,
Manuel

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

Jim,

Thanks for your help.

Quote:

1. Do you have the analog ground (the one between AVcc and ARef) grounded?

I have all the grounds connected to the same point.I have the analogue ground connected to the ground.
Quote:

2. Where do you connect the ground lead of your meter?

I connect the ground lead to the analog ground, but there isn't voltage differences between the several grounds.
Quote:

3. What does your meter read when you connect the two measuring leads together?

Putting the two measuring leads together I get 0.000 Volts

Thanks.
Manuel

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

Quote:

Do you see any thing wrong in the code? Can you please help me on solve the problem.

First, forget about the translation to voltage, and just report the A/D counts along with the corresponding voltages on the input pin.

Next, you mentioned "voltage divider". What does the source impedance of your signal end up to be? Take, say, 16 readings on the same channel one after the other. Report the A/D counts for each reading. Then we can start to investigate.

Also report on what capacitor you have attached to AREF, the voltage read on the AREF pin, and your AVR clock speed and model. Is there any noise on the signal, or Vcc, or AVcc, or ground? Have you used a 'scope?

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

Quote:

The calculation I do is the following:

read voltage= (AVCC/1024)* ADC read


BTW, that calculation should be /1023 IIRC. That can explain your "missing" mV. And the calculation as shown is not going to give good results with the division first.

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

Theusch,

I did a voltage divider with a 5K potentiometer and applied to the adc input a voltage of 0.050V.

I also used (the problem appeared here) a INA138 current shunt monitor and the problem was the same.

The AVCC voltage is 5,005V. the ADC pin is at 0.050V and the sixteen consecutive readings are 0x004, no change of the value.

I have a .1uF capacitor at the AREF pin.

The clock frequency is 18432000Hz.

The voltage read at the AREF pin is 5,004V

The AVCC voltage is 5,004V.

The ADC pin is clean, no noise.

All the other pins AVCC, VCC, Ground, AREF has about 5 millivolts p-p.

Thanks for your help.
Manuel

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

Well, if your Ground "measures" 5mV, then don't expect the ADC to start reading until the input is about 5mV.

Remember, the ADC measures with respect to the voltages that are actually on the pins of the micro. It will not read anything until the apparent input is greater than zero. And, any difference between the chip ground and where you generate the voltage will be seen as an offset to the input voltage.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

Quote:

All the other pins AVCC, VCC, Ground, AREF has about 5 millivolts p-p.

And what does that translate into in A/D counts? 1 count on a 5V setup. That's part of your situation.

Quote:

The AVCC voltage is 5,005V. the ADC pin is at 0.050V and the sixteen consecutive readings are 0x004, no change of the value.


I see; and you expect about twice that. 50mV is about 10 counts on a 5V setup.

Do the counts change when you have the 'scope on the signal? To get down to the last count with an AVR's A/D the entire analog subsystem must be squeaky-clean. If you see some ripple with the 'scope the probe capacitance is probably dampening it a bit.

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

ManuelSilva wrote:
read voltage= (AVCC/1024)* ADC read

Should this not be (AVCC * ADC) / 1024 ?

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

Quote:

Should this not be (AVCC * ADC) / 1024 ?

Yes - always multiply before divide in integer maths but watch for integer overflow.

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

Maximax,

The way I do calculation, may not be the correct way, but it is based on the following:

AVCC = 5.0V
10 bit= 1023

each bit value is 5.0V/1023= 0.00488.... Volts

If the ADC reads 10, the input voltage should be around
10*0.00488... Volts.

This is the way I do. Is this wrong?

regards,
Manuel

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

Quote:

This is the way I do. Is this wrong?


He was commenting on the order you used operators (you did divide then multiply). As I say you should always multiply then divide - but this doesn't matter as long as you used 5.0 and not 5 (i.e. if you promoted the calculation to float).

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

Theusch,

Thanks for your inputs.

The value doesn't change when I put the scope probe on the ADC pin.

I have one Arduino board, and I simulate the adc reading with the potentiometer and with 0.050V the ADC reads 10. The noise in the power line is much higher than in my board. I have the AVCC connected to VCC with a low pass filter a 100uH choke and 4.7uF tantalum capacitor and .1uF.

I really do not understand this behavior.

I am going to try to reduce the noise in the AVCC pin.

Thanks and regards,
Manuel

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

The behavior you describe DOES NOT fit errors or noise on AVCC. Such errors tend to increase with the input, not decrease.

Instead, the behavior is most similar to having a "zero offset". That is why I suggested looking at voltage differences between the place that the voltage is generated and the place where it is measured. It is almost certainly in your external circuit, not inside the AVR. An important thing to remember is: any input voltage AT THE MICROCONTROLLER PINS that is less than zero will be read as zero. One of the two pins is the "analog ground" pin and the other is the actual analog input pin.

By the way, have you turned off the digital buffer for that pin? Make sure that you initialize DIDR0 properly.

Your AVCC "filter" is not much good for line frequencies (that is, "hum"). A 100uH inductor and a 4.7uf cap make a corner frequency of about 7.3KHz, low-pass. That will not do anything to power line ripple or hum. Your best solution for that is better regulation.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

clawson wrote:
As I say you should always multiply then divide - but this doesn't matter as long as you used 5.0 and not 5 (i.e. if you promoted the calculation to float).

@ManuelSilva: Did you promote the calculation to float then? It could make a big difference if not!

Did you try the calculation the way I suggested?

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

Jim,

Thanks for the inputs.
Yes, I disable the digital inputs in the analogue inputs used.
I am going to check all the ground and VCc lines.

Maximax,
The example I gave is just for manual calculation. In fact, I checked the code and I always use to multiply and after divide.

Thanks and regards,
Manuel

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

Quote:
BTW, that calculation should be /1023 IIRC.
No, /1024 is the correct number. If I had a 3 bit ADC I'd /8, NOT /7 . Using ( 2^N -1 ) would mean the Vmax one can convert is Vcc. In tantalums, I've tried using those on the output of a 7805 regulator design in the past and it caused the regulator to oscillate. I replaced it with same valued ceramic and it ran cool and didn't oscillate ! Maybe I had a stank batch of tantulums... Maybe your tantulum is giving you a bit of trouble ( maybe not )...

Manuel you can just do :

return ADCW;

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

Quote:

No, /1024 is the correct number. If I had a 3 bit ADC I'd /8, NOT /7 . Using ( 2^N -1 ) would mean the Vmax one can convert is Vcc.

Indeed, the Vmax one can convert is Vcc. So, /1023 is IMO the correct number. Yes, the equation in the datasheet shows *1024.

Now you've gotten me all confused again...so in a 5V setup, you are saying that I'm going to get 1023 counts at ~4.95V?

Perhaps we'll discuss using a 4.096V reference as we use in some of our apps. At what voltage do we get 1023 A/D counts?

As OP has found, measuring a real world signal "in the mud" and "at the max" is a tricky business. I haven't found any significant situations in the AVR's ADC itself over the years with offset or linearity or lost counts or any of that.

But in practice, a real-world signal--e.g., 0-10V control signal from another device--isn't entirely clean. I typically take the 1023 count range and discard a few counts at the bottom, and then discard a few counts at the top, leaving me with an easy-to-handle 1000 count range that is 0% to 100%. One does not want the system to "creep" when the control signal is turned all the way down even though less-than-perfect conditions may result in a few A/D counts. Similarly at the top end one wants to get to 100% and not be stopped short based on real-world conditions.

In the A/D work, one can't give 110%. ;)

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

I happen to have an app board on the bench that indeed uses a 0-10V input control signal, scaled to a 4.096V reference.

The reference actually reads 4.0952/4.0953V.

The A/D counts move from 1021 to 1022 at about 4.0951V. It was hard to tell when the actual "trip" to 1023 happened 'cause the test pot is touchy. But I'd say that on this experiment, 1023 counts represented Vref.

The experiment also corresponds with my usual approach: For real-world signals toss away a few counts at the top and bottom.

BTW, I get 12 counts at 0.0543V with the aforementioned 4.095x reference. At ~4.1mV/count that is fairly close. That's as low as my pot would go. Using a clip lead to Gnd I get 1 A/D count at 4+mV so the low end that OP is fighting looks OK to me.

Now, y'all tell me whether it is *1023 or *1024 and how to prove it one way or the other...

Lee

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

1024 is 2**10. Bit weights of a binary number are 2**0, 2**1, ... so 2*10 takes 11 bits! 1023 is the largest number that can be held in a 10 bit binary value.

The ADC tops out at 1-bit less than Vref. The correct expression is Vref * N/1024, where N is in the range of 0 to 1023.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

theusch wrote:
Now, y'all tell me whether it is *1023 or *1024 and how to prove it one way or the other...
Also, the ADC works using GND as the low end ref., so a 0 count has to be used to represent zero volts, anything < ~4.8mV. This leaves 1023 counts out of 1024 left for > 0V ADC work.

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

Quote:

The correct expression is Vref * N/1024, where N is in the range of 0 to 1023.

That's the whole crux of the matter. With a perfect A/D system and a 4.096V reference, does 1023 counts represent 4.096V or 4.092V? With your equation, then it would appear that it would be 4.092V and 4.096V cannot be measured.

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

Correct. If you look at the ADC section in the spec sheet, at the top end, it maxes out 1 bit below Vref.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

Hello all,

I made another PCB and relayout the tracks. I verify the noise in the AVCC line with the scope at 10mv/div and it is clear, but, in spite of that I continue to have 5 bit difference when I measure 50mV.

I put the ADC work with a REF external voltage and the result is the same.

I am going to forget it and go add 5 bits to the ADC reading.

Thanks to you all.
Manuel

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

I wasn't clear. The external REFV was an external battery, so, there wasn't noise (it was just to make sure it wasn't a noise problem). After all of this trials without success, my conclusion goes to a MCU problem. May be a wrong batch, because, I also changed the MCU.

Regards,
Manuel

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

Let me guess... the new avr gives exactly the same results as the old one? Check the data sheet and see if the a/d pins are on the same pins as the jtag inputs. If so, writing MCUCR=0x80; twice will shut off the jtag.

Imagecraft compiler user

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

Bobgardner,

Thanks for your inputs. Yes the new AVR gave exactly the reading. The JTAG pins aren't in the same position of the ADC pins.

Thanks,
Manuel

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

I always have a 'testad' routine that reads an a/d channel and prints it out as %03x, and I use a pot from vcc to gnd. Numbers should smoothly go from 000 to 3ff. Usually there is flicker from one digit to another, but this this can be averaged out by averaging 8 or so readings.

Imagecraft compiler user

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

Bobgardner,

I also use also a pot as a voltage divider and with a voltmeter measuring the input voltage at the same time loking to the printed value.

what happens is that from 0.0v till 0.032V the ADC reads 0x000. Above 0.032 V it reads 0X001. It is very stable, that is another symptom the there isn't noise other wise we had the value changing up and down.

This is my problem.

Thanks.
Manuel

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

You are saying the first count/bit which should change every 5mv, doesnt change until 32mv? It might be that loose nut behind the keyboard. Better show us the program.

Imagecraft compiler user

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

Bobgardner,

I bit is ~= 5mV, and it doesn't change until 32mV.

The ADC set up is the following:

// ADC Enable
			ADCSRA |=(1<<ADEN);
			ADCSRA |=(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
			ADMUX  |=(1<<REFS0);
			DIDR0 =0b00001111;

The code to read the ADC is the following;

 uint16_t Read_ADC(uint8_t adc_adr)
{
		uint16_t adc_value =0;
	
		ADMUX =(adc_adr)|(1<<REFS0);
		asm("nop");
		asm("nop");
	
		ADCSRA |=(1<<ADSC);

			while(ADCSRA & (1<<ADSC)); {}
	
			adc_value=ADCW;

    return adc_value;
			 
}		

Function call:

adc_value = Read_ADC(1);
			 save_adc_data(37, adc_value);

The above code is all the code used to control the ADC.

Regards,
Manuel

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

Hello all,

Just for your information. I have another PCB (very simple one) with an ATmega644P to try simple routines before implement them and today I tested the ADC and it has the same problem.

Does any one of you have a Atmega644P installed and please do an ADC test to see if found the same problem or may be I am making always the same mistake.

Can any one of you also give a look for the above code and see if it is correct? I may put all the code here, but, it is a long list that you may find it boring, (and for sure will generate a lot of comments because I am in a learning process) any way, if you find it may interest no problem.

Thanks in advance.
Regards,
Manuel

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

Lets assume adc_value has the right number in it. Better show us what save_adc_data does to it. That's where my money is.

Imagecraft compiler user

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

Bobgradner,

Thanks for your interest and help.

the save code is the following:

void save_adc_data(uint8_t j, uint16_t adc_value)
{
	    
		   GPS_data[j]=(uint8_t)(adc_value>>8);
			j++;
		   GPS_data[j]=(uint8_t)(adc_value);


}

Thanks,
Manuel

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

That is storing the data "big endian". Is the consumer of the data expecting big endian or little endian?

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

Clawson,

I do not understand what you mean. Can you please be more specific.

Thanks,
Manuel

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

Well you tell me where GPS_data[] that you are creating there is being used? Why for example are you even splitting a uint16_t into two uint8_t anyway? Why not make GPS_data[] and array of uint16_t anyway?

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

Clawson,

I gave the name GPS to the vector as any other name. I receive the data from the GPS in binary format to be more compressed (latitude occupies only 4 bytes as well as longitude, etc). As the data arrives to the UART buffer in a byte format, I decided to save it in a vector. This GPS and the system (AVR) will be inside of an airmodel. I use the ADC to read the battery voltage, current drown, etc. I have also an atmospheric pressure sensor, measure revolutions per minute of the motor, etc.

This data is send down also in binary format using a Two way Tx Rx control system. The binary format is used due to constrains on amount of data that I can send down by second.

Summarizing:

All the data is put into a vector and sent down once per second.

On the ground I have another AVR (Arduino due to easy find libraries for displays), that computes the data and display it.

Regards,
Manuel

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

The 644 has 2 uarts. I guess you are using one of them to read the gps data from the receiver. How about rigging up the 2nd uart to print out variables? Try printing out adc_value right in the top of save_adc_data and see if it looks right at that point. I think you are swapping the hi and lo bytes inadvertently.

Imagecraft compiler user

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

Quote:

On the ground I have another AVR (Arduino due to easy find libraries for displays), that computes the data and display it.

As long as it agrees the protocol and reads that field as big endian too it should be OK.

But do you realise you could do it with a struct? Say you have a 11 byte packet consisting of a 4 byte lat, 4 byte lon, 2 byte ADC reading and a 1 byte packet number (this is just an example) then you have two choices:

uint8_t data[11];
data[0] = pkt_num;
data[1] = lat >> 24;
data[2] = lat >> 16;
data[3] = lat >> 8;
data[4] = lat;
data[5] = lon >> 24;
data[6] = lon >> 16;
data[7] = lon >> 8;
data[8] = lon;
data[9] = adc_reading>>8;
data[10] = adc_reading;

for (i=0; i<11; i++) {
  transmit(data[i]);
}

Or you could do this:

union {
  uint8_t data[11];
  struct {
    uint8_t pkt;
    uint32_t lat;
    uint32_t lon;
    uint16_t adc;
  };
} thedata;

thedata.pkt = pkt_num;
thedata.lat = lat;
thedata.lon = lon;
thedata.adc = adc_reading;

for (i=0; i<11; i++) {
  transmit(thedata.data[i]);
}

(the purists will be along in a minute to throw their hands up in horror - but if it's the same avr compiler at both ends and they both know the layout of "thedata" this will just work).

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

Bobgardner,

Yes, I use one UART to the GPS, Tx to send commands and RX to receive the data. The second UART I use only the Tx to send the data out. The Rx pin is also Int0 I use for counting the revolutions/minute.

Due to the type of data I get it can not be swapped, because 0.0V at ADC input I get 0x000, 0.030V I get 0x000, 0.035V i get 0x001.

I also connect the UART Tx before send it down to the serial input of the PC and the result is the same.

Do you see any problem in the code?

Thanks for your suggestions.

Regards,
Manuel

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

Clawson,

The examples you gave are great. But it is too much for me. I am beginner, I lear AVR assembler by myself, and now I am trying to learn C on my own. I think I am a bit pollarized by the way I was doing assembly, so, some times I am tempeted to do it the same way.

Thanks any way. I am going to try to implemente your sugestions, but now my priority is solve the ADC problem I have.

Do you see any code error that can generate the problem?

Regards,
Manuel

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

You need to arrange a way to print out intermediate results. Perhaps the adc_value is correct. How would we ever know unless you print it out? Maybe we need to see the schematic too?

Imagecraft compiler user

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

Bobgardner,

I did this change in the code and the result didn't change. It continues to read above 0.030V.

 uint16_t Read_ADC(uint8_t adc_adr)
{
		uint16_t adc_value =0;
	
		ADMUX =(adc_adr)|(1<<REFS0);
		asm("nop");
		asm("nop");
	
		ADCSRA |=(1<<ADSC);

			while(ADCSRA & (1<<ADSC)); {}
	
				adc_value=ADCW;
		
    			while (!(UCSR1A & (1<<UDRE1)));
				           					
				UDR1= (uint8_t)(adc_value>>8);
				

				while (!(UCSR1A & (1<<UDRE1)));
				
				UDR1=(uint8_t)(adc_value);


				return adc_value;
			 
}		

I read only one ADC channel and print it.

Attached please find the schematic

Manuel

Attachment(s): 

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

Looks to me like the 5V and gnd should be on pins 1 and 3 of the pots. The wiper (to the a/d) is pin 2 in the middle?

Imagecraft compiler user

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

Bobgardner,

This pins are pin headers. Pin 1 has the information, 2 is the +5V and pin 3 ground. I use this order because it is the standard in aeromodels like servos, receivers,etc.
Do you see any problem with this order?

Manuel

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

Can you tell us more about the pots, like their size (in ohms). Is the wiper (middle pin normally) connected to pin 1?
Also tell us how & where you are monitoring the voltage. Apologies if this was covered earlier.

Also, the code you posted suggested that you are using adc channel 1 and the schematic shows a 91K resistor in series with the input and a 22K going to ground. Can you explain the purpose of these?

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

Maximax,

The JP15, JP3, JP4 and JP6 aren't pots. They are pin headers to connect female type of plugs used in aeromodels.

Between JP15 and JP3 and the MCU ADC0 and 1 respectively, there is voltage divider 91K and 22K to allow measure voltages till 25,6V (6 elements of LiOn battery) The pin 1 goes to the positive and pin 3 goes to the ground of battery.

To the JP4 is connected a temperature sensor LM35. the pins 2and 3 are power to the sensor, pin 1 is the output of the sensor 10mV/deg.C.

To JP6 is connected a current sensor made with a INA139 with a 0.1V/ampere.

I use channels 0,1,2 and 3. for the above proposes.

I think I gave an idea of what is connected to the ADC inputs.

I notice the ADC problem when was calibrating the current sensor. I was measuring the voltage at the output of the sensor and looking to the ADC value and it didn't look right.

After that I used a 5K pot connecting one side to +5V and the other to the ground, the center pin connected to the ADC input and observed that till the 0.030V the ADC doesn't respond, always reading zero. this happens in all the channels. I suspected of the PCB because the MCU was on a header board, so, I decided to make a new PCB eliminating the header, but the result was exactly the same.

I changed the MCU, same result. I have a simple PCB with a Atmega644P to experiment same code and the result is the same.

Another observation is that the reading is very stable, so, if it was noise it should vary a lot. Another thing is it only responds at voltages above 30mV.
This is very strange because I used 3 different PCB's, more than one MCU, several types of components connected to the ADC, etc.

Thanks,
Manuel

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

You were asked to post your code and you showed an adc setup reading channel 1. You were then asked to show a schematic and this depicts a resistive divider on adc channel 1.
Are you now saying that this is not the actual circuit currently under test? The reason I ask is that the results you are getting are fairly consistent with those I'd expect from connecting another resistor in parallel with the wiper to ground resistance through a much bigger series resistance. :?

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

Maximax,

The schematic I sent is the circuit I use, but, as I already told, I used a 5k multiturn pot just to make a test.

If you look for the schematic the ADC2 there isn't voltage divider. If you use the 5K pot with the middle point connected to pin 1 and one side to ground and the other to +5V, and connect a voltemeter between the pin 1 (ADC2 input), when we increase the voltage from Zero the ADC only starts work at 30mV. this means, from zero volts till 30mv the output of the ADC is zero.

This has nothing to do with another resistor in parallel. We are measuring the real voltage at the ADC input pin. This is my problem.

Is there any one that has a Atmega644P to make a ADC test?

I did the same test using a Atmega328P (Arduino) and it responds correctly (5K pot) 1 bit~= 5 mili Volts.

thanks,
Manuel

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

Instead of 'inlining' the body of the putchar subroutine twice in the a/d routine, why not just write the putchar routine then call it? What if the a/d value is 0x12? You can't print out a binary 1 or a binary 2... they come out as happy face and clubs or something. At least add 0x30 to the binary number to get ascii decimal... 1 becomes 0x31... a '1' in ascii. THAT will print.

Imagecraft compiler user

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

Bobgardner,

Thanks again for your interest. I didn't understand what you mean, but, the data sent out is binary data as read from the ADC register. I am reading the data using the Br@y++ terminal as Hex value. There isn't possibility of being ASCII.

As I do not understand very well your comment I do not know if it answer to it.

Regards,
Manuel

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

OK, when the pot is all the way down, do you see 0x00 0x00 on brays Terminal? Now turn it up till it says 0x00 0x01. Measure the wiper. Should read 5mv. Repeat this test at 0x01 0xff and 0x03 0xff. Should get 2.5V and 5.0V.

Imagecraft compiler user

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

Bobgardner,

Here is the results:

0x000 -------- 0.000V
0x001 -------- 0.035V
0x1FA -------- 2.501V
0x1FF -------- 2.526V
0x3FF -------- 5.04V

Regards,
Manuel

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

As I said earlier, it is hard to measure things in the mud (at very low signal levels). As things appear pretty well spot-on at the higher signal levels, I'd wager that examination with a good 'scope at low V/division will show like 30mV of ripple somewhere--signal, reference, supply, ground. That has always been the result of these threads in the past.

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

It does look like the AVR is sitting in a 32mv deep hole. 32mv of IR drop from the AVR gnds back to the power supply?? Try a Big Fat Ground Wire from AVR gnd to power supply gnd? (all other VCC and GND pins connected, including AVCC?). Try another pot. Maybe that pot you have just has a big jump at zero volts? Is it wire wound?

Imagecraft compiler user

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

Hello all,

Just for your knowledge, I did another PCB, with the following changes:

- Below the MCU I left a square of copper track connected to the grand.

- The bottom copper layer I left an area according to the Atmega644P data sheet and connected it directly to the analog ground pin.

- All the bottom PCB layer is connected to the ground.

- All the ground pin of MCU are directly connected to the same ground point (wires).

- All VCC pins are decoupled as close as possible of the MCU pins.

- Measure the different ground points including the analog ground with the multimeter in uV scale I have 00.00uV.

- I do not have visible noise in the VCC, AVCC, analog lines and ground

In spite of all that I continue to have a 5 bits difference. only at 0.035V the output of the ADC is 0x001.

I am going to give up and chose another MCU.

Thanks for being patient with me.

Regards,
Manuel

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

Quote:

I am going to give up and chose another MCU.


If it's ripple on the PSU how does this help?

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

Run from a battery. No ripple

Imagecraft compiler user

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

Quote:

Just for your knowledge, I did another PCB, with the following changes:
...

From above https://www.avrfreaks.net/index.p...

Quote:

I get 12 counts at 0.0543V with the aforementioned 4.095x reference. At ~4.1mV/count that is fairly close. That's as low as my pot would go. Using a clip lead to Gnd I get 1 A/D count at 4+mV so the low end that OP is fighting looks OK to me.

It sounds like you have covered all the bases with your changes and testing. I've lost track: Have you used more than one piece of AVR and the results are the same? Are the same results repeatable from channel to channel?

As I posted earlier, I saw no problems at the low end with one of my production app boards, and the conditions were less than ideal: flying leads to a trim pot, for example.

Typically a situation like this involves ripple and other signal bounces. How about the measurement itself? Are you sure that your meter is happy reading a few millivolts?

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

Hello all,

Just for your knowledge, I did another PCB, with the following changes:

- Below the MCU I left a square of copper track connected to the grand.

- The bottom copper layer I left an area according to the Atmega644P data sheet and connected it directly to the analog ground pin.

- All the bottom PCB layer is connected to the ground.

- All the ground pin of MCU are directly connected to the same ground point (wires).

- All VCC pins are decoupled as close as possible of the MCU pins.

- Measure the different ground points including the analog ground with the multimeter in mV scale I have 00.00mV.

- I do not have visible noise in the VCC, AVCC, analog lines and ground

In spite of all that I continue to have a 5 bits difference. only at 0.035V the output of the ADC is 0x001.

I am going to give up and chose another MCU.

Thanks for being patient with me.

Regards,
Manuel

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

I'm getting an extremely strong sense of deja-vu!?!

BTW did I say that I'm getting an extremely strong sense of deja-vu?

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

My multimeter is a Fluke, and I use the 300mV scale.

I have 2 Atmega644P and already tried both, the same result.

Do you already look to the code I use? Can the code do some thing like this?

How can I use the "ADC noise canceler function to reduce induced noise from the CPU".

I have a .1uF capacitor on the AREF Pin. Is this OK?

Thanks,
Manuel

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

Hello all,

I used a Arduino Nano on a bread board and run the same ADC code and it gives about 0.005V by bit (long wires etc. and the reading is ok.).

I changed the Crystal in the original board from 18432000Hz to 16000000Hz and at 0,035V i get 0x003 instead of 0x001.

These observations give you some clues?

Thanks,
Manuel

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

Quote:

BTW did I say that I'm getting an extremely strong sense of deja-vu?

I think the repeat was due to my requote(s).

Quote:

These observations give you some clues?

On the original board, do you get the same result on all ADC channels, or just the one?

I've lost track---what prescaler are you using on the original board?

(It certainly is possible that one ADC channel got damaged, or even all of them. For example, a reference voltage error could have been made at some point in ADMUX setting.)

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

Maybe you were running the prescaler too fast for the crystal you were using?

Imagecraft compiler user

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

Quote:
Maybe you were running the prescaler too fast for the crystal you were using?

If you also observe 'bleeding-through' from another ADC channel this is the first thing you should check. Consult the datasheet for the maximum clock of the ADC on the Mega644.
Quote:
I have a .1uF capacitor on the AREF Pin. Is this OK?
It should be ok. In a former post you staed that all your voltages are clean , so 0.1 uF should be fine.

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

Hello all,

After all the problems I decided go to the Atmega328P, as I need 2 UARTS I made a switch with a 74hct08 and its working. I just made a PCB to connect an Arduino pro, http://arduino.cc/en/Main/Arduin... connect it to the PCB with jumper pins, and its working. the ADC reading its OK, 0,035V = 0X005 (five bits). I didn't care about grounds, noise etc. and as I said it is working. I suspect it is a MCU problem.

Thanks to you all to try help me.

Regards,
Manuel