SparkFun Forums 

Where electronics enthusiasts find answers.

What are we doing right with Artemis? What are we doing wrong? Let us know here!
User avatar
By E.HP.S
#244705
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.
Code: Select all
#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
Code: Select all
/*
  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?
User avatar
By liaifat85
#245846
I hope the problem is solved by this time. If not, ensure that the Artemis is properly set up for deep sleep and that all necessary configurations are made to wake it from sleep. disable unnecessary peripherals. configure power-down modes for different memory regions, and make sure the proper setup for wakeup timers (if any).
User avatar
By OlivianKocja
#246321
Based on the code you provided, it seems that the interrupt is not configured correctly to wake up the Artemis. The interrupt is set up to trigger when the number of milliseconds have elapsed, but it is not enabled to trigger the system into Deep Sleep.

To make the interrupt wake up the Artemis, you need to do the following:

Enable the timer interrupt in the NVIC. This can be done by calling the NVIC_EnableIRQ(STIMER_CMPR6_IRQn) function.
Set the system to Deep Sleep with the interrupt enabled. This can be done by calling the am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP) function.
Here is an example of how to do this:

// Enable the timer interrupt in the NVIC.
NVIC_EnableIRQ(STIMER_CMPR6_IRQn);

// Go to Deep Sleep with the interrupt enabled.
am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP);

Once the system is in Deep Sleep, the interrupt will be triggered and the system will wake up. You can then perform any necessary actions, such as turning on peripherals or processing data.

Here is an example of how to wake up the system and perform some actions:


void

wakeFromSleep()

{
// 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);

// Perform any necessary actions
// ...
}

I hope this helps!
 Topic permissions

You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum