I’m trying to use a GPIO interrupt to wake up an Artemis from Deep Sleep in the Arduino Core, but I haven’t met any success yet. I double-checked with the provided examples (Example6_ LowPower_Alarm and Example3_WDT_LowPower), and those at least worked, but I can’t get it to work with GPIO.
I’ve been using two LEDs to indicate whether or not the device is awake or asleep. If it’s asleep, one LED is on. If it’s awake, the other LED is on. When I press the button to put the Artemis into Deep Sleep mode, the sleep LED turns on, then goes out. Afterwards, no button press can prompt any reaction.
#define DEBOUNCETIME 1000 // number of milli seconds needed between pushes
#define BATTERY_LED 10
#define SLEEP_INTERRUPT 4
void setup(void)
{
int cnt = 0;
pinMode(LED_BUILTIN, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected
#ifdef DEBUG
digitalWrite(LED_BUILTIN, HIGH);
#endif
pinMode(BATTERY_LED, OUTPUT);
pinMode(SLEEP_INTERRUPT, INPUT_PULLUP);
#ifdef DEBUG
digitalWrite(SLEEP_INTERRUPT, HIGH);
#endif
delay(50);
#ifdef DEBUG
Serial.begin(115200);
#endif
debounce = millis();
#ifdef DEBUG
Serial.print("About to attach interrupt. button status: "); Serial.println(digitalRead(SLEEP_INTERRUPT));
#endif
attachInterrupt(digitalPinToInterrupt(SLEEP_INTERRUPT), sleepModeSwitch, FALLING);
#ifdef DEBUG
Serial.println("Interrupt attached");
#endif
deepSleepTimer = millis() ;
}
void sleepModeSwitch()
{
if (millis() - debounce < DEBOUNCETIME )
{
return;
}
if(sleep_mode_status == false)
{
debounce = millis();
goToSleep();
#ifdef DEBUG
digitalWrite(BATTERY_LED, HIGH);
digitalWrite(LED_BUILTIN, LOW);
//Serial.println("Going to sleep...");
sleep_mode_status = true;
#endif
}
else
{
#ifdef DEBUG
digitalWrite(BATTERY_LED, LOW);
digitalWrite(LED_BUILTIN, HIGH);
//Serial.println("Waking up! Hello World!");
sleep_mode_status = false;
#endif
wakeUp();
debounce = millis();
}
}
void goToSleep()
{
sleep_mode_status = true;
#ifdef DEBUG
Serial.println("Going to sleep");
delay(50); //Wait for serial to finish
Serial.end(); //Power down UART(s)
#endif
// turn off the led.
digitalWrite(LED_BUILTIN, LOW);
digitalWrite(BATTERY_LED, HIGH);
powerControlADC(false);
for(int x = 0; x < 50; x++)
{
if(x != SLEEP_INTERRUPT && x != BATTERY_LED && X != LED_BUILTIN )
{
am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE);
}
}
//Power down Flash, SRAM, cache
am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_CACHE); //Turn off CACHE
am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_FLASH_512K); //Turn off everything but lower 512k
am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_SRAM_64K_DTCM); //Turn off everything but lower 64k
//am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); //Turn off all memory (doesn't recover)
// // Enable interrupts to the core.
am_hal_interrupt_master_enable();
// //Enable the timer interrupt in the NVIC.
// NVIC_EnableIRQ(STIMER_CMPR6_IRQn);
//Go to Deep Sleep.
am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_NORMAL);
}
void wakeUp()
{
am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_MAX);
// Renable UART0 pins
am_hal_gpio_pinconfig(48, g_AM_BSP_GPIO_COM_UART_TX);
am_hal_gpio_pinconfig(49, g_AM_BSP_GPIO_COM_UART_RX);
am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_UART0);
initializeADC();
#ifdef DEBUG
Serial.begin(115200);
delay(10);
Serial.println("Waking up! Hello world!");
#endif
deepSleepTimer = millis() ;
sleep_mode_status = false;
digitalWrite(BATTERY_LED, LOW);
digitalWrite(LED_BUILTIN, HIGH);
}
I also added the same LED code to Example3_WDT_LowPower and the LED stayed on when it was asleep. It was hard to tell if it was turning off when it woke up, but it at least didn’t go into sleep mode, go out and not respond to anything afterwards. I also tried the code listed in the below topic, and instead I got a hardfault.
viewtopic.php?f=169&t=50904&start=15
/*
LowPower_WithWorkAndGPIOInterrupt
Adapted by Stephen Fordyce 2020-03-23 from:
Artemis Low Power: How low can we go?
By: Nathan Seidle
SparkFun Electronics
Date: February 26th, 2020
License: This code is public domain.
*/
uint32_t msToSleep = 5000; //This is the user editable number of ms to sleep between RTC checks
#define TIMER_FREQ 32768L //Counter/Timer 6 will use the 32kHz clock
uint32_t sysTicksToSleep = msToSleep * TIMER_FREQ / 1000;
const byte STATUS_LED = 14;//13 for Redboard onboard LED, 19 for Nano onboard LED
const byte INPUT_BUTTON = 19;//You'll have to add one, it needs to connect to GND for active
bool awakeFlag = true; //Stops wakeFromSleep() being run if the system is already awake
// GPIO Interrupt Service Routine
void myGPIO_ISR(void)
{
detachInterrupt(digitalPinToInterrupt(INPUT_BUTTON)); //Stop interrupt from being triggered again
wakeFromSleep(); //Without waking the processor properly, nothing more will happen. This means wakeFromSleep() is called twice though.
// am_hal_stimer_compare_delta_set(6, 0); //Or, force the timer to run out, and resume from where you left off.
}
void setup(void) {
Serial.begin(115200);
Serial.println("Artemis Low Power (with timer & GPIO wakeup) Example");
pinMode(STATUS_LED, OUTPUT);
pinMode(INPUT_BUTTON, INPUT_PULLUP);
//Initialise stuff like I2C/Wire/SPI here
}
void loop(void) {
Serial.println("Starting loop, and flashing LED");
digitalWrite(STATUS_LED, HIGH);
delay(200);
digitalWrite(STATUS_LED, LOW);
Serial.println("Phew, that was hard work");
goToSleep();
}
//Power everything down and wait for interrupt wakeup
void goToSleep()
{
attachInterrupt(digitalPinToInterrupt(INPUT_BUTTON), myGPIO_ISR, FALLING);
//End stuff like I2C/Wire/SPI here
power_adc_disable(); //Power down ADC. It it started by default before setup().
Serial.println("Going to sleep");
delay(50); //Wait for serial to finish
Serial.end(); //Power down UART(s)
awakeFlag = false;
//Disable all pads except the interrupt button
for (int x = 0 ; x < 50 ; x++)
{
if(x != INPUT_BUTTON)
am_hal_gpio_pinconfig(x , g_AM_HAL_GPIO_DISABLE);
}
//We use counter/timer 6 to cause us to wake up from sleep but 0 to 7 are available
//CT 7 is used for Software Serial. All CTs are used for Servo.
am_hal_stimer_int_clear(AM_HAL_STIMER_INT_COMPAREG); //Clear CT6
am_hal_stimer_int_enable(AM_HAL_STIMER_INT_COMPAREG); //Enable C/T G=6
//Use the lower power 32kHz clock. Use it to run CT6 as well.
am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
am_hal_stimer_config(AM_HAL_STIMER_XTAL_32KHZ | AM_HAL_STIMER_CFG_COMPARE_G_ENABLE);
//Setup interrupt to trigger when the number of ms have elapsed
am_hal_stimer_compare_delta_set(6, sysTicksToSleep);
//Power down Flash, SRAM, cache
am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_CACHE); //Turn off CACHE
am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_FLASH_512K); //Turn off everything but lower 512k
am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_SRAM_64K_DTCM); //Turn off everything but lower 64k
//am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); //Turn off all memory (doesn't recover)
// Enable interrupts to the core.
am_hal_interrupt_master_enable();
//Enable the timer interrupt in the NVIC.
NVIC_EnableIRQ(STIMER_CMPR6_IRQn);
//Go to Deep Sleep.
am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP);
/////////////////////////////////////////////////////////////////////
//<Pause here while sleeping> (and/or while interrupt routines run)//
/////////////////////////////////////////////////////////////////////
//Turn off timer interrupt
NVIC_DisableIRQ(STIMER_CMPR6_IRQn);
//Turn off GPIO interrupt
detachInterrupt(digitalPinToInterrupt(INPUT_BUTTON));
//We're BACK!
wakeFromSleep();
Serial.println("End of goToSleep()");
Serial.println();
}
//Power everything up gracefully
void wakeFromSleep()
{
if(awakeFlag) //Already awake
return;
//Power up SRAM, turn on entire Flash
am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_MAX);
//Go back to using the main clock
am_hal_stimer_int_enable(AM_HAL_STIMER_INT_OVERFLOW);
NVIC_EnableIRQ(STIMER_IRQn);
am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ);
//Turn on ADC
ap3_adc_setup();
//Set any pinModes
pinMode(STATUS_LED, OUTPUT);
pinMode(INPUT_BUTTON, INPUT_PULLUP);
//Optional - start again (will never reach the end of goToSleep() or wakeFromSleep() though)
//Note - global variables will be preserved if you don't power down SRAM (comment out the line)
//setup();
//Restart Serial
Serial.begin(115200);
delay(10);
Serial.println("Back on");
awakeFlag = true;
//Initialise stuff like I2C/Wire/SPI here
}
//Called once number of milliseconds has passed
extern "C" void am_stimer_cmpr6_isr(void)
{
uint32_t ui32Status = am_hal_stimer_int_status_get(false);
if (ui32Status & AM_HAL_STIMER_INT_COMPAREG)
{
am_hal_stimer_int_clear(AM_HAL_STIMER_INT_COMPAREG);
}
}
I’m still new to the Artemis sleep modes, so odds are I’m just missing something to make the interrupt wake up the Artemis. Does anyone have any suggestions on what I’m doing wrong, or further reading to help my understanding of what I might be missing?