Wake-up timer library to wake from deepsleep/power-down

Dependencies:   LPC1114_WakeInterruptIn

Fork of WakeUp by Erik -

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WakeUp_LPC11XX.cpp Source File

WakeUp_LPC11XX.cpp

00001 /**
00002 See homepage of this lib for LPC11xx special treatment
00003 **/
00004 
00005 #ifdef TARGET_LPC11XX_11CXX
00006 
00007 #include "WakeUp.h"
00008 #include "WakeInterruptIn.h"
00009 #include "pinmap.h"
00010 #include "toolchain.h"
00011 
00012 //Pin used, allowed pins = P0_1 (dp24, default), P0_8 (dp1) and P0_9 (dp2)
00013 //By defining WakeUpPin in for example your main.cpp this can be overridden
00014 WEAK PinName WakeUpPin = dp24;
00015 extern PinName WakeUpPin;
00016 
00017 WakeInterruptIn IRQ_in(WakeUpPin);
00018 PwmOut pulse_out(WakeUpPin);
00019 
00020 FunctionPointer WakeUp::callback;
00021 float WakeUp::cycles_per_ms = 20.0;
00022 
00023 static uint32_t old_clk_sel = ~0;
00024 static uint32_t SYSAHBCLKCTRL;
00025 static uint32_t TCR, PR, MR3;
00026 static LPC_TMR_TypeDef *WakeUpTimer;
00027 static uint32_t SYSAHBCLKCTRL_Sleep;
00028 static uint8_t WakeUpTimer_Match;
00029 
00030 static inline void restore(void);
00031 
00032 
00033 void WakeUp::set_ms(uint32_t ms)
00034 {
00035     if (old_clk_sel == ~0) {                                //Only during first run
00036         old_clk_sel = LPC_SYSCON->MAINCLKSEL;
00037         SYSAHBCLKCTRL = LPC_SYSCON->SYSAHBCLKCTRL;
00038         
00039         switch(WakeUpPin) {
00040             case dp24:
00041                 WakeUpTimer = LPC_TMR32B0;
00042                 SYSAHBCLKCTRL_Sleep = 0x15 | (1<<9);
00043                 WakeUpTimer_Match = 2;
00044                 break;
00045             case dp1:
00046                 WakeUpTimer = LPC_TMR16B0;
00047                 SYSAHBCLKCTRL_Sleep = 0x15 | (1<<7);
00048                 WakeUpTimer_Match = 0;
00049                 break;
00050             case dp2:
00051                 WakeUpTimer = LPC_TMR16B0;
00052                 SYSAHBCLKCTRL_Sleep = 0x15 | (1<<7);
00053                 WakeUpTimer_Match = 1;
00054                 break;
00055             default:
00056                 error("Invalid WakeUp pin, choose dp1, dp2 or dp24");
00057         }            
00058     }
00059         
00060     if (ms != 0) {        
00061         if (LPC_SYSCON->SYSAHBCLKCTRL != SYSAHBCLKCTRL_Sleep)    //Always when it is different from sleep settings
00062             SYSAHBCLKCTRL = LPC_SYSCON->SYSAHBCLKCTRL;
00063 
00064         LPC_SYSCON->PDRUNCFG &= ~PDRUNCFG_WDTOSC_PD;
00065         LPC_SYSCON->PDSLEEPCFG = 0x000018B7 | (LPC_SYSCON->PDRUNCFG & (PDRUNCFG_WDTOSC_PD | PDRUNCFG_BOD_PD)); 
00066         
00067         //Set oscillator for 20kHz
00068         LPC_SYSCON->WDTOSCCTRL = 14 | (1<<5);
00069         
00070         //Store old PWM
00071         TCR = WakeUpTimer->TCR;
00072         PR = WakeUpTimer->PR;
00073         MR3 = WakeUpTimer->MR3;
00074         
00075         //Setup PWM
00076         WakeUpTimer->TCR = TMR16B0TCR_CRST;
00077         uint32_t ticks = (float)ms * cycles_per_ms;
00078         
00079         //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)
00080         WakeUpTimer->PR = ticks >> 16;
00081         WakeUpTimer->MR[WakeUpTimer_Match] = ticks / ((ticks >> 16) + 1);
00082         WakeUpTimer->MR3 = 0xFFFF;
00083                 
00084         IRQ_in.rise(irq_handler);
00085         
00086         //Disable most peripherals
00087         LPC_SYSCON->SYSAHBCLKCTRL = SYSAHBCLKCTRL_Sleep;
00088         
00089         //Switch clock to WD OSC
00090         LPC_SYSCON->MAINCLKSEL = 0x2;
00091         LPC_SYSCON->MAINCLKUEN = 0;
00092         LPC_SYSCON->MAINCLKUEN = MAINCLKUEN_ENA;
00093         
00094         //Enable PWM:
00095         WakeUpTimer->TCR = TMR16B0TCR_CEN;
00096     } else {
00097         //Else restore normal settings
00098         restore();
00099     }
00100     
00101 }
00102 
00103 void WakeUp::irq_handler(void)
00104 {    
00105     restore();    
00106     callback.call();
00107 }
00108 
00109 void WakeUp::calibrate(void)
00110 {
00111     //Save current pin function
00112     __IO uint32_t *reg = (__IO uint32_t*)(LPC_IOCON_BASE + (dp24 & 0xFF));
00113     uint32_t old_pinfun = *reg;
00114     
00115     //Set oscillator for 20kHz
00116     LPC_SYSCON->PDRUNCFG &= ~PDRUNCFG_WDTOSC_PD;
00117     LPC_SYSCON->WDTOSCCTRL = 14 | (1<<5);
00118     
00119     //Direct WDT to the CLKOUT pin (dp24), sample it back
00120     DigitalIn din(dp24);
00121     Timer timer;
00122     
00123     LPC_SYSCON->CLKOUTDIV = 1;
00124     LPC_SYSCON->CLKOUTCLKSEL = 0x2;
00125     LPC_SYSCON->CLKOUTUEN = 0;
00126     LPC_SYSCON->CLKOUTUEN = CLKOUTUEN_ENA;
00127     pin_function(dp24, 1);
00128     
00129     int count = 0;
00130     timer.start();
00131     while (timer.read_ms() < 100) {
00132         while (din.read() == 0);
00133         while (din.read() == 1);
00134         count++;
00135     }
00136     cycles_per_ms = (float)count / 100.0f;
00137     
00138     //Set old pin function back, disable CLKOUT
00139     *reg = old_pinfun;
00140     LPC_SYSCON->CLKOUTDIV = 0;
00141 }
00142 
00143 static inline void restore(void) {
00144         
00145     WakeUpTimer->MR[WakeUpTimer_Match] = 0xFFFFFFFF;
00146 
00147     if (old_clk_sel == 3)                           //Was running on PLL
00148         while(LPC_SYSCON->SYSPLLSTAT != SYSPLLSTAT_LOCK);
00149     
00150     if (old_clk_sel < 4) {  //If valid setting
00151         LPC_SYSCON->MAINCLKSEL = old_clk_sel;
00152         LPC_SYSCON->MAINCLKUEN = 0;
00153         LPC_SYSCON->MAINCLKUEN = MAINCLKUEN_ENA;
00154     }
00155     
00156     IRQ_in.rise(NULL);
00157     
00158     LPC_SYSCON->SYSAHBCLKCTRL = SYSAHBCLKCTRL; 
00159     
00160     WakeUpTimer->MR3 = MR3;
00161     WakeUpTimer->PR = PR;
00162     WakeUpTimer->TCR = TCR;
00163 }
00164 
00165 #endif