Best Low Pwr option with ISR every 5s E402

I have an E402 based device which presently deep sleeps and wakes hourly. It is powered by solar and has a 5Ah battery. We wish to use an interrupt to track a pulse which happens roughly every 5s (can vary and be more or less).

Working code tracks the interrupt in an Always ON state during testing, but I want to reduce power use and am considering STOP mode in a loop to track interrupts between hourly cellular wake ups.

Unfortunately, although it was considered, an external counter cannot be used to solve the problem due to things beyond our control.

Is this the best approach or is there a better way to consider? Will it even help with such short times between ISRs?

Thanks!

5 seconds is workable, but just barely on the edge of what is feasible.

Make sure you disable the cloud connection and cellular modem, as if these are activated, you will not be able to wake up and sleep fast enough. This should allow you to wake, check the wake reason, increment the counter, and go back to sleep.

Only establish the cloud connection on your once-per-hour schedule.

You'll also need a runtime interrupt handler to count the interrupts when connecting to the cloud.

This will be close, but there is always a possibility you will miss a pulse if it occurs right around the time you are going to sleep or waking up.

You'd have to test to be sure if it actually saves power, but it probably will, especially on the STM32F205 (E402). The savings would be far lower on the nRF52 because it has a lower idle current.

2 Likes

In the main loop which runs once per Particle connection we check a number of things and this includes setting up an interrupt. Here's some pseudo code to highlight the important bits.

//setup
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);

... main loop starts....
//part of main loop
attachInterrupt(A1, pulseInc1, CHANGE);

...more things happen, then...

//Disconnect from network in anticipation of sleeping
Particle.disconnect();
waitFor(Particle.disconnected, 10000);

Cellular.disconnect();
delay(5000);
Cellular.off();
waitFor(Cellular.isOff, 60000);
delay(10000);

// After disconnection I'm anticipating adding this to handle the STOP

uint32_t hourlyCycle = millis();
uint32_t hourlyCycleEnd = hourlyCycle + 3300000;
while(hourlyCycle < hourlyCycleEnd){
hourlyCycle = millis();
System.sleep(A1,RISING,3300);
/Something like this is intended to allow multiple sleeps until the cycle ends
thinking it through on the fly here
- not sure if I can double this up on the attachInterrupt
on A1 or should just use time without a pin wakeup.
/
}

The pulse starts with a falling edge followed by a rising edge within 20-30ms. So the sleep should ideally happen afer each rising edge I think. Hopefully that's enough time to wake on the fall and catch the pulse in the interrupt. I guess some testing may be needed.

I've done a bit of testing over the weekend on this. I used SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);

Set up sleep as follows (removed waking on the edge in my previous post):
SystemSleepConfiguration config;
config.mode(SystemSleepMode::STOP)
.duration(60s);
//I had an edge wakeup here on my pulse pin, but I've now removed that and run time only

In main loop I run:
attachInterrupt(A1, pulseInc1, CHANGE);

I disconnect and power down cellular verifying with
waitFor(Cellular.isOff, 60000);

But, I found that the timeout based approach failed because the millis(); response wasn't consistent. For instance I first tried sleep for 3300s and it didn't wake up for hours and hours before I stopped the test. So I tested sleep for 10s but when checking the millis(); between iterations I got values that were lower than I expected. So instead I set a sleep time of 60s and am running in a 'for' loop through 55 iterations to approximate 55min. ie.

for(uint8_t min = 0; min < 55; min++){
//some debug code to print the pulse count and elapsed minutes
System.sleep(config);
}
//after this the main loop() restarts.

The count is accurately being verified in my debug output now unlike with my approach using millis(). Some basic testing also shows that multiple pulses are being picked up during STOP sleep. My next step is a longer test to verify that the loop cycles correctly using this approach, and that the pulse count is accurately taken while the unit is is STOP mode. Then I intend to extend the STOP mode time from 60s up and see if I can just set it for 55 minutes while counting in the background. I had previously understood that the ISR would end STOP mode, but that seems wrong, so I think I can just have the ISR happily incrementing a retained variable while I wait for 55 minutes and start my main loop again.

Oh one other thing I need to test is that in the pulse detection ISR I'm checking pulse width of 5ms-40ms by the use of millis() as well. I may need to change my approach here because I'm not sure that's going to work if the millis() return wasn't correct during STOP. It could be unstable now. I might need to accept that only rising edges should be counted or something less strict.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.