adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
MIT License
3.97k stars 1.16k forks source link

time.sleep() not working in 6.0.1 in a Blink program #3918

Closed dhalbert closed 3 years ago

dhalbert commented 3 years ago

Splitting this issue off from #3829:

from @dkirkby:

I just followed the Welcome to CircuitPython instructions for writing your first program on a Metro M4, using the recommended stable 6.0.1 and Mu editor, and it is now broken because time.sleep hangs.

Having a working new user tutorial is important, but that could mean simply downgrading the recommended stable release if there isn't a simple fix to the sleep issue.

Originally posted by @dkirkby in https://github.com/adafruit/circuitpython/issues/3829#issuecomment-753343698

dhalbert commented 3 years ago

[Omitting some false starts]

Originally posted by @dkirkby in https://github.com/adafruit/circuitpython/issues/3829#issuecomment-753359516:

Yes, the blink example, saved as code.py. The code hangs at the first time.sleep, so with the D13 LED on:

import board
import digitalio
import time

led = digitalio.DigitalInOut(board.D13)
led.direction = digitalio.Direction.OUTPUT

while True:
    led.value = True
    time.sleep(0.5) #### CODE HANGS HERE WITH 6.0.1
    led.value = False
    time.sleep(0.5)

If I replace time.sleep with a busy loop (for i in range(20000): y = math.sin(0.1)) it works as expected.

dhalbert commented 3 years ago

I tried the same blink program above on a Metro M4 Express with 5.3.1, 6.0.1, and 6.1.0-beta.3. They all work and blink as expected, whether plugged into a Linux box or a MacBook running the latest Big Sur.

(btw, getting mu to run on Big Sur is a chore, and I gave up. The old alpha supposedly works for some people. See https://github.com/mu-editor/mu/issues/1147)

otherguy commented 3 years ago

I have the same issue on a Feather M4 when plugged into a Mac. Both on Catalina and on Big Sur.

dhalbert commented 3 years ago

@otherguy and @dkirkby: Exactly what kind of Macs are you using, and which USB port are you using? I am using a "Macbook (Retina, 12-inch, 2017)", with a single USB-C port. For me it the exact program does not hang: it blinks.

otherguy commented 3 years ago

16” MacBook Pro 2019, happens on all 4 USB-C ports. USB-C to MicroUSB cable connected directly to the Mac without a hub. Now on Big Sur 11.1.

dhalbert commented 3 years ago

So, to be precise, when you plug in the board above that already contains a code.py the same as above, the D13 LED comes on and stays on, is that right?

otherguy commented 3 years ago

Correct, but not always. Sometimes it just works as expected. I initially thought it has something to do with being connected over screen but that's not it. It seems fairly random.

dhalbert commented 3 years ago

@otherguy I am trying to replicate exactly. On the Feather M4 Express, what version of CircuitPython are you using, and what is the version of the bootloader? You can find the version of the bootloader in FEATHERBOOT (double-click to get it) in INFO_UF2.TXT. Thanks!

otherguy commented 3 years ago

Circuitpython version 6.0.1 and bootloader v3.10.0

Believe me I would love to be able to replicate it! I thought I'm going crazy and it took me a while to figure out that time.sleep was the issue, when my Neopixel animations started to randomly freeze (time.sleep is used conditionally in my code so it took a while for the issue to pop up).

I still cannot reliably replicate it, though.

dhalbert commented 3 years ago

What percentage of the time would you say that it happens? I tried about 20 times and could not reproduce. Feather M4 is set up exactly as yours; my MacBook is also Big Sur 11.1, using a USB-C to micro cable. So everything is the same except for the actual MacBook. Is there anything connected to your Feather still, like the string of NeoPixels?

I also tried a Feather M0, because we're having other Mac problems with SAMD21. Could not reproduce there either. I'm not doubting you! It's just mysterious. It's not cosmic rays: there's always a reason.

otherguy commented 3 years ago

I cannot give you a percentage. Once it works, it works, for an extended period of time at least.

Yes, there are several peripherals connected. A NeoPixel matrix, a TSL2561, an AirLift featherwing (though not in use), a DS3231 and several buttons.

I'm thinking it has something to do with the M4 not being recognized correctly. Every time (at least I think it was every time) time.sleep hung, I saw the macOS dialog that a keyboard was detected when I plugged in the M4. It also seems to be something keyboard related because when this happens running time.sleep() inside the REPL hangs as well, but only until some keys are pressed (I didn't try to figure out which key).

Right now I cannot reproduce the keyboard dialogue (maybe I would need to reset SMC).

dkirkby commented 3 years ago

I am using a 15" 2018 MacBookPro (with 4 usb-c ports) running Catalina 10.15.6.

I am connected to a Metro M4 Express powered via usb and running the latest boootloader (v.3.10.0).

With CircuitPython 6.0.1 loaded, the blink program hangs in time.sleep 10 times out of 10 (i.e. 100% of the time, but with small statistics).

I am entering the code and saving it to the CIRCUITPY drive using the latest stable Mu editor. In other words, I am following the Welcome to CircuitPython tutorial.

Having the Mu editor serial tab open or closed makes no difference. Adding some print statements to trace how far the execution goes also makes no difference.

If I replace the time.sleep with a busy loop, the code works as expected.

If I install CircuitPython 5.3.1, the code works as expected.

CedarGroveStudios commented 3 years ago

I occasionally experienced this on a 2020 iMac running Catalina 10.15.7 and mu 1.0.3. Could not detect a pattern for when it happens. Restarting mu, resetting the board, rebooting the iMac, unplugging USB, etc., sometimes clears the condition, sometimes not.

When the code hangs on the time.sleep statement, pressing the return key will advance the code past the stalled statement.

Also, an argument of 0 seconds doesn't hang.

Tested on a Clue, ItsyBitsy M4 Express, and Feather M4 Express with CircuitPython 6.x.x

otherguy commented 3 years ago

For me it’s exactly the same as for @CedarGroveStudios only I can say with certainty that mu is not involved here. I don’t use it or have it installed.

I can also confirm that time.sleep(0) never hangs.

dhalbert commented 3 years ago

@otherguy @CedarGroveStudios Are you both saying that when you are running a code.py with a time.sleep() hangs, if you are connected via serial, that hitting return will cause the code.py to continue past the stalled time.sleep()? Or are you talking about typing time.sleep() in the REPL only?

otherguy commented 3 years ago

I wish I could replicate it for you, but I’m fairly certain it works also when running code.py.

What I can say with certainty is that when time.sleep hangs in the REPL, hitting enter after the sleep time is elapsed brings you back to the prompt. When time.sleep doesn’t hang, it returns you to the REPL prompt immediately after the sleep time is elapsed.

By the way, using the same USB-C cable with a USB-C wall plug never caused a hang so far.

CedarGroveStudios commented 3 years ago

@dhalbert: It behaved the same when executing the statement in code.py as well as the mu REPL.

CedarGroveStudios commented 3 years ago

In addition to pressing return, hitting any key but ctrl-C or enter (on the iMac 10-key portion of the keyboard) will continue past the stalled statement. Pressing ctrl-C or enterwill cause a keyboard interrupt.

dhalbert commented 3 years ago

@dkirkby @CedarGroveStudios @otherguy Could you test a fix we've worked up? Get a .uf2 for your board from the Artifacts on this page: https://github.com/adafruit/circuitpython/actions/runs/472523484

CedarGroveStudios commented 3 years ago

@dhalbert Tested the .uf2 on an oft-failing project with a Feather M4 Express. It worked from the get-go.

image

FYI, using the old .uf2, I was able to reliably force a failure by editing a line in code.py and saving it using mu while the serial window was open. The new .uf2 was not affected by that test scenario.

dhalbert commented 3 years ago

@CedarGroveStudios Fantastic! Thanks for the test.

CedarGroveStudios commented 3 years ago

Hope others see the same success. Was the issue related to the USB connection being dropped by the low-power changes to time.sleep()?

dhalbert commented 3 years ago

There were three bugs fixed: one was actually in the time.sleep() code, and was a truncation of a 64 bit large count to 32 bits. The other were two buffer overruns in tinyusb, one due to a value we didn't know we needed to define larger (the default value was increased), and the other due to an obscure feature in the USB peripheral that stores the CRC bytes after the actual USB message. The latter bug only affected sleep by accident, because a static variable used by sleep was immediately after the overrun buffer. Details in #3953.

otherguy commented 3 years ago

@dhalbert this worked instantly, thank you!

Adafruit CircuitPython 6.1.0-rc.0-13-g6abf0a5d1 on 2021-01-08; Adafruit Feather M4 Express with samd51j19
>>> import time
>>> time.sleep(0.5); print("This works")
This works

(I was hoping it would also fix this issue https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI/issues/123 but unfortunately no such luck)