Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
jwhance
PostPosted: Dec 12, 2011 - 01:29 AM
Newbie


Joined: Dec 02, 2011
Posts: 6


I'm trying to work with WDTON (WDT enable fuse bit) on an ATtiny85 and am having some difficulty.

1) I can get the WDT to work as expected in either interrupt or reset mode as long as I don't set WDTON.

2) If I get WDTON, my program runs until the WDT times out and then resets. That's to be expected except that I'm calling wdt_reset().

I must be missing something but I can't figure out what. Anyone have a good example of how to setup the WDT when WDTON is set and how to reset the timer and prevent the reset. I've read the ATtiny85 spec sheet over and over and there's just not quite enough information.

Thanks...
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Dec 12, 2011 - 09:28 AM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62371
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

That's to be expected except that I'm calling wdt_reset().

The key thing is WHERE are you calling wdt_reset() and will that point always be executed with a shorter period than that of the timeout?

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
jwhance
PostPosted: Dec 12, 2011 - 01:24 PM
Newbie


Joined: Dec 02, 2011
Posts: 6


I think I've tracked down the problem. I was following the example code in the ATtiny85 datasheet showing the "C method" of changing the WDTCL register when you are in "Safety Mode 2". You have only "4 clock cycles" to change the WDT prescaler after enabling the change. But when doing it in C the generated code takes too long.

I recoded that using ASM and it works fine. After looking at the generated code I can see that indeed there are too many instructions to make it within the 4 cycle limit. I'll post some code when I get a chance. It's possible I'm still doing something wrong as I'm pretty new to AVR architecture.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Dec 12, 2011 - 01:38 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62371
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

I recoded that using ASM and it works fine. After looking at the generated code I can see that indeed there are too many instructions to make it within the 4 cycle limit. I'll post some code when I get a chance. It's possible I'm still doing something wrong as I'm pretty new to AVR architecture.

Please don't tell me that you are yet another person using AS5+AVR Toolchain who's just been bitten by Atmel's madness of making the default build -O0 (that is no optimisation). if so someone at Atmel should be shot!

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
jwhance
PostPosted: Dec 12, 2011 - 02:08 PM
Newbie


Joined: Dec 02, 2011
Posts: 6


Yes (face ashamedly red!) I guess that would be me! I didn't change the compiler optimization from the default as I didn't think that something like:

WDTCTL = 0x00;

Could take much optimization... Seems obvious now, but them most problems seem opbious once you know the answer...
 
 View user's profile Send private message  
Reply with quote Back to top
jwhance
PostPosted: Dec 12, 2011 - 05:04 PM
Newbie


Joined: Dec 02, 2011
Posts: 6


Here's a recap of the situation and what I finally did to resolve it.

First, I was trying to make use of the WDTON fuse to ensure that the WDT is always active. No problem setting the fuse but every time I programmed it, my device just continuously ran through RESET at the DEFAULT rate, not the rate I was trying to set. It was like the AVR was not performing my code to change the prescaler for the WDT.

Here is the code I was starting with, based loosely on the code in the ATtiny85 document page 46:

Code:

int main(void)
{
   // Initialize the WDT
   wdt_reset();               // Atmel docs say to execute WDR first
   MCUSR = 0x00;               // Then clear the MCUSR flags
   WDTCR |= (1<<WDCE) | (1<<WDE);   // Write WDCE and WDE to 1 to "unlock" WDTCR and let us change it
   WDTCR = (1<<WDP2) | (1<<WDP1);   // Set prescale for 128K (~1.0 sec) with 0110 in WDP3-WDP0
   
    while(1)
    {
        //TODO:: Please write your application code
    }
}


Since I'm in "Safety level 2" (described on page 45) I have to:
Quote:

1. In the same operation, write a logical one to WDCE and WDE. Even though the WDE
always is set, the WDE must be written to one to start the timed sequence.
2. Within the next four clock cycles, in the same operation, write the WDP bits as desired,
but with the WDCE bit cleared. The value written to the WDE bit is irrelevant.


I would have thought that the:

WDTCR = (1<<WDP2) | (1<<WDP1);

would be able to meet the 4 clock cycle limit imposed on the WDTCR register. But it sure
seemed like it didn't work!

Looking at the generated ASM code (see the .lss file in the project folder) you can see the
AVR ASM instructions generated:

Code:

   WDTCR = (1<<WDP2) | (1<<WDP1);   // Set prescale for 128K (~1.0 sec) with 0110 in WDP3-WDP0
  54:   81 e4          ldi   r24, 0x41   ; 65
  56:   90 e0          ldi   r25, 0x00   ; 0
  58:   26 e0          ldi   r18, 0x06   ; 6
  5a:   fc 01          movw   r30, r24
  5c:   20 83          st   Z, r18   


As you can see we have 3 LDIs which take 1 cycle each, a MOVW which takes 1, and
an ST which takes 2 cycles. That totals 6 CLOCK CYCLES! No wonder this doesn't work
we missed our "window" by 2 clocks.

I chalked this up to a crappy C compiler and just wrote it in ASM (I started out with ASM on
the MOS 6502 CPU a long long time ago.) I modified the code to be:

Code:

   // Initialize the WDT
   wdt_reset();               // Atmel docs say to execute WDR first
   MCUSR = 0x00;               // Then clear the MCUSR flags
   WDTCR |= (1<<WDCE) | (1<<WDE);   // Write WDCE and WDE to 1 to "unlock" WDTCR and let us change it
   //WDTCR = (1<<WDP2) | (1<<WDP1);   // Set prescale for 128K (~1.0 sec) with 0110 in WDP3-WDP0
   
   // The above C code takes to long, try it in ASM
   asm("PUSH R18");      // Save R18 in case the compiler assumes it's not changed (1 clock)
   asm("LDI R18, 0x06");   // Get our value (1<<WDP2) | (1<<WDP1) into R18 (1 clock)
   asm("OUT 0x21, R18");   // Save in WDTCR (address 0x21) (1 clock)
   asm("POP R18");         // Restore R18.  Takes 1 clock but doesn't matter now.
   //


Now we get the 0x06 written to the WDTCR in 3 clocks which is within our 4 clock limit. And after testing I
find that this works. But it turns out this is the HARD way around. User clawson helpfully pointed out that
the default C optimization on the AVRGCC compiler is not a wise choice. So I tried with optimization turned on
instead. So I selected "-O1" from the compuiler optimization level and went back to my original code. And now
the compiler does a much better job of generating the code. Better than I did because it knows what registers
it needs to save:

Code:

   WDTCR = (1<<WDP2) | (1<<WDP1);   // Set prescale for 128K (~1.0 sec) with 0110 in WDP3-WDP0
  3a:   86 e0          ldi   r24, 0x06   ; 6
  3c:   81 bd          out   0x21, r24   ; 33
   //asm("LDI R18, 0x06");   // Get our value (1<<WDP2) | (1<<WDP1) into R18 (1 clock)


Now we see a much more efficient bit of code but more importantly, code that gets the needed value
into WDTCR in LESS than the 4 clock limit.

I'll follow this up with a more detailed WDT/WDTON fuse bit article when I'm done with this. I really didn't find
any good articles on this topic, which is what got me started down this rabbit-hole to begin with...

Enjoy and I hope this helps someone else new to AVR programming out in some way.

As always, any feedback or comments are welcome.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Dec 12, 2011 - 05:21 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62371
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

I chalked this up to a crappy C compiler and just wrote it in ASM

Which is exactly why Atmel should not have screwed it up in the IDE like they have.

It's clear why they did so that the "Debug" debugging session would work as the user expects. But it's pretty lame to nobble the entire operation of the C compiler just to achieve this small gain.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
jwhance
PostPosted: Dec 12, 2011 - 06:04 PM
Newbie


Joined: Dec 02, 2011
Posts: 6


Thanks for the tip on this.
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits