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. |
Power Management Routines for the eXPal Prototype A.
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.
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
[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
[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
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:
{ // 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
{ 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
[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:
{ 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:
The control should be returned as fast as pssible. Do not wait or complete any pending operations within the callback.
[in] | fkt2call | function pointer |
[in] | PwrStAllowed | pointer to power state bitmap |
{ cb_register_call (&cbListPowerFirst, fkt2call, PwrStAllowed); }
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