4
\$\begingroup\$

I'm working with an ATTINY26(L) learning about interrupts, and discovered a problem.

I am getting a different output voltage on PORTA (half) than I am on PORTB. To simplify things, I made a program to turn on a single LED on a given pin. I've tested so far on several pins from both ports.

ATTINY26L pinout

On PORTA, if I measure pin to ground without a load, I get 5V. If I connect the LED (3\$V_f\$) and a 100Ω resistor, the voltage drops to 2.5V, and the LED is dim (2.5V across the LED and 6mV across the resistor).

On PORTB the voltage stays 5V (3V across the LED and 2V across the resistor).

Code:

int main()
{
    DDRA = 0xFF;
    DDRB = 0xFF;

    while (1)
    {
        PORTA = (1 << PA6); // Half voltage?
        PORTB = (1 << PB6); // OK
        milli_delay(100);

        PORTA = (0 << PA6);
        PORTB = (0 << PB6);
        milli_delay(100);
    }
}

void milli_delay(int d)
{
    for (int i = 0; i < d; i++)
        _delay_ms(1);
}

Do I have a damaged microcontroller, or have I overlooked something?

Update:

I swapped out the microcontroller for an identical one, and have the same result. I think it's unlikely that two are damaged in the same way.

Update 2:

Some have requested the compiled HEX code: (Link now removed.)

Update 3:

@Jippie was kind enough to check out the ELF (decompiled) code and saw a weird change of PORTA back to input, immediately after setting it to output. What gives?

The code I pasted above isn't quite complete. There's a little extra line of code which should have been commented out, or pasted into this question:

DDRA = (0 << PA7); // input on PA7

PA7 was intended to read a switch as part of my pin change interrupt testing. I thought the line had been commented out, but it wasn't. And, if you look closely, you'll spot a problem.

It should be:

DDRA |= (0 << PA7);

Trying to set pin PA7 to 0 for input alone should be done with an OR-EQUALS operator (|=), not just EQUALS (=). As a result, the entire PORTA was set back to input.

The lesson here? A single pipe character ruined more than a whole day of learning and experimenting. A single line of code omitted from the question (or not properly commented out for testing) caused headaches.

I am always my own worst enemy when it comes to troubleshooting. It wasn't a faulty chip, a compile error, or some accidental configuration. Total newbie mistake in not thoroughly checking my own code.

Some pics:

Project setup

\$\endgroup\$
15
  • 1
    \$\begingroup\$ Did you measure the actual current draw on each of the two pins you are using? Is this on a breadboard or a development board? (obvious question, are you replacing the resistor or have you swapped the led/resistor on one pin to the other?). I'm not a avr guy, but you should be able to get atleast 20ma out of each port with a minimal voltage drop of 0.7v. Is there any default peripherals that you forgot to disable, or pullup/down resistors that are on? \$\endgroup\$
    – Passerby
    Jan 3, 2013 at 6:08
  • \$\begingroup\$ Each port can support up to 40mA per the datasheet. If I measure the current through the LED and resistor on the working side (PORT B) it's at 17mA. Both ports have all pull-up resistors enabled (set to output) by the respective DDRx = 0xFF; commands. It's quite confounding. \$\endgroup\$
    – JYelton
    Jan 3, 2013 at 6:15
  • \$\begingroup\$ @passerby: Sorry I missed one of your questions. It is on a breadboard at the moment, so the resistor has been the same on both ports. \$\endgroup\$
    – JYelton
    Jan 3, 2013 at 6:22
  • 1
    \$\begingroup\$ output and pullup resistors arn't the same thing, but how you have it should be correct. Try swapping the resistor out. Try connecting the led/resistor on a different PortA pin. Turn all of portA on (0xff) and see if it's the same for every portA pin (moving the led/resistor across the board) \$\endgroup\$
    – Passerby
    Jan 3, 2013 at 6:30
  • 2
    \$\begingroup\$ @jyelton Silly question, is AVCC connected correctly? Same for both GND pins? Found this "AVCC is the supply voltage pin for Port A and the A/D Converter (ADC). It should be externally connected to VCC, even if the ADC is not used. If the ADC is used, it should be connected to VCC through a low-pass filter... " \$\endgroup\$
    – Passerby
    Jan 3, 2013 at 19:00

1 Answer 1

4
\$\begingroup\$

Not a real answer, but too much information to include in a the comments:

I took a look at your disassembled code and this part is strange:

  18:   11 24           eor r1, r1          ; r1 = 0

...

0000005e <main>:
  5e:   8f ef           ldi r24, 0xFF   ; 255
  60:   8a bb           out DDRA, r24   ; DDRA=0xff (output)
  62:   87 bb           out DDRB, r24   ; DDRB=0xff (output)
  64:   1a ba           out DDRA, r1    ; DDRA=0x00 (input)

Definitely something strange is going on. DDRA is set to output and shortly after that it is set to input. This explains the 2V5 glowing of your LED's, you're seeing the LED's glow by the current through the internal pull up resistors. This explains what you see, but I cannot explain why this is happening.

I compiled the code on my own PC and although I cannot test it on an ATtiny26, it looks fine to me. So here are the tool versions that I use:

  • avr-gcc --version → avr-gcc (GCC) 4.7.0
  • avr-objcopy --version → GNU objcopy (GNU Binutils) 2.20.1.20100303
  • avr-objdump --version → GNU objdump (GNU Binutils) 2.20.1.20100303

These are the commands I use to generate the disassambly:

avr-gcc $(cflags) -mmcu=$(avrType) -c -o $(src).o $(src).cpp
avr-gcc $(cflags) -mmcu=$(avrType) -o $(src).elf $(src).o
avr-objdump -C -d $(src).elf

And to flash:

avr-objcopy -j .text -j .data -O ihex $(src).elf $(src).hex
avrdude -p$(avrType) -c$(programmerType) -P$(programmerDev) -b$(baud) -v -U flash:w:$(src).hex

Notice that $(..) are variables, in my test case:

baud=19200
src=main
avrType=attiny26
avrFreq=1000000
programmerDev=/dev/ttyUSB003
programmerType=stk500v1
cflags=-g -DF_CPU=$(avrFreq) -Wall -Os

The resulting code looks as follows (sniplet):

00000044 <main>:
  44:   8f ef           ldi     r24, 0xFF       ; 255
  46:   8a bb           out     DDRA, r24       ; 26
  48:   87 bb           out     DDRB, r24       ; 23
  4a:   c0 e4           ldi     r28, 0x40       ; 64
  4c:   cb bb           out     PORTA, r28      ; 27
  4e:   c8 bb           out     PORTB, r28      ; 24
  50:   84 e6           ldi     r24, 0x64       ; 100
  52:   90 e0           ldi     r25, 0x00       ; 0
  54:   e8 df           rcall   .-48            ; 0x26 <milli_delay(int)>
  56:   1b ba           out     PORTA, r1       ; 27
  58:   18 ba           out     PORTB, r1       ; 24
  5a:   84 e6           ldi     r24, 0x64       ; 100
  5c:   90 e0           ldi     r25, 0x00       ; 0
  5e:   e3 df           rcall   .-58            ; 0x26 <milli_delay(int)>
  60:   f5 cf           rjmp    .-22            ; 0x4c <main+0x8>

And in contrast to your code where DDRA is written twice (once 0x00 and once 0xff), here it is only written once.

\$\endgroup\$
6
  • \$\begingroup\$ I will definitely use this information to do further testing. My avr-gcc version is 4.3.3; it may well be worth updating that to see if the generated code is different. \$\endgroup\$
    – JYelton
    Jan 3, 2013 at 21:55
  • \$\begingroup\$ A lot happened since GCC 4.3.3, January 24, 2009 ;o) \$\endgroup\$
    – jippie
    Jan 3, 2013 at 22:03
  • \$\begingroup\$ Additionally, try disabling any optimization in your current toolchain. I've had optimization "ruin" perfectly valid C code during development before. This could also prove useful (for debugging, of course) if you still have issues after upgrading to the latest version of avr-gcc. \$\endgroup\$
    – Shamtam
    Jan 4, 2013 at 0:35
  • 1
    \$\begingroup\$ @jyelton sweet, that thing was bugging me and it wasn't even my code. \$\endgroup\$
    – Passerby
    Jan 4, 2013 at 8:47
  • 1
    \$\begingroup\$ @JYelton I bet you will never paste incomplete code again because you think a couple of lines aren't important ;o) \$\endgroup\$
    – jippie
    Jan 4, 2013 at 10:49

Not the answer you're looking for? Browse other questions tagged or ask your own question.