Best way to reduce this power consumption?

Status
Not open for further replies.

dash4g

Member
I have a basic MP3 player using the prop shield LC from Frank B's MP3 player here

The code below basically will play the MP3 file based off a pin trigger. With so many inputs (eventually possibly hooking up a matrix) I am wondering what the best way to save power moving forward... Ideally a trigger button can be pressed and wake up the teensy and jump right to the MP3 file being played. Any help is greatly appreciated!

Code:
// Simple MP3 file player example
// https://forum.pjrc.com/threads/27059-MP3-Player-Lib-with-example?p=101537&viewfull=1#post101537
// Requires the prop-shield and Teensy 3.2 or 3.1
// This example code is in the public domain.

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <play_sd_mp3.h> // https://github.com/FrankBoesing/Arduino-Teensy-Codec-lib
//#include <play_sd_aac.h>
#include <Bounce2.h>

// GUItool: begin automatically generated code
//AudioPlaySdWav           playSdWav1;     //xy=154,422
AudioPlaySdMp3           playMp31; //xy=154,422
AudioMixer4              mixer1;         //xy=327,432
AudioOutputAnalog        dac1;           //xy=502,412
AudioConnection          patchCord1(playMp31, 0, mixer1, 0);
AudioConnection          patchCord2(playMp31, 1, mixer1, 1);
AudioConnection          patchCord3(mixer1, dac1);
// GUItool: end automatically generated code

#define PROP_AMP_ENABLE    5
#define FLASH_CHIP_SELECT  6
//#define FLASH_CHIP_SELECT 21  // Arduino 101 built-in SPI Flash

// Bounce objects to read two pushbuttons (pins 0,1)
Bounce button0 = Bounce(0, 5);
Bounce button1 = Bounce(1, 5);  // 5 ms debounce time

void setup() {
  // Configure the pushbutton pins for pullups. Each button should connect from the pin to GND.
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  Serial.begin(9600);
  AudioMemory(8); //4
  delay(2000);

  // Start SerialFlash
  if (!SerialFlash.begin(FLASH_CHIP_SELECT)) {
    while (1) {
      Serial.println ("Cannot access SPI Flash chip");
      delay (1000);
    }
  }

  //Set Volume
  mixer1.gain(0, 0.9);
  mixer1.gain(1, 0.9);

  //Start Amplifier
  pinMode(PROP_AMP_ENABLE, OUTPUT);
  digitalWrite(PROP_AMP_ENABLE, HIGH);    // Enable Amplifier
}

void playFile(const char *filename)
{
  SerialFlashFile ff = SerialFlash.open(filename);
  Serial.print("Playing file: ");
  Serial.println(filename);

  uint32_t sz = ff.size();
  uint32_t pos = ff.getFlashAddress();

  // Start playing the file.  This sketch continues to
  // run while the file plays.
  playMp31.play(pos,sz);

  // Simply wait for the file to finish playing.
  /*
  while (playMp31.isPlaying()) {
    yield();
  }
  */
}

void loop() {
  //
  // Update all the button objects
  button0.update();
  button1.update();
  //
  if (button0.fell()) {
    // playMp31.stop();
    playFile("PinZero.mp3");
  } else if (button1.fell()) {
    // playMp31.stop();
    playFile("PinOne.mp3");
  }
  //
}
 
Or possibly just have a mechanical on/off switch (you would need to record into the EEPROM or the flash memory the current file being played to start where you left off).
 
Thanks for the input @Frank B and @MichaelMeissner

The project is actually a set of sound effects (no more than 2 seconds long) but with many buttons/inputs.

The aim is to have it be able to be picked up and used anytime rather than a delay with a switch. My inspiration comes from some of the off-the-shelf toys which have batteries which (seemingly) last years...

I will work towards getting Duff's snooze library implemented. I will do some more reasearch on it, but I am wondering if this would limit me to using just 2,4,6,7,9,10,11,13,16,21,22,26,30,33 as input pins? I wonder how this would work in a matrix setup...

Thanks!
 
I am working through the 3 suggestions above, but I realize that there is most likely not a way to power this off of 3xAA batteries?

I am measuring the voltage @ 4.15v from the battery pack and I am hoping to not have to get too sophisticated with the power supply after the 3xAA batteries

reading this:
https://www.pjrc.com/teensy/external_power.html

Am I correct to see that the max CPU speed is 16Mhz? I hope not to have to cross this bridge, as it won't compile below 48Mhz

Is there any option that would allow me to power this off of the 3xAA battery pack I have? Or maybe I just need new batteries...

Thanks in advance!

Jon
 
...but I am wondering if this would limit me to using just 2,4,6,7,9,10,11,13,16,21,22,26,30,33 as input pins? I wonder how this would work in a matrix setup...
Those are the wakeup pins for deepSleep and hibernate only so if you want every pin to be able wake the teensy up those are your choices.

If I where you I would work one step at a time, having a power switch hooked to the batteries is a sure fire way to save your batteries as long as the person turns it off. The other things I have done in the past is to uses some sort of IC switch to programmatically kill power to sub systems that eat up to much power when the Teensy is sleeping or not. I always start with a base-line power measurements (sleeping and run) of a Teensy with nothing hooked up to it. I then add components one at a time and re-measure everything while keeping journal of those measurements. I then go and research different ways to save power like setting pins into a high Z state and such if need be. Once you get more specific to what you need we can help more.
 
Hey Duff, just to say thanks for replying, love the implementation of the snooze library, thanks for your work!

Those are the wakeup pins for deepSleep and hibernate only so if you want every pin to be able wake the teensy up those are your choices.
Since I have posted, I have played a bit with these and I have found the combination of these pins along with others. Very slick.

If I where you I would work one step at a time, having a power switch hooked to the batteries is a sure fire way to save your batteries as long as the person turns it off.
Yes, this would be ideal; what I am actually doing is restructuring a child's toy, (children using the toy) which is why the wake up pins were so preferable and if a parent/adult remembers to switch it off, then great. But, perhaps I jumped the gun on working forward with this as I now have the code and snooze library implemented. I just found out that the 3xAA batteries won't just work with the teensy and this implementation

Which leads me to your other point

The other things I have done in the past is to uses some sort of IC switch to programmatically kill power to sub systems that eat up to much power when the Teensy is sleeping or not.
I have looked at a "LM2623" to provide 5v constant, however I suspect this would burn through the batteries like no business.

Another thing I was thinking of was a timed IC which switches the power in line with the HIBERNATE_DELAY but that seems convoluted

I also found out that an Anker powerbank hooked up to the Micro USB will not power on the teensy. I suspect there may be an issue with the cable or bank itslef, but I will investigate this as well.

For what it is worth, here is the code I have been working through:
Code:
// Simple MP3 file player example
//
// https://forum.pjrc.com/threads/27059-MP3-Player-Lib-with-example?p=101537&viewfull=1#post101537
//
// Requires the prop-shield and Teensy 3.2 or 3.1
// This example code is in the public domain.

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <play_sd_mp3.h> // https://github.com/FrankBoesing/Arduino-Teensy-Codec-lib
#include <Bounce2.h>
#include <Snooze.h>
#include <SnoozeBlock.h>

#define PINTER_DELAY 2000
#define HIBERNATE_DELAY  300000

#define PROP_AMP_ENABLE    5
#define FLASH_CHIP_SELECT  6
//#define FLASH_CHIP_SELECT 21  // Arduino 101 built-in SPI Flash

// GUItool: begin automatically generated code
//AudioPlaySdWav           playSdWav1;     //xy=154,422
AudioPlaySdMp3           playMp31; //xy=154,422
AudioMixer4              mixer1;         //xy=327,432
AudioOutputAnalog        dac1;           //xy=502,412
AudioConnection          patchCord1(playMp31, 0, mixer1, 0);
AudioConnection          patchCord2(playMp31, 1, mixer1, 1);
AudioConnection          patchCord3(mixer1, dac1);
// GUItool: end automatically generated code

const char *sounds[] = {
  "achest.mp3",
  "afoot.mp3",
  "ear.mp3",
  "lfoot.mp3",
  "rhand.mp3",
  "hand.mp3"
  };

bool buttons[33];    // create a symbol for every button
Bounce buttonsB[33]; // debounce handler for each button not excluded.
//
uint8_t exclude_buttons[] = { 6, 7, 10, 11, 12, 13 };   // exclude pins that may be required for communication or other
uint8_t switch_buttons[] = { 23, 24 };

// button 0 -> 33
void initButtonStates() {
  for ( uint8_t i = 0; i < 33; i++ ) {
    buttons[i] = false;
  }
}

bool isSwitch(uint8_t b) {
  uint8_t n = sizeof(switch_buttons);
  for ( uint8_t i = 0; i < n; i++ ) {
      if ( b == switch_buttons[i] ) {
        return(true);
      }
  }
  return(false);
}

bool excludedButton(uint8_t b) {
  uint8_t n = sizeof(exclude_buttons);
  for ( uint8_t i = 0; i < n; i++ ) {
      if ( b == exclude_buttons[i] ) {
        return(true);
      }
  }
  return(false);
}

void setupBouncers(void) {
  for ( uint8_t i = 0; i < 33; i++ ) {
    if ( !excludedButton(i) ) {
      buttonsB[i].attach( i , INPUT_PULLUP  );  //setup the bounce instance for the current button
      buttonsB[i].interval(10);                 // interval in ms
    }
  }
}

void buttonUpdates(void) {
  // Update all the button objects
  for ( uint8_t i = 0; i < 33; i++ ) {
    if ( !excludedButton(i) ) {
      buttonsB[i].update();
    }
  }
}

bool buttonSense(void) {
  //
  buttonUpdates();
  //
  bool hasActivity = false;
  for ( uint8_t i = 0; i < 33; i++ ) {
    if ( !excludedButton(i) ) {
      bool bstate = ( buttonsB[i].read() == 0 );
      bool bfell = buttonsB[i].fell();
      if ( isSwitch(i) ) {
        buttons[i] = bstate;
      } else {
        buttons[i] = bstate && bfell;
      }
      hasActivity = hasActivity || bstate;
    }
  }
  //
  return(hasActivity);
}

SnoozeDigital digital;
// install drivers to a SnoozeBlock
SnoozeBlock config(digital);

uint8_t wakeupPins[] = { 2, 4, 6, 7, 9, 10, 11, 13, 16, 21, 22, 26, 30, 33 };

void initWakeupPins(void) {
  uint8_t n = sizeof(wakeupPins);
  for ( uint8_t i = 0; i < n; i++ ) {
    if ( !excludedButton(wakeupPins[i]) ) {
      pinMode(wakeupPins[i], INPUT_PULLUP);
      digital.pinMode(wakeupPins[i], INPUT_PULLUP, FALLING);  // pin, mode, type
    }
  }
}

void setAmpliferState(bool ampEnableState) {
  if ( ampEnableState ) {
    digitalWrite(PROP_AMP_ENABLE, HIGH);    // Enable Amplifier
  } else {
    digitalWrite(PROP_AMP_ENABLE, LOW);    // Disable Amplifier
  }
}

void init_amplifier(void) {
  //Start Amplifier
  pinMode(PROP_AMP_ENABLE, OUTPUT);
  setAmpliferState(true);
}

void setup() {
  //
  // Configure the pushbutton pins for pullups.
  // Each button should connect from the pin to GND.
  initButtonStates();
  setupBouncers();
  //
  initWakeupPins();
  //
  pinMode(LED_BUILTIN, OUTPUT);
  //Serial.begin(9600);
  while (!Serial);
  AudioMemory(8); //4
  delay(2000);
  Serial.println("start...");

  // Start SerialFlash
  if (!SerialFlash.begin(FLASH_CHIP_SELECT)) {
    while (1) {
      Serial.println ("Cannot access SPI Flash chip");
      delay (1000);
    }
  }

  //Set Volume
  mixer1.gain(0, 0.5);
  mixer1.gain(1, 0.5);

  init_amplifier();

  Serial.println("ready...");
}

void playFile(const char *filename)
{
  SerialFlashFile ff = SerialFlash.open(filename);
  Serial.print("Playing file: ");
  Serial.println(filename);

  uint32_t sz = ff.size();
  uint32_t pos = ff.getFlashAddress();

  // Start playing the file.  This sketch continues to
  // run while the file plays.
  playMp31.play(pos,sz);

  // Simply wait for the file to finish playing.
  /*
  while (playMp31.isPlaying()) {
    yield();
  }
  */
}



// JUST A LITTLE CHANGE:  Just put in the buttons on this one. But. It looks like the whole thing will delay until the file is done playing.
// That means the buttons should be useless until the sound is done.
// One way to fix that is to quit using the call to yield() above. Eliminate the loop.
// Again, the stops might have to be uncommented.

elapsedMillis gt_activityTimeout = 0;

bool activityTimeout(void) {
  if ( gt_activityTimeout > HIBERNATE_DELAY ) {
    return(true);
  }
  return(false);
}

void actvityRefreshTimer(void) {
  gt_activityTimeout = 0;
}

void actvityWakeup() {
  delay(PINTER_DELAY);
  actvityRefreshTimer();
}


void triggerAwake(void) {

  if ( !playMp31.isPlaying() ) {
    if ( activityTimeout() ) {
      digitalWrite(LED_BUILTIN, LOW);
      Serial.println("going to sleep...");
      setAmpliferState(false);
      delay(100);
      //Snooze.sleep( config );

      Serial.print(gt_activityTimeout);
      Serial.print(" ");

      elapsedMillis timeout = 0;

      Serial.println(gt_activityTimeout);
      // bounce needs to call update longer than the debounce time = 5ms,
      // which is set in constructor.
      while (timeout < 10)  buttonUpdates();
      //
      Snooze.hibernate( config );
      //Snooze.sleep( config );
      //
      actvityWakeup();
      setAmpliferState(true);
      Serial.println("Woke up");
      digitalWrite(LED_BUILTIN, HIGH);
    }
    // actually never really returns.
  } else {
    actvityRefreshTimer();
  }
}




void loop() {
  //
  triggerAwake(); // block on sleeping so does not have to be boolean
  if (  buttonSense() ) {
    actvityRefreshTimer();

    if ( buttons[0]) {
      playFile(sounds[0]);

    } else if ( buttons[1]) {
      playFile(sounds[1]);

    } else if ( buttons[2]) {
      playFile(sounds[2]);

    } else if ( buttons[3]) {
      playFile(sounds[3]);

    } else if ( buttons[4]) {
      playFile(sounds[4]);

    } else if ( buttons[5]) {
      playFile(sounds[5]);

    } else {
      // no selections
    }
  }
  //
}

The core of the code is the ability to use booleans to trigger the buttons and audio files, allowing me to use switches and buttons in combination.

Again, any help is greatly appreciated!
 
Status
Not open for further replies.
Back
Top