Modified WakeUp program to run on STM32L152RE
Dependencies: mbed LPC1114_WakeInterruptIn
Fork of WakeUp by
Revision 25:5147cde086fd, committed 2017-11-24
- Comitter:
- mx300
- Date:
- Fri Nov 24 00:04:03 2017 +0000
- Parent:
- 24:65c04a02ad45
- Commit message:
- Modified for use on STM32L152RE
Changed in this revision
diff -r 65c04a02ad45 -r 5147cde086fd Device/WakeUp_Freescale.cpp --- a/Device/WakeUp_Freescale.cpp Tue Jul 04 07:59:06 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -#if defined(TARGET_Freescale) - -#include "WakeUp.h" -#include "us_ticker_api.h" - -Callback<void()> WakeUp::callback; -float WakeUp::cycles_per_ms = 1.0; - -static uint16_t remainder_count; -static uint32_t oldvector; -static uint8_t oldPSR; - -//See if we have a 32kHz crystal on the clock input -//Check if the DMX32 bit is set, not perfect, but most cases will work -static inline bool is32kXtal(void) { - return (MCG->C4 & MCG_C4_DMX32_MASK); -} - -void restore(void); - -void WakeUp::set_ms(uint32_t ms) -{ - /* Clock the timer */ - SIM->SCGC5 |= 0x1u; - - //Check if it is running, in that case, store current values - remainder_count = 0; - if (NVIC_GetVector(LPTimer_IRQn) != (uint32_t)WakeUp::irq_handler) { - oldvector = NVIC_GetVector(LPTimer_IRQn); - oldPSR = LPTMR0->PSR; - - if (LPTMR0->CSR & LPTMR_CSR_TIE_MASK) { - //Write first to sync value - LPTMR0->CNR = 0; - uint16_t countval = LPTMR0->CNR; - if (countval < LPTMR0->CMR) - remainder_count = countval - LPTMR0->CMR; - } - } - - LPTMR0->CSR = 0; - - if (ms != 0) { - /* Set interrupt handler */ - NVIC_SetVector(LPTimer_IRQn, (uint32_t)WakeUp::irq_handler); - NVIC_EnableIRQ(LPTimer_IRQn); - - uint32_t counts; - //Set clock - if (is32kXtal()) { - SIM->SOPT1 &= ~SIM_SOPT1_OSC32KSEL_MASK; //Put RTC/LPTMR on 32kHz external. - #ifdef OSC0 - OSC0->CR |= OSC_CR_EREFSTEN_MASK; - #else - OSC->CR |= OSC_CR_EREFSTEN_MASK; - #endif - LPTMR0->PSR = LPTMR_PSR_PCS(2); - counts = (uint32_t)((float)ms * 32.768f); - } else { - //Clock from the 1kHz LPO - LPTMR0->PSR = LPTMR_PSR_PCS(1); - counts = (uint32_t)((float)ms * cycles_per_ms); - } - - //If no prescaler is needed - if (counts <= 0xFFFF) - LPTMR0->PSR |= LPTMR_PSR_PBYP_MASK; - else { //Otherwise increase prescaler until it fits - counts >>= 1; - uint32_t prescaler = 0; - while (counts > 0xFFFF) { - counts >>= 1; - prescaler++; - } - LPTMR0->PSR |= LPTMR_PSR_PRESCALE(prescaler); - } - LPTMR0->CMR = counts; - - LPTMR0->CSR = LPTMR_CSR_TIE_MASK; - LPTMR0->CSR |= LPTMR_CSR_TEN_MASK; - } else { - restore(); - } - -} - - -void WakeUp::irq_handler(void) -{ - // write 1 to TCF to clear the LPT timer compare flag - LPTMR0->CSR |= LPTMR_CSR_TCF_MASK; - restore(); - callback.call(); -} - -void WakeUp::calibrate(void) -{ - if (!is32kXtal()) { - wait_us(1); //Otherwise next wait might overwrite our settings - cycles_per_ms = 1.0; - set_ms(1100); - wait_ms(100); - - //Write first to sync value - LPTMR0->CNR = 0; - uint32_t ticks = LPTMR0->CNR; - cycles_per_ms = ticks / 100.0; - set_ms(0); - } -} - -void restore(void){ - /* Reset */ - LPTMR0->CSR = 0; - - /* Set interrupt handler */ - NVIC_SetVector(LPTimer_IRQn, oldvector); - NVIC_EnableIRQ(LPTimer_IRQn); - - /* Clock at (1)MHz -> (1)tick/us */ - LPTMR0->PSR = oldPSR; - - if (remainder_count) { - /* Set the compare register */ - LPTMR0->CMR = remainder_count; - - /* Enable interrupt */ - LPTMR0->CSR |= LPTMR_CSR_TIE_MASK; - - /* Start the timer */ - LPTMR0->CSR |= LPTMR_CSR_TEN_MASK; - } -} - -#endif \ No newline at end of file
diff -r 65c04a02ad45 -r 5147cde086fd Device/WakeUp_LPC11XX.cpp --- a/Device/WakeUp_LPC11XX.cpp Tue Jul 04 07:59:06 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,165 +0,0 @@ -/** -See homepage of this lib for LPC11xx special treatment -**/ - -#ifdef TARGET_LPC11XX_11CXX - -#include "WakeUp.h" -#include "WakeInterruptIn.h" -#include "pinmap.h" -#include "toolchain.h" - -//Pin used, allowed pins = P0_1 (dp24, default), P0_8 (dp1) and P0_9 (dp2) -//By defining WakeUpPin in for example your main.cpp this can be overridden -WEAK PinName WakeUpPin = dp24; -extern PinName WakeUpPin; - -WakeInterruptIn IRQ_in(WakeUpPin); -PwmOut pulse_out(WakeUpPin); - -Callback<void()> 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 LPC_TMR_TypeDef *WakeUpTimer; -static uint32_t SYSAHBCLKCTRL_Sleep; -static uint8_t WakeUpTimer_Match; - -static inline void restore(void); - - -void WakeUp::set_ms(uint32_t ms) -{ - if (old_clk_sel == ~0) { //Only during first run - old_clk_sel = LPC_SYSCON->MAINCLKSEL; - SYSAHBCLKCTRL = LPC_SYSCON->SYSAHBCLKCTRL; - - switch(WakeUpPin) { - case dp24: - WakeUpTimer = LPC_TMR32B0; - SYSAHBCLKCTRL_Sleep = 0x15 | (1<<9); - WakeUpTimer_Match = 2; - break; - case dp1: - WakeUpTimer = LPC_TMR16B0; - SYSAHBCLKCTRL_Sleep = 0x15 | (1<<7); - WakeUpTimer_Match = 0; - break; - case dp2: - WakeUpTimer = LPC_TMR16B0; - SYSAHBCLKCTRL_Sleep = 0x15 | (1<<7); - WakeUpTimer_Match = 1; - break; - default: - error("Invalid WakeUp pin, choose dp1, dp2 or dp24"); - } - } - - if (ms != 0) { - 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 = WakeUpTimer->TCR; - PR = WakeUpTimer->PR; - MR3 = WakeUpTimer->MR3; - - //Setup PWM - WakeUpTimer->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) - WakeUpTimer->PR = ticks >> 16; - WakeUpTimer->MR[WakeUpTimer_Match] = ticks / ((ticks >> 16) + 1); - WakeUpTimer->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: - WakeUpTimer->TCR = TMR16B0TCR_CEN; - } else { - //Else restore normal settings - restore(); - } - -} - -void WakeUp::irq_handler(void) -{ - restore(); - callback.call(); -} - -void WakeUp::calibrate(void) -{ - //Save current pin function - __IO uint32_t *reg = (__IO uint32_t*)(LPC_IOCON_BASE + (dp24 & 0xFF)); - uint32_t old_pinfun = *reg; - - //Set oscillator for 20kHz - LPC_SYSCON->PDRUNCFG &= ~PDRUNCFG_WDTOSC_PD; - LPC_SYSCON->WDTOSCCTRL = 14 | (1<<5); - - //Direct WDT to the CLKOUT pin (dp24), sample it back - DigitalIn din(dp24); - Timer timer; - - LPC_SYSCON->CLKOUTDIV = 1; - LPC_SYSCON->CLKOUTCLKSEL = 0x2; - LPC_SYSCON->CLKOUTUEN = 0; - LPC_SYSCON->CLKOUTUEN = CLKOUTUEN_ENA; - pin_function(dp24, 1); - - int count = 0; - timer.start(); - while (timer.read_ms() < 100) { - while (din.read() == 0); - while (din.read() == 1); - count++; - } - cycles_per_ms = (float)count / 100.0f; - - //Set old pin function back, disable CLKOUT - *reg = old_pinfun; - LPC_SYSCON->CLKOUTDIV = 0; -} - -static inline void restore(void) { - - WakeUpTimer->MR[WakeUpTimer_Match] = 0xFFFFFFFF; - - 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; - - WakeUpTimer->MR3 = MR3; - WakeUpTimer->PR = PR; - WakeUpTimer->TCR = TCR; -} - -#endif
diff -r 65c04a02ad45 -r 5147cde086fd Device/WakeUp_LPC11u24.cpp --- a/Device/WakeUp_LPC11u24.cpp Tue Jul 04 07:59:06 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/** -Due to lack of another option for the LPC11u24 the watchdog timer is used as wakeup source. -Since if the reset on watchdog event bit is set, I cannot remove it again, this means if you also got watchdog code running -the most likely result is that it just resets your board. -**/ - - -#ifdef TARGET_LPC11U24 - -#include "WakeUp.h" - -Callback<void()> WakeUp::callback; -float WakeUp::cycles_per_ms = 5.0; - -void WakeUp::set_ms(uint32_t ms) -{ - if (ms != 0) { - LPC_SYSCON->SYSAHBCLKCTRL |= 0x8000; - LPC_SYSCON->PDRUNCFG &= ~(1<<6); - LPC_SYSCON->PDSLEEPCFG &= ~(1<<6); - LPC_SYSCON->STARTERP1 |= 1<<12; - - //Set oscillator for 20kHz = 5kHz after divide by 4 in WDT - LPC_SYSCON->WDTOSCCTRL = 14 | (1<<5); - - LPC_WWDT->MOD = 1; //Enable WDT - LPC_WWDT->TC = (uint32_t)((float)ms * cycles_per_ms); - LPC_WWDT->CLKSEL = 1; //WDTOSC - LPC_WWDT->WARNINT = 0; - - NVIC_SetVector(WDT_IRQn, (uint32_t)WakeUp::irq_handler); - - //Feeeeeed me - LPC_WWDT->FEED = 0xAA; - LPC_WWDT->FEED = 0x55; - - NVIC_EnableIRQ(WDT_IRQn); - } else - NVIC_DisableIRQ(WDT_IRQn); - -} - -void WakeUp::irq_handler(void) -{ - LPC_WWDT->MOD = 1<<3; - callback.call(); -} - -void WakeUp::calibrate(void) -{ - cycles_per_ms = 5.0; - set_ms(1100); - wait_ms(10); //Give time to sync - uint32_t count1 = LPC_WWDT->TV; - wait_ms(100); - uint32_t count2 = LPC_WWDT->TV; - set_ms(0); - count1 = count1 - count2; - - cycles_per_ms = count1 / 100.0; -} - -#endif
diff -r 65c04a02ad45 -r 5147cde086fd Device/WakeUp_LPC812.cpp --- a/Device/WakeUp_LPC812.cpp Tue Jul 04 07:59:06 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -#ifdef TARGET_LPC812 - -#include "WakeUp.h" - -Callback<void()> WakeUp::callback; -float WakeUp::cycles_per_ms = 10.0; - -void WakeUp::set_ms(uint32_t ms) -{ - //Enable clock to register interface: - LPC_SYSCON->SYSAHBCLKCTRL |= 1<<9; - - //Clear the counter: - LPC_WKT->CTRL |= 1<<2; - if (ms != 0) { - //Enable clock to register interface: - LPC_SYSCON->SYSAHBCLKCTRL |= 1<<9; - - //Set 10kHz timer as source, and just to be sure clear status bit - LPC_WKT->CTRL = 3; - - //Enable the 10kHz timer - LPC_PMU->DPDCTRL |= (1<<2) | (1<<3); - - //Set interrupts - NVIC_SetVector(WKT_IRQn, (uint32_t)WakeUp::irq_handler); - NVIC_EnableIRQ(WKT_IRQn); - - //Load the timer - LPC_WKT->COUNT = (uint32_t)((float)ms * cycles_per_ms); - - } else { - //Disable clock to register interface: - LPC_SYSCON->SYSAHBCLKCTRL &= ~(1<<9); - - //Disable the 10kHz timer - LPC_PMU->DPDCTRL &= ~((1<<2) | (1<<3)); - } -} - -void WakeUp::irq_handler(void) -{ - //Clear status - LPC_WKT->CTRL |= 2; - - //Disable clock to register interface: - LPC_SYSCON->SYSAHBCLKCTRL &= ~(1<<9); - - //Disable the 10kHz timer - LPC_PMU->DPDCTRL &= ~((1<<2) | (1<<3)); - - callback.call(); -} - -void WakeUp::calibrate(void) -{ - cycles_per_ms = 10.0; - set_ms(1100); - wait_ms(100); - - uint32_t prevread = LPC_WKT->COUNT; - uint32_t read = LPC_WKT->COUNT; - while( read != prevread) { - prevread = read; - read = LPC_WKT->COUNT; - } - - uint32_t ticks = 11000 - read; - - cycles_per_ms = ticks / 100.0; - set_ms(0); -} - -#endif
diff -r 65c04a02ad45 -r 5147cde086fd main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Nov 24 00:04:03 2017 +0000 @@ -0,0 +1,29 @@ + +// Depending on the LED connections either the LED is off the 2 seconds +// the target spends in deepsleep(), and on for the other second. Or it is inverted + +#include "mbed.h" +#include "WakeUp.h" + +DigitalOut myled(LED1); + +int main() { + //The low-power oscillator can be quite inaccurate on some targets + //this function calibrates it against the main clock + WakeUp::calibrate(); + + while(1) { + //Set LED to zero + myled = 0; + + //Set wakeup time for 2 seconds + WakeUp::set_ms(2000); + + //Enter deepsleep, the program won't go beyond this point until it is woken up + sleep(); + + //Set LED for 1 second to one + myled = 1; + wait(1); + } +} \ No newline at end of file
diff -r 65c04a02ad45 -r 5147cde086fd mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Fri Nov 24 00:04:03 2017 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/235179ab3f27 \ No newline at end of file