Close

Go To (Deep) Sleep!

A project log for Smart SmartyKat Toy

Making the SmartyKat Crazy Cruiser smart to lower battery usage.

leumasyerrpleumasyerrp 02/25/2023 at 12:430 Comments

I wrote some code for the PFS154-S08 using interrupts to wake the uC using the vibration switch, turn on the LED and motor for a few seconds and then turn everything off and go into deep sleep. This was simple code to make sure my code structure would work and then I would build on it for more complicated features such as blinking the LED and PWMing the motor. Everything was going just fine with the vibration switch waking up the uC and the LED and motor turning on and off as expected. The only issue I found that was when the uC was set to deep sleep it was drawing around 50uA.

The datasheet for the PFS154 claims a typical deep sleep using stopsys should consume around 0.5uA (pg. 16). I suspected that for some reason the uC was not going into deep sleep so I wrote some super simple code that setup the uC similar to how I had it setup but went into stopsys before reaching the forever loop. The current draw was still higher then the datasheet. I wanted the uC to go to sleep and I suspected that it was not.

To prove to myself that it was not going into sleep I wrote the following code that toggles a PIN in a while loop after a call to stopsys. Since I don't have any wake pins enabled the uC should never reach the pin toggling code.

/* Go To (Deep) Sleep! V1
 *  testing the deep sleep of the PFS154-S08
 *  compiled using free-pdk
 */ 
 
#include <stdint.h>
#include <pdk/device.h>
#include "auto_sysclock.h"

// Pin Defines - all pins are on port A
#define PIN   3

// Output Pin Function Defines
#define PIN_TOGGLE()  PA ^= (1 << PIN)

// Main Program
void main() {
  MISC |= MISC_FAST_WAKEUP_ENABLE;  /* enable faster wakeup, 45 ILRC clocks instead of 3000 */

  PADIER = 0;                       /* on reset all pins are set as wake pins, 
                                       setting register to 0 to disable */

  PAC |= (1 << PIN);                /* set pin as output */

  __stopsys();                      /* go to deep sleep */

  // forever loop - code execution should never reach this
  while(1) {
    PIN_TOGGLE();
    
    // simple delay
    for (int16_t i=0; i<1000; i++) {
      __nop();
    }
  }
}

// Startup code - Setup/calibrate system clock
unsigned char _sdcc_external_startup(void) {
  /* Set the system clock 
   * note it is necessary to enable IHRC clock while updating clock settings or CPU will hang  */
  PDK_USE_ILRC_SYSCLOCK();          /* use ILRC 55kHz clock as sysclock */
  PDK_DISABLE_IHRC();               /* disable IHRC to save power */
  EASY_PDK_CALIBRATE_ILRC(F_CPU, TARGET_VDD_MV);

  return 0;   // Return 0 to inform SDCC to continue with normal initialization.
}

To my surprise when I probed PA3 it was toggling and my current draw was again ~50uA. Why wont you go to sleep!

When I first started playing around with the PFS154-S08 I found a project for an Ultra Low Power LED Flasher using the PFS154. I remembered that in that code the author also disabled the wake function on port B since it would cause the uC to wake even though there is no port B on the -S08 variant of the PFS154. So with the modified code below I was finally able to get the uC to go to (deep) sleep with a current draw of around 0.3uA at Vdd=3.0V.

/* Go To (Deep) Sleep! V2
 *  testing the deep sleep of the PFS154-S08
 *  compiled using free-pdk
 */ 
 
#include <stdint.h>
#include <pdk/device.h>
#include "auto_sysclock.h"

// Pin Defines - all pins are on port A
#define PIN   3

// Output Pin Function Defines
#define PIN_TOGGLE()  PA ^= (1 << PIN)

// Main Program
void main() {
  MISC |= MISC_FAST_WAKEUP_ENABLE;  /* enable faster wakeup, 45 ILRC clocks instead of 3000 */

  PADIER = 0;                       /* on reset all pins are set as wake pins, 
                                       setting register to 0 to disable */
  PBDIER = 0;                       /* there is no port B on the -S08 package, 
                                       without setting this to 0 the uC will wake unexpectedly */

  PAC |= (1 << PIN);                /* set pin as output */

  __stopsys();                      /* go to deep sleep */

  // forever loop - code execution should never reach this
  while(1) {
    PIN_TOGGLE();
    
    // simple delay
    for (int16_t i=0; i<1000; i++) {
      __nop();
    }
  }
}

// Startup code - Setup/calibrate system clock
unsigned char _sdcc_external_startup(void) {
  /* Set the system clock 
   * note it is necessary to enable IHRC clock while updating clock settings or CPU will hang  */
  PDK_USE_ILRC_SYSCLOCK();          /* use ILRC 55kHz clock as sysclock */
  PDK_DISABLE_IHRC();               /* disable IHRC to save power */
  EASY_PDK_CALIBRATE_ILRC(F_CPU, TARGET_VDD_MV);

  return 0;   // Return 0 to inform SDCC to continue with normal initialization.
}

Discussions