Merge pull request #494 from ADVANSEE/cc2538-lpm-fixes

cc2538: lpm: Fix several issues
This commit is contained in:
George Oikonomou 2013-12-05 15:27:28 -08:00
commit 79e6514c80
4 changed files with 48 additions and 15 deletions

View file

@ -83,10 +83,10 @@ notify(uint8_t mask, uint8_t port)
void
gpio_port_a_isr()
{
ENERGEST_ON(ENERGEST_TYPE_IRQ);
lpm_exit();
ENERGEST_ON(ENERGEST_TYPE_IRQ);
notify(REG(GPIO_A_BASE | GPIO_MIS), GPIO_A_NUM);
GPIO_CLEAR_INTERRUPT(GPIO_A_BASE, 0xFF);
@ -99,10 +99,10 @@ gpio_port_a_isr()
void
gpio_port_b_isr()
{
ENERGEST_ON(ENERGEST_TYPE_IRQ);
lpm_exit();
ENERGEST_ON(ENERGEST_TYPE_IRQ);
notify(REG(GPIO_B_BASE | GPIO_MIS), GPIO_B_NUM);
GPIO_CLEAR_INTERRUPT(GPIO_B_BASE, 0xFF);
@ -115,10 +115,10 @@ gpio_port_b_isr()
void
gpio_port_c_isr()
{
ENERGEST_ON(ENERGEST_TYPE_IRQ);
lpm_exit();
ENERGEST_ON(ENERGEST_TYPE_IRQ);
notify(REG(GPIO_C_BASE | GPIO_MIS), GPIO_C_NUM);
GPIO_CLEAR_INTERRUPT(GPIO_C_BASE, 0xFF);
@ -131,10 +131,10 @@ gpio_port_c_isr()
void
gpio_port_d_isr()
{
ENERGEST_ON(ENERGEST_TYPE_IRQ);
lpm_exit();
ENERGEST_ON(ENERGEST_TYPE_IRQ);
notify(REG(GPIO_D_BASE | GPIO_MIS), GPIO_D_NUM);
GPIO_CLEAR_INTERRUPT(GPIO_D_BASE, 0xFF);

View file

@ -158,16 +158,28 @@ enter_pm0(void)
static void
select_32_mhz_xosc(void)
{
/*First, make sure there is no ongoing clock source change */
while((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SOURCE_CHANGE) != 0);
/* Turn on the 32 MHz XOSC and source the system clock on it. */
REG(SYS_CTRL_CLOCK_CTRL) &= ~SYS_CTRL_CLOCK_CTRL_OSC;
/* Wait for the switch to take place */
while((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_OSC) != 0);
/* Power down the unused oscillator. */
REG(SYS_CTRL_CLOCK_CTRL) |= SYS_CTRL_CLOCK_CTRL_OSC_PD;
}
/*---------------------------------------------------------------------------*/
static void
select_16_mhz_rcosc(void)
{
/*
* Power up both oscillators in order to speed up the transition to the 32-MHz
* XOSC after wake up.
*/
REG(SYS_CTRL_CLOCK_CTRL) &= ~SYS_CTRL_CLOCK_CTRL_OSC_PD;
/*First, make sure there is no ongoing clock source change */
while((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SOURCE_CHANGE) != 0);
@ -187,6 +199,16 @@ lpm_exit()
return;
}
/*
* When returning from PM1/2, the sleep timer value (used by RTIMER_NOW()) is
* not up-to-date until a positive edge on the 32-kHz clock has been detected
* after the system clock restarted. To ensure an updated value is read, wait
* for a positive transition on the 32-kHz clock by polling the
* SYS_CTRL_CLOCK_STA.SYNC_32K bit, before reading the sleep timer value.
*/
while(REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SYNC_32K);
while(!(REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SYNC_32K));
LPM_STATS_ADD(REG(SYS_CTRL_PMCTL) & SYS_CTRL_PMCTL_PM3,
RTIMER_NOW() - sleep_enter_time);
@ -301,6 +323,11 @@ lpm_enter()
select_32_mhz_xosc();
REG(SYS_CTRL_PMCTL) = SYS_CTRL_PMCTL_PM0;
/* Remember IRQ energest for next pass */
ENERGEST_IRQ_SAVE(irq_energest);
ENERGEST_ON(ENERGEST_TYPE_CPU);
ENERGEST_OFF(ENERGEST_TYPE_LPM);
} else {
/* All clear. Assert WFI and drop to PM1/2. This is now un-interruptible */
assert_wfi();

View file

@ -150,6 +150,12 @@ void lpm_enter(void);
* interrupt. This may lead to other parts of the code trying to use the RF,
* so we need to switch the clock source \e before said code gets executed.
*
* This function also makes sure that the sleep timer value is up-to-date
* following wake-up from PM1/2 so that RTIMER_NOW() works.
*
* \note This function should be called at the very beginning of ISRs waking up
* the SoC in order to restore all clocks and timers.
*
* \sa lpm_enter(), rtimer_isr()
*/
void lpm_exit(void);

View file

@ -136,13 +136,6 @@ rtimer_arch_now()
void
rtimer_isr()
{
ENERGEST_ON(ENERGEST_TYPE_IRQ);
next_trigger = 0;
nvic_interrupt_unpend(NVIC_INT_SM_TIMER);
nvic_interrupt_disable(NVIC_INT_SM_TIMER);
/*
* If we were in PM1+, call the wake-up sequence first. This will make sure
* that the 32MHz OSC is selected as the clock source. We need to do this
@ -150,6 +143,13 @@ rtimer_isr()
*/
lpm_exit();
ENERGEST_ON(ENERGEST_TYPE_IRQ);
next_trigger = 0;
nvic_interrupt_unpend(NVIC_INT_SM_TIMER);
nvic_interrupt_disable(NVIC_INT_SM_TIMER);
rtimer_run_next();
ENERGEST_OFF(ENERGEST_TYPE_IRQ);