You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I made the sleepWithGPIOInterrupts example and it was great, although in my application I have 3 buttons, all of which should trigger an interrupt. Mostly though, the uC sleeps for a fixed time period and is woken by the timer.
Two instances of the interrupt code seem to be ok, but three or more will cause a hang after X number of sleeps and timer wakeups. The hang is in pinMode, and the number of sleeps before hang varies from 145 to 1177 depending on how many GPIO interrupts there are, and whether they are attached to valid or invalid pins. It's really weird, and I've been staring at it for days, am out of ideas for the moment.
Your workbench
I'm using a custom Artemis board, being programmed as an ATP board, core 1.0.30 on Arduino IDE 1.8.12, Windows 10. Don't really need the pins to trigger the interrupt, as it's the timer that is failing.
Steps to reproduce
Here's my complete test code, including comments on test cases and results:
`
//(from 2020-02-21 Sparkfun DeepSleep_with_Work example)
//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);
}
}
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;
bool awakeFlag = true; //Stops wakeFromSleep() being run if the system is already awake
//Pin 35,19,18 (as interrupt pins 1,2,3), freezes at loop 147
//Pin 35,18,17 (as interrupt pins 1,3,4), freezes at loop 147
//With all enabled, freezes at loop 147
//Commented out the #define and all traces of interruptPin3 & 4, and freezes at loop 1177
//Commented out the #define and all traces of interruptPin4, and freezes at loop 312
//With all 4 as real pins, tried moving the block of detachInterrupt calls around (ie. after processor is re-woken), didn't seem to make a difference
uint32_t loopCount = 1;
bool DEBUG = false;
void setup()
{
Serial.begin(115200); //Start Serial
//Go to Deep Sleep.
am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP);
/////////////////////////////////////////////////////////////////////
// (and/or while interrupt routines run)//
/////////////////////////////////////////////////////////////////////
//Turn off timer interrupt
NVIC_DisableIRQ(STIMER_CMPR6_IRQn);
//Turn off GPIO interrupt (necessary if timer triggered the wake-up)
detachInterrupt(digitalPinToInterrupt(interruptPin1));
detachInterrupt(digitalPinToInterrupt(interruptPin2));
detachInterrupt(digitalPinToInterrupt(interruptPin3));
detachInterrupt(digitalPinToInterrupt(interruptPin4));
// //Shouldn't, and doesn't do anything
// am_hal_gpio_pinconfig(interruptPin1, g_AM_HAL_GPIO_DISABLE);
// am_hal_gpio_pinconfig(interruptPin2, g_AM_HAL_GPIO_DISABLE);
// am_hal_gpio_pinconfig(interruptPin3, g_AM_HAL_GPIO_DISABLE);
// am_hal_gpio_pinconfig(interruptPin4, g_AM_HAL_GPIO_DISABLE);
//We're BACK!
wakeFromSleep();
//Doesn't actually go here, since setup() is called in wakeFromSleep()
Serial.println("End of goToSleep()");
}
void configureForDeepSleep(int wakeOption)
{
if(wakeOption == GPIO_WAKE || wakeOption == GPIO_TIMER_WAKE)
{
//It doesn't seem to matter whether they have the same ISR, or different ones
attachInterrupt(digitalPinToInterrupt(interruptPin1), myGPIO_ISR1, FALLING);
attachInterrupt(digitalPinToInterrupt(interruptPin2), myGPIO_ISR2, FALLING);
attachInterrupt(digitalPinToInterrupt(interruptPin3), myGPIO_ISR3, FALLING);
attachInterrupt(digitalPinToInterrupt(interruptPin4), myGPIO_ISR4, FALLING);
}
power_adc_disable(); //Power down ADC. It it started by default before setup().
//Disable all pads except the interrupt button
//Pads must be disabled beforehand
if(wakeOption == TIMER_WAKE || wakeOption == GPIO_TIMER_WAKE)
{
//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);
if(wakeOption == TIMER_WAKE || wakeOption == GPIO_TIMER_WAKE)
am_hal_stimer_compare_delta_set(6, sysTicksToSleep); //Setup interrupt to trigger when the number of ms have elapsed
//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();
if(wakeOption == TIMER_WAKE || wakeOption == GPIO_TIMER_WAKE)
NVIC_EnableIRQ(STIMER_CMPR6_IRQn); //Enable the timer interrupt in the NVIC.
}
//Power everything up gracefully
void wakeFromSleep()
{
if(!awakeFlag) //Processor already awake (probably from GPIO ISR)
recoverFromDeepSleep();
setup();
}
void recoverFromDeepSleep()
{
//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);
ap3_adc_setup(); //Turn on ADC
awakeFlag = true; //Indicate this routine doesn't need to be called again
}
// Disable any GPIOs that might be the source of stray or leaking current going in or out of the Apollo3.
void disableMyGpios()
{
for (int i = 0; i <= 49; i++)
{
if(i==interruptPin1 || i==interruptPin2 || i==interruptPin3 || i==interruptPin4)
{} //Don't disable
else
am_hal_gpio_pinconfig(i, g_AM_HAL_GPIO_DISABLE);
}
}
// GPIO Interrupt Service Routine
void myGPIO_ISR1(void)
{
detachInterrupt(digitalPinToInterrupt(interruptPin1)); //Stop interrupt from being triggered again
recoverFromDeepSleep(); //Wake the processor, but don't do anything fancy like initialising Serial or whatever
// am_hal_stimer_compare_delta_set(6, 0); //Or, force the timer to run out, and resume from where you left off.
}
// GPIO Interrupt Service Routine
void myGPIO_ISR2(void)
{
detachInterrupt(digitalPinToInterrupt(interruptPin2)); //Stop interrupt from being triggered again
recoverFromDeepSleep(); //Wake the processor, but don't do anything fancy like initialising Serial or whatever
// am_hal_stimer_compare_delta_set(6, 0); //Or, force the timer to run out, and resume from where you left off.
}
// GPIO Interrupt Service Routine
void myGPIO_ISR3(void)
{
detachInterrupt(digitalPinToInterrupt(interruptPin3)); //Stop interrupt from being triggered again
recoverFromDeepSleep(); //Wake the processor, but don't do anything fancy like initialising Serial or whatever
// am_hal_stimer_compare_delta_set(6, 0); //Or, force the timer to run out, and resume from where you left off.
}
// GPIO Interrupt Service Routine
void myGPIO_ISR4(void)
{
detachInterrupt(digitalPinToInterrupt(interruptPin4)); //Stop interrupt from being triggered again
recoverFromDeepSleep(); //Wake the processor, but don't do anything fancy like initialising Serial or whatever
// am_hal_stimer_compare_delta_set(6, 0); //Or, force the timer to run out, and resume from where you left off.
}`
Expected behaviour
The code should just keep on running forever.
Actual behaviour
It stops at repeatable points during a call to pinMode
The text was updated successfully, but these errors were encountered:
I suspect there is a missing line: "gpio_num_isr --;" at the end of function "detachInterrupt" in the core library file "ap3_gpio.cpp". The end of the function should be:
// Clear out the last entry
gpio_isr_entries[gpio_num_isr].pad = 0;
gpio_isr_entries[gpio_num_isr].callback = NULL;
gpio_isr_entries[gpio_num_isr].mode = LOW;
gpio_isr_entries[gpio_num_isr].arg = NULL;
**gpio_num_isr --;**
I have an application the attaches and detaches interrupts regularly and "gpio_num_isr" was growing, causing multiple calls to the isr routine and eventually crash. The correction seems to solve the problem for me. This could be the cause for Stephen's problem also.
Subject of the issue
I made the sleepWithGPIOInterrupts example and it was great, although in my application I have 3 buttons, all of which should trigger an interrupt. Mostly though, the uC sleeps for a fixed time period and is woken by the timer.
Two instances of the interrupt code seem to be ok, but three or more will cause a hang after X number of sleeps and timer wakeups. The hang is in pinMode, and the number of sleeps before hang varies from 145 to 1177 depending on how many GPIO interrupts there are, and whether they are attached to valid or invalid pins. It's really weird, and I've been staring at it for days, am out of ideas for the moment.
Your workbench
I'm using a custom Artemis board, being programmed as an ATP board, core 1.0.30 on Arduino IDE 1.8.12, Windows 10. Don't really need the pins to trigger the interrupt, as it's the timer that is failing.
Steps to reproduce
Here's my complete test code, including comments on test cases and results:
`
//(from 2020-02-21 Sparkfun DeepSleep_with_Work example)
//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);
}
}
//Sleeping
#define GPIO_WAKE 1
#define TIMER_WAKE 2
#define GPIO_TIMER_WAKE 3
#define TIMER_GPIO_WAKE 3
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;
bool awakeFlag = true; //Stops wakeFromSleep() being run if the system is already awake
//Misc
#define interruptPin1 35
#define interruptPin2 19
#define interruptPin3 18 //-1
#define interruptPin4 17 //-1
//With all as -1, doesn't freeze
//Only pin 35 (as interruptPin1), doesn't freeze
//Only pin 19 (as interruptPin1), doesn't freeze
//Only pin 19 (as interruptPin2), freezes at loop 801
//Only pin 18 (as interruptPin3), freezes at loop 801
//Only pin 17 (as interruptPin4), freezes at loop 801
//Pin 35 & 19 (as interrupt pins 1 & 2), doesn't freeze
// Removed pin 3/4 calls to pinMode, doesn't freeze
// Removed pin 3/4 calls to detachInterrupt after sleeping, doesn't freeze
// Removed pin 3/4 calls to attachIinterrupt, freezes at loop 1177
//Pin 35 & 19 (as interrupt pins 1 & 3), doesn't freeze
//Pin 35 & 17 (as interrupt pins 1 & 4), doesn't freeze
//Pin 18 & 17 (as interrupt pins 3 & 4), freezes at loop 265
//Pin 19 & 18 (as interrupt pins 2 & 3), freezes at loop 265
//Pin 35,19,18 (as interrupt pins 1,2,3), freezes at loop 147
//Pin 35,18,17 (as interrupt pins 1,3,4), freezes at loop 147
//With all enabled, freezes at loop 147
//Commented out the #define and all traces of interruptPin3 & 4, and freezes at loop 1177
//Commented out the #define and all traces of interruptPin4, and freezes at loop 312
//With all 4 as real pins, tried moving the block of detachInterrupt calls around (ie. after processor is re-woken), didn't seem to make a difference
uint32_t loopCount = 1;
bool DEBUG = false;
void setup()
{
Serial.begin(115200); //Start Serial
if(DEBUG) Serial.println("\npinMode 1...");
if(DEBUG) delay(30);
pinMode(interruptPin1, INPUT_PULLUP);
if(DEBUG) Serial.println("\npinMode 2...");
if(DEBUG) delay(30);
pinMode(interruptPin2, INPUT_PULLUP);
if(DEBUG) Serial.println("\npinMode 3...");
if(DEBUG) delay(30);
pinMode(interruptPin3, INPUT_PULLUP);
if(DEBUG) Serial.println("\npinMode 4...");
if(DEBUG) delay(30);
pinMode(interruptPin4, INPUT_PULLUP);
if(DEBUG) Serial.println("\nOk");
}
void loop()
{
Serial.print("Running loop #"); Serial.println(loopCount);
if(loopCount > 10000)
DEBUG = true;
loopCount++;
goToSleep(10);
// setup();
}
//Power everything down and wait for interrupt wakeup
void goToSleep(int sleepTimeMs)
{
Serial.println("Starting goToSleep()");
msToSleep = sleepTimeMs;
sysTicksToSleep = msToSleep * TIMER_FREQ / 1000;
awakeFlag = false;
Serial.end(); //Power down UART(s)
am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0);
disableMyGpios();
if(sleepTimeMs == 0)
configureForDeepSleep(GPIO_WAKE);
else
configureForDeepSleep(GPIO_TIMER_WAKE);
//Go to Deep Sleep.
am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP);
/////////////////////////////////////////////////////////////////////
// (and/or while interrupt routines run)//
/////////////////////////////////////////////////////////////////////
//Turn off timer interrupt
NVIC_DisableIRQ(STIMER_CMPR6_IRQn);
//Turn off GPIO interrupt (necessary if timer triggered the wake-up)
detachInterrupt(digitalPinToInterrupt(interruptPin1));
detachInterrupt(digitalPinToInterrupt(interruptPin2));
detachInterrupt(digitalPinToInterrupt(interruptPin3));
detachInterrupt(digitalPinToInterrupt(interruptPin4));
// //Shouldn't, and doesn't do anything
// am_hal_gpio_pinconfig(interruptPin1, g_AM_HAL_GPIO_DISABLE);
// am_hal_gpio_pinconfig(interruptPin2, g_AM_HAL_GPIO_DISABLE);
// am_hal_gpio_pinconfig(interruptPin3, g_AM_HAL_GPIO_DISABLE);
// am_hal_gpio_pinconfig(interruptPin4, g_AM_HAL_GPIO_DISABLE);
//We're BACK!
wakeFromSleep();
//Doesn't actually go here, since setup() is called in wakeFromSleep()
Serial.println("End of goToSleep()");
}
void configureForDeepSleep(int wakeOption)
{
if(wakeOption == GPIO_WAKE || wakeOption == GPIO_TIMER_WAKE)
{
//It doesn't seem to matter whether they have the same ISR, or different ones
attachInterrupt(digitalPinToInterrupt(interruptPin1), myGPIO_ISR1, FALLING);
attachInterrupt(digitalPinToInterrupt(interruptPin2), myGPIO_ISR2, FALLING);
attachInterrupt(digitalPinToInterrupt(interruptPin3), myGPIO_ISR3, FALLING);
attachInterrupt(digitalPinToInterrupt(interruptPin4), myGPIO_ISR4, FALLING);
}
power_adc_disable(); //Power down ADC. It it started by default before setup().
//Disable all pads except the interrupt button
//Pads must be disabled beforehand
if(wakeOption == TIMER_WAKE || wakeOption == GPIO_TIMER_WAKE)
{
//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);
if(wakeOption == TIMER_WAKE || wakeOption == GPIO_TIMER_WAKE)
am_hal_stimer_compare_delta_set(6, sysTicksToSleep); //Setup interrupt to trigger when the number of ms have elapsed
//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();
if(wakeOption == TIMER_WAKE || wakeOption == GPIO_TIMER_WAKE)
NVIC_EnableIRQ(STIMER_CMPR6_IRQn); //Enable the timer interrupt in the NVIC.
}
//Power everything up gracefully
void wakeFromSleep()
{
if(!awakeFlag) //Processor already awake (probably from GPIO ISR)
recoverFromDeepSleep();
setup();
}
void recoverFromDeepSleep()
{
//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);
ap3_adc_setup(); //Turn on ADC
awakeFlag = true; //Indicate this routine doesn't need to be called again
}
// Disable any GPIOs that might be the source of stray or leaking current going in or out of the Apollo3.
void disableMyGpios()
{
for (int i = 0; i <= 49; i++)
{
if(i==interruptPin1 || i==interruptPin2 || i==interruptPin3 || i==interruptPin4)
{} //Don't disable
else
am_hal_gpio_pinconfig(i, g_AM_HAL_GPIO_DISABLE);
}
}
// GPIO Interrupt Service Routine
void myGPIO_ISR1(void)
{
detachInterrupt(digitalPinToInterrupt(interruptPin1)); //Stop interrupt from being triggered again
recoverFromDeepSleep(); //Wake the processor, but don't do anything fancy like initialising Serial or whatever
// am_hal_stimer_compare_delta_set(6, 0); //Or, force the timer to run out, and resume from where you left off.
}
// GPIO Interrupt Service Routine
void myGPIO_ISR2(void)
{
detachInterrupt(digitalPinToInterrupt(interruptPin2)); //Stop interrupt from being triggered again
recoverFromDeepSleep(); //Wake the processor, but don't do anything fancy like initialising Serial or whatever
// am_hal_stimer_compare_delta_set(6, 0); //Or, force the timer to run out, and resume from where you left off.
}
// GPIO Interrupt Service Routine
void myGPIO_ISR3(void)
{
detachInterrupt(digitalPinToInterrupt(interruptPin3)); //Stop interrupt from being triggered again
recoverFromDeepSleep(); //Wake the processor, but don't do anything fancy like initialising Serial or whatever
// am_hal_stimer_compare_delta_set(6, 0); //Or, force the timer to run out, and resume from where you left off.
}
// GPIO Interrupt Service Routine
void myGPIO_ISR4(void)
{
detachInterrupt(digitalPinToInterrupt(interruptPin4)); //Stop interrupt from being triggered again
recoverFromDeepSleep(); //Wake the processor, but don't do anything fancy like initialising Serial or whatever
// am_hal_stimer_compare_delta_set(6, 0); //Or, force the timer to run out, and resume from where you left off.
}`
Expected behaviour
The code should just keep on running forever.
Actual behaviour
It stops at repeatable points during a call to pinMode
The text was updated successfully, but these errors were encountered: