I got my program running fine as explained at: How can you make a micropython program on a raspberry pi pico autorun?
I’m installing a main.py
that does:
import machine
import time
led = machine.Pin('LED', machine.Pin.OUT)
# For Rpi Pico (non-W) it was like this instead apparently.
# led = Pin(25, Pin.OUT)
i = 0
while (True):
led.toggle()
print(i)
time.sleep(.5)
i += 1
When I power the device on by plugging the USB to my laptop, it seems to run fine, with the LED blinking.
Then, if I connect from my laptop to the UART with:
screen /dev/ttyACM0 115200
I can see the numbers coming out on my host terminal correctly, and the LED still blinks, all as expected.
However, when I disconnect from screen with Ctrl-A K, after a few seconds, the LED stops blinking! It takes something around 15 seconds for it to stop, but it does so every time I tested.
If I reconnect the UART again with:
screen /dev/ttyACM0 115200
it starts blinking again.
Also also noticed that after I reconnect the UART and execution resumes, the count has increased much less than the actual time passed, so one possibility is that the Pico is going into some slow low power mode?
If I remove the print()
from the program, I noticed that it does not freeze anymore after disconnecting the UART (which of course shows no data in this case).
screen -fn
, screen -f
and screen -fa
made no difference.
Micropython firmware: rp2-pico-w-20221014-unstable-v1.19.1-544-g89b320737.uf2, Ubuntu 22.04 host.
Some variants follow.
picocom /dev/ttyACM0
instead of screen and disconnect with Ctrl-A Ctrl-Q: still freezes like with screen
.
If I exit from picocom
with Ctrl-A Ctrl-X instead however, then it works. The difference between both seems to be that Ctrl-Q logs:
Skipping tty reset...
while Ctrl-X doesn’t, making this a good possible workaround.
The following C analog of the MicroPython hacked from:
- https://github.com/raspberrypi/pico-examples/blob/a7ad17156bf60842ee55c8f86cd39e9cd7427c1d/pico_w/blink
- https://github.com/raspberrypi/pico-examples/blob/a7ad17156bf60842ee55c8f86cd39e9cd7427c1d/hello_world/usb
did not show the same problem, tested on https://github.com/raspberrypi/pico-sdk/tree/2e6142b15b8a75c1227dd3edbe839193b2bf9041
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
int main() {
stdio_init_all();
if (cyw43_arch_init()) {
printf("WiFi init failed");
return -1;
}
int i = 0;
while (true) {
printf("%in", i);
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, i % 2);
i++;
sleep_ms(500);
}
return 0;
}
Reproduction speed can be greatly increased from a few seconds to almost instant by printing more and faster as in:
import machine
import time
led = machine.Pin('LED', machine.Pin.OUT)
i = 0
while (True):
led.toggle()
print('asdf ' * 10 + str(i))
time.sleep(.1)
i += 1
This corroborates people’s theories that the problem is linked to flow control: the sender appears to stop sending if the consumer stops being able to receive fast enough.
Also asked at:
Possibly related:
2
Answers
I don't know why it works, but based on advie from larsks:
and then quit with Ctrl-A Ctrl-X (not Ctrl-A Ctrl-Q) does do what I want. Not sure what
screen
is doing differently exactly.When quitting, Ctrl-Q shows on terminal:
and Ctrl-X does not, which may be a major clue.
What appears to be happening here is that exiting
screen
(or exitingpicocom
without the tty reset) leaves theDTR
line on the serial port high. We can verify this by writing some simple code to control the DTR line, like this:Compile this into a tool called
setdtr
:Connect to your Pico using
screen
, start your code, and then disconnect. Wait for the LED to stop blinking. Now run:You will find that your code starts running again. If you run:
You will find that your code gets stuck again.
The serial chip on the RP2040 interprets a high DTR line to mean that a device is still connected. If nothing is reading from the serial port, it eventually blocks. Setting the DTR pin to 0 — either using this
setdtr
tool or by explicitly resetting the serial port state on close — avoids this problem.