Watchdog reset doesn't work properly

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
iphi
Rank 2
Rank 2
Posts: 68
Joined: Mon Jun 25, 2007 11:37 am

Watchdog reset doesn't work properly

Post by iphi » Fri Feb 08, 2008 8:26 am

Hello,

I have AVRUSB running on ATTINY45 with RC oscillator on 16.5MHz. I have coded such that I can reset the device via Watchdog timer like this:

Code: Select all

USB_PUBLIC uchar usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (void *)data;
...
   if(rq->bRequest == 0xf){             // Reset by Watchdog
        for (;;){};
        return 0;
    }


When I invoke the watchdog the device will fail to enumerate again.
Here's my main code:

Code: Select all

int main(void)
{
    OSCCAL=0x5b;
    DDRB = (1 << USB_CFG_DMINUS_BIT) | (1 << USB_CFG_DPLUS_BIT);
    PORTB = 0;             // indicate USB disconnect to host */
    delay(1400000);         // delay 6x1.4=8.4 million clocks = 0.51secs
    DDRB = 0;            //all inputs
    wdt_enable(WDTO_15MS);
    usbInit();
    sei();
    for(;;){    /* main event loop */
           wdt_reset();
           usbPoll();
    }
}


The OSCCAL value is experimentally determined and optimum.
What am I doing wrong?

BTW: Basically the same code on an ATMEGA8 with 12MHz reenumerates fine after watchdog reset.

BR Tom

Regards, Tom

christian
Objective Development
Objective Development
Posts: 1443
Joined: Thu Nov 09, 2006 11:46 am

Post by christian » Fri Feb 08, 2008 5:07 pm

You force a RESET in the middle of a USB command. This may confuse the host. It would be cleaner to set a global variable so that the main loop does not call wdt_reset(), but still calls usbPoll() until the reset occurs.

Other than that: Did you check whether delay(1400000) really generates a long enough (> 250 ms) delay? There might be an integer overflow.

iphi
Rank 2
Rank 2
Posts: 68
Joined: Mon Jun 25, 2007 11:37 am

Post by iphi » Fri Feb 08, 2008 7:42 pm

You force a RESET in the middle of a USB command. This may confuse the host. It would be cleaner to set a global variable so that the main loop does not call wdt_reset(), but still calls usbPoll() until the reset occurs.

Good point. But why is it working every time without fault on a crystal driven atmega8 then? I'll give it a try.

Other than that: Did you check whether delay(1400000) really generates a long enough (> 250 ms) delay? There might be an integer overflow.

I use long integer here which doesn't overflow. Also identical code which works on the atmega8/12MHz.

Could there be something connected to the RC oscillator or the 16.5MHz driver?

Best regards, Tom

christian
Objective Development
Objective Development
Posts: 1443
Joined: Thu Nov 09, 2006 11:46 am

Post by christian » Fri Feb 08, 2008 7:46 pm

Just because it works with 12 MHz does not mean that the code does what it's intended to do. Many problems depend on tiny deviations in the timing.

BTW: 1400000 is an integer constant, it would be 1400000L otherwise. Do you get a compiler warning for this?

iphi
Rank 2
Rank 2
Posts: 68
Joined: Mon Jun 25, 2007 11:37 am

Post by iphi » Fri Feb 08, 2008 8:40 pm

BTW: 1400000 is an integer constant, it would be 1400000L otherwise. Do you get a compiler warning for this?


No, there's no compiler warning. As I'm a C beginner I'm quite paranoic to avoid any compiler warnings as I have learned that C warnings are serious in contrast to Pascal warnings. My code compiles with zero errors and zero warnings. I have also checked functionality of the delay loop inside the AVR Studio simulator in sourcecode and in disassembler. All is definitely fine here.

Regards, Tom

P.S. Think I have a hint: I have connected an oscilloscope to one of the USB data lines. I do see the 0.5 second pulse at first connection. But when I invoke the watchdog I do see many and more short pulses but no 0.5 second pulse. Now I just have to think about how to explain this.

iphi
Rank 2
Rank 2
Posts: 68
Joined: Mon Jun 25, 2007 11:37 am

Post by iphi » Fri Feb 08, 2008 11:40 pm

Hi Christian,

my confusion is growing. I have made the following experiments:

1. Done the modification you suggested with the global variable and suppressing the wdtreset in the main loop.
=> doesn't work, same as my first attempt

2. Tried a hardware reset on pin 1 instead:
a) An initial hardware reset works fine, also repeatedly.
b) A hardware reset after the above software reset doesn't bring the device back to life. It continues sending strange signals out the USB bus.

I thought there's nothing higher priority than a hardware reset!???

Do you have any more ideas?

Regards Tom

Grendel
Rank 4
Rank 4
Posts: 167
Joined: Sat Dec 16, 2006 9:53 pm
Location: Oregon, USA
Contact:

Post by Grendel » Sat Feb 09, 2008 9:26 am

How is that delay() function defined ?

Do you have a "dynamic" speed R that allows you to use usbDeviceConnect() and usbDeviceDisconnect() ? I use the same logic to reset my converter but w/ a usbDeviceDisconnect() just before the forever loop. Works every time :) Plus, you don't need to create a reset condition on the bus after a usbDeviceConnect():

Code: Select all

    wdt_enable( WDTO_500MS ) ;                  // Unleash watchdog

    sei() ;                                     // Enable interrupts
                                                // Preset report
    usbSetInterrupt( sw_report, SW_REPORTSZ ) ;

    usbDeviceConnect() ;                        // Activate ID resistor

    for ( ;; )                                  // Forever..
    {
        wdt_reset() ;                           // Calm watchdog

        usbPoll() ;                             // Do USB stuff


No problems whatsoever.

iphi
Rank 2
Rank 2
Posts: 68
Joined: Mon Jun 25, 2007 11:37 am

Post by iphi » Sat Feb 09, 2008 7:10 pm

Hi Grendel,

thanks for your proposal. I'll try that.

All,

I think I have found the reason for the strange behavior of my ATTINY45 compared to the ATMEGA8:

The watchdog remains on even after watchdog reset, thus the system won't stay in the 0.5 second delay loop. This is described in the AVR-libc documentation:

Note that for newer devices (ATmega88 and newer, effectively any AVR that has the option to also generate interrupts), the watchdog timer remains active even after a system reset (except a power-on condition), using the fastest prescaler value (approximately 15 ms). It is therefore required to turn off the watchdog early during program startup, the datasheet recommends a sequence like the following:...


Regards, Tom

iphi
Rank 2
Rank 2
Posts: 68
Joined: Mon Jun 25, 2007 11:37 am

Post by iphi » Sat Feb 09, 2008 10:01 pm

I can fonfirm that the above was the reason for my watchdog problems.
After having added the following piece of code suggested in AVR-libc my watchdog reset works perfectly.

Code: Select all

#include <stdint.h>
    #include <avr/wdt.h>

    uint8_t mcusr_mirror _attribute_ ((section (".noinit")));

    void get_mcusr(void) \
      __attribute__((naked)) \
      __attribute__((section(".init3")));
    void get_mcusr(void)
    {
      mcusr_mirror = MCUSR;
      MCUSR = 0;
      wdt_disable();
    }


Regards, Tom

Grendel
Rank 4
Rank 4
Posts: 167
Joined: Sat Dec 16, 2006 9:53 pm
Location: Oregon, USA
Contact:

Post by Grendel » Mon Feb 18, 2008 4:00 am

Funny, I just ran into the same thing after I switched from a mega8 to a tiny461 :)

Post Reply