Watchdog reset in LLS

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Watchdog reset in LLS

3,293 Views
alessandromorni
Contributor III

Hi,

 

I'm using a Kinetis K22 MCU (but the same problem is noticeable also on a K11 device).

 

You can find attached to this message a zip archive with both Processor Expert/IAR project and sources (MK22FX512VMC12  used as target).

 

My "test setup":

 

- MK22FX512VMC12 (MK11DN512VLK5)
- Processor Expert 10.4.2 standalone for code generation

- IAR 7.10.1.6735 for compiler/IDE

 

Scenario:

 

- watchdog period set @ 1200ms (no window mode)

- external accelerometer configured to generate an interrupt @2khz each new data ready (interrupt data ready pin is configured as wakeup source). Accelerometer data ready interrupt is enabled after 5 seconds that program is running

- low power timer (LPTMR) configured as wakeup source @1khz. Within LPTMR interrupt, a counter is incremented. When the timer reachs 1000 (1 second elapsed), a flag is set in order to signal that the watchdog should be cleared

- two led used as debug

- MCU used in stop mode (LLS) after the initial configuration

 

Problem:

 

- as soon as the accelerometer data ready interrupt is enabled, watchdog resets the MCU

 

My main.c:

 

#include "Cpu.h" #include "IO_Map.h" #include "LED1_PE.h" #include "PE_Const.h" #include "SPI_PE.h" #include "WAIT_PE.h" #include "WD_PE.h"   /**  * 1 if WD should be cleared / 0 otherwise.  */ unsigned char wdTrigger;   /**  * Values for configuring the accelerometer (in order to generate wakeup  * interrupt in LLS)  */ static const char accConfig[9][2] = {     {0x14, 0xB6},     {0x12, 0x40},     {0x11, 0x80},     {0x10, 0x0F},     {0x20, 0x00},     {0x21, 0x00},     {0x1A, 0x01},     {0x11, 0x00},     {0x17, 0x10} };   /**  * Main function.  */ int main (void) {     /**      * Flag telling after how many seconds accelerometer interrupt is enabled.      */     static unsigned char accCounter = 5;       unsigned char  i;     unsigned short reset;       /* Read the reset cause register. */     reset  = (RCM_SRS1 << 8);     reset |= RCM_SRS0;       /* Internal WD reset? */     if (reset & RSTSRC_WDOG)     {         /* Debug. */         asm ("nop");     }       /* PE low level init. */     PE_low_level_init();       /* Enable interrupt. */     Cpu_EnableInt ();       /* Configure accelerometer. */     for (i = 0; i < 8; i++)     {         /* Send command via SPI. */         SPI_PE_SendBlock (PE_LDD_GetDeviceStructure (PE_LDD_COMPONENT_SPI_PE_ID), (void*) &accConfig[i], 2);           /* Wait some time (just in case). */         WAIT_PE_Waitms (1);     }       /* Loop forever... */     while (1)     {         /* Go to LLS. */         Cpu_SetOperationMode (DOM_STOP, NULL, NULL);           /* Clear WD? */         if (wdTrigger)         {             /* Toggle debug led1. */             LED1_PE_NegVal (NULL);               /* Clear WD. */             WD_PE_Clear (NULL);               /* Accelerometer interrupt still not enabled? */             if (accCounter)             {                 /* Decrement counter. */                 if (!(--accCounter))                 {                     /* Enable interrupt. */                     SPI_PE_SendBlock (PE_LDD_GetDeviceStructure (PE_LDD_COMPONENT_SPI_PE_ID), (void*) &accConfig[8], 2);                       /* Wait some time (just in case). */                     WAIT_PE_Waitms (1);                 }             }         }           /* Clear flag. */         wdTrigger = 0;     } }

 

My Events.c

 

/* ################################################################### **     Filename    : Events.c **     Project     : WD_K22 **     Processor   : MK22FX512VMC12 **     Component   : Events **     Version     : Driver 01.00 **     Compiler    : IAR ARM C Compiler **     Date/Time   : 2015-05-27, 14:29, # CodeGen: 0 **     Abstract    : **         This is user's event module. **         Put your event handler code here. **     Settings    : **     Contents    : **         Cpu_OnNMIINT - void Cpu_OnNMIINT(void); ** ** ###################################################################*/ /*! ** @file Events.c ** @version 01.00 ** @brief **         This is user's event module. **         Put your event handler code here. */ /*! **  @addtogroup Events_module Events module documentation **  @{ */ /* MODULE Events */   #include "Cpu.h" #include "Events.h"   #ifdef __cplusplus extern "C" { #endif     /* User includes (#include below this line is not maintained by Processor Expert) */   /* ** =================================================================== **     Event       :  LPTMR_PE_OnCounterRestart (module Events) ** **     Component   :  LPTMR_PE [TimerUnit_LDD] */ /*! **     @brief **         Called if counter overflow/underflow or counter is **         reinitialized by modulo or compare register matching. **         OnCounterRestart event and Timer unit must be enabled. See **         [SetEventMask] and [GetEventMask] methods. This event is **         available only if a [Interrupt] is enabled. **     @param **         UserDataPtr     - Pointer to the user or **                           RTOS specific data. The pointer passed as **                           the parameter of Init method. */ /* ===================================================================*/ void LPTMR_PE_OnCounterRestart(LDD_TUserData *UserDataPtr) {     /**      * External flag for clearing WD (declared by main).      */     extern unsigned char wdTrigger;       /**      * Counter for set WD flag each second.      */     static unsigned short counter;       /* Toggle debug led0. */     LED0_PE_NegVal (NULL);       /* Increment counter. */     counter++;       /* 1second elapsed? */     if (counter == 1000)     {         /* Clear counter. */         counter = 0;           /* Set WD flag. */         wdTrigger = 1;     } }   /* ** =================================================================== **     Event       :  Cpu_OnLLSWakeUpINT (module Events) ** **     Component   :  Cpu [MK22FN1M0MC12] */ /*! **     @brief **         This event is called when Low Leakage WakeUp interrupt **         occurs. LLWU flags indicating source of the wakeup can be **         obtained by calling the [GetLLSWakeUpFlags] method. Flags **         indicating the external pin wakeup source are automatically **         cleared after this event is executed. It is responsibility **         of user to clear flags corresponding to internal modules. **         This event is automatically enabled when [LLWU interrupt **         request] is enabled. */ /* ===================================================================*/ void Cpu_OnLLSWakeUpINT(void) {     unsigned int i32ulFlag = Cpu_GetLLSWakeUpFlags ();       /* Low power timer wakeup. */     if (i32ulFlag & LLWU_INT_MODULE0)     {         /* Clear LPTMR interrupt flag. */         LPTMR_PDD_ClearInterruptFlag (LPTMR0_BASE_PTR);     }       /* Accelerometer interrupt wakeup. */     if (i32ulFlag & LLWU_EXT_PIN11)     {         /* Debug. */         asm ("nop");     } }   /* END Events */   #ifdef __cplusplus }  /* extern "C" */ #endif   /*! ** @} */ /* ** ################################################################### ** **     This file was created by Processor Expert 10.4 [05.11] **     for the Freescale Kinetis series of microcontrollers. ** ** ################################################################### */

 

Using an oscilloscope to check the toggle of LED1 (which is done before the clear of the WD), the reset occurs before the timeout period elapses (resets at ~750ms), as you can see from this image (channel 2 is the LED1, channel 1 is the acceleromeer interrupt data ready pin at 2khz).

 

32297_32297.JPGIMG_6213.JPG

 

The strange thing is that If I change the data ready interrupt frequency of the acceloremeter from 2khz to 250hz, the program is working correctly w/o resetting, as you can see from the next image.

 

32300_32300.JPGIMG_6216.JPG

 

It seems that the MCU doesn't like waking up from LLS too fast (is really 2khz too fast, compared with the core clock running at 96mhz?) when the WD is enabled.

 

If the watchdog is disabled, no problems occur.

 

Another strange thing: changing watchdog timeout period from 1200ms to 2500ms (with interrupt @2khz), everything works correctly.

 

32301_32301.jpg2500ms.jpg

 

Has anyone ever noticed a problem like this?

 

Alessandro

Original Attachment has been moved to: WD_K22.zip

Labels (1)
0 Kudos
Reply
11 Replies

2,347 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Alessandro,

I've no idea with the issue until now. It seems so weird.

I've downloaded your demo, however it can't open normally in IAR or CW.

And I was wondering if you can create a demo on FRDM-K22F to reproduce this phenomenon, then I can debug the demo on my board too.

I think it's efficient way to solve this issue.
Have a great day,
Ping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
Reply

2,347 Views
alessandromorni
Contributor III

Hi Jeremy,

actually I don't have a FRDM-K22F board, but I managed to create a demo for that. Attached to this message you'll find a IAR / KDS project based on FRDM-K22F board (I hope you can open them normally).

The test scenario is the same described in my first message, adapted to FRDM-K22F pinout:

- red LED (PTA1) is used for toggling;

- LPTMR interrupt and PTBO pin on falling edge are used for waking up from STOP mode (LLS);

In my setup test I used the data ready interrupt of an external accelerometer mounted on my board to generate the falling edge @2khz on the wake up pin.

You should find a way to generate the same behavior on your FRDM-K22F board (maybe a function generator?).

Let me know if you need more information.

Thank you for the support.

Alessandro

0 Kudos
Reply

2,347 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Alessandro,

If a system fails to refresh the watchdog due to an unknown or persistent cause, it will be caught in an endless cycle of resets from the watchdog, just as your issue.

To analyze the cause of such conditions, you can program the watchdog to first issue an interrupt, followed by a reset.

In the interrupt service routine, the software can analyze the system stack to aid debugging.

Hope it helps.
Have a great day,
Ping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
Reply

2,347 Views
alessandromorni
Contributor III

Hi,

I've got some updates (not very encouraging).

I added a sort of 'datalogger' using the 32khz prescaler register (which is not stopped in LLS) as 'system timer' (rtcTime variable).

    Cpu_SetOperationMode (DOM_STOP, NULL, NULL);

    Cpu_DisableInt ();

    rtcNow = RTC_PDD_ReadTimePrescalerReg (RTC_BASE_PTR);

    if (rtcOld > rtcNow)

    {

        rtcTime += 0x8000 - rtcOld + rtcNow;

    }

    else

    {

        rtcTime += rtcNow - rtcOld;

    }

    rtcOld = rtcNow;

    Cpu_EnableInt ();

Each second, when WD must be refreshed, I'm logging the following:

- system timer current value (rtcTime variable value);

- the value of the watchdog timer before the refresh;

- the value of the watchdog timer after the refresh;

    before = WDOG_TMROUTL;

    /* Clear WD. */

    WD_PE_Clear (NULL);

    WAIT_PE_Waitms (3);

    after = WDOG_TMROUTL;

    log[index].rtc    = rtcTime;

    log[index].before = before;

    log[index].after  = after;

    index++;

Furthermore, I enabled the watchdog interrupt generation before the reset. In the ISR I'm latching the system timer current value (isrRtc variable) and the value of the watchdog timer (isrWd).

void WD_PE_OnWatchDog(LDD_TUserData *UserDataPtr)

{

    rtcNow = RTC_PDD_ReadTimePrescalerReg (RTC_BASE_PTR);

    if (rtcOld > rtcNow)

    {

        rtcTime += 0x8000 - rtcOld + rtcNow;

    }

    else

    {

        rtcTime += rtcNow - rtcOld;

    }

    isrRtc = rtcTime;

    isrWd  = WDOG_TMROUTL;

}

Here's the 'logger' output:

log[0] -> { rtc = 0x8100, before = 0x3e8, after = 0x0}

log[1] -> { rtc = 0x1020F, before = 0x3e5, after = 0x0}

log[2] -> { rtc = 0x1831D, before = 0x3e5, after = 0x0}

log[3] -> { rtc = 0x2042B, before = 0x3e5, after = 0x0}

log[4] -> { rtc = 0x2853B, before = 0x3e5, after = 0x0}

isrRtc -> 0x2D284

isrWd -> 0x4B1

So, till the 2khz interrupt is not enabled, all is working fine (rtc diffs log and 'before' values are always ~1000ms).

As soon as the interrupt generation is enabled (after 5 seconds), the board resets due to the internal watchdog. As you can see, 19785 32khz ticks (~603ms) are elapsed since the last watchdog refresh, but the watchdog timer (isrWd) says 1201ms (0x4b1), even if log[4] -> after was 0 (meaning the watchdog was refreshed correctly).

I'm a bit worried about this problem: watchdog is very important in our application, and we must use LLS power mode.

0 Kudos
Reply

2,347 Views
alessandromorni
Contributor III

Hi,

I did some other tests, and the output of the 'datalogger' is very alarming.

I changed the interrupt frequency from 2khz to 125hz (enabled after 5 seconds). Program is not resetting, but here's the output:

log[0] -> { rtc = 0x80FF, before = 0x3DC, after = 0x0}

log[1] -> { rtc = 0x1020D, before = 0x3E5, after = 0x0}

log[2] -> { rtc = 0x1831A, before = 0x3E5, after = 0x0}

log[3] -> { rtc = 0x20429, before = 0x3E5, after = 0x0}

log[4] -> { rtc = 0x28535, before = 0x3E5, after = 0x0}

--- interrupt enabled @ 125hz ---

log[5] -> { rtc = 0x3063F, before = 0x464, after = 0x0}

log[6] -> { rtc = 0x38749, before = 0x465, after = 0x0}

log[7] -> { rtc = 0x40854, before = 0x464, after = 0x0}

log[8] -> { rtc = 0x48961, before = 0x461, after = 0x0}

log[9] -> { rtc = 0x50A71, before = 0x462, after = 0x0}

As you can see, rtc time diffs between log(n+1) and log(n) are ok (~1000ms), but WDOG counter ('before' values) are not 'synced', reporting that ~1124ms elapsed since last refresh. It seems that waking up from LLS mode, WDOG counter increments faster than it's source clock (LPO).

0 Kudos
Reply

2,347 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Alessandro,

After had a look through the restriction on watchdog operation, I've guess that the watchdog counter increments faster that source clock if enter and exit stop mode happen in one watchdog clock cycle.

I'll contact with AE team about this issue and inform you ASAP when I get the reply.
Have a great day,
Ping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
Reply

2,347 Views
alessandromorni
Contributor III

Hi,

maybe I've just undertsood what's happening.

Scenario1, LPTMR wakeup @1khz and interrupt frequency @125hz. Prior to refresh the watchdog, system is waking up from LLS 1000times because of the LPTMR (1ms period) and 125 times because of the interrupt (8ms period). 'before' values are 1124ms.

--- interrupt enabled @ 125hz ---

log[5] -> { rtc = 0x3063F, before = 0x464, after = 0x0}

log[6] -> { rtc = 0x38749, before = 0x465, after = 0x0}

log[7] -> { rtc = 0x40854, before = 0x464, after = 0x0}

log[8] -> { rtc = 0x48961, before = 0x461, after = 0x0}

log[9] -> { rtc = 0x50A71, before = 0x462, after = 0x0}

Scenario2, LPTMR wakeup @20hz, and interrupt disabled. Prior to refresh the watchdog, system is waking up from LLS 20times because of the LPTMR (50ms period) and 0 times because of the interrupt. 'before' values are 20ms.

log[0] -> { rtc = 0x07A78, before = 0x1B, after = 0x0}

log[1] -> { rtc = 0x0FB4F, before = 0x14, after = 0x0}

log[2] -> { rtc = 0x17C28, before = 0x14, after = 0x0}

log[3] -> { rtc = 0x1FD00, before = 0x14, after = 0x0}

log[4] -> { rtc = 0x22DD8, before = 0x14, after = 0x0}

Scenario3, LPTMR wakeup @20hz and interrupt frequency @125hz. Prior to refresh the watchdog, system is waking up from LLS 20times because of the LPTMR (1ms period) and 125 times because of the interrupt (8 period). 'before' values are 20ms with interrupt disabled, and ~145ms with interrupt enabled.

log[0] -> { rtc = 0x20353, before = 0x1C, after = 0x0}

log[1] -> { rtc = 0x28423, before = 0x14, after = 0x0}

log[2] -> { rtc = 0x3052F, before = 0x14, after = 0x0}

log[3] -> { rtc = 0x3863B, before = 0x14, after = 0x0}

log[4] -> { rtc = 0x40747, before = 0x14, after = 0x0}

--- interrupt enabled @ 125hz ---

log[5] -> { rtc = 0x0003052F, before = 0x99, after = 0x0}

log[6] -> { rtc = 0x0003863B, before = 0x98, after = 0x0}

log[7] -> { rtc = 0x00040747, before = 0x96, after = 0x0}

log[8] -> { rtc = 0x00048854, before = 0x9A, after = 0x0}

log[9] -> { rtc = 0x00050961, before = 0x98, after = 0x0}

From what I'm seeing, it's like that WDOG counter is not incrementing while the CPU is in LLS, but it increments of 1 unit each wakeup from LLS.

This is my watchdog configuration: STOPEN bit is set correctly.

LDD_TDeviceData* WD_PE_Init(LDD_TUserData *UserDataPtr)

{

  /* Allocate device structure */

  WD_PE_TDeviceData *DeviceDataPrv;

  /* {Default RTOS Adapter} Driver memory allocation: Dynamic allocation is simulated by a pointer to the static object */

  DeviceDataPrv = &DeviceDataPrv__DEFAULT_RTOS_ALLOC;

  DeviceDataPrv->UserDataPtr = UserDataPtr; /* Store the RTOS device structure */

  /* Interrupt vector(s) allocation */

  /* {Default RTOS Adapter} Set interrupt vector: IVT is static, ISR parameter is passed by the global variable */

  INT_Watchdog__DEFAULT_RTOS_ISRPARAM = DeviceDataPrv;

  /* NVICIP22: PRI22=0x80 */

  NVICIP22 = NVIC_IP_PRI22(0x80);

  /* NVICISER0: SETENA|=0x00400000 */

  NVICISER0 |= NVIC_ISER_SETENA(0x00400000);

  /* {Default RTOS Adapter} Critical section begin, general PE function is used */

  EnterCritical();

  /* WDOG_UNLOCK: WDOGUNLOCK=0xC520 */

  WDOG_UNLOCK = WDOG_UNLOCK_WDOGUNLOCK(0xC520); /* Key 1 */

  /* WDOG_UNLOCK: WDOGUNLOCK=0xD928 */

  WDOG_UNLOCK = WDOG_UNLOCK_WDOGUNLOCK(0xD928); /* Key 2 */

  /* WDOG_WINH: WINHIGH=0 */

  WDOG_WINH = WDOG_WINH_WINHIGH(0x00); /* Setup window register high */

  /* WDOG_WINL: WINLOW=0 */

  WDOG_WINL = WDOG_WINL_WINLOW(0x00);  /* Setup window register low */

  /* WDOG_TOVALH: TOVALHIGH=0 */

  WDOG_TOVALH = WDOG_TOVALH_TOVALHIGH(0x00); /* Setup time-out value register high */

  /* WDOG_TOVALL: TOVALLOW=0x04B0 */

  WDOG_TOVALL = WDOG_TOVALL_TOVALLOW(1300); /* Setup time-out value register low */

  /* WDOG_PRESC: ??=0,??=0,??=0,??=0,??=0,PRESCVAL=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0 */

  WDOG_PRESC = WDOG_PRESC_PRESCVAL(0x00); /* Setup status register */

  /* WDOG_STCTRLL: INTFLG=1,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=1 */

  WDOG_STCTRLL = (WDOG_STCTRLL_INTFLG_MASK | 0x01U); /* Setup status register */

  /* WDOG_STCTRLH: ??=0,DISTESTWDOG=1,BYTESEL=0,TESTSEL=0,TESTWDOG=0,??=0,??=1,WAITEN=1,STOPEN=1,DBGEN=0,ALLOWUPDATE=1,WINEN=0,IRQRSTEN=1,CLKsrc=0,WDOGEN=1 */

  WDOG_STCTRLH = WDOG_STCTRLH_DISTESTWDOG_MASK |

                WDOG_STCTRLH_BYTESEL(0x00) |

                WDOG_STCTRLH_WAITEN_MASK |

                WDOG_STCTRLH_STOPEN_MASK |

                WDOG_STCTRLH_ALLOWUPDATE_MASK |

                WDOG_STCTRLH_IRQRSTEN_MASK |

                WDOG_STCTRLH_WDOGEN_MASK |

                0x0100U;              /* Setup control register */

  /* {Default RTOS Adapter} Critical section end, general PE function is used */

  ExitCritical();

  /* Registration of the device structure */

  PE_LDD_RegisterDeviceStructure(PE_LDD_COMPONENT_WD_PE_ID,DeviceDataPrv);

  return ((LDD_TDeviceData *)DeviceDataPrv); /* Return pointer to the device data structure */

}

If I enter in LLS with LPTMR disabled (no wakeup from LLS then), WD is not resetting, meaning that counter is not incrementing.

0 Kudos
Reply

2,347 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Alessandro,

It's so interesting and I think I need to check this phenomenon by myself or with the AE team.

I'll inform you ASAP when I get the result.
Have a great day,
Ping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
Reply

2,347 Views
alessandromorni
Contributor III

Hi,

after consulting with a Freescale Field Application Engineer, we probably figured out what were the problems.

First of all, watchdog module is not Full Functionality in LLS mode but is instead static (module register states and associated memories are retained) as reported in the datasheet.

Immagine.jpg

So it's correct that in LLS watchdog is not couting.

As regards the wrong increment of the watchdog counter waking up from LLS mode, disabling WDOG_STCTRLH[STOPEN] resolves.

Thank you the support.

Alessandro

0 Kudos
Reply

2,347 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Alessandro,

Unfortunately, both of demos fail on the FRDM-K22F board and I'll created a demo for test later.

Do you have some updated about your issue?
Have a great day,
Ping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
Reply

2,347 Views
alessandromorni
Contributor III

Hi,

unfortunately no futher updates. I'm sorry to hear that both demos are not working: what kind of error are you getting?

0 Kudos
Reply