LPC1756 PowerDown Issue/Questions

robert1356 wrote on Thursday, September 27, 2012:

I know about the master’s paper with power mode covering the EFM parts.  However, my needs are not as complex and I’ve attempted to implement what I THINK I need, but I’m having some problems.

First off:
Processor: LPC1756
Compiler: LPCXpresso/CodeRed
FreeRTOS version: 6.0.0

Most of the time, I just go into CLKPWR_Sleep() mode in the vApplicationIdleHook().  This works perfectly.  However, there are times when I want to go to sleep for a LONG time (could be hours or days) and will be awakened by an external device activating one of two interrupts:

Device 1: EINT0
Device 2: GPIO/EINT3 (a GPIO pin configured for interrupt)

I’m currently testing the situation with Device 2 only, i.e. Device 1 is never generating an interrupt.

In my vApplicationIdleHook(), I have a test to see if I need to go into the extra low power mode, CLKPWR_PowerDown();
If I do go into low power mode, I understand that all the task timers and such are suspended, but I don’t really care - I have no need to keep any level of “accurate” time while I’m suspended, there is nothing in MY code that needs to be serviced periodically.  My code only needs to be able to wakeup when one of the two interrupts are activated.  At that point, the tasks can pick up where they left off and continue processing.

The problem I’m having is that when the processor wakes up, it appears to be resetting after the vApplicationIdleHook() returns. I see all of my initialization strings on my UART debug console, these are NOT generated by the debug initialization seen below, they are part of my main() function

I know the processor is waking up because I see the DEBUG string, right before the xTaskResumeAll(), on my debug console.  I am careful to disconnect the hardware debugger before testing since the debugger will disable the EINT IRQs.  The Debug output functions are direct calls to the UART, they are not messages to another task.

So the question is, while my solution doesn’t keep track of time over the long powerdown mode, is there anything technically wrong with it that should/would cause the FreeRTOS to fail?

void EINT3_IRQHandler(void)
{
    mlsDebugGPIO2Clear();

    if(GPIO_GetIntStatus(PINSEL_PORT_2, PINSEL_PIN_8, 1)){
        GPIO_ClearInt(PINSEL_PORT_2, (1<<PINSEL_PIN_8));    // clear the interrupt flag
    }

    mlsDebugGPIO2Set();
}

void vApplicationIdleHook()
{

   if(doPowerDownMode)
   {
        vTaskSuspendAll();      // suspend the scheduler (does NOT disable the SysTick interrupt (???)

        LOGD(MOD_663IRQ, “WaitOnIRQ - just before PLL disconnect\n”);
        //-----------------------------------
        // code per errata for rev A silicon
        //
        // NOTE: once this is complete, cannot use the UART until it is re-initialized! i.e. NO DEBUG MESSAGES!
        //—
        LPC_SC->PLL0CON     &= ~(1<<1);                 /*  Disconnect the main PLL (PLL0) */
        LPC_SC->PLL0FEED    = 0xAA;                     /*  Feed */
        LPC_SC->PLL0FEED    = 0x55;                     /*  Feed */
        while ((LPC_SC->PLL0STAT & (1<<25)) != 0x00);   /*  Wait for main PLL (PLL0) to disconnect */
        LPC_SC->PLL0CON     &= ~(1<<0);                 /*  Turn off the main PLL (PLL0) */
        LPC_SC->PLL0FEED    = 0xAA;                     /*  Feed */
        LPC_SC->PLL0FEED    = 0x55;                     /*  Feed */
        while ((LPC_SC->PLL0STAT & (1<<24)) != 0x00);   /*  Wait for main PLL (PLL0) to shut down */
        //—

        //—
        // Enter lowest power mode possible - we cannot go into DeepPowerDown because cannot have the GPIO pins disconnect
        // At this stage, the ONLY thing that will wake up the processor is either the I2C_INT or the LPCD_INT
        CLKPWR_PowerDown();

        //—
        // Reinitialize the system immediately after wakeup
        // need to wait for the oscillators to achieve operational state (i.e. need to do all the clock setup stuff)
        SystemInit();  // init the PLL and Flash
        mlsDebugGPIOInit();  // config IO pins
        debug_frmwrk_init();  // config the debug UART

       LOGD(MOD_663IRQ, “WaitOnIRQ - just after SystemInit”);

        xTaskResumeAll();   // restart the scheduler
   }
   else
   {
       CLKPWR_Sleep();
   }
}

rtel wrote on Friday, September 28, 2012:

FreeRTOS version: 6.0.0

Why so old?

In my vApplicationIdleHook(), I have a test to see if I need to go into the extra low power mode, CLKPWR_PowerDown();
If I do go into low power mode, I understand that all the task timers and such are suspended, but I don’t really care - I have no need to keep any level of “accurate” time while I’m suspended, there is nothing in MY code that needs to be serviced periodically.  My code only needs to be able to wakeup when one of the two interrupts are activated.  At that point, the tasks can pick up where they left off and continue processing.

The problem I’m having is that when the processor wakes up, it appears to be resetting after the vApplicationIdleHook() returns. I see all of my initialization strings on my UART debug console, these are NOT generated by the debug initialization seen below, they are part of my main() function

I’m not sure of the chip specific behaviour, but looking at the data sheet and source code, it seems that calling CLKPWR_PowerDown() will turn the flash off, and you need to wait 100us approx before you can execute from flash again.  In the mean time, you can only execute from RAM.  I have no idea what the practicalities of that are, or what it means with regards to how you are supposed to wait this 100us, or how the IRQ handler is even supposed to execute if that is not in RAM, but it is the only thing that comes to mind at the moment.  Have you tried running the code that goes into and out of the power down mode from RAM, and checking the flash status bits before exiting the RAM function?

There is nothing in the manual about having to reset the SysTick registers, which is probably the only thing the kernel itself cares about.

if(doPowerDownMode)
   {
        vTaskSuspendAll();      // suspend the scheduler (does NOT disable the SysTick interrupt (???)

I don’t think suspending the scheduler here is going to make any difference to your code as it does not stop the tick interrupt - it only stops context switching.  Ticks that occurred while the scheduler was suspended will be processed (or maybe that is what you want actually, if you then want the PLL to come up to speed before the ticks get processed).

Regards.

robert1356 wrote on Monday, October 01, 2012:

Why so old?

I’m using 6.0.0 because that’s what was already in place and was working.  Once everything complete and stable, I may upgrade to the latest release.

I think the Flash is the issue - I had missed that.  I’m going to try the next higher sleep level first, which keeps the FLASH active.  If that works fine, then I’ll add code to move the handler and vector table into SRAM before going to sleep.

I don’t think suspending the scheduler here is going to make any difference to your code as it does not stop the tick interrupt

I wasn’t worried about the tick interrupt - it won’t wake up the processor.  I was concerned about switching tasks in the middle of preparing to sleep or coming out of sleep.  I want to make sure that this block of code is not interrupted.

rtel wrote on Monday, October 01, 2012:

The next version of FreeRTOS has some features you might like…it will be along soon.

Regards.

robert1356 wrote on Tuesday, October 02, 2012:

Ok, I’ve made some progress, but still a bit stumped…

I changed the PowerDown() call to DeepSleep() this is the next mode below Sleep(), it uses the interrupt to wake, but the FLASH is not put to sleep and the IRC continues to run.

I have two GPIO pins I’m using for debug. 

I was able to comment out the GPIOInit() and the debug_frmwrk_inti() because, in the DeepSleep() mode all of the state is maintained.  I only have to continue to reconfigure the PLL (call SystemInit());

I placed GPIO set immediately after the CLKPWR_DeepSleep(); call
I placed a GPIO clear immediately after the SystemInit() call;

There are two Debug statements that successfully generate output on my debug trace UART.  One is new and adds a check to see if the LPC_SC->PCON bit indicating success in entering DEEPSLEEP is set.  It IS set, meaning DEEPSLEEP was successfully entered.

I then set the GPIO again
call xTaskResumeAll()
clear the GPIO
return

IMMEDIATELY (less than a few uSec) upon return, the GPIO pin goes to 2V (instead of my Vcc of 3V) this indicates to me that a Reset has occurred and the GPIO is now in Input with pull-up to the core voltage (2V).

My startup code executes and generates the Debug Traces seen at the beginning of the program.

Ok, here’s the interesting part…
If I put an infinite loop after the xTaskResumeAll(), BEFORE returning from the idle hook and have this loop just toggle the GPIO pin.  I no longer see a reset, I DO see the GPIO pin toggling indefinitely and I DO see the missing pulses, indicating a context switch, which is confirmed by the fact that my code is generating Debug traces to the UART from another task.

Any ideas on what I should look for/ look at? Why might the code be reseting as soon as the IdleHook returns.

BTW, I have disabled the WDT - I’m not using it right now.

rtel wrote on Tuesday, October 02, 2012:

In a word, “no”, I don’t know.

If you just call WFI, without going into a mode that stops the PLL, does it make any difference?

Are you sure it is resetting when the idle hook exits, and not when it has gone through one loop of the idle task and re-entered the idle hook (and therefore crashing the next time you sleep)?

It is very unusual for a Cortex-M to reset.  You would normally expect the CPU to go into a fault handler, such as the hard fault handler.  It not be resetting, but just corrupting the program counter and somehow jumping to the beginning of you program.  Do you have a fault handler defined?  If so, is it sitting in a loop so it can’t exit?

Regards.

robert1356 wrote on Tuesday, October 02, 2012:

The ApplicationIdleHook normally calls Sleep(), the lowest low power mode, which will wake up on the next IdleTick.  This works fine.  No problems with it.

I’ll take a closer look at your other questions.  I think I know the answers, but I want to be 100% sure.

robert1356 wrote on Thursday, October 11, 2012:

I wanted to follow up on the resolution here.  Richard, thank you for the assistance and pointing me in the right direction. It actually did turn out to be resetting on the next time Sleep was called.  This was NOT related to FreeRTOS and once I figured out my work around, FreeRTOS handles this just fine. 

Actually there were two issues:
1., the Sleep() call provided by NXP does not clear the DEEPSLEEP bit in the Cortex-M3 so if you call a sleep mode that does use this bit, then later call Sleep() you’ll end up in DeepSleep instead of Sleep;
2., there is some, yet to be fully understood, issue around the BOGD.  Again, referring to the NXP provided calls (CMSIS 2.0) the DeepSleep() and PowerDown() calls DISABLE BOGD, the Sleep() call ENABLES BOGD.  If I called the DeepSleep() and then followed that up with a call to Sleep(), the processor would reset as soon as the BOGD was ENABLED, BEFORE WFI was even reached, so the reset was triggered in the Sleep() call, but not actually the WFI itself. 

I’m still trying to understand this BOGD issue, but as long as I keep it disabled, everything works fine.