This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

WDT interval timer mode with 4 minutes interval. Possible ?

Other Parts Discussed in Thread: MSP430F2012

Hi,

I was wondering if it could be possible to use the watchdog in interval timer mode, with a interval of 4 minutes? If possible, how would i program the interval time (I haven't found yet how to set this kind of value).

My goal in this minicode is to produce a 1ms pulse on an output pin, and then to wait 4 minutes before pulsing again etc... and obviously with the lowest consumption possible ;)

I used an example code to try in a first attempt, so pulse time value is not yet the right value. But I'm having trouble finding how to set 4minutes as the interval timer.

  #include <msp430x20x3.h>
int i;
void main(void)
{
  WDTCTL = WDT_MDLY_32;                     // Set Watchdog Timer interval to ~30ms
  IE1 |= WDTIE;                             // Enable WDT interrupt
  P1DIR |= 0x01;                            // Set P1.0 to output direction

  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
}

// Watchdog Timer interrupt service routine
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
{
  P1OUT ^= 0x01;  
  for(i=0;i<20000;i++)
  {}
  P1OUT^=0x01;                         // Toggle P1.0 using exclusive-OR
}

The for loop is set here to let the output on during XX seconds

So thanks again to the community and TI employees for their support :)

Nicolas

  • That's a bit difficult with the 2xx series.

    The WDT is sourced by either SMCLK or ACLK. This inherits the problem that WDT is effectively disabled when the assgined clock fails, either due to low power mode (LPM) or because of an oscillator failure. But it also allows control over the speed at which the WDT counter is clocked.

    Also, the WDT only has a maximum trigger count setting of 32768. To reach this in >4min, you'll need an ACLK of 136.5Hz. Since ACLK is sourced by VLOCLK or LFXT1CLK and has a maximum divider of 8, you'll need an external 1kHz clock applied to XIN. Not a desireable way. And I don't think it will work at all since a 1kHz signal isn't fast enough to avoid an oscillator fault signal, causing ACLK to switch back to VLO.
    The 54xx series' WDT has a 32 bit WDT counter which allows a divider of up to 2G, resulting in 18 hrs timeout on 32kHz clock.

    There's a different approach.

    You'll need: a timer that is running all the time, an ISR and a global variable.

    Set the WDT to the longest timeout you can. e.g. sourced by VLOCLK.

    Set the timer so that it is triggering an overflow IRQ and is sourced by at least twice the VLOCLK.

    In the ISR of the time, you check the global variable. If it is <x, increment it by 1 and trigger the WDT. If it is >=x, don't do anything.

    In your application, you do not trigger the WDT anymore, but instead reset the global variable to 0.

    The WDT will still trigger a RESET of the ISR hasn't been called for ~1s (depending on ACLK/VLOCLK), but your application only needs to reset the global variable in a much larger interval. e.g . if the timer is clocked with 1MHz, it will call the ISR with 15Hz. So setting the 'x' threshold to 240*15= 3600 will allow the application to reset the variable every 4 minutes only, as long as IRQs are not disabled for longer than the (shorter) WDT timeout.

     

    If you do not plan to use the WDT for its original purpose, well, then this can be simplified. Just 'extend' the wdt range.

    In your WDT ISR, count up a variable to a value that gives, multiplied with the WDT timeout time, your desired delay. SO if the WDT triggers every 32.768ms, count the variable up to 7324. If it has reached this value, set it back to 0 and you whatever you want to do after 4 minutes.

    __interrupt void watchdog_timer(void)
    {
      static int delay = 0;
      delay++;
      if(delay==7324){
        P1OUT ^= 0x01;  
        for(i=0;i<20000;i++)
        {}
        P1OUT^=0x01;                         // Toggle P1.0 using exclusive-OR
        delay=0;
      }
    }

    But a busy-waiting delay inside an ISR is, well, "666". Also, this kind of delay loop will most likely be eliminated as dead code by every good optimizing compiler.  I'd suggest the following:

    __interrupt void watchdog_timer(void)
    {
      static int delay = 0;
      delay++;
      if(delay==7324){  // 7324 * 32.768ms = 4 min
        P1OUT ^= 0x01; 
        WDTCTL=WDT_MDLY_0_5
      }
      if(delay==7326){        // 2*0.5ms later
        P1OUT ^= 0x01;   
        WDTCTL=WDT_MDLY_32
        delay=0;
      }
    }

     

  • Thank you Jens-michel for your replie and suggestions :)

    I discovered this controler few weeks ago, and I would have a little explanation about this kind of pragma vector interruption :

    If i'm not mistaking, in low power mode 3 (for example) when the watchdog timer counts up to his max value, it sets on an interrupt flag. Then the pragma comes into the party.

    Still not sure, following the interrupt flag set by wdt, pragma execute the code written in the function just like following

    #pragma vector=WDT_VECTOR
    __interrupt void watchdog_timer(void)
    {
      //code executed when lmp3 is interrupted ?

    }

    Then I don't really know (in that case) where does the code restart after this interrupt function ? Does it reboot the program or just jump to a specific line ? That's very nice to you to share your knowledges with a newcomer :)

  • When the WT is configured in timer mode, it will trigger an IRQ, an interrupt request. Just like any other hardware module.

    If an IRQ happens and the GIE bit is set, the processor will
    1) switch to active mode (wakeup from any LPM)
    2) put the current program counter on stack
    3) put the current status register on stack (including the bits which have initiated LPM)
    4) fetch the address of the associated ISR from the vector table
    5) start executing code at this address.

    The #pragma tells the compiler to put the current position in the generated code (whatever this code may be) into the specified position (WDT_VECTOR) of the vector table. So if a WDT-interrupt occurs, the processor will start executing the ISR (or whatever else code followed the pragmas position) at the point where the pragma is.

    Usually, the pragma is followed by code for an ISR. This means the following code usually start with an __interrupt qualifier with the following effects:
    1) the function will save ALL used/clobbered registers to stack and restore them. This includes those which usually are used for returning the functions return value and which are considered clobbered after a normal function call (this is necessary since the main code doesn't know that a 'virtual function call' happened)
    2) the function will - depending on the compiler settings - not use the hardware multiplier (as this would interrupt any ongoing multiplication in the main code). Normally, the compiler will enclose any multiplication that use the hardware multiplier by clearing and restoring GIE, sit isn't interrupted, but if you do complex multiply/accumulate operations...
    3) the function will return with an RETI statement rather than a normal RET. This RETI will fetch the previously stored content of the status register from stack and then restore the program counter from stack. This will also restore the LPM bits in the status register, so the processor will immediately return into the previous LPM.
    If you want to wake the main code up deom LMP, the ISR needs to alter the LPM bits in the status register content that was saved on the stack. There are different macros available for clearing the LPM bits on ISR exit.

    So after an ISR has been executed, the code continues as if nothing happened at all. This includes changes to variables that might have been done by the ISR. Therefore all global variables which are subject to change inside an ISR must be declared volatile, so the compiler will never assume that they are still in the same state they were right before and skips any optimizing.

    If the watchdog runs in watchdog mode, it will not flag an interrupt request, but will unconditionally initiate a reset procedure instead, which will (mostly) act as if the power was just switched on. In interval mode (and this is what you're using), it will just flag a normal maskable interrupt request as any other hardware module or timer does.

    p.s: the watchdog timer does not count to its max value. It rather counds to 64, 512, 8192 or 32768, depending on its configuration.

  • I managed to make it run with a code, based on the same idea you gave me ( static variable incremented in the ISR..), so thanks again (for your ideas, and all controler explanations !) :D

     

  • Hi,

    I stil have something to ask you : the code ran perfectly in the debug session (in run free exectution, or animate... in code composer essentials)[EDIT : It doesn't run in "Run free", but runs when i use the "run" button or animate] , but it doesn't want to run when not in debug session. Do you have any idea of what's wrong ? (my code is just below)

    #include <msp430x20x3.h>
    void main(void)
    {

      WDTCTL = WDT_ADLY_1000;               // Set Watchdog Timer interval
      IE1 |= WDTIE;                         // Enable WDT interrupt
      P1DIR=0xff;    // all pins as output
      P1OUT=0x00;    // all pins on low level
      P1OUT|=0x01;    // Current mirror ON 
      P1OUT=0x00;    //all pins on low level
      
      _BIS_SR(LPM3_bits + GIE);                 // Enter LPM0 w/ interrupt enable
     
    }

    #pragma vector=WDT_VECTOR
    __interrupt void watchdog_timer(void)
    {
     static int x=0, i=0;
     x++;
     if ( x>=28 )  

     {
      P1OUT^=0x01;  // current mirror ON
      for(i=0; i<100; i++) // waiting
      {}  
      P1OUT^=0x01;
      x=0;
     }

    else
     {
     x++;
     }

    }

     

    EDIT : in fact, the first blinking occurs (before entering lpm), but after there's nothing happening (only without the debug session or in run free mode)

  • nicolas said:
    for(i=0; i<100; i++) // waiting
      {}  


    First of all, this is no waiting loop, even if intended to be one. In the optimizing stage, the compiler will see that you don't do anything inside this loop and will eliminate it by just setting i=100. Also, it will probably notice, that i is local to the funciton and never used anywhere, so it may well be that i is eliminated totally. So you'll only see the port change its value for a few processor cycles. Adding a __no_operation(); statement inside the lopp will help a bit. At least this statement will be executed 100 times. The compiler may still unroll the loop, executing the NOP 10 times in a row and incrementing i by 10 each loop. This has a totally different timing (much faster) than the unoptimized loop.
    It's better to count X up to 14 and just let the LED toggle once, and the next time 14 calls later. If you really need a short blip, well, that's difficult with the WDT. TimerA and TimerB are better suited for this. But you can split the if statement into (x==28) and (x>28), toggling P1.0 in both, but resetting x only in the second one. This way the blip is only as long as the time between two interrupts.
    One more thing: doing a busy-waiting loop (even if it would work) inside an ISR is a bad thing too. it will block other ISRs from being executed and it will keep the processor in active state for the whole delay instead of returning to low-power mode as fast as possible.

    Anyway, if you can see the blinking between your three initial settings of P1OUT, which also lasts some nanoseconds only... Or do you see the port being high after a reset, then going low by your code? I don't knwo your hardware, so i cannot tell.

    Running the processor under debugger control changes the timings, even if not actually debugging (run mode). It is possible that it influences the initialisation of the clock module which is driving the timers. I don't know. Since I'm not using CCE/IAR and their debugging modes, I have no experience with this.

    There are some bugs related to LFXT1. It is possible that the absence/failure of LFXT1 is not detected, causing the WDT being not clocked at all. If you don't have a clock crystal attached at all, go and manually disable XT1 by setting OSCOFF in SR or set the proper LFXT1Sx bits in BCSCTL3. Then the WDT is clocked by the VLO.
    Or if you have a crystal, check the load capacity setting. The default is 6pF, but maybe the crystal needs more or less XCAPx in BCSCTL3.

  • Thanks for you reply, I'm sorry I've been on training for 3 weeks

    Thanks to your suggestions, I've managed to make it run, but only with smclk. There was nothing possible when ACLK was selected. I'd like to monitor this clock in LPM3 mode to see if it's properly running but I'm not sure of the method. On my version (f2012), aclk could be output on the P1.0 pin (the same as the LED).
    How to monitor ACLK on this pin ?

    Just putting P1.0  direction as output ?

  • nicolas said:

    On my version (f2012), aclk could be output on the P1.0 pin (the same as the LED).
    How to monitor ACLK on this pin ?

    Just putting P1.0  direction as output ?

    You will find a table in the datasheet for the MSP430F2012 that indicates which control signals need to be set and how they are to be configured to propagate ACLK to P1.0.

    You will find this on page 58 and an illustration of the pin schematic on page 59.

    Specifically, for ACLK to propagate onto P1.0, you need to set the following : P1DIR.0=1, P1SEL.0=1, ADC10AE.0=0

  • Thanks for the answer

    But i've got a problem with setting these signals :
    First of all, i can't write down in my code P1DIR.0=1; because of the .0 : the compiler return me an error : a ; is expected. I get around this problem by writing P1DIR=0x01; ADC10AE has also been replaced by ADC10AE0 (CF : lnk_msp430f2012.cmd)

    When this signals are set, I can observe some irregular 3.64V peaks. But nothing looking like a clock :/

  • I think i've found out my problem .... if i'm right shame on me :!

    ACLK isn't an internal clock, am I right ? So without any external crystal, not any clock....

    Since the beggining, I thought ACLK was an internal 32kHz clock .. but A is for auxilary. The run mode of Code Composer Essentials seems to simulate these kind of clocks, that's why I manage to make it run in "run mode" but not in run free..So I'll put a crystal on Xin and Xout and as soon as I'll have checked it works I'll tick "verify answer" and paste my code if it could help anybody


    Thanks again for everybody's support :)

    PS : If i'm still wrong with my the ACLK point of view, let me know !

    [EDIT] : Reading some topics, I got a question : Is there a crystal onto the ez430 - T2012 board, wich could not connected to LFTX1 ? 

  • nicolas said:
    Since the beggining, I thought ACLK was an internal 32kHz clock .. but A is for auxilary.


    Not exactly.
    The term 'clock' is a bit misleading. I think the names derive from teh basic idea that the SMCLK (sub-main-clock) is synchroneous to MCLK, while ACLK (auxiliary clock, that's right) is independent from the two. But things have been implemented not so clearly on most MSPs. On the latest ones, ACLK and SMCLK are 100% exchangeable.
    Anyway, a 'clock' is just a (logical) clock signal provider, not a (physical) clock frequency generator.
    All three clocks available on all MSPs (ACLK, MCLK and SMCLK) require an oscillation source. And based on this oscillation sources frequency, divided by an adjustable divider, the 'clock' provides a clock signal that can be used in the different hardware modules.
    If (on the newer MSPs) ACLK and SMCLK are source by the same oscillator, but with different dividers, you can provide two different, synchroneous frequencies to the hardware modules, while you only need one active frequency source. So you can have an 8MHz crystal on XT2 and get an 8MHz SMCLK and an 1MHz ACLK from it if you want.

    Possible oscillator sources are the DCO or the one or two external XT inputs. On later MSPs, there are also an internal REFO (a reference oscillator), a MODOSC for the ADC12 or the flash controller and also a VLO, a very low power low frequency oscillator. All can be enabled or disabled depending on your needs.

    On the older MSPs, ACLK can be only sourced from LFXT1, on the 21x1 devices also from the VLO. You can do a trick by outputting the MCLK or the SMCLK to a port pin and route it back to the XT1 input.

    I wonder why CCE seems to simulate the clock. It's nothing a debugger should do. If ACLK is not sourced, it is not sourced and should not 'tick', whether in debugging mode nor in run mode. All the debugger can do (and does on the MSPs where it is possible) is to 'detach' the sytems clocks from their oscillation sources as long as the cpu is halted by the debugger. Maybe this generates an erroneous tick if the attached source is empty. It shouldn't anyway.

     

  • How will the use of this global variable and an interval timer work if the failure is due to a stack overflow and corruption of the memory space ? This is one of the scenarios when you want a watchdog to reset the system.

  • Ian Pratt said:
    How will the use of this global variable and an interval timer work if the failure is due to a stack overflow and corruption of the memory space ? This is one of the scenarios when you want a watchdog to reset the system.

    This thread was about interval timer mode, not watchdog reset. So the proposed solution was for extending the interval timer delay, not for extending a watchdog reset timeout. It surely wouldn't work for this.

    However, a watchdog is NOT for hotfixing faulty code. Even though many coders abuse it for this purpose. It is there for resetting the device if it should crash due to ESD or supply voltage problems. Things that are outside the control of the coder. So it makes no sense deactivating the WDT during startup, so it won't timeout when the variables are copied. (this stupid and even undocumented behavior was found on the MSPGCC3 startup code - it wasn't even reactivated before starting main)

    BTW: corrupted memory space does not necessarily mean that the code will stop executing the WDT trigger. Worst case, the watchdog will still be triggered, e.g. by a timer ISR, while the main code is already trapped dead.

**Attention** This is a public forum