Search code examples
ioavratmegadigital-logic

Oscillating signal on a digital output of AVR ATmega32U4


I set up my Atmel ATMega32U4 with a relay (using an NPN transistor to control the 5V supply to the relay, not driving it directly with the microcontroller). I want to use PD4 as a digital output to control the relay's state. As I'll be using USB communication later, I've got an external crystal oscillator attached, so I set the appropriate fuse and left the others at their default.

When I run a very simple program like the one below, which should just switch the relay on once, instead I hear the relay switching on and off rapidly at about 10 Hz.

#include <avr/io.h>

int main(void)
{
    // toggle PD4 as an output
    DDRD |= _BV(4);

    // set output high
    PORTD |= _BV(4);
}

I noticed that commenting out the PORTD |= _BV(4); line stops the oscillation, but of course that doesn't solve my problem. It seems to be that line that's creating the problem, anyway.

I'm using Atmel Studio 6.2, programming with JTAG via an Atmel-ICE programmer.

Taking a wild stab in the dark, I guess it might have something to do with PD4's alternative function as ICP1/ADC8 as shown in the datasheet (section 10.3.3, p78), but I don't know how to disable this functionality.

Does anyone have any ideas where I'm going wrong?


Solution

  • The problem was the watchdog timer. Setting the WDTON (watchdog timer always on) fuse to false didn't help with the oscillation problem - I guess that setting it false makes sure it's not always on, but doesn't make sure it's definitely off. Putting the following line in main() did:

    MCUSR &= ~(1 << WDRF);
    

    You also need to import the watchdog timer header avr/wdt.h at the top of your script, or in the header file:

    #include <avr/wdt.h>
    

    So now the code reads:

    #include <avr/io.h>
    #include <avr/wdt.h>
    
    int main(void)
    {
        // turn off watchdog
        MCUSR &= ~(1 << WDRF);
    
        // toggle PD4 as an output
        DDRD |= _BV(4);
    
        // set output high
        PORTD |= _BV(4);
    
        // wait
        while(1)
        {
            // do nothing
        }
    }