mega169 ADC not working

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

I'm developing a project which requires the use of the internal ADC to monitor battery voltage. I had designed a "breakout board" for the mega169 to allow access to the various I/O pins. I wrote my ADC code to select ADC0 as the input, and the internal 1.1 volt reference. I could not get any kind of rational result from the ADC. After hours of trying a variety of "fixes", I found that little note in the data sheet - "If the user has a fixed voltage source connected to the AREF pin, the user may not use the other
reference voltage options in the application, as they will be shorted to the external voltage." I had tied the AREF to AVCC on my board :-(

I carefully pried pin 62 (AREF) from my board (as the track to which is was attached was beneath the device), carefully soldered a small tantalum cap across it to ground, and tried again. The reference voltage on the cap shows 1.08 volts, and if I select either ground or the 1.1 volt reference in the ADMUX, I get a good result. However - if I select any external ADC input, I always get 0x03ff as the result, no matter what the actual voltage is.

I am assuming that this means I have tanked my mega169, correct? Any other options I should try before replacing the device?
 

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

 I have tanked my mega169, correct?

Maybe...

 

I think right now you have not yet determined, with certainty, whether or not this is a hardware problem or a software problem.

 

It is likely a hardware problem, but isn't yet proven to be so.

 

You really need a second M169 with which to test your current code, and show that it works, before you right off the chip.

 

Typically one hooks up a POT, (10K or whatever, Vcc and Gnd, wiper to the ADC input), and reads the input voltage on a voltmeter while looking at the ADC count, (and then, next step, at the ADC input voltage).

 

So, you could post your ADC code, (short, minimally compilable program), and have a few people look at it, but the real test is running it on real hardware.

 

Do you have a second M169 available for testing before you trash the first one?

 

 

Off topic:

 

The M169, IIRC, has an LCD glass driver built in, and was used in the Atmel Butterfly credit card sized demo boards. 

If you had one of those you could easily test your ADC setup and measurement routines, and even display the results on the Butterfly's built-in display.

 

If you switched to a M168 or M328, on an Arduino Nano board, it would cost $3 USD, (Clone), and would include a power supply and USB output to display your ADC data on a PC terminal program.

(Although an "Arduino" board, you can program it in whatever language you like)

 

If you have a good reason to use the M169 then so be it, otherwise there might be other options that are easier to use / debug, etc.

 

JC

 

Edit:Typo

 

 

  

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

DocJC,

"

Typically one hooks up a POT, (10K or whatever, Vcc and Gnd, wiper to the ADC input), and reads the input voltage on a voltmeter while looking at the ADC count, (and then, next step, at the ADC input voltage).

 

So, you could post your ADC code, (short, minimally compilable program), and have a few people look at it, but the real test is running it on real hardware."

That is what I have done - as I mentioned, I designed a PCB with power supply parts and breakout pads to be able to connect to I/O. I had a 10K pot supplying the input voltage, with a DVM monitoring the input to the device.

Also, as I mentioned, I have used the ADC on a variety of other Atmel devices without issue.

I can change the part much faster than trying to locate a Butterfly board.

FWIW, code is below.

Thanks for your input!

 

ADC initialization:

    DIDR0 = 0x01; // Disconnect digital buffer from analog pin    
    ADCSRA = 0b10000011; // Enable ADC, use /8 clock divisor    
    ADMUX = 0b11100000; // Select PF0, ADLAR set, internal 1.1V ref

 

Main loop:

    while (1)
    {
        activeSwitches = PINE;
        ADCSRA |= (1<<ADIF); // clear any pending flag
        ADCSRA |= (1<<ADSC); // start conversion
        while (!(ADCSRA & 0x10)) // wait for ADIF to go high
        {
            ;
        }
        batteryVoltage = ADCH;

 

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

  I had tied the AREF to AVCC on my board

internal 1.1V ref

 

That's a good way to kill your chip.  surprise

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

js wrote:

  I had tied the AREF to AVCC on my board

internal 1.1V ref

 

That's a good way to kill your chip.  surprise

Yep, that's exactly what happened! New chip, cut the trace beneath before soldering the new device, re-attached all the parts, plugged in the Dragon, and voila! ADC works like a charm!

Thanks for the feedback!

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

davetelling wrote:
Yep, that's exactly what happened!

So now please mark the solution - see Tip #5

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1
    ADCSRA = 0b10000011; // Enable ADC, use /8 clock divisor    
    ADMUX = 0b11100000; // Select PF0, ADLAR set, internal 1.1V ref

    while (1)
    {
        activeSwitches = PINE;
        ADCSRA |= (1<<ADIF); // clear any pending flag
        ADCSRA |= (1<<ADSC); // start conversion
        while (!(ADCSRA & 0x10)) // wait for ADIF to go high
        {
            ;
        }
        batteryVoltage = ADCH;

What an interesting mish-mash of code styles. Sometime symbolic with (1 << signal_name), some time meaningless binary (0b10000011) and some time meaningless hex (ADCSRA & 0x10). The code would be so much easier to read if it were all symbolic:

    ADCSRA = (1 << ADEN) | (0b11 << ADPS0); // Enable ADC, use /8 clock divisor    
    ADMUX = (0b11 << REFS0) | (1 << ADLAR); // Select PF0, ADLAR set, internal 1.1V ref

    while (1)
    {
        activeSwitches = PINE;
        ADCSRA |= (1<<ADIF); // clear any pending flag
        ADCSRA |= (1<<ADSC); // start conversion
        while (!(ADCSRA & (1 << ADIF))) // wait for ADIF to go high
        {
            ;
        }
        batteryVoltage = ADCH;

However it can be simpler than this - forget about ADIF all together and it becomes:

    ADCSRA = (1 << ADEN) | (0b11 << ADPS0); // Enable ADC, use /8 clock divisor    
    ADMUX = (0b11 << REFS0) | (1 << ADLAR); // Select PF0, ADLAR set, internal 1.1V ref

    while (1)
    {
        activeSwitches = PINE;
        ADCSRA |= (1<<ADSC); // start conversion
        while (ADCSRA & (1 << ADSC)) // wait while ADSC remains high
        {
            ;
        }
        batteryVoltage = ADCH;