Modules like the ESP8266 which have no on-board regulator but do need a regulated power supply. Indeed, a power supply voltage that is too low will cause the module to reset.
What I would do in your case is get a boost module like this one to convert the voltage from the batteries to 3.3 V. On the module there's a trimmer to set the output to 3.3 V, set this BEFORE connecting the ESP8266 because such an upconverter module can easily generate 12 V which would fry the ESP module !
You go to sleep unconditionally in every iteration of loop()
. That's not what you want. The way your code is now, you'll miss every wake up event that happens while your normal program code runs.
Your code spends most of the time delaying inside flash()
. And the controller goes to sleep after flash()
is done. Always. This means that whenever a wake up event occurrs while the LED is flashing, it will not cause a wake up. That's just because the interrupt occurred and was serviced before you went to sleep.
Have a look at the example in the avr-libc docs here.
Your code should look like this:
void loop(){
cli(); // Disable interrupts to avoid race condition.
if ( !resetEsp ) {
// Only go to sleep if we have nothing to do right now.
// Safe(*) code from the example in avr-libc:
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
} else {
sei(); // Can go on processing IRQs.
}
if (resetEsp) {
cli();
resetEsp = false; // clear the flags
resetEnabled = false;
sei();
digitalWrite(pinRST, LOW); // reset the ESP
delayMicroseconds(240);
digitalWrite(pinRST, HIGH); // let the ESP Boot
flash(10, 50); // flash the led fast to show we're waking the ESP
} else if (resetEnabled) {
flash(10, 500); // mostly never get here
} else {
flash(2, 500); // these are the flashes I see most of the time
}
}
The point here is that we disable all interrupts while we check to see if we want to go to sleep. This way, we make sure that no interrupt can happen after we checked but before we actually sleep.
Is is crucial, however, that we enable interrupts again just before going to sleep, or we will never be woken up again.
Also, @jms is right in stating that you have another potential race codition when resetting your flags, so include some cli/sei there too.
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
can go into setup()
. And if you're not controlling spacecraft the same goes for sleep_enable();
, while omitting sleep_disable();
completely.
(*) The code labelled "safe" above is not absolutely bullet-proof because, in theory, during optimization the compiler could decide to reorder some instructions so that sei()
and sleep_cpu()
could end up not being in direct sequence. To be absolutely safe, check the generated assembler code (gcc -save-temps
), or just write the reqired instructions as inline assembler yourself. (Can be as simple as asm volatile (" sei \r\n sleep \r\n " :::);
.)
Best Answer
There are generally three classes of issue here:
Generally speaking there are two worthwhile paths you could pursue:
Another option to using a high-side switch is to find a 3v3 regulator to feed the ESP8266 which has an enable input, and drive that.