2016年11月6日 星期日

STM8L Power Saving : How to Implement Auto Wake-Up Mode in STM8L101xx


In this document (4.2.1):

The STM8L101xx devices feature the following main low power modes:
Wait mode: CPU stopped and peripherals kept running
      - Wait RTC (peripheral module) interrupting.

Active-halt mode: MCU(microchip) stopped, AWU(auto-wakeup) and IWDG (independent watchdog) kept running if enabled.
      - Internal AWU timer would rouse MCUitself.

Halt mode: MCUand peripheral clocks stopped.
     - Wait external interrupting to wake-up, the external interrupting be User (pressing button) typically.


In here I discuss about Active-halt mode.
If your MCU be the others (like STM8L15xxx), I am sorry for that the MCU needs a RTC to enter the active-halt mode, please weld/connect a RTC to your MCU, and this article is not suitable for you!
零.  My development environment be :
  Cosmic STM8 compiler (32K is ample for stm8L)
  STM8L10X Library with STM8l10x_conf.h header (which wrap all headers of stm8L10X)

一. My demonstration code be :


#include "STM8l10x_conf.h"

void main(void)
{

 CLK_PeripheralClockConfig(CLK_Peripheral_AWU, ENABLE);
 AWU_IdleModeEnable();
 AWU_DeInit();
 
 AWU_LSICalibrationConfig(CLK_GetClockFreq());
 AWU_Init(AWU_Timebase_512ms);
 AWU_Cmd(ENABLE);
 
 
 /*do your stuff*/
 
 enableInterrupts();


 while(1)
 {
  halt();
 }/*while 1*/
 
}/*main*/

That is very straightforward, set AWU clock, then reset, adjust and set the AWU timer as 512 ms.


Your stm8_interrupt_vector.c should be modified to add AWU interrupt callback function :


/* BASIC INTERRUPT VECTOR TABLE FOR STM8 devices
 * Copyright (c) 2007 STMicroelectronics
 */

typedef void @far (*interrupt_handler_t)(void);

struct interrupt_vector {
 unsigned char interrupt_instruction;
 interrupt_handler_t interrupt_handler;
};

@far @interrupt void NonHandledInterrupt (void)
{
 /* in order to detect unexpected events during development, 
    it is recommended to set a breakpoint on the following instruction
 */
 return;
}

extern void _stext();     /* startup routine */

@far @interrupt void AWU_Trigger_Interrupt(void)
{
 AWU_GetFlagStatus();
}/*AWU_Trigger_Interrupt*/


struct interrupt_vector const _vectab[] = {
 {0x82, (interrupt_handler_t)_stext}, /* reset */
 {0x82, NonHandledInterrupt}, /* trap  */
 {0x82, NonHandledInterrupt}, /* irq0  */
 {0x82, NonHandledInterrupt}, /* irq1  */
 {0x82, NonHandledInterrupt}, /* irq2  */
 {0x82, NonHandledInterrupt}, /* irq3  */
 
 {0x82, AWU_Trigger_Interrupt}, /* irq4  */
 
 {0x82, NonHandledInterrupt}, /* irq5  */
 {0x82, NonHandledInterrupt}, /* irq6  */
 {0x82, NonHandledInterrupt}, /* irq7  */
 {0x82, NonHandledInterrupt}, /* irq8  */
 {0x82, NonHandledInterrupt}, /* irq9  */
 {0x82, NonHandledInterrupt}, /* irq10 */
 {0x82, NonHandledInterrupt}, /* irq11 */
 {0x82, NonHandledInterrupt}, /* irq12 */
 {0x82, NonHandledInterrupt}, /* irq13 */
 {0x82, NonHandledInterrupt}, /* irq14 */
 {0x82, NonHandledInterrupt}, /* irq15 */
 {0x82, NonHandledInterrupt}, /* irq16 */
 {0x82, NonHandledInterrupt}, /* irq17 */
 {0x82, NonHandledInterrupt}, /* irq18 */
 {0x82, NonHandledInterrupt}, /* irq19 */
 {0x82, NonHandledInterrupt}, /* irq20 */
 {0x82, NonHandledInterrupt}, /* irq21 */
 {0x82, NonHandledInterrupt}, /* irq22 */
 {0x82, NonHandledInterrupt}, /* irq23 */
 {0x82, NonHandledInterrupt}, /* irq24 */
 {0x82, NonHandledInterrupt}, /* irq25 */
 {0x82, NonHandledInterrupt}, /* irq26 */
 {0x82, NonHandledInterrupt}, /* irq27 */
 {0x82, NonHandledInterrupt}, /* irq28 */
 {0x82, NonHandledInterrupt}, /* irq29 */
};


Calling The function AWU_GetFlagStatus() would clean the AWU interruption flag, to avoid the callback function be called over one time for an event(the function would be called one time for per 512 ms).

That is all. But, before you adopt AWU as a ploy for STM8L power saving, you should slow down the master clock of the MCU. You could call the function CLK_MasterPrescalerConfig to achieve the goal.