ESP8266 keep pin states during deepsleep - ESP8266 Register configuration

I did a lot of googling and could not find my answer, nor a hint.
I have experience with the MCP23017, know about pull-ups, I2C and I am also using interrupt with MCP23017.

In short: can the MCP23017 output an interrupt and keep output pin states while the microcontroller is in deepsleep and there is no bus activity (no clock signal on SCL)?

In long:
Setup: ESP8266 as single I2C master, MCP23017 (configured to output interrupt on pin change on the desired pin)
Adafruit mcp23017 library
Mirroring active for intA and intB
Interrupt open drain (active LOW)
Pull-ups 1,8k for SCL and SDA
MCP23017 and ESP-12@ 3,3V
Interrupt works perfectly when ESP is running
Reset pin of MCP23017 is not left unconnected
All on a decent PCB that I designed, so no crappy connections

Now I successfully send the ESP-12 module (which I use here) to deepsleep.

What I want to do:
I want the MCP23017 to set interrupt just as normal but when there is no I2C bus activity (because ESP is sleeping).

What I tried after failing - besides googling and reading MCP datasheet 4 times:
call wire.endTransmission();
before sending the ESP to deepsleep, also added 1000ms delay between the commands
Intention of that: to free the bus, so that SDA/SCL are not held LOW in case that this could block the MCP23017 from setting its interrupt internally (would make no sense to me, but try-and-error before asking stupid questions)
Then I verified that Wire.endTransmission(true); behaves the same (without argument it defaults to true, while the argument „false“ should block the bus)

I cannot really accept to block the bus if that was necessary because i have to have very low standby current - but point out if that would work...
I suppose that MCP23017 goes to some sleep mode itself because of lacking bus activity, because if I drive a LED from another IO pin of the MCP23017, it also switches off shortly after the ESP enters deepsleep (within 1s).

I cannot find any documentation nor projects that tried that, so I am lost and hope for some input.

Sidenote: What I really intend to do is to wake up the ESP from deepsleep by the interrupt of MCP23017.
To achieve that I designed a pretty neat and cheap circuit (around 1€ In parts ) that does not need an attiny or any programming to reset the ESP, and that can have multiple different wakeup-sources that can be enabled or disabled seperately (like a SIM800L Module in my case), so that I could call the device and cause a wakeup, or even a reset during operation, but this can also be blocked. As second wakeup-source I need the MCP23017‘s interrupt pin.

Now that all relies on the idea that MCP23017 will keep its configuration while the microcontroller sleeps, but it does not seem to do so.
As I am controlling the reset pin of MCP23017 with D3/GPIO0 I should triple check that this pin does not output a short low pulse when entering deepsleep, but according to some other guy who measured pin behaviour (Deep sleep, reset & restart behaviour by pin - Everything ESP8266)
it does not drop below 1,8 V, and MCP23017 reset Pin should recognize LOW signal only below 0,5V when powered @3,3V.
Also D3/GPIO0 should have some weak pull-up in deepsleep, so that the pin is not floating.

Before I start deepdiving in pin behavior of ESP-12 I would like to know if it is generally possible to have an MCP23017 to interrupt and to keep output pin states while there is no I2C bus activity.

Lademeister:
Before I start deepdiving in pin behavior of ESP-12 I would like to know if it is generally possible to have an MCP23017 to interrupt and to keep output pin states while there is no I2C bus activity.

Considering the I2C bus is idle when not in use (no clock signal) and the MCP23017 keeps its states throughout, no problem there.

Why do you even think the MCP would care about bus activity other than what is addressed to itself?

I didn’t even ask myself the question before encountering that it does not keep its values nor set an interrupt if bus is idle.
I was sure it would behave just as you pointed out, but it doesn’t.

Why I think it could take care about bis activity: I’ve read some posts about a rather undocumented low-power/sleep feature of MCP23017, which should use something in the microamps range, but the datasheet does not point out how to reach that state.
So I thought it might just enter some sleep state when there is no bus activity.
This could cause my experienced behavior, so I wanted to know if anyone can tell if it is possible to keep MCP23017 „alive“ during inactive bus.
Maybe you are right and the MCP would behave as desired and I have some other issue, but I am missing a definite answer if it is possible to have the MCP23017 output an interrupt even after days of no bus activity.

Lademeister:
I didn’t even ask myself the question before encountering that it does not keep its values nor set an interrupt if bus is idle.
I was sure it would behave just as you pointed out, but it doesn’t.

Then there's obviously something else wrong with your circuit, because my experience with that IC is that it keeps its pins perfectly well with the I2C bus idle. It keeps its pin settings over resets of the main controller even. I never used the interrupt function but no reason to believe that works different.

Wow, that’s what I wanted to hear :slight_smile:
Thank you so much. That confirms my assumption.
If it is able to keep pin states on idle bus it definitely will also be able to set interrupt, I agree on that.

Topic solved for me - I will dig into ESP8266 pin behaviour then. The reason for my problem must be an unwanted low spike of GPIO0 of my ESP-12 module while entering deepsleep. This seems to reset my MCP23017, because I have ESP-12 GPIO0 connected to MCP23017 reset pin.

I will try a additional pullup and if that doesn’t help I will have to add a lowpass filter.

Thank you very much for confirming MCP23017 behavior on uC sleep!

Just having that pin set to INPUT may cause a reset if you don't have an external pull-up.

I don't know what the ESP pins do in deep sleep, never used that function.

The pin of my ESP-12 module that I use for resetting MCP23017 is definitely set as output - but ESP deepsleep will make all pins lose their configuration, thus leaving some pins floating. Others do have internal (or need external) pull-up or pull-down.
In my case I chose ESP8266 GPIO0 for my reset line because this pin needs to be held LOW for flashing new sketch, thus all other devices like my MCP23017 are held in reset state during flashing. May not be necessary but seemed a good approach to me.

Nevertheless it seems that I may still need a pull-up or a low pass filter on GPIO0 because ESP8266 will have short spikes from 3,3V towards 1,5V or lower while entering deepsleep.
They might be enough to reset MCP23017.

I did a lot of googling and some guy tested the behavior of the pins of an ESP8266 using an oszilloscope during boot, another guy did that for ESP8266 while entering deepsleep.
Somehow the outcome of those analyses seem not to correspond completely with what I experience, so before doubting some detailed oscilloscope measurements I thought that I should doublecheck first if my bare assumption is correct that MCP23017 will continue operation normally even when I2C bus is idle.

As confirmed by wvmarle above this should be the case.
In case someone finds this post, let me point out that an Arduino (Armega328P) will keep its pin states during deepsleep, but not an ESP8266.
An easy solution might be to just use a pull-up resistor to VCC on MCP23017 reset pin and not to connect it to any pin of the microcontroller.
But as I have a quite remote usecase for my system I wanted to be able to reset the MCP23017 as well, although I did never read about issues with that chip that would need to hardreset it. But you never know...

You can of course use another pin of the ESP, then reset the MCP in the setup() function.

Use an external pull-up (10k or so) on that pin; then setting that pin to OUTPUT, LOW for a short time (I'm sure you can find the minimum in the data sheet) resets the MCP. Set the pin to INPUT afterwards so the pull-up resistor does its job and there should be no issue when going to deep sleep as the pin is INPUT already.

Hello wvmarle,
I did some testing now and still could not solve the problem.
I could narrow down the problem though.
The MCP23017 will work as desired, it is definitely a problem that is caused by ESP8266.
I suppose that ESP8266 outputs some oscillating voltage level after entering deepsleep.
I verified the resetting behavior with ESP-12 as well as Wemos D1 Mini. I am currently bound to use GPIO3 (or D3 on Wemos D1 Mini).
I decided to use that pin because it has to be LOW during flashing anyways which greatly combines with holding reset LOW for the rest of the electronics, so I want to stick to that GPIO.
I already have a pullup resistor in my circuit, and besides that the Wemos hardware Layout also has a unique one, so when using Wemos D1 Mini I even had 5K pullup and not 10k.

I think I have to add a hardware lowpass filter to get rid of the problem, but I still don’t know why I encounter it at all.

Confirmed: MCP23017 will set its interrupt when Microcontroller is in deepsleep as desired as long as RST is not connected to GPIO0 (only pullup to 3V3).
If connected to GPIO0:
When ESP8266 enters deepsleep, approximately 1-2 seconds later(!) MCP23017 gets resetted.
This happens
-if GPIO0 is set as OUTPUT HIGH
-if GPIO0 is set as INPUT_PULLUP
before entering deepsleep.

It does have to do nothing with I2C bus, as I have been calling Wire.endTransmission() before entering deepsleep and have been probing if that function returns 0 (success).
Afterwards I did set the I2C pins of esp8266 to input_pullup just to be absolutely sure that the bus is freed.

So, my problem is that ESP8266 GPIO obviously outputs a LOW pulse after entering deepsleep.

Where it really gets me is that the reset does not happen while entering deepsleep but shortly after.

I am trying to figure out if that could be prevented somehow, and where it comes from at all.
I did google a lot about that as well, but the closest I came to an answer was this post, where somebody oscilloscoped all ESP8266 pins during run, deepsleep and restart using different pullups or none at all.
Pretty neat.
https://www.esp8266.com/viewtopic.php?f=5&t=11282
In the diagram one can see that GPIO0 only drops to approximately 2.8V when using a 10k pullup, which should not lead to a reset of an MCP23017 connected with its RST pin to GPIO0.
Besides being not sure which frequency I would have to tune a low pass filter to as a workaround (1Hz?—> needs large cap) I would still like to find out what is causing this and if I could prevent that using software.

I do not know deeply enough what else could fire a low pulse inside ESP8266 on that pin, and also the oscilloscope readings in the link above seem to have no indication that it should happen at all.
Keep in mind that the low pulse obviously happens 1 or 2s later, maybe this time stamp is not included in the oscilloscope readings.

Lademeister:
The pin of my ESP-12 module that I use for resetting MCP23017 is definitely set as output - but ESP deepsleep will make all pins lose their configuration, thus leaving some pins floating.

Where does it say that the ESP8266 resets all its pin modes on deep sleep? :astonished:

Not totally sure about that, but this thread addresses the topic:

Fascinating.

This suggests that the device is almost useless in Deep Sleep mode.

Now of course we would expect that to happen when Enable is low, so it seems the only advantage of Deep Sleep is that it retains some - but not all - state and starts faster.

Never mind, I was only intending to use the Enable as a zero power standby anyway. :roll_eyes:

I found some espressif documentation today that clearly states that there are registers to configure pin state behavior during deep sleep, it is also possible to set pullups.
This topic addresses that (link is to page 3 of the thread):
https://www.esp8266.com/viewtopic.php?f=23&t=13616&p=82916&hilit=Gpio14#p82916

The problem I now have is the lack of unterstanding on my side.
An example code to set GPIO 14 to pullup-enable in deepsleep was postet within this thread, but reading all datasheets from espressif I cannot figure out how the example code (GPIO14) relates to any Register address in the datasheets (also linked in the thread)

Getting a little off topic now so I would like to see if someone could help me with my problem, but I should open a new topic because it turned out that the problem is not MCP23017 related but ESP8266...

Lademeister:
Getting a little off topic now so I would like to see if someone could help me with my problem, but I should open a new topic because it turned out that the problem is not MCP23017 related but ESP8266...

If you cross post, then it will likely be reported as such to the moderators and joined back to this post to ensure clarity. :astonished:

You may alter the topic of your original post at the top to better describe the problem.

Good point. Just adapted the topic