Help with ADC problems (solved)

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

System is Mega48PA, 4.6864MHz powered by 4.2V Lipo and charged by USB. It has 2 digit LED multilplexed and TXd comms at 1200 baud for debug.

AVcc is connected to Vcc(+100nF) and AREF is decoupled with 100nF. The system also has 3 buttons and an I/R transmission system with DOW 8 bit CRC checking.

Everything works just fine, but for the life of me, I can't get the ADC system to give me any sensible results. I get a few odd random meaningless  readings, then the ADC gives a stream of constant readings.

Those readings won't change if I vary the input voltage...

There is a 39K from Vcc to ADC channel 7 then a 10K from there to PD2 which I pull low to activate the potential divider.

I calculated expected ADC values in the range of 0xB4 to 0xC7 using 1.1Vref and 8 bit resolution

In the code, I have left out the delay routine and the comms transmit. 

Can someone give me a sanity check on the ADC code and point me in the right direction.....( I'm 99% certain there isn't a hardware issue)

I also tried reading the temperature Mux=8 with the similar results- no change in ADC value when I heated up the chip...

TIA

 

BATTERY:

CLR TEMP
STS ADCSRB,TEMP

LDI TEMP,0xC7			;1.1v REF;8 BIT ANS;CHANNEL 7
STS ADMUX,TEMP

LDI TEMP,0XC6			;ADEN,START,clk/64
STS ADCSRA,TEMP

ADCWAIT:

LDS TEMP,ADCSRA
ANDI TEMP,0x10			;TEST ADIF BIT
BREQ ADCWAIT
			
LDS TEMP1,ADCL			;GET LOW 8 BITS FROM ADC

RCALL SENDCHR			;SEND TO UART

RCALL DELAY			;WAIT 300mS

RJMP BATTERY			;REPEAT

 

Last Edited: Mon. Aug 3, 2015 - 08:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are trying to measure Vcc, why not to use Vcc as adc reference and measure 1.1V internal bandgap reference? No dividers or so..

Computers don't make errors - What they do they do on purpose.

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

Because the PCB is already designed and I used a similar solution using the analogue comparator, so I was happy with that.I did consider the upside down method you describe...

Reading some other posts , I might try a 100nF across the 10K but the results I get don't suggest that will be the solution...

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

It won't change anything on pcb - Avcc can be used as reference internally (with cap on Aref) - you just have to read correct channel.

And I think input impedance should be less than 10kOhms for ADC.

 

And you might want ADLAR=1 to have bits ADC9:ADC2 in ADCH. Now you have two of most significant bits in ADCH and rest in ADCL

Computers don't make errors - What they do they do on purpose.

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

OK I'll look at that later... First up is to get going what I have and discover what the problem is!  ADLAR = 0 gives me 8 bits, I don't need 10 bits resolution.

Thx.

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

Where do you clear ADIF? Why not just test for ADSC?

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

You state that with ADLAR =0 you have 8 bits......

You need to set ADLAR to 1 to have 8 bits. 10 bits is default with ADLAR = 0;

 

Also you need to read ADCH before a new conversion result will be available.

You only read ADCL so new conversion results will never be stored.

 

see the register description section in the datasheet

 

regards

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

ADC gives you always 10bits resolution. If you have ADLAR=0 that value is perfect for C compiler as there are 8lower bits in ADCL and bits with values 256 and 512 are in ADCH. So you have values from 0x000 to 0x3FF and you ignore MOST SIGNIFICANT BITS.
 

Also ADCL is buffered and never updated again until you read ADCH!!!!

 

When ADCL is read, the ADC Data Register is not updated until ADCH is read. Consequently, if
the result is left adjusted and no more than 8-bit precision is required, it is sufficient to read
ADCH
. Otherwise, ADCL must be read first, then ADCH.
The ADLAR bit in ADMUX, and the MUXn bits in ADMUX affect the way the result is read from
the registers. If ADLAR is set, the result is left adjusted. If ADLAR is cleared (default), the result
is right adjusted.

Computers don't make errors - What they do they do on purpose.

Last Edited: Mon. Aug 3, 2015 - 05:54 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Seems I have made two errors.... one is not reading ADCH, the other is assuming that I effectively get the 8 bits that I want in ADCl.

What I actually want/need is the top 8 bits from 10 and drop the 2 LSBs, so all I have to do is change ADLAR to 1 and just read ADCH.

Thanks all. :)

Last Edited: Mon. Aug 3, 2015 - 11:50 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Made the changes ( read ADCH) and it now works 100%. yes

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

Do you now clear ADIF as Kartman wrote in post#6?
 

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

No, It seems I don't need to...

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

But did you check? Read the datasheet on the operation of ADIF.
The complete flag is simpler.

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

chartman,

I guess you then made 3 mistakes......

IIRC (see datasheet as suggested by kartman) the adif bit is only cleared when entering the adc complete interrupt.

If after the first conversion it is set forever, you will never wait for a next conversion to be completed, hence you will read a faulty value a couple of times before you get a correct readout.

if you continuously just read and spit out the read data you will not see this as spitting out the data slows down your reading. But when the received data is to be used internally you will be acting on faulty data...

 

 

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

OK I need to look at that.... all I can say is that when I vary the input volts on the target system, I see a valid value sent over comms.... maybe the delay routine and going back and initialising the ADC negates the need to clead the ADIF flag.

I'll have another play when I get some time. Also, I think I will need a delay after setting the low end of the 10K, to give time for the 100n to get to a steady state ( which is why I get a couple of low readings to start off...

I suppose I could use interrupts and just read and store ADCH +reti then I don't have to worry about clearing ADIF...

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

I think you've missed the point we're trying to make - rather than testing ADIF, the ADSC flag can be used instead and doesn't need to be cleared. Why people use the ADIF flag is beyong me.

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

I think that's because a lot of examples out there use/test ADIF. I'll try ADSC...

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

I changed the software to test ADSC and that works fine. Also, putting in a delay after grounding the low end of the 10K got rid of the initial spurious results and now the first and following results are rock solid +/- 1 bit.

Lots of lessons learnt here so thanks to everyone. I might try the other suggestion re battery to Aref and read Vref .....

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

It works only if you have battery directly connected to Vcc/Avcc. No need to connect anything to Aref (except for cap). It won't work if you have some kind of LDO between battery and mcu (at least since voltage drop on LDO from source will be more than its output)

Computers don't make errors - What they do they do on purpose.

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

That works for me... The system is driven directly from a LiPo.