Functions | Variables

xpal_power.c File Reference

Power Management Routines for the eXPal Prototype A. More...

#include "config.h"
#include <avr/io.h>
#include <stdio.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <util/delay.h>
#include "xpal_board.h"
#include "xpal_power.h"
#include "xpal_async32khz.h"
#include "keys.h"
#include "lh155.h"
#include "cb_list.h"
#include "xpal_extmem.h"
#include "adc.h"
#include "xpal_StatBar.h"
#include "xpal_bat.h"

Functions

void hl_pwr_InitBoard (void)
 Primary Hardware Init Function.
uint16_t hl_pwr_slow (void *p)
 Slow Timer Call.
uint16_t hl_pwr_fast (void *p)
 Fast Timer Call.
void hl_pwr_InitPwrMan (void)
 Init power management system.
void hl_pwr_3V3reg (hl_pwr_state_t state)
 3.3V reulator Control
void hl_pwr_5Vreg (hl_pwr_state_t state)
 5V reulator Control
void hl_pwr_LCDreg (hl_pwr_state_t state)
 LCD HV reulator Control.
uint8_t hl_pwr_EnterSleep (void)
 Try to switch system in the deepest allowed sleep mode.
void hl_RegisterPwrCb (cb_function_t fkt2call, void *PwrStAllowed)
 Register a call back function to request power down in higher SW layers.

Variables

volatile hl_pwr_state_t hl_pwr_state
 System power state (current setting).
volatile hl_pwr_state_t hl_pwr_info
 Power States,the system is allowed to use.
volatile uint16_t PowerOffTimer
 Second timer until power off.
cb_list_t cbListPowerFirst
 First element in power callback list.
volatile uint8_t WakeUpSource
 Bitmap variable to indicate the wake-up source.

Detailed Description

Power Management Routines for the eXPal Prototype A.

This module contains routines for the following functions:
Basic Concept for the power management

The application has to send the system in a power save state by calling hl_pwr_EnterSleep(); This function does return the wake-up source. Based on that the application can determine if there is something to do or if this function can be called again immediately.

The application can register a call back function to control the allowed sleep modes.

When HL_PWR_ALLOW_OFF is set, the system will turn into this state when the timer is down to zero and USB is not active. In this case the 3.3V and the other regulators will get switched off.

When returning from OFF state, the application is in charge to do a power-up with the 3.3V when required.

To save power, the controller will reduce speed and switch the 5V regulator off as well. 5V, full speed and VLcd are switched on from the power management module. Due to the speed reduction, the power consumption for the ramp-up phase is still reduced. The same is true for all activity caused by the 1s interrupt in power off state.

When in Power OFF state, the function hl_pwr_EnterSleep() will not return for the 1s timer. The watch will be maintained in the interrupt routine. The system will run at slow speed at battery voltage.

The timer can be set to zero by calling hl_pwr_OffNow(); This is used by the power off button for instence.

By calling hl_pwr_AppBusy(); the timer is set to HL_PWR_OFF_TIME again.


Function Documentation

void hl_pwr_3V3reg ( hl_pwr_state_t  state  ) 

3.3V reulator Control

Control the 3.3V regulator.

Switch the 3.3V reg. on or off

Parameters:
[in] desired state, HL_PWR_ON / HL_PWR_OFF

                                        {
        if (state == HL_PWR_OFF){
                /* power down 3.3 */
                HL_PWR_VCC33_PORT &= ~(_BV(HL_PWR_VCC33));
                hl_pwr_state &= ~HL_PWR_3V3_ACTIVE;     
        }else{
                /* power up 3.3 */
                HL_PWR_VCC33_PORT |= _BV(HL_PWR_VCC33); 
                hl_pwr_state |= HL_PWR_3V3_ACTIVE;      
        }
}

void hl_pwr_5Vreg ( hl_pwr_state_t  state  ) 

5V reulator Control

Control the 5V regulator.

Switch the 5V reg. on or off

Parameters:
[in] desired state, HL_PWR_ON / HL_PWR_OFF

                                       {
        if (state == HL_PWR_OFF){
                /* power down 3.3 */
                HL_PWR_VCC5_PORT &= ~(_BV(HL_PWR_VCC5));                
                hl_pwr_state &= ~HL_PWR_5V_ACTIVE;      
        }else{
                /* power up 3.3 */
                HL_PWR_VCC5_PORT |= _BV(HL_PWR_VCC5);   
                hl_pwr_state |= HL_PWR_5V_ACTIVE;       
        }
}

uint8_t hl_pwr_EnterSleep ( void   ) 

Try to switch system in the deepest allowed sleep mode.

Function to enter "PwrState". If a sleep power state is entered, the Control will stay within this function until wake-up

Returns:
wake-up source
Note:
This function must be called outside of an ISR, or special care must be taken to ensure the system wake-up, since inside of an ISR the global IRQ is disabled.

ZZZzzz...

                               {

        // *************************************************************************
        // Do OperatingSystem idle operations

        // Update battery display
        uint8_t BatState = hl_bat_GetBatStatus();
        if((BatState & HL_BAT_NEWSTAT) != 0){
                hl_stb_BattState(Empty + (BatState & HL_BAT_ST_MASK));
        }

        // *************************************************************************
        // Check what sleep mode is allowed
        uint16_t allowed_pwr_mode = 0xffff;

        // ask applications what's possible
        allowed_pwr_mode = callback_iterate_and_until0 (cbListPowerFirst);

/*      if(hl_pwr_state & HL_PWR_USB_ACTIVE){   
                // USB is active, stay in full on
                allowed_pwr_mode = HL_PWR_ALLOW_NOSAVE;
        }
*/
        // reset system power state for update below
        hl_pwr_state &= ~(HL_PWR_ST_RUNNING | HL_PWR_ST_IDLE | HL_PWR_ST_33SLEEP | HL_PWR_ST_SLEEP | HL_PWR_ST_OFF);

        // *************************************************************************
        // prepare for the individual sleep modes
        if ((allowed_pwr_mode & HL_PWR_ALLOW_OFF) && (PowerOffTimer == 0)){
                // All registered applications did allow power off
                // and the shut off timer is zero too

                // Display status symbol
                hl_stb_PwrState(SLEEPsymbol);

                // update power state
                hl_pwr_state |= HL_PWR_ST_OFF;

                // for off use pwr-save to allow wake up from async timer
                set_sleep_mode (SLEEP_MODE_PWR_SAVE);

                // switch power sources off
                hl_pwr_LCDreg(HL_PWR_OFF);
                hl_pwr_3V3reg(HL_PWR_OFF);

                // LCD Controller off
                HL_LCD_PowerOff();

                // enable wake up for power key
                hlRow3KeyWakeup();              

                // RAM interface disable and deselect RAM
                // ExtMemDisable();

                // stop fast system timer
                hl_asyn_StopSysTimer();

                // Stop ADC as well
                hl_adc_off();

                // reduce clock and switch 5V reg off
                clock_prescale_set( clock_div_16 );
                hl_pwr_5Vreg(HL_PWR_OFF);

        }else if (allowed_pwr_mode & HL_PWR_ALLOW_SLEEP){
        
                // Display status symbol
                hl_stb_PwrState(SLEEPsymbol);

                // All registered applications did allow sleep
                hl_pwr_state |= HL_PWR_ST_SLEEP;

                // for off use pwr-save to allow wake up from async timer
                set_sleep_mode (SLEEP_MODE_PWR_SAVE);

                // switch power sources off
                hl_pwr_3V3reg(HL_PWR_OFF);

                // enable wake up for power key
                hlAllKeyWakeup();

                // RAM interface disable and deselect RAM
                // ExtMemDisable();

                // stop fast system timer
                hl_asyn_StopSysTimer();

                // Stop ADC as well
                // ADC result will not be evaluated when SysTimer is off
                hl_adc_off();

        }else if (allowed_pwr_mode & HL_PWR_ALLOW_33SLEEP){
        
                // Display status symbol
                hl_stb_PwrState(SLEEPsymbol);

                // All registered applications did allow sleep
                hl_pwr_state |= HL_PWR_ST_33SLEEP;

                // for off use pwr-save to allow wake up from async timer
                set_sleep_mode (SLEEP_MODE_PWR_SAVE);

                // enable wake up for power key
                hlAllKeyWakeup();

                // RAM interface disable and deselect RAM
                // ExtMemDisable();

                // stop fast system timer
                hl_asyn_StopSysTimer();

                // Stop ADC as well
                // ADC result will not be evaluated when SysTimer is off
                hl_adc_off();

        }else if (allowed_pwr_mode & HL_PWR_ALLOW_IDLE){

                // Display status symbol
                hl_stb_PwrState(IDLEsymbol);

                // All registered applications did allow idle
                hl_pwr_state |= HL_PWR_ST_IDLE;

                // Only idle mode to react on all sources
                set_sleep_mode (SLEEP_MODE_IDLE);       
        }

        // *************************************************************************
        // enter sleep mode
        if (allowed_pwr_mode != 0){

                do{ // loop to stay in sleep for 1s timer in OFF mode

                        WakeUpSource = HL_PWR_WAKE_NO_SOURCE;

                        // Enter sleep mode
                        sleep_enable ();
                    sleep_cpu ();   
                        sleep_disable ();

                        // Wait for ISR to set wake source if not done yet
                        // while (WakeUpSource == HL_PWR_WAKE_NO_SOURCE);
                        // we expect the ISR to be completed when WakeUpSource is set

                }while((WakeUpSource & HL_PWR_WAKE_BY_1S_TMR) && (hl_pwr_state & HL_PWR_ST_OFF));

                // *************************************************************************
                // manage wake up

                // System clock speed up when start from off
                if(hl_pwr_state & HL_PWR_ST_OFF){

                        hl_pwr_5Vreg(HL_PWR_ON);
                        hl_pwr_LCDreg(HL_PWR_ON);
                        HL_LCD_PowerOn();

                        // wait for 5V to rise
                        //
                        // While the voltage is rising up to 5V, the system is still running with 
                        // reduced speed. Since the delay time calculation works for 14.7456MHz,
                        // the actual time had to be adjusted. In case of 1/16 of the original
                        // clock, the value of 70us caused a delay of ~1.2ms.
                        _delay_us (70); 

                        // Full speed ahead
                        clock_prescale_set( clock_div_1 );
                }

                // enable in case it was off or stay on
                // ExtMemEnable(); 

                // do sys timer start in case it's off
                // hl_asyn_StartSysTimer();

        }else{
                // System is required to stay ON, 
                // no sleep function called, 
                // return without wakeup

                // Display status symbol
                if(hl_pwr_state & HL_PWR_USB_ACTIVE){
                        hl_stb_PwrState(USBsymbol);
                }else{
                        hl_stb_PwrState(RUNsymbol);
                }

                WakeUpSource = HL_PWR_WAKE_NO_SOURCE;
                hl_pwr_state |= HL_PWR_ST_RUNNING;
        }
        return WakeUpSource;
}

uint16_t hl_pwr_fast ( void *  p  ) 

Fast Timer Call.

fast system timer call (20ms)

Do fast operations for power management:

  • Manage USB power detection
Todo:
Replace the USB polling by a pin change interrupt. This will also make sure, that the voltage can not drop below the limits for 14MHz.

                             {

        // disable 5V reg. if Vusb available
        if ( (HL_USB_PWREN_PIN & _BV(HL_USB_PWREN)) == 0){
                // device configured and active
            // Disable 5V reg.
            HL_PWR_VCC5_PORT &= ~(_BV(HL_PWR_VCC5));
                hl_pwr_state &= ~HL_PWR_5V_ACTIVE;
                hl_pwr_state |= HL_PWR_USB_ACTIVE;
        }else{
            // device not configured or in suspend
            // Enable 5V reg.
            HL_PWR_VCC5_PORT |= (_BV(HL_PWR_VCC5));             
                hl_pwr_state |= HL_PWR_5V_ACTIVE;
                hl_pwr_state &= ~HL_PWR_USB_ACTIVE;
        }
        return 0;
}

void hl_pwr_InitBoard ( void   ) 

Primary Hardware Init Function.

This function has to be called as the first action in main() It will ensure the correct setting of all processor IO lines and other board hardware. The function will only set everything in a defined, power saving state and not init any hardware unit to work.

                           {

        /*
                Initialize the ports to avoid floating signals and excessive power
                consumption.
                To be complete it is more obvious to access the ports directly here.
        */
        // Port A
        // can stay as is after reset

        // Port B
        PORTB= 0x80 | _BV(HL_SD_SS);  // USB_RESET inakt, sauberer Pegel für SD Treiber
        DDRB = 0x87; 

        // Port C
        DDRC = 0xFF;  // Addr.Augaenge
        PORTC= 0xC0;  // RAM Disable

        // Port D
        PORTD = 0xFF; // PullUp on for KeyLines

        // Port E
        PORTE = 0xFF; // PullUp on

        // Port F
        PORTF = 0x0F & ~_BV(PF0); // PullUp for unused AD Inputs

        // Port G
        DDRG = 0x07;
        PORTG = 0x07; // RD/WR disable

        // Port H
        PORTH = 0xFF; // PullUp on

        // Port J
        PORTJ = 0xFF; // PullUp on

        // Port K
        PORTK = 0xFF; // PullUp on

        // Port L
        DDRL = 0x07 | _BV(HL_EX232_FRCON) | _BV(HL_EX232_EN);

        // 5V ON, pull up at open pins
        PORTL = _BV(HL_PWR_VCC5) | _BV(PL3)|_BV(PL4)
          | 0*_BV(HL_EX232_FRCON) | 1*_BV(HL_EX232_EN);

        /* set power reduction registers */
        PRR0 = _BV(PRTWI) /* | _BV(PRTIM2)  | _BV(PRTIM0) */
                | _BV(PRTIM1) | _BV(PRSPI) | _BV(PRUSART0)
            | _BV(PRADC)
            ;
        PRR1 = _BV(PRTIM5) | _BV(PRTIM4) | _BV(PRTIM3)
                | _BV(PRUSART3) | _BV(PRUSART2) | _BV(PRUSART1)
            ;

}

void hl_pwr_InitPwrMan ( void   ) 

Init power management system.

Initialize

  • Variables
  • Register timer calls

                            {

        hl_pwr_state = HL_PWR_5V_ACTIVE | HL_PWR_ST_RUNNING;
        hl_pwr_info = 0; // Stay in full on
        PowerOffTimer = HL_PWR_OFF_TIME;

        hl_asyn_Register1sTimer( (&hl_pwr_slow), NULL);
        hl_asyn_RegisterFastTimer( (&hl_pwr_fast), NULL);
}

void hl_pwr_LCDreg ( hl_pwr_state_t  state  ) 

LCD HV reulator Control.

Control the 15V regulator.

Switch the LCD High Voltage (~15V) reg. on or off

Parameters:
[in] desired state, HL_PWR_ON / HL_PWR_OFF

                                        {
        if (state == HL_PWR_OFF){
                /* power down 3.3 */
                HL_PWR_VLCD_PORT &= ~(_BV(HL_PWR_VLCD));                
                hl_pwr_state &= ~HL_PWR_LCD_ACTIVE;     
        }else{
                /* power up 3.3 */
                HL_PWR_VLCD_PORT |= _BV(HL_PWR_VLCD);   
                hl_pwr_state |= HL_PWR_LCD_ACTIVE;      
        }
}

uint16_t hl_pwr_slow ( void *  p  ) 

Slow Timer Call.

slow system timer call (1sec)

Do slow operations for power management:

  • OFF timer count down

                             {

        if (PowerOffTimer > 0){
                PowerOffTimer--;
        }
        return 0;
}

void hl_RegisterPwrCb ( cb_function_t  fkt2call,
void *  PwrStAllowed 
)

Register a call back function to request power down in higher SW layers.

The function will add an entry to the list of functions to be called when the power management tries to enter a lower power state. The new entry is added to the front of the list.

An Application routine can use the call back for the following actions:

  • Check if current states or operations require the system to stay on
  • set the allowed states

The control should be returned as fast as pssible. Do not wait or complete any pending operations within the callback.

Parameters:
[in] fkt2call function pointer
[in] PwrStAllowed pointer to power state bitmap

{
  cb_register_call (&cbListPowerFirst, fkt2call, PwrStAllowed);
}


Variable Documentation

volatile uint16_t PowerOffTimer

Second timer until power off.

If power off is allowed but the timer is not NULL, the system will only enter sleep mode.

volatile uint8_t WakeUpSource

Bitmap variable to indicate the wake-up source.

WakeUpSource is a symmary of system actions that caused the system to wake up. It's cleared before entering sleep, any wake-up ISR will set the individual bit. When checked some time after wake-up, more than one source might be active