Page 1 of 1
Watchdog reset doesn't work properly
Posted: Fri Feb 08, 2008 8:26 am
by iphi
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
Posted: Fri Feb 08, 2008 5:07 pm
by christian
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.
Posted: Fri Feb 08, 2008 7:42 pm
by iphi
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
Posted: Fri Feb 08, 2008 7:46 pm
by christian
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?
Posted: Fri Feb 08, 2008 8:40 pm
by iphi
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.
Posted: Fri Feb 08, 2008 11:40 pm
by iphi
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
Posted: Sat Feb 09, 2008 9:26 am
by Grendel
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.
Posted: Sat Feb 09, 2008 7:10 pm
by iphi
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
Posted: Sat Feb 09, 2008 10:01 pm
by iphi
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
Posted: Mon Feb 18, 2008 4:00 am
by Grendel
Funny, I just ran into the same thing after I switched from a mega8 to a tiny461