PDA

View Full Version : Teensy++ 2.0 low power wake up on external interrupt



liuhuan
03-25-2013, 07:51 AM
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



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:



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 .
343

local_dani_21
07-02-2013, 09:41 PM
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


#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

el_supremo
07-02-2013, 11:03 PM
You can't use delay in an interrupt routine. Your wakeUp function should just set a flag which loop() watches for.



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

local_dani_21
07-03-2013, 09:14 AM
Cool, thanks!