Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

espressif: Pins preserved during deep-sleep cannot be toggled after wakeup #9622

Open
Sola85 opened this issue Sep 14, 2024 · 6 comments
Open

Comments

@Sola85
Copy link

Sola85 commented Sep 14, 2024

CircuitPython version

Adafruit CircuitPython 9.1.1 on 2024-07-23; Waveshare ESP32-S3-Zero with ESP32S3
Adafruit CircuitPython 9.1.3 on 2024-08-30; Waveshare ESP32-S3-Zero with ESP32S3
Adafruit CircuitPython 9.1.3 on 2024-08-30; ESP32-S3-DevKitM-1-N8 with ESP32S3

Code/REPL

import alarm, board, time
from digitalio import DigitalInOut

led = DigitalInOut(board.IO1)
led.switch_to_output()
led.value = 1

time.sleep(1)

led.value = 0
time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 10)
alarm.exit_and_deep_sleep_until_alarms(time_alarm, preserve_dios=[led])

Behavior

The led blinks once and then remains dark until the chip is reset.

Excpected behaviour: Led blinks once every 10 seconds.

Description

This happens in both fake deep sleep as well as in real deep sleep.

If preserve_dios=[led] is omitted, the led blinks brightly and glows dimly during deep sleep and becomes bright again after deep sleep (which is correct behaviour as far as I know).

Additional information

No response

@Sola85 Sola85 added the bug label Sep 14, 2024
@Sola85
Copy link
Author

Sola85 commented Sep 14, 2024

After some tinkering I found a workaround: Calling .deinit() on the stuck pins causes them to reset to a working state, e.g.

led = DigitalInOut(board.IO1)
led.deinit()
led = DigitalInOut(board.IO1) #led works again

The reason for this issue seems to be that preserve_pin_number() calls gpio_hold_en() but the corresponding call to gpio_hold_dis() only happens in _reset_pin() and _reset_pin() is not called after wake from deep sleep, hence the gpio hold is never disabled.

The workaround works because .deinit() calls _reset_pin() and therefore also gpio_hold_dis().

Not sure what the best strategy would be to fix this. Reset every pin after wake from deepsleep? Or call gpio_hold_dis() on all pins after wake?

@tannewt
Copy link
Member

tannewt commented Sep 16, 2024

Or call gpio_hold_dis() on all pins after wake?

I think the DigitalInOut constructor should call this. It is taking control back over from the hold. Want to make a PR for this? Thanks for testing!

@Sola85
Copy link
Author

Sola85 commented Sep 17, 2024

I think the DigitalInOut constructor should call this.

I thought about this too but wasn't sure: Would it be only DigitalInOut, or every class that manages a pin? Like PWMOut, AnalogOut, I2C/SPI, ... Thats why I thought managing it centrally could maybe be easier

@tannewt
Copy link
Member

tannewt commented Sep 18, 2024

I think DigitalInOut would be enough because that is what preserve_dios takes.

@Sola85
Copy link
Author

Sola85 commented Sep 18, 2024

But DigitalInOut might not necessarily be the first object to take control of the pin after deepsleep.

@tannewt
Copy link
Member

tannewt commented Sep 19, 2024

But DigitalInOut might not necessarily be the first object to take control of the pin after deepsleep.

Ya, that's true. I wonder if we should detect that a pin is held and then make a DigitalInOut available for it. Then you would need to deinit it to use it for something else. Otherwise we have to decide when to un-hold the pin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants