watchdog timer question [solved: delay_ms includes WDR]

Go To Last Post
16 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I make use of the watchdog timer by setting the period to 125ms, I reset the watchdog in my main loop every 20ms based on a timer counter.  I also wrote a function whereby I can force an Atmel reset by making use of the watchdog timer.  The intention was to set the period to 8 ms and then delay long enough to ensure the watchdog is invoked:

 

void hari_kari(void)
{
    unsigned char s,n;

    // Optimize for speed
    #pragma optsize-
    // Save interrupts enabled/disabled state

    s=SREG;
    // Disable interrupts
    #asm("cli")

    // Watchdog Timer: Oni_
    // Watchdog timeout period: 8 ms
    n=(WDT.CTRL & (~WDT_PER_gm)) | WDT_PER_8CLK_gc | WDT_ENABLE_bm | WDT_CEN_bm;
    CCP=CCP_IOREG_gc;
    WDT.CTRL=n;
    // Watchdog window mode: Off
    n=(WDT.WINCTRL & (~WDT_WEN_bm)) | WDT_WCEN_bm;
    CCP=CCP_IOREG_gc;
    WDT.WINCTRL=n;

    #ifdef ADD_UART
    printf("hari_kari Watchdog timer normal ctrl = %02X window ctrl = %02X\n",WDT.CTRL,WDT.WINCTRL);
    #endif
    // Restore interrupts enabled/disabled state
    SREG=s;
    // Restore optimization for size if needed
    #pragma optsize_default
   // delay_ms(200);
}

Originally I set the delay to 10ms and everything seemed to work as designed.  Suddenly we started to see boards where it could take up to seconds for the watchdog to trigger a reset.  The function above is called within the main loop and continues to be called as long as I am in the state where I want to reset the Atmel.  

 

My initial thought was that either I was not enabling the configuration write correctly, or 10 ms was not a sufficient time to delay given possible variability among parts.  I increased the delay to 200 ms which would exceed the original period and printed out the configuration registers after I wrote them.  Here's where it got wierd!  Now it appeared as if the watchdog would never get invoked (output follows):

[2015/06/15 15:32:33.708]hari_kari Watchdog timer normal ctrl = 02 window ctrl = 00
[2015/06/15 15:32:34.115]hari_kari Watchdog timer normal ctrl = 02 window ctrl = 00
[2015/06/15 15:32:34.521]hari_kari Watchdog timer normal ctrl = 02 window ctrl = 00
[2015/06/15 15:32:34.927]hari_kari Watchdog timer normal ctrl = 02 window ctrl = 00
[2015/06/15 15:32:35.318]hari_kari Watchdog timer normal ctrl = 02 window ctrl = 00
[2015/06/15 15:32:35.724]hari_kari Watchdog timer normal ctrl = 02 window ctrl = 00
[2015/06/15 15:32:36.130]hari_kari Watchdog timer normal ctrl = 02 window ctrl = 00
[2015/06/15 15:32:36.537]hari_kari Watchdog timer normal ctrl = 02 window ctrl = 00
[2015/06/15 15:32:36.943]hari_kari Watchdog timer normal ctrl = 02 window ctrl = 00
[2015/06/15 15:32:37.349]hari_kari Watchdog timer normal ctrl = 02 window ctrl = 00
[2015/06/15 15:32:37.755]hari_kari Watchdog timer normal ctrl = 02 window ctrl = 00

 

So it looks as if my configuration change worked, but delaying longer to force an invocation made the problem worse.  So naturally, since my main loop is 20ms (far exceeding 8ms) I took the delay out and the watchdog timer was invoked on the first loop:

 [2015/06/15 15:40:39.399]PowerDown called stage = 3
[2015/06/15 15:40:39.415]PowerDown called stage = 4
[2015/06/15 15:40:39.415]PowerDown called stage = 5
[2015/06/15 15:40:39.430]SSD PowerSequence called stage = 1
[2015/06/15 15:40:39.430]SSD PowerSequence called stage = 2
[2015/06/15 15:40:39.493]hari_kari Watchdog timer normal ctrl = 02 window ctrl = 00
[2015/06/15 15:40:39.508]load version 1.0
[2015/06/15 15:40:39.508]reset due to watchdog timer

 

So the only conclusion I can draw is the timer does not actually start until after my delay statement.  This is fine and I can live with that, but to insure I have a comprehensive understanding of the WD mechanism, I would like to know:  If I polled on the syncbusy bit of the status register before calling my delay function would that solve the problem?  

 

My theory is my issue is due to my delay preventing the WD from starting and the only thing I can think of is that the delay is preventing the data synchronization from happening.  Because I was delaying 10ms, the timer counter would trigger the next tick of my main loop 7-10ms later.  By increasing the delay I was ensuring the watchdog timer would be reset almost immediately after the delay returned.

 

Any comments?

 

Brian

Last Edited: Tue. Jun 16, 2015 - 09:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmm?   I did not actually write delay_ms, so I decided to look at the assembly of that function:

 

_delay_ms:
    adiw r26,0
    breq __delay_ms1
__delay_ms0:
    __DELAY_USW 0x1F40
    wdr                                   ;//is the function actually conveniently resetting the watchdog for me?
    sbiw r26,1
    brne __delay_ms0
__delay_ms1:
    ret

 

 So my convoluted theory is full of it, the delay function itself is resetting the watchdog!  At least that's how I see it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you sure that code is part of the _delay_ms() function? I just checked my own code and there is no wdr instruction.

 

I think we need to see some complete code, your GCC/avr-libc versions etc. That code you posted doesn't look like the normal output from the .lss file. Can you post that, and perhaps a minimal example project?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Mojo,

 

He's using CodeVsion not GCC. As Lee often reminds us, Pavel has the good sense to put a WDR in their delay_ms(). The _delay_ms() in AVR-LibC does not include it, though perhaps it should.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi I have also same problem. I tried to find out delay_ms() function everywhere but unable to do so. 

I got in mind that wdt reset  is included in delay_ms() function and reset watchdog every 1ms. As briandstark said wdr is found in asm _delay_ms: file. and when I delete it and recompile, wdr appears again. where the c function delay_ms() is located. I am using Codevision AVR 2.05. I only found delay.h but not its library file and anything related to it.

 

Thanks in advance.

 

if anyone know plz tell me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Silly question but why would a "serious app" that uses the watchdog ever be doing "soft delays" anyway?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am developing a project based on atmega2560 (not using arduino mega). And I want to avoid system crash or any cpu hanging problem when this product is used by customer. my code is now working very well. But as the input to controller is 16bit data (used 16 ADCs) and also if RTC ds1307 is faild system may crash or waits for RTC response. thus this case may leads cpu to go infinity loop. thats why i am using wdt. every thing working fine but as wdr instruction is given in delay_ms() function it kicks the wdt always. So I want to remove this WDR instruction from delay function.

Last Edited: Wed. Nov 8, 2017 - 04:28 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dnyanesh1 wrote:
So I want to remove this WDR instruction from delay function.
But if you do that then as soon as you enter a lengthy delay_ms() it will reset the CPU? Is that really what you want?

 

But as my previous comment:

 

1) what are you doing using delay_ms() in a real program anyway? delay_ms() is fine if you want a small loop flashing an LED or something but as soon as you start to use micros for real applications there are usually too many things going on to ever waste time just sitting in a delay loop. If you need some activity to happen N milliseconds after some other event then use a timer.

 

2) if you really do want a delay loop and want to take control of WDR then implement your own delay loop and either do / don't do WDRs in it as you choose.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dnyanesh1 wrote:
 this case may leads cpu to go infinity loop. 

That is a design flaw.

 

You need to re-design your software so that it does not have infinite loops like that!

 

The WDT should really just be for catching unexpected faults ... 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, this delay_ms is used to acquire millisecond delay in my application. and some where i wait for exactly 1 second. I can't avoid using delay_ms ( ) function because needed exact time in ms and s. and as you said that use timer. it is best way. it would be better if i can remove wdr from delay_ms(). Anyway I will develop my own delay using timer or simple loop functions. 

thank you!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dnyanesh1 wrote:
 I can't avoid using delay_ms ( ) function

Nonsense! Of course you can!

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dnyanesh1 wrote:
would be better if i can remove wdr from delay_ms().
I think you haven't understood how WDT works. The point is that you WANT there to be WDRs in the middle of anything "long" and that includes soft delay loops like delay_ms(). The last thing you would want to do is REMOVE it. What you might want is to actually add WDR to some delay() function that does not already contains WDRs. For example if you were using avr-gcc and not Codevision then it's a possible oversight in the implementation of _delay_ms() that comes from <util/delay.h> that it does NOT contain WDRs. So if you really feel the need to use _delay_ms() in a GCC program and the WDT is enabled there's quite a chance you might accidentally reset the CPU just while a delay() routine is running.  Of course if you have such a compiler that did not already factor WDR into the delay routine you could "fix" it with something like replacing:

_delay_ms(100);

with something like:

for (int n=0; n < 100; n++) {
    _delay_ms(0.96); // not quite 1 to allow for for() and WDR
    wdt_reset();
}

That would add back the WDR that makes this "safe".

 

But you are already using Codevision. It has the luxury of a delay_ms() that already contains WDRs so why on earth would you ever want to remove them? Is this because you are deliberately trying to reset the CPU with something like:

enable_watchdog();
delay_ms(BIG_NUMBER); // WDT will reset CPU in here

if so then just use:

enable_watchdog();
while(1); // WDT will reset CPU in here

The while() does not contain any WDR so after a while WDT will reset the machine.

 

Otherwise your posts don't make any sense.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The only time I might use the delay_Xs functions is during startup where I am initializing peripherals (e.g. lcd). After that a timer is used to provide whatever intervals are to be measured whether ms, seconds, or hours.

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But you are already using Codevision. It has the luxury of a delay_ms() that already contains WDRs so why on earth would you ever want to remove them? Is this because you are deliberately trying to reset the CPU with something like:

enable_watchdog();
delay_ms(BIG_NUMBER); // WDT will reset CPU in here

if so then just use:

enable_watchdog();
while(1); // WDT will reset CPU in here

The while() does not contain any WDR so after a while WDT will reset the machine

 yeah, it will, but then what about delay loop i am using? I have used same code that is used in delay_ms() function which works fine but dont know how some time it takes long to come back. does it happens because of simulation software (Proteus) ? i doesnt tried on actual HW. coz its in development process. should i go for my own delay function ignoring its minor issue?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have no idea what you are talking about. What do you mean by "have used same code that is used in delay_ms()"? If you have done that then delay_ms() does WDRs so what is the problem? Also why are you reimplementing library code that already exists?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 why are you reimplementing library code that already exists?

the problem is that:

1] in-built delay_ms() works fine but kicks wdt every 1ms. (I want it to be kicked by myself depending on my program execution time  and if execution takes more than 2s then restart whole system.)

2] my delay_ms() also works fine but it sometime takes more time than usual (ex. delay_ms(10) may takes sometime 20ms or whatever but not as expected).

 

but I think my problem is not going to be solved. Continuing with in-built delay_ms() function.

 

thanks all for trying to help.