PWR_DOWN & external interrupt


(Scott R) #1

Expanding on the discussion on using PWR_DOWN Arduboy Game Jam! and on my project Tamaguino AB --Tamagotchi for Arduino
Anyway I’ve been at it on and off since 10AM and its now 7PM (Yeah I’m like super fast at this stuff) I think I’ve almost got it figured using the Breakout example my only issue now is I have to hold the A button in for the system to run… I’m at a loss now and going in circles.

Example Test Sketch–All instances of A_BUTTON have been replaced with UP_BUTTON

  /*
  Breakout
 Copyright (C) 2011 Sebastian Goscik
 All rights reserved.

 Modifications by Scott Allen 2016 (after previous changes by ???)

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.
 */

#include <Arduboy2.h>

#include <avr/sleep.h>/*-------------------------ADDED PWR STUFF-----------------*/


// block in EEPROM to save high scores
#define EE_FILE 2

Arduboy2 arduboy;

const unsigned int COLUMNS = 13; //Columns of bricks
const unsigned int ROWS = 4;     //Rows of bricks

int wakePin = digitalRead(7);                 // pin used for waking up /*-------------------------ADDED PWR STUFF-----------------*/

int dx = -1;        //Initial movement of ball
int dy = -1;        //Initial movement of ball
int xb;           //Balls starting possition
int yb;           //Balls starting possition
boolean released;     //If the ball has been released by the player
boolean paused = false;   //If the game has been paused
byte xPaddle;       //X position of paddle
boolean isHit[ROWS][COLUMNS];   //Array of if bricks are hit or not
boolean bounced=false;  //Used to fix double bounce glitch
byte lives = 3;       //Amount of lives
byte level = 1;       //Current level
unsigned int score=0;   //Score for the game
unsigned int brickCount;  //Amount of bricks hit
boolean pad, pad2, pad3;  //Button press buffer used to stop pause repeating
boolean oldpad, oldpad2, oldpad3;
char text_buffer[16];      //General string buffer
boolean start=false;    //If in menu or in game
boolean initialDraw=false;//If the inital draw has happened
char initials[3];     //Initials used in high score

//Ball Bounds used in collision detection
byte leftBall;
byte rightBall;
byte topBall;
byte bottomBall;

//Brick Bounds used in collision detection
byte leftBrick;
byte rightBrick;
byte topBrick;
byte bottomBrick;

byte tick;
/*-------------------------ADDED PWR STUFF-----------------*/
void wakeUpNow() {
  //arduboy.displayOn();
  // execute code here after wake-up before returning to the loop() function
  // timers and code using timers (serial.print and more...) will not work here.
  // we don't really need to execute any special functions here, since we
  // just want the thing to wake up
}
/*------------------------------------------*/
void setup()
{
  arduboy.begin();
  arduboy.setFrameRate(40);
  arduboy.initRandomSeed();
/*-------------------------ADDED PWR STUFF-----------------*/
  pinMode(wakePin, INPUT_PULLUP); 
  attachInterrupt(4, wakeUpNow, LOW); // use interrupt  4 (pin 7) and run function wakeUpNow when pin 7 gets LOW
}
//External Interrupts: Pin 3 (interrupt 0),Pin 2 (interrupt 1), Pin 0 (interrupt 2), Pin 1 (interrupt 3) and Pin 7 (interrupt 4).
void sleepNow() {
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
   // arduboy.displayOff();
    sleep_enable();          // enables the sleep bit in the mcucr register
    attachInterrupt(4,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
    sleep_mode();            // here the device is actually put to sleep!!
    // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
    sleep_disable();         // first thing after waking from sleep: disable sleep...
    detachInterrupt(4);      // disables interrupt 4 on pin 7 so the wakeUpNow code will not be executed during normal running time.
}
/*------------------------------------------*/
void loop()
{
  // pause render until it's time for the next frame
  if (!(arduboy.nextFrame()))
    return;
 /*--------------------ADDED PWR STUFF & Last alteration to code line 98-----------------------------------*/   
  if (arduboy.pressed(wakePin)){sleepNow();}     // sleep function called here
 
  //Title screen loop switches from title screen
  //and high scores until FIRE is pressed
  while (!start)
 ///////////////////////////////////////////////////////////SNIP --Nothing to see down here///////////////////////////////////////////////////////////

Edit also:
Should I use a INPUT_PULLDOWN instead of INPUT_PULLUP?


Complete newbie looking for help with a goal
Tamaguino AB --Tamagotchi for Arduino
(Scott) #2

The ATmega32U4 doesn’t have INPUT_PULLDOWN capability.


(Scott R) #3

I made a “blink” sketch using the example [HERE] (https://gist.github.com/stojg/aec2c8c54c29c0fab407#file-sleep-ino)for testing and I get as far as going to sleep. If I re-enter sleep it seems to sleep some more rather than returning to the loop.

#include <Arduboy2.h>

Arduboy2 arduboy;

// This variable is made volatile because it is changed inside
// an interrupt function
volatile int sleepwake=1;
 
void wakeUpNow() {
  if(sleepwake == 1) {
  arduboy.setCursor(0,28);
  arduboy.setTextSize(2);
  arduboy.print(F("NOW ASLEEP!"));
  sleepwake = 0;}
}
// Enters the arduino into sleep mode.

void enterSleep() {
  // There are five different sleep modes in order of power saving:
  // SLEEP_MODE_IDLE - the lowest power saving mode
  // SLEEP_MODE_ADC
  // SLEEP_MODE_PWR_SAVE
  // SLEEP_MODE_STANDBY
  // SLEEP_MODE_PWR_DOWN - the highest power saving mode
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  attachInterrupt(4,wakeUpNow, LOW); // use interrupt  (pin 7) and run function
  // Now enter sleep mode.
  sleep_mode();
  // The program will continue from here after 
  // First thing to do is disable sleep.
  sleep_disable();
  detachInterrupt(4);      // disables interrupt 4 on pin 7 so the wakeUpNow code will not be executed during normal running time.
  // Re-enable the peripherals.
  power_all_enable();
}

void setup()
{
  arduboy.begin();
  arduboy.setFrameRate(40);
  arduboy.initRandomSeed();
/*-------------------------ADDED PWR STUFF-----------------*/
  pinMode(A_BUTTON, INPUT_PULLUP); 
  attachInterrupt(4, wakeUpNow, LOW); // use interrupt  4 (pin 7) and run function wakeUpNow when pin 7 gets LOW
}


// main loop
void loop() {
  
  if(sleepwake != 1) {
    return;
  }
  arduboy.clear();
  if (arduboy.justPressed(A_BUTTON)){enterSleep();}     // sleep function called here pressing the button again will wake
  // Toggle the LED on/off
  digitalWrite(GREEN_LED, LOW); // turn on green LED
  digitalWrite(RED_LED, HIGH);  // turn off red LED
  digitalWrite(BLUE_LED, HIGH);  // turn off blue LED
  arduboy.delayShort(500);
  digitalWrite(GREEN_LED, HIGH); // turn off green LED
  digitalWrite(RED_LED, LOW);  // turn on red LED
  digitalWrite(BLUE_LED, HIGH);  // turn off blue LED
  arduboy.delayShort(500);
  digitalWrite(GREEN_LED, HIGH); // turn off green LED
  digitalWrite(RED_LED, HIGH);  // turn off red LED
  digitalWrite(BLUE_LED, LOW);  // turn on blue LED
  arduboy.delayShort(500);
  digitalWrite(BLUE_LED, HIGH);  // turn off blue LED
  //Print on screen
  arduboy.print(F("I AM AWAKE!!!"));

  //arduboy.clear();
  // clear the flag so we can run above code again after the MCU wake up
  //sleepwake = 0;

  // Re-enter sleep mode.
  //enterSleep();
arduboy.display();
}

I also wonder if a lighter mode or even may be a wiser choice?


The External Interrupts can be triggered by a falling or rising edge or a low level. This is set up as indicated in the specification for the External Interrupt Control Registers – EICRA (INT3:0) and EICRB (INT6). When the external interrupt is enabled and is configured as level triggered, the interrupt will trigger as long as the pin is held low. Note that recognition of falling or rising edge interrupts on INT6 requires the presence of an I/O clock, described in “System Clock and Clock Options” on page 27. Low level interrupts and the edge interrupt on INT3:0 are detected asynchronously. This implies that these interrupts can be used for waking the part also from sleep modes other than Idle mode. The I/O clock is halted in all sleep modes except Idle mode.

I have highlighted some text from page 88 of the 32u4 data sheet and am confused if INT6 can or cannot be used in a state other than IDLE.


Apologies for the multiple edits i’m Pondering aloud…

Skimming the Arduboy2 documentation I noticed that there’s an IDLE mode and 8mhz.
This got me thinking about downclocking to 8mhz and regular idle’s to conserve power.


(Simon) #4

I am interested to see you get this right. It might be something we could incorporate into Dark & Under to allow users to complete the larger maps (that or saving!).


(Scott R) #5

Me too my Tamaguino decides to poop or die whilst I’m sleeping…

Where I’m trying to use a dedicated button to sleep and wake I guess for D&U or other games using all buttons you could send to sleep in software attach an interrupt to the A button to wake, then detach it.

Another option for timed events is to possibly extend the watchdog timer with a counter to increase it beyond 8 seconds.


(Scott R) #6

Day 3:
I am able to sleep the Arduboy and wake it by holding the A Button using the Rocketscream Low-Power Library

REQUIRES RESET BUTTON FOR NEW SKETCH

#include <Arduboy2.h>
#include "LowPower.h"

int filmotex = 54;
int filmotey = 1;

const unsigned char PROGMEM filmote[] =
{
// width, height,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
};



Arduboy2 arduboy;


const int wakeUpPin = digitalRead(7);

void wakeUp()
{
    // Just a handler for the pin interrupt.
}

void setup()
{
  arduboy.begin();
  arduboy.setFrameRate(60);
  arduboy.initRandomSeed();
pinMode(wakeUpPin, INPUT); 
}


// main loop
void loop() {
    if (!(arduboy.nextFrame()))
    return;
    // Allow wake up pin to trigger interrupt on low.
    attachInterrupt(4, wakeUp, LOW);
    
    // Enter power down state with ADC disabled and BOD module enabled.
    // Wake up when wake up pin is low.
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_ON); 
    
    // Disable external pin interrupt on wake up pin.
    detachInterrupt(4);
    digitalWrite(GREEN_LED, HIGH); // turn off green LED
     
    // Do something here
    // Example: Read sensor, data logging, data transmission.
  arduboy.clear();
 // if (arduboy.justPressed(A_BUTTON)){enterSleep();}     // sleep function called here pressing the button again will wake
  
  if (arduboy.everyXFrames(20)){digitalWrite(GREEN_LED, LOW); // turn on green LED

  }
  //write to screen and allow sprite to move
  arduboy.print(F("WHEN LED FLASH AWAKE"));
  arduboy.drawBitmap(filmotex, filmotey, filmote, 55, 45, WHITE);
  
        if(arduboy.pressed(LEFT_BUTTON)) {
       filmotex = filmotex - 1;
    }
    if(arduboy.pressed(RIGHT_BUTTON)) {
          filmotex = filmotex + 1;
    }
    if(arduboy.pressed(UP_BUTTON)) {
          filmotey = filmotey - 1;
  
    }
    if(arduboy.pressed(DOWN_BUTTON)) {
        filmotey = filmotey + 1;}

arduboy.display();
}

(Scott R) #7

SO CLOSE
I’ve moved the sleep stuff into a separate function I can call with the B button

  • A Button wakes
  • B Button sleeps.sketch2
#include <Arduboy2.h>
#include "LowPower.h"

int filmotex = 54;
int filmotey = 1;

const unsigned char PROGMEM filmote[] =
{
// width, height,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
};



Arduboy2 arduboy;


const int wakeUpPin = digitalRead(7);

void wakeUp()
{
    // Just a handler for the pin interrupt.
}

void setup()
{
  arduboy.begin();
  arduboy.setFrameRate(60);
  arduboy.initRandomSeed();
pinMode(wakeUpPin, INPUT); 
}
void GoToSleep() {
    digitalWrite(GREEN_LED, HIGH); // turn off green LED
    arduboy.delayShort(500);
      // Enter power down state with ADC disabled and BOD module enabled.
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_ON); 
    
    // Disable external pin interrupt on wake up pin.
    detachInterrupt(4);
    
}

// main loop
void loop() {
    if (!(arduboy.nextFrame()))
    return;
    // Allow wake up pin to trigger interrupt on low.
    attachInterrupt(4, wakeUp, LOW);
    
  if (arduboy.pressed(B_BUTTON)){GoToSleep();} //pressing the B Button starts the GoToSleep function
       
    // Do something here
    // Example: Read sensor, data logging, data transmission.
  arduboy.clear();
 // if (arduboy.justPressed(A_BUTTON)){enterSleep();}     // sleep function called here pressing the button again will wake
  
  if (arduboy.everyXFrames(20)){digitalWrite(GREEN_LED, LOW); // turn on green LED

  }
  //write to screen and allow sprite to move
  arduboy.print(F("WHEN LED ON AWAKE"));
  arduboy.drawBitmap(filmotex, filmotey, filmote, 55, 45, WHITE);
  
        if(arduboy.pressed(LEFT_BUTTON)) {
       filmotex = filmotex - 1;
    }
    if(arduboy.pressed(RIGHT_BUTTON)) {
          filmotex = filmotex + 1;
    }
    if(arduboy.pressed(UP_BUTTON)) {
          filmotey = filmotey - 1;
  
    }
    if(arduboy.pressed(DOWN_BUTTON)) {
        filmotey = filmotey + 1;}

arduboy.display();
}

(Scott R) #8

@filmote its done :slight_smile:

Directional Buttons = move
A Button = Green LED on - Red off
B Button = Red LED on - Green off
Left + B = Sleepmode + OLED off
A = Wake

#include <Arduboy2.h>
#include "LowPower.h"

int filmotex = 54;
int filmotey = 1;

const unsigned char PROGMEM filmote[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
};



Arduboy2 arduboy;


const int wakeUpPin = digitalRead(7);

void wakeUp()
{
    // Just a handler for the pin interrupt.
}

void setup()
{
  arduboy.begin();
  arduboy.setFrameRate(60);
  arduboy.initRandomSeed();
pinMode(wakeUpPin, INPUT); 
}

void GoToSleep() {
    digitalWrite(GREEN_LED, HIGH); // turn off green LED
    digitalWrite(RED_LED, HIGH);// turn off red LED
    arduboy.displayOff();//Turn the Screen OFF
    arduboy.delayShort(500);// Buy a little time before power down
      // Enter power down state with ADC disabled and BOD module enabled.
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_ON); 
    
    // Disable external pin interrupt on wake up pin.
    detachInterrupt(4);    
}

// main loop
void loop() {
    if (!(arduboy.nextFrame()))
    return;
    // Allow wake up pin to trigger interrupt on low.
    attachInterrupt(4, wakeUp, LOW);
    arduboy.displayOn();//Turn the Screen ON when waking
    if (arduboy.pressed(LEFT_BUTTON | B_BUTTON)){GoToSleep();}//pressing the Left + B Button starts the GoToSleep function
    if (arduboy.pressed(B_BUTTON)){digitalWrite(GREEN_LED, HIGH);// turn off green LED
    digitalWrite(RED_LED, LOW);}// turn on red LED
    if (arduboy.pressed(A_BUTTON)){digitalWrite(GREEN_LED, LOW);// turn on green LED
    digitalWrite(RED_LED, HIGH);}// turn off red LED

    // Do something here
    // Example: Read sensor, Run game code, data logging, data transmission.
  arduboy.clear();

  //write to screen and allow sprite to move
  arduboy.print(F("WHEN LED ON AWAKE")); // print text to screen
  arduboy.drawBitmap(filmotex, filmotey, filmote, 55, 45, WHITE); //draw sprite
  
        if(arduboy.pressed(LEFT_BUTTON)) {//move left
       filmotex = filmotex - 1;
    }
    if(arduboy.pressed(RIGHT_BUTTON)) {//move right
          filmotex = filmotex + 1;
    }
    if(arduboy.pressed(UP_BUTTON)) {//move up
          filmotey = filmotey - 1;
  
    }
    if(arduboy.pressed(DOWN_BUTTON)) {//move down
        filmotey = filmotey + 1;}

arduboy.display();
}

(Simon) #9

I can’t run this at work but I am guessing I will see a Galaga character onscreen?


(Pharap) #10

Put it this way, if it had been named ‘pharap’ then there would have been a skull on the screen :P


(Simon) #11

Yep … mine is a much smaller graphic for people to put together!


(Scott R) #12

There’s some power saving already in the Library
Sorry includes line numbers it’s a pita to use on mobile.

260 /* Power Management */
  261 
  262 void Arduboy2Core::idle()
  263 {
  264   set_sleep_mode(SLEEP_MODE_IDLE);
  265   sleep_mode();
  266 }
  267 
  268 void Arduboy2Core::bootPowerSaving()
  269 {
  270   // disable Two Wire Interface (I2C) and the ADC
  271   PRR0 = _BV(PRTWI) | _BV(PRADC);
  272   // disable USART1
  273   PRR1 = _BV(PRUSART1);
  274   // All other bits will be written with 0 so will be enabled
  275 }
  276 
  277 // Shut down the display
  278 void Arduboy2Core::displayOff()
  279 {
  280   LCDCommandMode();
  281   SPItransfer(0xAE); // display off
  282   SPItransfer(0x8D); // charge pump:
  283   SPItransfer(0x10); //   disable
  284   delayShort(250);
  285   bitClear(RST_PORT, RST_BIT); // set display reset pin low (reset state)
  286 }

D&U could use regular idles probably more so than games with animated sprites.


#13

This is very interesting. I’m very curious about how much power is used while in powerdown mode.


(Kevin) #14

In the quest for low power you can actually put the display controller inside the OLED to sleep also! :slight_smile:

Oh I see that was already discovered! :smiley:


(Josh Goebel) #15

Happy to finally see someone playing around with the deeper sleep modes. Very curious if someone actually takes the time to measure how long the battery lasts in deep sleep vs “normal” runtime.


(Scott R) #16

Ditched the following lines all they did was waste 264 bytes.

const int wakeUpPin = digitalRead(7);
pinMode(wakeUpPin, INPUT);

@Dreamer3
I did a ‘quick’ test using the below sketch over a period of 1 hour checking the battery with a multimeter.

  • Normal + Display on = start battery 4.11v after 1 hour battery = 3.94v or battery drain of 0.17v
  • Normal + Display off = start battery 4.11v after 1 hour battery = 3.95v or battery drain of 0.16v <–WTF ???
  • With Sleep + Display off =start battery 4.11v after 1 hour battery = 4.09 or battery drain of 0.02v
#include <Arduboy2.h>
#include "LowPower.h"


Arduboy2 arduboy;


void setup()
{
  arduboy.begin();
}

void GoToSleep() {
    arduboy.displayOff();//Turn the Screen OFF
    arduboy.delayShort(100);// Buy a little time before power down
      // Enter power down state with ADC disabled and BOD module enabled.
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); 
     
}

// main loop
void loop() {
arduboy.clear();  
//GoToSleep(); 
//arduboy.displayOff();
arduboy.display();
}

(Scott) #17

Measuring battery drain based on voltage isn’t going to be very precise. You should be measuring the current draw, but to do that you would have to disconnect one of the battery leads and connect an ammeter between the lead and the pad.

Edit: Actually, disconnecting a battery lead isn’t required. You can leave the Arduboy switched off and then connect the ammeter between the + terminal of the battery and Vcc.


(Scott R) #18

Yeah, I made do with what I had to hand I’m not really that into it enough to start desoldering the battery, especially when it could be done easier with a devkit or breadboard setup.

I don’t really want to be the guy goes timing until a full power down whilst in sleep either.


I did actually think about using the vcc pad earlier but not really knowing what I’m doing I didn’t want to blow anything up.


(Josh Goebel) #19

I’m interested in “time until dead”, although current draw would also be interesting (and should theoretically allow you to calculate time until dead IIRC.


(Scott R) #20

Not sure if there’s anything out there for the 32u4 but whilst researching power modes I came across this post (your probably aware of it) by Nick Gammon