161 lines
4.3 KiB
C
161 lines
4.3 KiB
C
|
/***************************************************************
|
||
|
*
|
||
|
* OpenBeacon.org - LPC13xx Power Management Functions
|
||
|
*
|
||
|
* Copyright 2011 Milosch Meriac <meriac@openbeacon.de>
|
||
|
*
|
||
|
***************************************************************
|
||
|
|
||
|
This program is free software; you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation; version 2.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License along
|
||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
|
||
|
*/
|
||
|
#include <openbeacon.h>
|
||
|
#include "pmu.h"
|
||
|
#include "spi.h"
|
||
|
#include "nRF_API.h"
|
||
|
#include "nRF_CMD.h"
|
||
|
#include "openbeacon-proto.h"
|
||
|
|
||
|
static uint32_t g_sysahbclkctrl;
|
||
|
|
||
|
#define MAINCLKSEL_IRC 0
|
||
|
#define MAINCLKSEL_SYSPLL_IN 1
|
||
|
#define MAINCLKSEL_WDT 2
|
||
|
#define MAINCLKSEL_SYSPLL_OUT 3
|
||
|
|
||
|
#define SYSTEM_TMR16B0_PRESCALER 10000
|
||
|
|
||
|
void
|
||
|
WAKEUP_IRQHandlerPIO0_8 (void)
|
||
|
{
|
||
|
if(LPC_SYSCON->MAINCLKSEL != MAINCLKSEL_SYSPLL_OUT)
|
||
|
{
|
||
|
/* switch to IRC oscillator */
|
||
|
LPC_SYSCON->MAINCLKSEL = MAINCLKSEL_SYSPLL_OUT;
|
||
|
/* push clock change */
|
||
|
LPC_SYSCON->MAINCLKUEN = 0;
|
||
|
LPC_SYSCON->MAINCLKUEN = 1;
|
||
|
/* wait for clock change to be finished */
|
||
|
while (!(LPC_SYSCON->MAINCLKUEN & 1));
|
||
|
/* power down watchdog oscillator */
|
||
|
LPC_SYSCON->PDRUNCFG |= WDTOSC_PD;
|
||
|
}
|
||
|
|
||
|
/* re-trigger match output */
|
||
|
LPC_TMR16B0->EMR &= ~1;
|
||
|
/* reset wakeup logic */
|
||
|
LPC_SYSCON->STARTRSRP0CLR = STARTxPRP0_PIO0_8;
|
||
|
/* disable deep sleep */
|
||
|
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
|
||
|
|
||
|
/* enable previous clock settings */
|
||
|
LPC_SYSCON->SYSAHBCLKCTRL = g_sysahbclkctrl;
|
||
|
/* select MISO function for PIO0_8 */
|
||
|
LPC_IOCON->PIO0_8 = 1;
|
||
|
|
||
|
/* vodoo -NOP */
|
||
|
__NOP ();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
pmu_wait_ms (uint16_t ms)
|
||
|
{
|
||
|
LPC_IOCON->PIO0_8 = 2;
|
||
|
|
||
|
g_sysahbclkctrl = LPC_SYSCON->SYSAHBCLKCTRL;
|
||
|
LPC_SYSCON->SYSAHBCLKCTRL |= EN_CT16B0;
|
||
|
|
||
|
/* prepare 16B0 timer */
|
||
|
LPC_TMR16B0->TCR = 2;
|
||
|
LPC_TMR16B0->PR = SYSTEM_CORE_CLOCK/SYSTEM_TMR16B0_PRESCALER;
|
||
|
LPC_TMR16B0->EMR = 2 << 4;
|
||
|
LPC_TMR16B0->MR0 = ms*10;
|
||
|
/* enable IRQ, reset and timer stop in MR0 match */
|
||
|
LPC_TMR16B0->MCR = 7;
|
||
|
|
||
|
/* prepare sleep */
|
||
|
LPC_PMU->PCON = (1 << 11) | (1 << 8);
|
||
|
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
|
||
|
|
||
|
/* start timer */
|
||
|
LPC_TMR16B0->TCR = 1;
|
||
|
/* sleep */
|
||
|
__WFI ();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
pmu_sleep_ms (uint16_t ms)
|
||
|
{
|
||
|
if (ms < 10)
|
||
|
ms = 10;
|
||
|
|
||
|
/* select CT16B0_MAT0 function for PIO0_8 */
|
||
|
LPC_IOCON->PIO0_8 = 2;
|
||
|
|
||
|
/* Turn off all other peripheral dividers FIXME save settings */
|
||
|
/* LPC_SYSCON->SSPCLKDIV = 0;
|
||
|
LPC_SYSCON->USBCLKDIV = 0;
|
||
|
LPC_SYSCON->WDTCLKDIV = 0;
|
||
|
LPC_SYSCON->SYSTICKCLKDIV = 0;*/
|
||
|
|
||
|
g_sysahbclkctrl = LPC_SYSCON->SYSAHBCLKCTRL;
|
||
|
LPC_SYSCON->SYSAHBCLKCTRL = EN_RAM | EN_GPIO | EN_CT16B0 | EN_FLASHARRAY | EN_IOCON;
|
||
|
|
||
|
/* prepare 16B0 timer */
|
||
|
LPC_TMR16B0->TCR = 2;
|
||
|
LPC_TMR16B0->PR = 8;
|
||
|
LPC_TMR16B0->EMR = 2 << 4;
|
||
|
LPC_TMR16B0->MR0 = ms - 7;
|
||
|
/* enable IRQ, reset and timer stop in MR0 match */
|
||
|
LPC_TMR16B0->MCR = 7;
|
||
|
|
||
|
/* prepare sleep */
|
||
|
LPC_PMU->PCON = (1 << 11) | (1 << 8);
|
||
|
SCB->SCR = SCB_SCR_SLEEPDEEP_Msk;
|
||
|
|
||
|
/* power up watchdog */
|
||
|
LPC_SYSCON->PDRUNCFG &= ~WDTOSC_PD;
|
||
|
/* save current power settings, power WDT on wake */
|
||
|
LPC_SYSCON->PDAWAKECFG = LPC_SYSCON->PDRUNCFG;
|
||
|
/* power watchdog oscillator in deep sleep mode */
|
||
|
LPC_SYSCON->PDSLEEPCFG = (~WDTOSC_PD) & 0xFFF;
|
||
|
/* switch MAINCLKSEL to Watchdog Oscillator */
|
||
|
LPC_SYSCON->MAINCLKSEL = MAINCLKSEL_WDT;
|
||
|
/* push clock change */
|
||
|
LPC_SYSCON->MAINCLKUEN = 0;
|
||
|
LPC_SYSCON->MAINCLKUEN = 1;
|
||
|
/* wait for clock change to be executed */
|
||
|
while (!(LPC_SYSCON->MAINCLKUEN & 1));
|
||
|
|
||
|
/* start timer */
|
||
|
LPC_TMR16B0->TCR = 1;
|
||
|
/* sleep */
|
||
|
__WFI ();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
pmu_init (void)
|
||
|
{
|
||
|
/* reset 16B0 timer */
|
||
|
LPC_TMR16B0->TCR = 2;
|
||
|
/* Turn on the watchdog oscillator */
|
||
|
LPC_SYSCON->WDTOSCCTRL = 0x3F;
|
||
|
/* enable IRQ routine for PIO0_8 */
|
||
|
NVIC_EnableIRQ (WAKEUP_PIO0_8_IRQn);
|
||
|
/* initialize start logic for PIO0_8 */
|
||
|
LPC_SYSCON->STARTAPRP0 |= STARTxPRP0_PIO0_8;
|
||
|
LPC_SYSCON->STARTRSRP0CLR = STARTxPRP0_PIO0_8;
|
||
|
LPC_SYSCON->STARTERP0 |= STARTxPRP0_PIO0_8;
|
||
|
}
|