Teensy++ 2.0 low power wake up on external interrupt

Status
Not open for further replies.

liuhuan

Member
The problem is solved :)
I simply need to uncomment the attachInterrupt line in setup(). The interrupt can wake up teensy.
Also, documentation on sleep modes can be found on page 51 of http://www.pjrc.com/teensy/at90usb1286.pdf


Dear Paul and friends,

I am trying to run Teensy on battery and I hope to make the battery last as long as possible.

My plan is to have Teensy wake up on an external interrupt signal. I can reliably detect the external interrupt signal (please see more info at the end of the post), but I don't know how to write the code to properly put Teensy into and out of sleep mode.

More specifically, I don't know how to set up Teensy with the interrupt port I wish to wake it up with.

Below is the code I got from http://www.pjrc.com/teensy/low_power.html . Maybe I'm just missing a line? I have also put some questions inline.

As you can see, I am a little clueless about how sleep mode works. I would love to be pointed to an external reference where I can learn more about it.

Thanks for your help!

Huan

Code:
const int ledPin = 6;
const int wakeupPin = 2;
volatile int ledState = LOW;
volatile int ledVal;

void wakeUp()
{
  Serial.println("in wakeUp()");
  ledState = HIGH;
  Serial.println(ledState);
  Serial.println("Turn on");
  digitalWrite(ledPin, HIGH);
  delay(5000);
  Serial.println("Turn off");
  digitalWrite(ledPin, LOW);
}

void setup()
{
  Serial.begin(38400);
  pinMode(ledPin, OUTPUT);
  pinMode(wakeupPin, INPUT);
  //attachInterrupt(wakeupPin, wakeUp, FALLING); //LOW,RISING, FALLING,CHANGE
  ledVal=0;
  digitalWrite(ledPin, ledVal);
  Serial.println("done init");
}

#include <avr/sleep.h>

void powerdown() {
  digitalWrite(ledPin, HIGH);
  delay(1000);
  digitalWrite(ledPin, LOW);
  Serial.println("bye world!");
  delay(1000);
  Serial.end(); // shut off USB
  ADCSRA = 0;   // shut off ADC
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // QUESTION: what about PWR_SAVE mode?
  noInterrupts(); // QUESTION: are we disabling the interrupts so that the powerdown procedure can finish?
  sleep_enable();
  interrupts(); // QUESTION: how do I specify which port? can I specify multiple ports?
  sleep_cpu(); // QUESTION: does teensy go to sleep here?
  sleep_disable(); // QUESTION: why do we clear the sleep bit here?
  // QUESTION: will the code below ever get executed?
  Serial.begin(38400);
  delay(1000);
  Serial.println("hello world!");
  delay(1000);
  digitalWrite(ledPin, HIGH);
  delay(1000);
}

void loop() 
{
  powerdown();
}


I am using Teensy++ 2.0. I have tested the external interrupt with the following code:

Code:
const int ledPin = 6;
const int wakeupPin = 2;
volatile int ledState = LOW;

void wakeUp()
{
  Serial.println("in wakeUp()");
  Serial.println("Turn on");
  digitalWrite(ledPin, HIGH);
  delay(5000);
  Serial.println("Turn off");
  digitalWrite(ledPin, LOW);
}

volatile int ledVal;
void setup()
{
  Serial.begin(38400);
  pinMode(ledPin, OUTPUT);
  pinMode(wakeupPin, INPUT);
  attachInterrupt(wakeupPin, wakeUp, FALLING); //LOW,RISING, FALLING,CHANGE
  ledVal=0;
  digitalWrite(ledPin, ledVal);
  Serial.println("done init");
}

The external interrupt is set up with a pull up resistor, and I am detecting the falling signal. INPUT in the diagram is connected to INT2 (D2) on Teensy++ 2.0 .
pullup.png
 
Last edited:
wakeUp()-function is not called when waking up from sleep (teensy++ 2.0)

I tried to adapt your code, lihuan, thanks for it. I use a teensy++ 2.0 with an attached button to put it to sleep and an LDR to wake it back up. The µP goes to sleep very nicely when the button (pin 41) is pulled low. It wakes up when the LDR detects turned on light. But I don't understand, why my wakeUp()-function is never called. Instead, the code right below sleep_disable() is called when waking up.

Does anyone have an idea, why the wakeUp-function is not called?

Thanks a bunch for any hints!

Dani

Code:
#include <avr/sleep.h>

const int ledPin = 6;
const int wakeupPin = 0;
const int buttonPin = 41;


void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  digitalWrite(buttonPin, HIGH); //Pullup
  pinMode(wakeupPin, INPUT);
  attachInterrupt(wakeupPin, wakeUp, FALLING); //LOW,RISING, FALLING,CHANGE
  digitalWrite(ledPin, HIGH);
}

void wakeUp() // This routine is never called - not even after a successful wake up - Why?
{
    for (int i = 0; i < 10; i++){
    digitalWrite(ledPin, HIGH);
    delay(500);
    digitalWrite(ledPin, LOW);
    delay(500);
  }
  digitalWrite(ledPin, HIGH);
}


void powerdown() {
  for (int i = 0; i < 10; i++){
    digitalWrite(ledPin, HIGH);
    delay(100);
    digitalWrite(ledPin, LOW);
    delay(100);
  }
  //Serial.end(); // shut off USB
  ADCSRA = 0;   // shut off ADC
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  noInterrupts(); 
  sleep_enable();
  interrupts(); 
  sleep_cpu(); 
  sleep_disable(); 
  
  // QUESTION: Why is the code below executed after the wakeup?

    for (int i = 0; i < 10; i++){
      digitalWrite(ledPin, HIGH);
      delay(100);
      digitalWrite(ledPin, LOW);
      delay(100);
    }
    digitalWrite(ledPin, HIGH);
}

void loop() 
{
  if(digitalRead(buttonPin) == LOW) {powerdown();}
}

Edit:
I think I figured out how it works:
The µP goes to sleep right after the call of sleep_cpu(); (see code above).
When the interrupt-trigger has happened, wakeUp() is called but - within the interrupt-function, delay does not work properly. Therefore the LED just flickers strangely.
After wakeUp(), the function sleep_disable() is called and the board is working as before.

I hope I'm right with my guesses - any corrections are very welcome!
/Edit
 
Last edited:
You can't use delay in an interrupt routine. Your wakeUp function should just set a flag which loop() watches for.

Code:
volatile wakeup_flag = 0;
void wakeUp()
{
  wakeup_flag = 1;
}

void loop() 
{
  if(digitalRead(buttonPin) == LOW) {
    powerdown();
  }
  if(wakeup_flag) {
    wakeup_flag = 0;
    for (int i = 0; i < 10; i++){
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
      delay(500);
    }
    digitalWrite(ledPin, HIGH);
  }
}

You must also ensure that the action in loop() doesn't take longer than the time between two interrupts - in this case the interrupts must not occur any closer than ten seconds.


Pete
 
Status
Not open for further replies.
Back
Top