This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RE: F280x HALT mode

Hi Champs,

A customer is having trouble getting datasheet performance for current consumption in HALT mode of the F2808. From what they can tell, all they need to do is configure the low power mode registers and execute the HALT instruction, and they should be getting HALT mode current consumption in the uA. But, when they do this, the processor seems to still be consuming 10's of mA's of current. Is there something they're missing? Is there any documentation on entering and exiting low power modes for the 280x devices?

Thanks,

Randy

 

 

  • Randy,

       There are primarily 4 things to take care fo to put the device in HALT:

    Make sure EALLOW is valid.

    Flash is powered down

    Write a value of 2 in LPMCR0 register

    Execute the IDLE instruction.

     If you do the above correctly, the device will definitely go into HALT.

    See attached code. If you have a problem with this, please send me an email offline.

    Hareesh.

  • Randy,

    If customer seees few 10's of mA, device is definitely not in HALT mode. Have them try the code I had sent earlier. one more thing: To see the number quoted in the datasheet for the analog rail, they need to explicitly turn off the clock to the ADC module.

  • Hi Champs,
     
    Is there anything other than the GPIO selected in the GPIOLPMSEL register that can wake the CPU out of HALT mode? I'm watching code execution go right over the instruction without halting, and I know this because I've instrumented the sleep enable pin that I'm toggling before I enter halt and after I exit halt (It only stays active for 250ns, instead of forever!). I've also done it within the debugger with breakpoints after the halt instruction. In an even stranger turn of events, sometimes the code runs right past the halt instruction (at least past 8 NOP's to a GPIO wiggle) and then halts the clock, locking the processor with the GPIO in the none sleep-active state.
     
    Is there something I'm missing? I've verified that SysCtrlRegs.LPMCR0.bit.LPM = 2U and that the right GPIO is set to wake from HALT, and that the WAKE GPIO is solid in the non-waking state throughout the event. Any ideas?  See below code snippets which are executing in ram. Note, SM_sleep_SWI is a posted software interrupt using DSP/BIOS.
     
    // in ram because the flash will be powered off
    #pragma CODE_SECTION(SM_sleep_SWI, ".text_fast");
    void SM_sleep_SWI(void)
    {
            if (!SysCtrlRegs.PLLSTS.bit.MCLKSTS)            // make sure the PLL isn't in standby
            {
                CAN_control.flags.b.attemptSleep = FALSE;   // so we don't go right back to sleep
                DIO_clear(DIO_LED);                         // turn the LED off so we don't leave that power draw on.
    
                interruptContext = HWI_disable();                                       // disable interrupts so we don't get a vector into flash or something trying to use the ADC
    
                EALLOW;
                SysCtrlRegs.LPMCR0.bit.LPM = 2U;            // set HALT as low power mode
                SysCtrlRegs.WDCR = 0x006FU;                 // disable watchdogs
                SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0U;     // turn off clocks to all PWMs
    
                GpioIntRegs.GPIOLPMSEL.bit.GPIO14 = 1U;     // set wake input for low power mode wakeup
    
                DIO_setMux(DIO_INA209_CONVERT,0U);          // Un mux from PWM peripheral, back to input
                DIO_setMux(DIO_BMB_SYNC,0U);                // Un mux from PWM peripheral, back to input
                DIO_setMux(DIO_PUMP_ON,0U);                 // Un mux from PWM peripheral, back to input
    
                DIO_input(DIO_ED_WAKEUP);                   // don't treat ED_wakeup as an output during sleep
                DIO_output(DIO_HUMIDITY_DATA);              // humidity data needs to be an output so we can set it low during sleep
                EDIS;
    
                // FIX: humidity routine could be hosed at this point if in the middle of a transmission
                DIO_clear(DIO_HUMIDITY_DATA);               // humidity data needs to be low during sleep
                DIO_clear(DIO_HUMIDITY_CLK);                // humidity clock needs to be low during sleep
                DIO_set(DIO_EEPROM_CS);                     // low (active) to reduce quiescient during sleep
    
                DELAY_US(1000U);                            // wait 1ms for things to quiet down and for BMB can messages to get out.
    
                // Cancel all remaining messages
                ECanaRegs.CANTRR.all = 0xFFFFFFFFLU;
                ECanbRegs.CANTRR.all = 0xFFFFFFFFLU;
                while((ECanaRegs.CANTRS.all !=0U) || (ECanbRegs.CANTRS.all !=0U))
                {
                    // wait until cancelled.
                }
    
                EALLOW;
                ECanaRegs.CANMC.bit.PDR = 1U; // Put peripheral to sleep
                ECanbRegs.CANMC.bit.PDR = 1U; // Put peripheral to sleep
                EDIS;
                while ((ECanaRegs.CANES.bit.PDA != 1U) || (ECanbRegs.CANES.bit.PDA != 1U))
                {
                    // Loop here if PDA != 1
                }
    
                EALLOW;
                DIO_setMux(DIO_CANA_TX,0U);                 // steal BMS can transmit pin away from peripheral so TX goes low.
                DIO_setMux(DIO_CANB_TX,0U);                 // steal BMB can transmit pin away from peripheral so TX goes low.
                EDIS;
    
                DELAY_US(30U);                              // wait 30us for external transciever to do it's thing so it doesn't wake us back up.
    
                ISO_pause(5000U);                           // turn the iso test resistors off for 5 seconds before going to sleep
                ADC_powerDown();
                smFlashPowerDown();
    
                DIO_set(DIO_SLEEP_EN);                      // set sleep enable to CPLD
                asm(" NOP");
                asm(" NOP");
                asm(" NOP");
                asm(" NOP");
                asm(" NOP");
                asm(" NOP");
                asm(" NOP");
                asm(" NOP");
                asm(" IDLE");                               /* Force device into HALT  */
                asm(" NOP");
                asm(" NOP");
                asm(" NOP");
                asm(" NOP");
                asm(" NOP");
                asm(" NOP");
                asm(" NOP");
                asm(" NOP");
    
                /***********************SLEEP**************************************/
    
                // wake back up
                DIO_clear(DIO_SLEEP_EN);                    /// clear sleep enable to CPLD
                EALLOW;
                GpioIntRegs.GPIOLPMSEL.bit.GPIO14 = 0U;     // set wake input for low power mode wakeup
                SysCtrlRegs.LPMCR0.bit.LPM = 0U;            // set IDLE as low power mode
                EDIS;
    
                smFlashPowerUp();
                smWakeUp();
                HWI_restore(interruptContext);
            }
    }
    // in ram because the flash will be powered off
    #pragma CODE_SECTION(smFlashPowerDown, ".text_fast");
    void smFlashPowerDown(void)
    {
        EALLOW;
        FlashRegs.FPWR.bit.PWR = FLASH_SLEEP;  // Put the Flash to sleep
        EDIS;
        asm(" RPT #7 || NOP");
    }
    
    #pragma CODE_SECTION(smFlashPowerUp, ".text_fast");
    void smFlashPowerUp(void)
    {
        EALLOW;
        FlashRegs.FPWR.bit.PWR = FLASH_ACTIVE;  // Wake the Flash up
        EDIS;
        asm(" RPT #7 || NOP");
    }
    
    #pragma CODE_SECTION(ADC_powerDown, ".text_fast");
    void ADC_powerDown(void)
    {
        struct ADC_REGS AdcShadow;                  // shadow register to optimize initialization
    
        AdcShadow.ADCTRL3.all = AdcRegs.ADCTRL3.all;
        AdcShadow.ADCTRL3.bit.ADCBGRFDN = 0U;         // power down bandgap and reference circuitry
        AdcShadow.ADCTRL3.bit.ADCPWDN = 0U;           // power down analog circuitry inside the core
        AdcRegs.ADCTRL3.all = AdcShadow.ADCTRL3.all;
    
        AdcShadow.ADCTRL2.all = AdcRegs.ADCTRL2.all;
        AdcShadow.ADCTRL2.bit.RST_SEQ2 = 1U;        // reset SEQ2, in case we were mid conversion
        AdcShadow.ADCTRL2.bit.RST_SEQ1 = 1U;        // reset SEQ1, in case we were mid conversion
        AdcRegs.ADCTRL2.all = AdcShadow.ADCTRL2.all;
    
        EALLOW;
        SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 0U;      // disable ADC peripheral clock // called out on datasheet, I don't know why.
        EDIS;
    }
  • Randy,

       You have posted this in an old thread. Does this mean the original problem is yet unsolved? Did you try the code i attached in my earlier post? I am interested in isolating the issue between a code issue as opposed to a hardware issue. If a GPIO pin is configured for wakeup, nothing else should wake the part, unless of course there is noise on the GPIO pin itself.

  • Hi Hareesh,

    The original problem of being able to go into HALT mode successfully is solved, but now the customer is seeing the following problem:

    "I'm watching code execution go right over the instruction without halting, and I know this because I've instrumented the sleep enable pin that I'm toggling before I enter halt and after I exit halt (It only stays active for 250ns, instead of forever!). I've also done it within the debugger with breakpoints after the halt instruction. In an even stranger turn of events, sometimes the code runs right past the halt instruction (at least past 8 nops to a GPIO wiggle) and then halts the clock, locking the processor with the GPIO in the none sleep-active state."

     

    Is there some way we can explain this behavior, or maybe have him try something else to avoid this scenario?

     

    Thanks,

    -Randy

     

  • Hi Hareesh,

    To get everything to work, the customer had to do the following in their code:
     
                lastIER = IER;                              // save existing interrupt enable
                IER &= 0U;                                  // clear existing interrupt enables
                IER |= M_INT14;                             // enable INT14, required for wake up
                IFR &= ~M_INT14;                            // remove INT14 flag bit so we can go to sleep.
     
                DIO_set(DIO_SLEEP_EN);                      // set sleep enable to CPLD
     
                asm(" IDLE");                               /* Force device into HALT  */
     
                /***********************SLEEP**************************************/
     
                // wake back up
                smFlashPowerUp();
     
                DIO_clear(DIO_SLEEP_EN);                    /// clear sleep enable to CPLD
                EALLOW;
                GpioIntRegs.GPIOLPMSEL.bit.GPIO14 = 0U;     // set wake input for low power mode wakeup
                SysCtrlRegs.LPMCR0.bit.LPM = 0U;            // set IDLE as low power mode
                EDIS;
                IER |= lastIER;
     
    They needed to clear the IER so no pending interrupts in IFR could get to the CPU (which according to the assembly code manual for IDLE is necessary for the IDLE instruction to keep the part asleep, which contradicts the System Control and Interrupts Guide description of Halt mode).  They then needed to enable IER for INT14 (we are not sure why) but clear any pending interrupt in IFR for INT14 (again not sure why).  Do you think the customer had to do all this because they're using DSP/BIOS?
     
    We might want to consider documenting this situation somewhere, because the customer has spent almost a man-week troubleshooting this.
     
    Thanks,
    -Randy