Different Watchdog timer ISRs

Status
Not open for further replies.

Edward

Well-known member
Hi all,

I'm using a teensy 3.2 as the brain of a Laser Power Supply. It essentially boots up, waits, powers up the laser when told, powers down when told. I want to use the watch dog timer as a backup just in case the teensy hangs or gets stuck, but depending on where the hang happens I'd need different behaviour. I'm therefore wondering if anyone can give me pointers on if this can be done, and the safest way to do it. My initial ideas are:

I could configure the WDT to either use or not use the ISR on timeout; giving me two options which would be better than none and still reasonably safe.
I could configure the ISR with a funciton pointer, and change what it points to in the code to change the function. That seems like a bad/unsafe idea.

As a side note, I was also wondering about what can/can't (or morelikely should/shouldn't) be done inside a WDT ISR. I'd need to modify the DAC, and i'd like to write to the EEPROM if I can.

Thanks for your help!
 
I've made some progress towards this but I'm still quite stuck. Firstly it doesn't seem to be as simple using the WDT in teensy compared to the Arduino, I've rather over estimated what I can do!
The digging I've done has revealed that you only get to play with the watch dog settings once, right after you unlock the register; attempting to do so again will be interrupted as improper behaviour and trigger reset.

I have at this point gotten the watchdog timer to cause a time-out and reset the teensy, but I can't get the interrupt to work. As far as I can tell, there's a register to enable the WDT to fire an intterrupt and also one to tell the teensy to look for it. The register WDOG_STCTRLH has a bit IRQRSTEN to enable the intterupt (from the datasheet page 419) and according to this page on interrupts there's a register/bit WDTCSR,WDIE to enable the interrupt.

I get the error WDTCSR is not declared in this scope; and I've no Idea where it's supposed to be defined. Sifting around I've found that intterrupts.h is deliberalty blank, it's only included so older libraries that call it can still compile - yet PJRC's page on interrupts state you have to include it, which seems odd to me. avr/io.h redirects to another header, again I assume this is for older libraries.

My best guesses are that either PJRC's page on interrupts was written early on in teensy development and has gone slightly out of date, based on the fact that it says you need to include out of date headers;
Or I'm still missing something in how the WDT works.

here's the code i'm using, the reset triggers but not the interrupt

Code:
#ifdef __cplusplus
extern "C" {
#endif
void startup_early_hook() {
WDOG_TOVALL = 2000; // The next 2 lines sets the time-out value. This is the value that the watchdog timer compares itself to
WDOG_TOVALH = 0;
WDOG_PRESC = 0; // prescaler
WDOG_STCTRLH = (WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_IRQRSTEN ); // Enable WDG
}
#ifdef __cplusplus
}
#endif
#include<avr/io.h>
#include<avr/interrupt.h>


ISR(WDOG_vect) 
{
  digitalwrite(13, HIGH);
  for(volatile unsigned long int i = 0; i <15000000; i++);  // a nasty way of adding delay when you cant call any other timers or delay(). I'm not saying it's a good idea, but it seems to work
// if this function is called we should see the LED on for a few seconds 
}

void setup(){
  WDOG_UNLOCK = WDOG_UNLOCK_SEQ1;
  WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
  WDOG_TOVALL = 2000; // The next 2 lines sets the time-out value. This is the value that the watchdog timer compares itself to
  WDOG_TOVALH = 0;
  WDOG_PRESC = 3; // prescaler
  WDOG_STCTRLH = (WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_IRQRSTEN); // Enable WDG
  WDTCSR |= (1<<WDIE);
  pinMode(13,OUTPUT);
}


void loop(){
  delay(1000);
}

I've confirmed the reset is happening by writing 13 high in setup() and watching the LED blink.
 
Don't understand why you include the avr/interrupt.h and avr/io.h libraries. Interrupts and IO operations for the Kinetis ARM processors are only handled correctly by the Teensyduino core files which are automatically included when your Arduino/Teensyduino environment is correctly set up.
 
Don't understand why you include the avr/interrupt.h and avr/io.h libraries. Interrupts and IO operations for the Kinetis ARM processors are only handled correctly by the Teensyduino core files which are automatically included when your Arduino/Teensyduino environment is correctly set up.
Yes, and that ISR function is for AVR's, it needs to be:
Code:
void watchdog_isr() {
  // your watchdog code here.
}
for Teensy 3.x!
 
I'd included those headers becuase the page I found on PJRC
here
said I needed to, but like I said I appreciate they don't really do anything, removing them has no effect either.

Duff I've changed my function to suit but it's still not being called. I'm not absolute but I'm pretty sure I've got my libraries in order; I installed teensyduino on this machine a few months ago and I've not messed with the libraries since. Is there anything else I'm missing? How does the comiler link the function I define to the interrupt triggered by the WDT?

thanks
 
Yes that thread was very helpful in getting to the point where the watchdog causes a reset but there's nothing in there about using watchdog_isr(); there's also quite a few different solutions in there. I've preferred using start_early_hook() rather than altering the library files and I'd prefer to reset the timer in code rather than on another timer but that's besides the point. Was there something specific in that thread I should be looking at?
 
Yes that thread was very helpful in getting to the point where the watchdog causes a reset but there's nothing in there about using watchdog_isr(); there's also quite a few different solutions in there. I've preferred using start_early_hook() rather than altering the library files and I'd prefer to reset the timer in code rather than on another timer but that's besides the point. Was there something specific in that thread I should be looking at?
You need to enable that interrupt first, then you need to read the k20 manual about the watch dog to fully understand it which I haven't looked at in long time so I can't help with fine details right now.
 
I've been through the K20 data sheet a couple of times and I'm pretty sure I get it. Setting the bit WDOG_STCTRLH_IRQSTEN enables the interrupt, which then appears on the MSB in the register WDOG_STCTRLL. What I'm not sure of is how teensyduino ties that flag to the interrupt I define watchdog_isr(). I've found watchog_isr() declared as an external void function; so it's clearly there, and left to be defined. The only reference I've found to the interrupt flag on PJRC is bit WDIF, on register WDTCSR which isn't defined.
I haven't found any instance of someone using the watchdog ISR, only the reset function, and somewhere a post from paul saying he's not looked much at the WDT either so fine details are out of the question but can you point me to the right libraries to have a look in?
 
Sorry, I know very little about this, but I believe WDTCSR is an AVR register and not ARM. It is mentioned in avr/cores/teensy not in in teensy3 also it loos like the LowPower library is defined for AVR
 
Yes that's the register for AVR, the ARM version is teensy3/kinetis.h WDOG_STCTRLH. I've got the WDT running and resetting the board but I can't get it to trigger the interrupt; and by extention I can't be 100% sure the interrupt is firing but I'm 100% I'm setting the right bit!

I'm currently digging through data sheets and trying to find out how to manually link the flag to the isr, but I'm not getting far. There's an example in documentation triggering an interrupt from the low power from
HERE
and should be a case of just swapping the numbers/registers/bits but I'm not sure If i'm getting anywhere. I've also stumbled across the macros NVIC_SET_PRIORITY and NCIV_ENABLE_IRQ which I've seen used
HERE
to create and interrupt.
 
Last edited:
and should be a case of just swapping the numbers/registers/bits but I'm not sure If i'm getting anywhere. I've also stumbled across the macros NVIC_SET_PRIORITY and NCIV_ENABLE_IRQ which I've seen used
HERE
to create and interrupt.
Yes thats what I was talking about "NCIV_ENABLE_IRQ". Use need to enable the isr in the NVIC and whatever bits that the module requires.
 
I've tried those to no avail. I'm digging through the data sheets and there's a bunch of registers for handling the ISR, but as far as I can tell those two macros should be all that's needed; they do pretty much exactly what they say on the tin!
So I'm now a lot more informed but just as stuck. All I can wonder about is how watchdog_isr() is tied to be called when that interrupt is triggered, I've still not been able to find where/understand how.
There's a big old array of pointers to isr's in mk20dx128.c where's it's declared and its setup to default to unsued_isr() which does nothing unless overwritten - so that's where the function "watchdog_isr" comes from but I'm not sure how it's linked to the ISR I enabled using NVIC_ENABLE_IRQ()
 
Maybe post what you have so far as a small program. I see you did in #2, but obviously more has been added. The NVIC_ENABLE_IRQ part is needed, for example.
 
of course, here is the updated code

Code:
#ifdef __cplusplus // not going to pretend I 100% get this wrapper, it's just something I've seen done.
extern "C" {
#endif
void startup_early_hook() { // using start early hook is only necessary in larger projects when the time to complete setup() could be longer than the update window for the WDOG register
WDOG_TOVALL = 2000; // The next 2 lines sets the time-out value. This is the value that the watchdog timer compares itself to
WDOG_TOVALH = 0;
WDOG_PRESC = 0; // prescaler
WDOG_STCTRLH = (WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_IRQRSTEN ); // Enable WDG, and Interrupt
NVIC_ENABLE_IRQ(IRQ_WDOG); // this should enable the ISR, both the macros and the IQR_WDOG are defined in kinetis.h
//NVIC_SET_PRIORITY(IRQ_DOG, 120); // not necessary to set priority of the only isr 
}
#ifdef __cplusplus
}
#endif


void watchdog_isr() // this is defined as a weak alias of unused_isr() hence we "over write" it here to replace with our function 
{
  digitalwrite(13, HIGH);
  for(volatile unsigned long i = 0; i <100000000; i++);  // a nasty way of adding delay when you cant call any other timers or delay(). I'm not saying it's a good idea, but it seems to work
// if this function is called we should see the LED on for a few seconds 
}

void setup(){
  pinMode(13,OUTPUT); // initialise the pin as output
// digitalWrite(13, HIGH); // uncomment this line to see the LED blinking and confirm wdog is resetting the teensy
}


void loop(){
  delay(1000); // do nothing
}

when it works the above code should turn the LED on for a short ammount of time, as is reset does occur but without calling the isr.
 
Status
Not open for further replies.
Back
Top