SparkFun Forums 

Where electronics enthusiasts find answers.

Topics pertaining to the Arduino Core & software used with the Artemis module and Artemis development boards.
User avatar
By E.HP.S
#244633
paulvha wrote: Wed Oct 18, 2023 7:53 am I see you define SLEEP_INTERRUPT as 4, but you disable that GPIO (but exclude 18?)
Do you have a pull-up resistor on line between the switch and Nano ? Else the line is floating.
I do have a pullup both internally and externally. Also yeah, that was a bug I fixed. Like I said, pin 4 for the Artemis Nano also gets labelled D18 in other places, so I got mixed up. At the moment. I've removed all the sleep and wakeup stuff from the interrupt and am just toggling two LEDs on and off to see if the interrupt is being triggered constantly or if something else is going on.

It seems that what's going on is that the Artemis is "remembering" that a falling edge condition occurred when the pin was floating before I configured it as an input pullup (even with the external 10k pullup) and running one loop of the interrupt prematurely. After that, I can press the button and get the desired response the desired number of times without issue. Following that, I just need to clear the interrupt flag after I change the pin to input pullup, but before I attach the interrupt to it.

After that, I figure out what's going on with my sleep code
User avatar
By E.HP.S
#244675
stephenf wrote: Sun Mar 22, 2020 10:49 pm I looked quite hard and couldn't find an example which uses a GPIO interrupt instead of the timer to wake from deep sleep. It wasn't quite as intuitive as I thought, so I made an example, which is below in case anyone is interested (pull request for the core is about to be pending).
I just gave this example a try with an Artemis Nano and the GPIO can't wake it up. I'm running on 2.2.1 of the Arduino Core for the Apollo3, so could it have been broken over time? I tried implementing pieces of this into a different project I'm working on and it didn't work, so I figured I was just missing something. I tried running the original wholesale (save for adjusting what pin is connected to the button, Pin 4 in my case), and the same result. It flashes the LEDs, goes to sleep, and won't wake up.
User avatar
By E.HP.S
#244699
stephenf wrote: Sun Mar 22, 2020 10:49 pm I looked quite hard and couldn't find an example which uses a GPIO interrupt instead of the timer to wake from deep sleep. It wasn't quite as intuitive as I thought, so I made an example, which is below in case anyone is interested (pull request for the core is about to be pending).
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 gave this code another shot and now the Nano I'm working with is hardfaulting when I try, S.O.S. LED and all. I'll keep working at it and see what I can dig up
By paulvha
#244702
I think originally this sketch was run on V 1.x.x, which has the stack starting at address 0x0 growing up.
In V2.x.x the stack is at the TOP of memory growing down, thus turning off any RAM memory above 64K will cause the stack information to be lost and thus a hardfault on trying to wakeup.
User avatar
By E.HP.S
#244744
paulvha wrote: Fri Oct 20, 2023 8:57 am I think originally this sketch was run on V 1.x.x, which has the stack starting at address 0x0 growing up.
In V2.x.x the stack is at the TOP of memory growing down, thus turning off any RAM memory above 64K will cause the stack information to be lost and thus a hardfault on trying to wakeup.
You said a hardfault, right? Wouldn't the built-in LED start doing that S.O.S style flashing pattern if that was the case? I don't see that happening here, only the other LED going from illuminated to dark after a second or two. I tried cutting out the parts that mess with memory and so far its the same result.
User avatar
By E.HP.S
#244746
E.HP.S wrote: Mon Oct 23, 2023 6:46 am
paulvha wrote: Fri Oct 20, 2023 8:57 am I think originally this sketch was run on V 1.x.x, which has the stack starting at address 0x0 growing up.
In V2.x.x the stack is at the TOP of memory growing down, thus turning off any RAM memory above 64K will cause the stack information to be lost and thus a hardfault on trying to wakeup.
You said a hardfault, right? Wouldn't the built-in LED start doing that S.O.S style flashing pattern if that was the case? I don't see that happening here, only the other LED going from illuminated to dark after a second or two. I tried cutting out the parts that mess with memory and so far its the same result.
I ran a modified version of Example6_LowPower_Alarm to use a GPIO interrupt instead of the RTC interrupt, and I got mostly the same results, sans the LED shutting down.
Code: Select all

#include "RTC.h"
#define BUTTON_CTRL 14
#define DEBOUNCETIME 1000   // number of milli seconds needed between pushes

unsigned long debounce;     // Stores the last millis()

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(BUTTON_CTRL, INPUT_PULLUP);
  Serial.begin(115200);
  Serial.println("SparkFun RTC Low-power Alarm Example");

  // // Easily set RTC using the system __DATE__ and __TIME__ macros from compiler
  //RTC.setToCompilerTime();

  // Manually set RTC date and time
  rtc.setTime(0, 50, 59, 12, 3, 6, 20); // 12:59:50.000, June 3rd, 2020 (hund, ss, mm, hh, dd, mm, yy)

  // Set the RTC's alarm
  //rtc.setAlarm(0, 0, 0, 13, 3, 6); // 13:00:00.000, June 3rd (hund, ss, mm, hh, dd, mm). Note: No year alarm register

  // Set the RTC alarm mode
  /*
    0: Alarm interrupt disabled
    1: Alarm match every year   (hundredths, seconds, minutes, hour, day, month)
    2: Alarm match every month  (hundredths, seconds, minutes, hours, day)
    3: Alarm match every week   (hundredths, seconds, minutes, hours, weekday)
    4: Alarm match every day    (hundredths, seconds, minute, hours)
    5: Alarm match every hour   (hundredths, seconds, minutes)
    6: Alarm match every minute (hundredths, seconds)
    7: Alarm match every second (hundredths)
  */
  //rtc.setAlarmMode(6); // Set the RTC alarm to match on minutes rollover
  //rtc.attachInterrupt(); // Attach RTC alarm interrupt
  debounce = millis();
  attachInterrupt(digitalPinToInterrupt(BUTTON_CTRL), goToSleep, FALLING);
}

void loop()
{
  // Print date and time of RTC alarm trigger
  //Serial.print("Alarm interrupt: "); printDateTime();
  delay(1000);

  // Enter deep sleep and await RTC alarm interrupt
  //goToSleep();
}

// Print the RTC's current date and time
void printDateTime()
{
  rtc.getTime();

  Serial.printf("20%02d-%02d-%02d %02d:%02d:%02d.%03d\n",
          rtc.year, rtc.month, rtc.dayOfMonth,
          rtc.hour, rtc.minute, rtc.seconds, rtc.hundredths);
  Serial.println();
}

// Power down gracefully
void goToSleep()
{
  digitalWrite(LED_BUILTIN, HIGH);
  if (millis() - debounce < DEBOUNCETIME ) 
  {
    debounce = millis();
    return;
  }
  detachInterrupt(digitalPinToInterrupt(BUTTON_CTRL));
  attachInterrupt(digitalPinToInterrupt(BUTTON_CTRL), wakeUp, FALLING);
  // Disable UART
  Serial.end();

  // Disable ADC
  powerControlADC(false);

  // Force the peripherals off
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM3);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM4);
  //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM5);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0);
  am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1);

  // Disable all pads (except UART TX/RX)
  for (int x = 0 ; x < 50 ; x++)
  {
    if(x != LED_BUILTIN && x != BUTTON_CTRL)
    {
      am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE);
    }
  }
  //Power down CACHE, flashand SRAM
  am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); // Turn off CACHE and flash
  am_hal_pwrctrl_memory_deepsleep_retain(AM_HAL_PWRCTRL_MEM_SRAM_384K); // Retain all SRAM (0.6 uA)
  
  // Keep the 32kHz clock running for RTC
  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_interrupt_master_enable();


  am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP); // Sleep forever

  // And we're back!
  wakeUp();
}

// Power up gracefully
void wakeUp()
{
  // Go back to using the main clock
  am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
  am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ);

  // 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_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
  am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ);

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

  // Renable power to UART0
  am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_UART0);
  
  // Enable ADC
  initializeADC();

  // Enable Serial
  Serial.begin(115200);
  digitalWrite(LED_BUILTIN, LOW);
  debounce = millis();
}
At this point, I'm starting to question whether or not it's possible to have a GPIO interrupt wake the Artemis up after it goes to sleep. I know the RTC and Watchdog both work, but I need to be able to wake the device up outside of a regimented schedule
User avatar
By E.HP.S
#244747
I might have figured out what's going on, but I don't know for certain. This might, MIGHT be a case of "order of operations" getting in the way. If the interrupt flag is only cleared when returning from the interrupt function, We'd effectively "stay interrupted" until we wake up. However, we need an interrupt to wake it up.

So we're stuck inside an interrupt, waiting for an interrupt.
By paulvha
#244780
The real root cause is the incorrect definition of BUTTON_CTRL due to "pin to pad" mapping.

A pin is what is mentioned on the board side (e.g A14), a pad is a connection to the processor. Looking at the schematic for the Nano, pin A14 is connected to pad AD35.

When you disable the pads in GoToSleep(), you check to exclude pad BUTTON_CTRL (defined as 14) instead of excluding pad 35.

The easy solution is the correct define : #define BUTTON_CTRL D14 ( D14 NOT 14)
User avatar
By E.HP.S
#244788
I'll give that a try, but last I attempted it, I recall it not working. And besides, I have the button able to toggle both, it's just that, per my notes in the other forum post, now that I've introduced BLE to the mix, it's seemingly getting caught in a feedback loop after the first button press
 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