76 posts / 0 new

## Pages

Author
Message

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
DIDR0 =0b00011111;
```

```

/****************************************************************
* motor battery voltage, receiver battery voltage, temperature and
* air speed.
*/
{

}		```

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

Regards,
Manuel

Quote:

With this you clear the reference setting (REFS0).

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!)

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

Quote:

`adc_value = Read_ADC(0);`

and

``` uint16_t Read_ADC(uint8_t adc_adr)
{

```

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.

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:

The inaccuracy is decreasing as the voltage read is higher.

Thanks
Manuel

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

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).

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?

Jim

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

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

Jim,

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:

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

Putting the two measuring leads together I get 0.000 Volts

Thanks.
Manuel

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.

Quote:

The calculation I do is the following:

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.

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.

Manuel

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"!

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.

ManuelSilva wrote:

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

Quote:

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

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

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

10*0.00488... Volts.

This is the way I do. Is this wrong?

regards,
Manuel

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).

Theusch,

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

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"!

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?

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

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

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.

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 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.

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"!

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

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.

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"!

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.

Thanks to you all.
Manuel

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

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

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

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

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

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

Bobgardner,

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

The ADC set up is the following:

```// ADC Enable
DIDR0 =0b00001111;```

``` uint16_t Read_ADC(uint8_t adc_adr)
{

asm("nop");
asm("nop");

}		```

Function call:

```adc_value = Read_ADC(1);

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

Regards,
Manuel

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.

Regards,
Manuel

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

Thanks for your interest and help.

the save code is the following:

```void save_adc_data(uint8_t j, uint16_t adc_value)
{

j++;

}```

Thanks,
Manuel

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

Clawson,

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

Thanks,
Manuel

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?

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

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

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;

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;
};
} thedata;

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

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).

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?

Regards,
Manuel

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