lpcware

Waking up from deep-sleep with timer32/WDTOSC

Discussion created by lpcware Employee on Jun 15, 2016
Latest reply on Jun 15, 2016 by lpcware
Content originally posted in LPCWare by ktownsend on Fri Mar 26 10:58:30 MST 2010
I've been trying to write some generic code to enter deep sleep mode with the LPC1114 (easy enough), and then wakeup after a fixed number of seconds using 32-bit timer 0 off WDTOSC.

Entering deep sleep is fine, but it I haven't been able to get the device to wakeup using the timer, and I'm really starting to scratch my head on this.

My apologies if the code below is partial, but I'm using a header file I wrote myself since I hate having magic-numbers everywhere [reg1 = 0xA033F300] ... it should be clear with the names what values are being set, though.

The methods below are used with the following test code in main:


    U32 pmuRegVal;

    // Configure wakeup sources before going into sleep/deep-sleep.
    // By default, pin 0.1 is configured as wakeup source (falling edge)
    pmuInit();

    // Put peripherals into sleep mode (leave WDTOSC enabled)
    pmuRegVal = SCB_PDSLEEPCFG_IRCOUT_PD |
                SCB_PDSLEEPCFG_IRC_PD |
                SCB_PDSLEEPCFG_FLASH_PD |
                SCB_PDSLEEPCFG_BOD_PD |
                SCB_PDSLEEPCFG_ADC_PD |
                SCB_PDSLEEPCFG_SYSPLL_PD;

    // Enter deep sleep mode (wakeup after 5 seconds)
    pmuDeepSleep(pmuRegVal, 5);


It's a long read, but here are the key methods if someone is brave enough to look through them. If there are any clear examples of waking up from deep sleep on a timer capture that would be useful as well.

Kevin.

 
/**************************************************************************/
/*!
    \brief Initialises the power management unit
    Initialise the power management unit, and configure pin 0.1 to act as
    a wakeup source from sleep or deep-sleep mode.
    For sleep and deep-sleep modes, entered via pmuSleep(), P0.0..11 and
    P1.0 can be used as a wakeup source.  For deep power-down mode, entered
    via pmuPowerDown(), only a low level on pin 1.4 (WAKEUP) can wake the
    device up.
*/
/**************************************************************************/
void pmuInit( void )
{
  /* Enable all clocks, even those turned off at power up. */
  SCB_PDRUNCFG &= ~(SCB_PDRUNCFG_WDTOSC_MASK |
                    SCB_PDRUNCFG_SYSOSC_MASK |
                    SCB_PDRUNCFG_ADC_MASK);
  /* Enable wakeup interrupts (P0.1..11 and P1.0 can be used) */
  NVIC_EnableIRQ(WAKEUP1_IRQn);      // P0.1
  /* Configure pin 0.1 as wakeup source (MAT2 on 32-bit Timer 0) */
  IOCON_PIO0_1 &= ~IOCON_PIO0_1_FUNC_MASK;
  IOCON_PIO0_1 |= (IOCON_PIO0_1_FUNC_GPIO |
                   IOCON_PIO0_1_HYS_ENABLE);
  /* Set pins to input for wakeup */
  gpioSetDir( 0, 1, gpioDirection_Input );
  /* Only edge trigger. activation polarity on P0.1 is FALLING EDGE. */
  SCB_STARTAPRP0 = ~SCB_STARTAPRP0_MASK;      // ~0xFFFFFFFF;
  /* Clear all wakeup source */
  SCB_STARTRSRP0CLR = SCB_STARTRSRP0CLR_MASK;
  /* Enable Port 0.1 as wakeup source. */
  SCB_STARTERP0 |= SCB_STARTERP0_ERPIO0_1;
  return;
}
/**************************************************************************/
/*!
    Setup the clock for the watchdog timer.  The default setting is 10kHz.
*/
/**************************************************************************/
static void pmuWDTClockInit (void)
{
  /* Configure watchdog clock */
  /* Freq. = 0.5MHz, div = 50: WDT_OSC = 10kHz  */
  SCB_WDTOSCCTRL = SCB_WDTOSCCTRL_FREQSEL_0_5MHZ |
                   SCB_WDTOSCCTRL_DIVSEL_DIV50;
  /* Set clock source (use external crystal) */
  SCB_WDTCLKSEL = SCB_WDTCLKSEL_SOURCE_INPUTCLOCK;
  SCB_WDTCLKUEN = SCB_WDTCLKUEN_UPDATE;
  SCB_WDTCLKUEN = SCB_WDTCLKUEN_DISABLE;
  SCB_WDTCLKUEN = SCB_WDTCLKUEN_UPDATE;
  /* Wait until updated */
  while (!(SCB_WDTCLKUEN & SCB_WDTCLKUEN_UPDATE));
  /* Set divider */
  SCB_WDTCLKDIV = SCB_WDTCLKDIV_DIV1;
  /* Enable WDT clock */
  SCB_PDRUNCFG &= ~(SCB_PDRUNCFG_WDTOSC);
  // Switch main clock to WDT output
  SCB_MAINCLKSEL = SCB_MAINCLKSEL_SOURCE_WDTOSC;
  SCB_MAINCLKUEN = SCB_MAINCLKUEN_UPDATE;       // Update clock source
  SCB_MAINCLKUEN = SCB_MAINCLKUEN_DISABLE;      // Toggle update register once
  SCB_MAINCLKUEN = SCB_MAINCLKUEN_UPDATE;
  // Wait until the clock is updated
  while (!(SCB_MAINCLKUEN & SCB_MAINCLKUEN_UPDATE));
}
/**************************************************************************/
/*!
    \brief  Turns off select peripherals and puts the device in deep-sleep
            mode.
    This function will put the device into deep-sleep mode.  Most gpio
    pins can be used to wake the device up, but the pins must first be
    configured for this in pmuInit.  By default, only pin 0.1 (ISP) is
    configured as a wakeup source.
    The device can be configured to wakeup from deep-sleep mode after a
    specified delay with the wakeupSeconds parameter.  This will configure
    32-bit timer 0 to set a match on pin 0.1 (ISP), which will wakeup
    the device up.  The timer will be configured to run off the WDT OSC
    while in deep-sleep mode, meaning that WDTOSC should not be powered
    off (using the sleepCtrl parameter) when a wakeup delay is specified.
    The sleepCtrl parameter is used to indicate which peripherals should
    be put in sleep mode (see the SCB_PDSLEEPCFG register for details).

    @param[in]  sleepCtrl 
                The bits to set in the SCB_PDSLEEPCFG register.  This
                controls which peripherals will be put in sleep mode.
    @param[in]  wakeupSeconds
                The number of seconds to wait until the device will
                wakeup.  If you do not wish to wakeup after a specific
                delay, enter a value of 0.
*/
/**************************************************************************/
void pmuDeepSleep(U32 sleepCtrl, U32 wakeupSeconds)
{
  SCB_PDAWAKECFG = SCB_PDRUNCFG;
  sleepCtrl &= ~(1 << 9);               // MAIN_REGUL_PD
  sleepCtrl |= (1 << 11) | (1 << 12);   // LP_REGUL_PD
  SCB_PDSLEEPCFG = sleepCtrl;
  SCB_SCR |= SCB_SCR_SLEEPDEEP;
  /* Configure system to run from WDT and set TMR32B0 for wakeup          */
  if (wakeupSeconds > 0)
  {
    // Make sure WDTOSC isn't disabled in PDSLEEPCFG
    SCB_PDSLEEPCFG &= ~(SCB_PDSLEEPCFG_WDTOSC_PD);
    // Disable 32-bit timer 0 if currently in use
    timer32Disable(0);
    // Reconfigure clock to run from WDTOSC
    pmuWDTClockInit();
    /* Enable the clock for CT32B0 */
    SCB_SYSAHBCLKCTRL |= (SCB_SYSAHBCLKCTRL_CT32B0);

    /* Configure PIO0.1 as Timer0_32 MAT2 */
    IOCON_PIO0_1 &= ~IOCON_PIO0_1_FUNC_MASK;
    IOCON_PIO0_1 |= IOCON_PIO0_1_FUNC_CT32B0_MAT2;
    /* Set appropriate timer delay */
    TMR_TMR32B0MR0 = PMU_WDTCLOCKSPEED_HZ * wakeupSeconds;

    /* Configure match control register to raise an interrupt and reset on MR0 */
    TMR_TMR32B0MCR = (TMR_TMR32B0MCR_MR0_INT_ENABLED | TMR_TMR32B0MCR_MR0_RESET_ENABLED);

    /* Configure external match register */
    TMR_TMR32B0EMR &= ~(0xFF<<4);                   // Clear EMR config bits
    TMR_TMR32B0EMR |= TMR_TMR32B0EMR_EMC2_TOGGLE;   // MR2 (GPIO0.1) Toggle

    /* Enable the TIMER0 interrupt */
    NVIC_EnableIRQ(TIMER_32_0_IRQn);

    /* Start the timer */
    TMR_TMR32B0TCR = TMR_TMR32B0TCR_COUNTERENABLE_ENABLED;
  }
  // Send Wait For Interrupt command
  __asm volatile ("WFI");
  return;
}

Outcomes