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

deep sleep works the first time it is called for the set time and then the microcontroller always wakes up again immediately #7300

Closed
BeatArnet opened this issue Dec 3, 2022 · 6 comments · Fixed by #7359 or #7441

Comments

@BeatArnet
Copy link

CircuitPython version

Adafruit CircuitPython 8.0.0-beta.4-57-ge82a8bf8b on 2022-11-30; Adafruit Feather ESP32-S3 TFT with ESP32S3

Code/REPL

# Powering down TFT-display and sensors
p.value = False 

# Create a an alarm that will trigger 120 seconds from now.
time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 120)
# Exit the program, and then deep sleep until the alarm wakes us.
print ("120 seconds in deep sleep")
alarm.exit_and_deep_sleep_until_alarms(time_alarm)
# Does not return, so we never get here.

Behavior

First time after booting: waits 120 seconds in deep sleep
Second time and the following: immediately wakes up again and starts

Description

No response

Additional information

No response

@BeatArnet BeatArnet added the bug label Dec 3, 2022
@tannewt tannewt self-assigned this Dec 5, 2022
@tannewt tannewt added this to the 8.0.0 milestone Dec 5, 2022
@tannewt
Copy link
Member

tannewt commented Dec 5, 2022

I'm not seeing this behavior on an ESP32-S3 USB OTG board. Here is my bootloader output showing repeated 2 minute deep sleeps:

[00:02:06.793] ESP-ROM:esp32s3-20210327
[00:00:00.006] Build:Mar 27 2021
[00:00:00.000] rst:0x5 (DSLEEP),boot:0x8 (SPI_FAST_FLASH_BOOT)
[00:00:00.005] pro cpu reset by JTAG
[00:00:00.000] SPIWP:0xee
[00:00:00.000] mode:DIO, clock div:1
[00:00:00.000] load:0x3fce3808,len:0x68
[00:00:00.005] load:0x403c9700,len:0x980
[00:00:00.000] load:0x403cc700,len:0x25a0
[00:00:00.005] SHA-256 comparison failed:
[00:00:00.000] Calculated: ba9b2d4eb238d33c8b2df1f10920a53b5a565dd3a0a23ff135232249c77b4a85
[00:00:00.005] Expected: bd6e2eb493ec8e2143cb0d39c23b5c2005f98ed268d8910021afbdfc58c4fde7
[00:00:00.012] Attempting to boot anyway...
[00:00:00.000] entry 0x403c98a4
[00:02:06.732] ESP-ROM:esp32s3-20210327
[00:00:00.007] Build:Mar 27 2021
[00:00:00.000] rst:0x5 (DSLEEP),boot:0x8 (SPI_FAST_FLASH_BOOT)
[00:00:00.005] SPIWP:0xee
[00:00:00.000] mode:DIO, clock div:1
[00:00:00.000] load:0x3fce3808,len:0x68
[00:00:00.005] load:0x403c9700,len:0x980
[00:00:00.000] load:0x403cc700,len:0x25a0
[00:00:00.000] SHA-256 comparison failed:
[00:00:00.005] Calculated: ba9b2d4eb238d33c8b2df1f10920a53b5a565dd3a0a23ff135232249c77b4a85
[00:00:00.005] Expected: bd6e2eb493ec8e2143cb0d39c23b5c2005f98ed268d8910021afbdfc58c4fde7
[00:00:00.005] Attempting to boot anyway...
[00:00:00.004] entry 0x403c98a4
[00:02:06.705] ESP-ROM:esp32s3-20210327
[00:00:00.006] Build:Mar 27 2021
[00:00:00.000] rst:0x5 (DSLEEP),boot:0x8 (SPI_FAST_FLASH_BOOT)
[00:00:00.005] SPIWP:0xee
[00:00:00.000] mode:DIO, clock div:1
[00:00:00.000] load:0x3fce3808,len:0x68
[00:00:00.005] load:0x403c9700,len:0x980
[00:00:00.000] load:0x403cc700,len:0x25a0
[00:00:00.000] SHA-256 comparison failed:
[00:00:00.005] Calculated: ba9b2d4eb238d33c8b2df1f10920a53b5a565dd3a0a23ff135232249c77b4a85
[00:00:00.005] Expected: bd6e2eb493ec8e2143cb0d39c23b5c2005f98ed268d8910021afbdfc58c4fde7
[00:00:00.005] Attempting to boot anyway...
[00:00:00.004] entry 0x403c98a4

My test code is:

import alarm
import time
import board


board.DISPLAY.brightness = 1
time.sleep(1)

# Create a an alarm that will trigger 120 seconds from now.
time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 120)
# Exit the program, and then deep sleep until the alarm wakes us.
print ("120 seconds in deep sleep")
board.DISPLAY.brightness = 0
alarm.exit_and_deep_sleep_until_alarms(time_alarm)
# Does not return, so we never get here.

@tannewt
Copy link
Member

tannewt commented Dec 5, 2022

Version: Adafruit CircuitPython 8.0.0-beta.4-75-gd7874e65c on 2022-12-05; ESP32-S3-USB-OTG-N8 with ESP32S3

@sas42
Copy link

sas42 commented Dec 6, 2022

Version tested 12/6/2022 2:20 pm est
Adafruit CircuitPython 8.0.0-beta.4-77-g5cb867e85 on 2022-12-06; Adafruit Feather ESP32S3 No PSRAM with ESP32S3

This code does not even go into light sleep much less deep sleep

import alarm
import time
import board
import digitalio

# board.DISPLAY.brightness = 1

led = digitalio.DigitalInOut(board.LED)
led.switch_to_output(True)
time.sleep(2)
led.value = False

# Create a an alarm that will trigger 120 seconds from now.
time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 30)
# Exit the program, and then deep sleep until the alarm wakes us.
print ("30 seconds in deep sleep")
# board.DISPLAY.brightness = 0

led.value = True
alarm.exit_and_deep_sleep_until_alarms(time_alarm)

@BeatArnet
Copy link
Author

Latest uf2-File installed - no change in behaviour: First time: 120 seconds sleep, from then on starts immediately

#Adafruit` CircuitPython 8.0.0-beta.4-77-g5cb867e85 on 2022-12-06; Adafruit Feather ESP32-S3 TFT with ESP32S3
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

# Adafruit esp32-s3 TFT feather Board
# mit drei Sensoren:
# - Distanz vl53l4cd
# - Helligkeit bh1750
# - Luftqualität, Luftdruck, Temperatur, Feuchtigkeit, Höhe über Meer bme680
# Soll die Distanz zur Wasseroberfläche messen, aber dank der Sensorenabschaltung im DeepSleep auch über Tage messen können
# Beat Arnet, 01.10.2022
# art, 13.10.2022
#    Es fehlt noch der Schlafmodus und die Messung der Batteriespannung
# art, 15.10.2022
# Circuitpython 8.0.0 Beta 4 installiert und die beiden bisher nicht funktionierenden Funktionen getestet;
# - Batteriespannung messen: Funktioniert nur mit vorangehendem i2c-Scanning
# - deep sleep funktioniert nicht, auch wenn nur Batterie angehängt ist. der esp32 startet sofort wieder und macht keine Pause

import time
import alarm
import board
import digitalio
import adafruit_bme680
import adafruit_bh1750
import adafruit_vl53l4cd
from adafruit_lc709203f import LC709203F, PackSize
import displayio
import terminalio
from adafruit_display_text import label
import ssl
import socketpool
import wifi
import adafruit_minimqtt.adafruit_minimqtt as MQTT
import json
import gc

board.TFT_I2C_POWER
# TFT_I2C_POWER initialisieren
p = digitalio.DigitalInOut(board.TFT_I2C_POWER)
p.switch_to_output()   # turned the display OFF (default output is False)
p.value = True  # Display und Sensoren einschalten

# Create sensor object, communicating over the board's default I2C bus
i2c = board.I2C()  # uses board.SCL and board.SDA
bme680 = adafruit_bme680.Adafruit_BME680_I2C(i2c, debug=False)
bh1750 = adafruit_bh1750.BH1750(i2c)
vl53 = adafruit_vl53l4cd.VL53L4CD(i2c)

# TFT-Display initialisieren
# built-in display
display = board.DISPLAY

# Make the display context
main_group = displayio.Group()
display.show(main_group)

# change this to match the location's pressure (hPa) at sea level
bme680.sea_level_pressure = 995.0

# You will usually have to add an offset to account for the temperature of
# the sensor. This is usually around 5 degrees but varies by use. Use a
# separate temperature sensor to calibrate this one.
temperature_offset = -5

# OPTIONAL: can set non-default values
vl53.inter_measurement = 0
vl53.timing_budget = 200

# Der nachfolgende Code zum Scannen der I2C-Adressen ist notwendig, damit die Spannung gemessen werden kann
BATTERY_MON_ADDRESS = 0x0B  # Address for ESP32-s3 tft Feather

def hack_for_i2c_issue():
    i2c = board.I2C()
    while not i2c.try_lock():
        pass
    running = True
    try:
        while running:
            print("I2C addresses found:", 
                [hex(device_address) for device_address in i2c.scan()]
            )
            # time.sleep(2)
            running = False
        return i2c
    finally:  # unlock the i2c bus when ctrl-c'ing out of the loop
        i2c.unlock()

try:
    print("Searching for battery monitor...")

    # There is a known issue with the ESP32-S3: 
    # https://github.com/adafruit/circuitpython/issues/6311
    # Therefore this will not work -> board.I2C()
    i2c = hack_for_i2c_issue()
    battery_monitor = LC709203F(i2c)

    # Update to match the mAh of your battery for more accurate readings.
    # Can be MAH100, MAH200, MAH400, MAH500, MAH1000, MAH2000, MAH3000.
    # Choose the closest match. Include "PackSize." before it, as shown.
    battery_monitor.pack_size = PackSize.MAH2000  # type: ignore

    print(f"Battery Percent: {battery_monitor.cell_percent:.2f} %")
    print(f"Battery Voltage: {battery_monitor.cell_voltage:.2f} V")
    time.sleep(1)

except Exception as e:
    print(f"Error reading battery: {e}")
    print("All done.")

yDist = 15
labelTemperatur = label.Label(
    font=terminalio.FONT, scale=1, anchor_point=(0, 0), anchored_position=(10, yDist)
)
labelLuftqualitaet = label.Label(
    font=terminalio.FONT,
    scale=1,
    anchor_point=(0, 0),
    anchored_position=(10, 2 * yDist),
)
labelFeuchtigkeit = label.Label(
    font=terminalio.FONT,
    scale=1,
    anchor_point=(0, 0),
    anchored_position=(10, 3 * yDist),
)
labelLuftdruck = label.Label(
    font=terminalio.FONT,
    scale=1,
    anchor_point=(0, 0),
    anchored_position=(10, 4 * yDist),
)
labelHoehe = label.Label(
    font=terminalio.FONT,
    scale=1,
    anchor_point=(0, 0),
    anchored_position=(10, 5 * yDist),
)
labelHelligkeit = label.Label(
    font=terminalio.FONT,
    scale=1,
    anchor_point=(0, 0),
    anchored_position=(10, 6 * yDist),
)
labelDistanz = label.Label(
    font=terminalio.FONT,
    scale=1,
    anchor_point=(0, 0),
    anchored_position=(10, 7 * yDist),
)
labelSpannung = label.Label(
    font=terminalio.FONT,
    scale=1,
    anchor_point=(0, 0),
    anchored_position=(10, 8 * yDist),
)

# add label to group that is showing on display
main_group.append(labelTemperatur)
main_group.append(labelLuftqualitaet)
main_group.append(labelFeuchtigkeit)
main_group.append(labelLuftdruck)
main_group.append(labelHoehe)
main_group.append(labelHelligkeit)
main_group.append(labelDistanz)
main_group.append(labelSpannung)

# Add a secrets.py to your filesystem that has a dictionary called secrets with "ssid" and
# "password" keys with your WiFi credentials. DO NOT share that file or commit it into Git or other
# source control.
# pylint: disable=no-name-in-module,wrong-import-order
try:
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")
    raise
# Set your Adafruit IO Username and Key in secrets.py
# (visit io.adafruit.com if you need to create an account,
# or if you need your Adafruit IO key.)
aio_username = secrets["aio_username"]
aio_key = secrets["aio_key"]

print("Connecting to %s" % secrets["ssid"])
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to %s!" % secrets["ssid"])
### Feeds ###

# Setup a feed named 'distance' for publishing to a feed
distance_feed = secrets["aio_username"] + "/distance"
light_feed = secrets["aio_username"] + "/light"
soil_feed = secrets["aio_username"] + "/soil"
salt_feed = secrets["aio_username"] + "/salt"
voltage_feed = secrets["aio_username"] + "/voltage"
voltagepercent_feed = secrets["aio_username"] + "/voltagepercent"
batterytemperature_feed = secrets["aio_username"] + "/batterytemperature"
temperature_feed = secrets["aio_username"] + "/temperature"
humidity_feed = secrets["aio_username"] + "/humidity"
airpressure_feed = secrets["aio_username"] + "/airpressure"
altitude_feed = secrets["aio_username"] + "/altitude"
salt_feed = secrets["aio_username"] + "/salt"
wasserfass_feed = secrets["aio_username"] + "/wasserfass"

# Setup a feed named 'switch' for subscribing to changes
switch_feed = secrets["aio_username"] + "/output"

# Define callback methods which are called when events occur
# pylint: disable=unused-argument, redefined-outer-name
def connected(client, userdata, flags, rc):
    # This function will be called when the client is connected
    # successfully to the broker.
    print("Connected to raspiart IO! Listening for topic changes on %s" % switch_feed)
    # Subscribe to all changes on the switch_feed.
    client.subscribe(switch_feed)

def disconnected(client, userdata, rc):
    # This method is called when the client is disconnected
    print("Disconnected from raspiart!")

def message(client, topic, message):
    # This method is called when a topic the client is subscribed to
    # has a new message.
    print("New message on topic {0}: {1}".format(topic, message))

# Create a socket pool
pool = socketpool.SocketPool(wifi.radio)

# Set up a MiniMQTT Client
mqtt_client = MQTT.MQTT(
    broker=secrets["broker"],
    port=secrets["port"],
    username=secrets["aio_username"],
    password=secrets["aio_key"],
    socket_pool=pool,
    ssl_context=ssl.create_default_context(),
)

# Setup the callback methods above
mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_message = message

# Connect the client to the MQTT broker.
print("Connecting to raspiart IO...")
mqtt_client.connect()

# Dummy Werte zur Initialisierung
Temperatur = 20.0
Luftqualitaet = 100.0
Feuchtigkeit = 40.0
Luftdruck = 1000.0
Hoehe = 500.0
Helligkeit = 100.0
Distanz = 1.0
Spannung = 5.0
SpannungProzent = 100.0
AkkuTemperatur = 20.0
Salz = 0.0  # Dummy-Wert, weil der nicht h^gemessen werden kann

Temperatur = bme680.temperature + temperature_offset
Luftqualitaet = bme680.gas
Feuchtigkeit = bme680.relative_humidity
Luftdruck = bme680.pressure
Hoehe = bme680.altitude
Helligkeit = bh1750.lux
SpannungProzent = battery_monitor.cell_percent
Spannung = battery_monitor.cell_voltage
AkkuTemperatur = battery_monitor.cell_temperature

vl53.start_ranging()
while not vl53.data_ready:
    pass
vl53.clear_interrupt()
Distanz = vl53.distance

labelTemperatur.text = "Temperatur:        %0.1f C" % Temperatur
labelLuftqualitaet.text = "Luftqualität:      %d Index" % Luftqualitaet
labelFeuchtigkeit.text = "Feuchtigkeit:      %0.1f %%" % Feuchtigkeit
labelLuftdruck.text = "Luftdruck:         %0.3f hPa" % Luftdruck
labelHoehe.text = "Höhe über Meer:    %0.2f Meter" % Hoehe
labelHelligkeit.text = "Helligkeit:        %.2f Lux" % Helligkeit
labelDistanz.text = "Distanz:           {} cm".format(Distanz)
labelSpannung.text = "Spannung:          {} V, {} %".format(Spannung, SpannungProzent)

print("\nTemperatur:        %0.1f C" % Temperatur)
print("Luftqualität:      %d Index" % Luftqualitaet)
print("Feuchtigkeit:      %0.1f %%" % Feuchtigkeit)
print("Luftdruck:         %0.3f hPa" % Luftdruck)
print("Höhe über Meer:    %0.2f Meter" % Hoehe)
print("Helligkeit:        %.2f Lux" % Helligkeit)
print("Distanz:           {} cm".format(Distanz))
print("Spannung:          {} V, {} %".format(Spannung, SpannungProzent))

# Nachrichten empfangen
try:
    mqtt_client.loop()
except (ValueError, RuntimeError) as e:
    print("Failed to get data, retrying\n", e)
    wifi.reset()
    mqtt_client.reconnect()
    # continue

# Send a new message
print("Es werden nun die Werte via MQTT an den raspiart gesendet")
mqtt_client.publish(distance_feed, Distanz)
mqtt_client.publish(temperature_feed, Temperatur)
mqtt_client.publish(soil_feed, Luftqualitaet)
mqtt_client.publish(light_feed, Helligkeit)
mqtt_client.publish(airpressure_feed, Luftdruck)
mqtt_client.publish(humidity_feed, Feuchtigkeit)
mqtt_client.publish(altitude_feed, Hoehe)
mqtt_client.publish(voltage_feed, Spannung)
mqtt_client.publish(voltagepercent_feed, SpannungProzent)
mqtt_client.publish(batterytemperature_feed, AkkuTemperatur)

wasserfass={
    "distance":Distanz,
    "temperature":Temperatur,
    "soil":Luftqualitaet,
    "light":Helligkeit,
    "pressure":Luftdruck,
    "humidity":Feuchtigkeit,
    "altitude":Hoehe,
    "voltage":Spannung,
    "voltagepercent":SpannungProzent,
    "batterytemeperature":AkkuTemperatur,
    "salt":Salz
}
wasserfass_json=json.dumps(wasserfass)
# print(wasserfass_json)
try:
    mqtt_client.publish(wasserfass_feed,wasserfass_json)
    print("Werte wurden gesendet")
except (ValueError, RuntimeError) as e:
    print("Werte konnten nicht gesendet werden\n", e)

# 5" warten bis zum tiefen Schlaf gewechselt wird
print ("5 Sekunden bei voller Leistung")
time.sleep(5)

# Delete objects before powering down
#del i2c
#del bme680
#del bh1750
#del vl53
#del display
#del battery_monitor
# garbage collector
#gc.collect()
# Powering down TFT-display and sensors
p.value = False 


# Create a an alarm that will trigger 10 seconds from now.
#time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 4)
# Do a light sleep until the alarm wakes us.
#print ("4 Sekunden im leichtem Schlaf")
#alarm.light_sleep_until_alarms(time_alarm)
# Finished sleeping. Continue from here.

# Create a an alarm that will trigger 120 seconds from now.
time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 120)
# Exit the program, and then deep sleep until the alarm wakes us.
print ("120 Sekunden im tiefen Schlaf")
alarm.exit_and_deep_sleep_until_alarms(time_alarm)
# Does not return, so we never get here.

@Neradoc
Copy link

Neradoc commented Dec 8, 2022

In my tests with beta 5, it never goes to deep sleep but just resets, like before I think.
Feather ESP32-S3 TFT

Adafruit CircuitPython 8.0.0-beta.5 on 2022-12-08; Adafruit Feather ESP32-S3 TFT with ESP32S3

Running that code.

import alarm
import time
time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 20)
alarm.exit_and_deep_sleep_until_alarms(time_alarm)

Does not go to deep sleep but resets immediately instead when on power only (USB power adapter or battery).
It does "sleep" for approximately 20 seconds when on USB (fake deep sleep).

Same thing with a UM FeatherS3.

Adafruit CircuitPython 8.0.0-beta.5 on 2022-12-08; FeatherS3 with ESP32S3

@tannewt
Copy link
Member

tannewt commented Dec 9, 2022

I tested this yesterday and found that the ULP was incorrectly waking up the S3. I'll try and sort it out today.

@tannewt tannewt mentioned this issue Dec 10, 2022
4 tasks
dhalbert pushed a commit that referenced this issue Dec 21, 2022
It is now a generic `memorymap` API and an ESP specific `espulp` module.

Fixes #7218. Fixes #3234. Fixes #7300.
dhalbert pushed a commit that referenced this issue Jan 11, 2023
The IDF's wakeup cause is only for deep sleep. Without ignoring it,
light sleep will wake up too early when done after a deep sleep
wake.

Fixes #7300
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants