Added Restart(by RESET) function from Standby mode only for some Nucleo boards (STM32 series)

Dependencies:   LPC1114_WakeInterruptIn

Dependents:   Check_StandBy

Fork of WakeUp by Erik -

Example program using "Standby function" for Nucleo series is here.
/users/kenjiArai/code/Check_StandBy/

Device/WakeUp_LPC11XX.cpp

Committer:
Sissors
Date:
2014-07-28
Revision:
10:c41bc9154a7c
Child:
11:72db657fc572

File content as of revision 10:c41bc9154a7c:

/**
See homepage of this lib for LPC11xx special treatment
**/

#ifdef TARGET_LPC11XX_11CXX

//dp1 or dp2 can be chosen
#define WAKEUP_PIN      dp1
//#define WAKEUP_PIN      dp2

#define WAKEUP_MATCH        (((WAKEUP_PIN >> PIN_SHIFT) & 0xF) - 8)
#define WAKEUP_CHANNEL      ((WAKEUP_PIN >> PIN_SHIFT) & 0xF)

#define WAKEUP_TIMER        LPC_TMR16B0
#define WAKEUP_TIMER_EN     7

#define SYSAHBCLKCTRL_SLEEP     (0x15 | (1<<WAKEUP_TIMER_EN))  

#include "WakeUp.h"
#include "WakeInterruptIn.h"

WakeInterruptIn IRQ_in(WAKEUP_PIN);
PwmOut pulse_out(WAKEUP_PIN);

FunctionPointer WakeUp::callback;
float WakeUp::cycles_per_ms = 20.0;

static uint32_t old_clk_sel = ~0;
static uint32_t SYSAHBCLKCTRL;
static uint32_t TCR, PR, MR3;

static inline void restore(void);


void WakeUp::set_ms(uint32_t ms)
{
    if (ms != 0) {
        if (old_clk_sel == ~0) {                                //Only during first run
            old_clk_sel = LPC_SYSCON->MAINCLKSEL;
            SYSAHBCLKCTRL = LPC_SYSCON->SYSAHBCLKCTRL;
        }
        
        if (LPC_SYSCON->SYSAHBCLKCTRL != SYSAHBCLKCTRL_SLEEP)    //Always when it is different from sleep settings
            SYSAHBCLKCTRL = LPC_SYSCON->SYSAHBCLKCTRL;

        LPC_SYSCON->PDRUNCFG &= ~PDRUNCFG_WDTOSC_PD;
        LPC_SYSCON->PDSLEEPCFG = 0x000018B7 | (LPC_SYSCON->PDRUNCFG & (PDRUNCFG_WDTOSC_PD | PDRUNCFG_BOD_PD)); 
        
        //Set oscillator for 20kHz
        LPC_SYSCON->WDTOSCCTRL = 14 | (1<<5);
        
        //Store old PWM
        TCR = WAKEUP_TIMER->TCR;
        PR = WAKEUP_TIMER->PR;
        MR3 = WAKEUP_TIMER->MR3;
        
        //Setup PWM
        WAKEUP_TIMER->TCR = TMR16B0TCR_CRST;
        uint32_t ticks = (float)ms * cycles_per_ms;
        
        //whatever timer it is, we treat it as 16-bit (with PR that is 32-bit still, do the math, it is enough for this)
        WAKEUP_TIMER->PR = ticks >> 16;
        WAKEUP_TIMER->MR[WAKEUP_MATCH] = ticks / ((ticks >> 16) + 1);
        WAKEUP_TIMER->MR3 = 0xFFFF;
                
        IRQ_in.rise(irq_handler);
        
        //Disable most peripherals
        LPC_SYSCON->SYSAHBCLKCTRL = SYSAHBCLKCTRL_SLEEP;
        
        //Switch clock to WD OSC
        LPC_SYSCON->MAINCLKSEL = 0x2;
        LPC_SYSCON->MAINCLKUEN = 0;
        LPC_SYSCON->MAINCLKUEN = MAINCLKUEN_ENA;
        
        //Enable PWM:
        WAKEUP_TIMER->TCR = TMR16B0TCR_CEN;
    } else {
        //Else restore normal settings
        restore();
    }
    
}

void WakeUp::irq_handler(void)
{    
    restore();    
    callback.call();
}

void WakeUp::calibrate(void)
{
}

static inline void restore(void) {
        
    WAKEUP_TIMER->MR[WAKEUP_MATCH] = 0xFFFF;

    if (old_clk_sel == 3)                           //Was running on PLL
        while(LPC_SYSCON->SYSPLLSTAT != SYSPLLSTAT_LOCK);
    
    if (old_clk_sel < 4) {  //If valid setting
        LPC_SYSCON->MAINCLKSEL = old_clk_sel;
        LPC_SYSCON->MAINCLKUEN = 0;
        LPC_SYSCON->MAINCLKUEN = MAINCLKUEN_ENA;
    }
    
    IRQ_in.rise(NULL);
    
    LPC_SYSCON->SYSAHBCLKCTRL = SYSAHBCLKCTRL; 
    
    WAKEUP_TIMER->MR3 = MR3;
    WAKEUP_TIMER->PR = PR;
    WAKEUP_TIMER->TCR = TCR;
}

#endif