Locked out of Pico after main runs?

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
martincho
Posts: 96
Joined: Mon May 16, 2022 9:59 pm

Locked out of Pico after main runs?

Post by martincho » Mon Jul 04, 2022 3:02 am

I've been developing without many issues for several weeks. The workflow has been:

Edit code on PyCharm Pro -> use Thonny to send file to Pico -> Use Thonny to run the file (not necessarily main.py).

Today I added a "main.py" that simply imports "app.py" from a release directory on the Pico. It's a two line program:

Code: Select all

from v1_0_0 import app
app.run()
The program runs just fine. I can see it does because I have a logic analyzer connected to a dozen pins monitoring activity. For lack of a better word, it runs perfectly.

The app has a very tight loop that is scheduling tasks and doing a bunch of work, including communicating via both serial ports. That works fine.

The issue is that the Pico runs the app immediately and, I think, Windows has no time to connect to and initialize the USB serial port Thonny uses to talk to it. The port (com 3) never shows up in devices. Thonny can't connect to it and, of course, can't interrupt the program if it can't connect.

My first thought was to just reinstall the MicroPython UF2, load all of the software again and, this time, add something like a 30 second delay in main.py before it calls app.run().

I can reset the board and use the bootsel button to bring it up as a USB flash drive.

To my surprise, dragging and dropping the MicroPython UF2 file does NOT seem to erase my code. As soon as the UF2 is copied over and Pico reboots, my main.py runs again and it calls app.run() instantly.

I thought uploading a new UF2 would flash over any user python code on reboot. Clean slate. Not the case?

How do I get rid of this code?

martincho
Posts: 96
Joined: Mon May 16, 2022 9:59 pm

Re: Locked out of Pico after main runs?

Post by martincho » Mon Jul 04, 2022 3:51 am

UPDATE:

I took another Pico and started over. I'm kind of glad I am doing this on a Pico rather than our custom boards. It would not be fun to "brick" them this way (although, I suspect they could be unbricked using SWD...I just don't have the time to go down that rabbit hole).

Anyhow, I installed the MicroPython UF2 on a new Pico, followed by the same software as before. Except, this time, main.py has this:

Code: Select all

import time
from v1_0_0 import app
time.sleep(60)
app.run()
This time the USB serial port configures just fine. I can connect to it using a terminal program of my choice and see status messages from the software as it runs. Of course, trying to connect using Thonny is possible during this time, except it will interrupt main.py (which is normal). If I ignore Thonny and use a terminal program I can do everything I need to do.

For some reason, immediately launching the app does not allow for the USB port to do whatever it must do in order to become a serial port on a connected system. I'll play with different delays and see what I learn. Any insights on this would be useful.

How do you blow away your MicroPython code if reinstalling the MicroPython UF2 does not do it? As I said, I a sure this can be handled via SWD, however, just thinking of users for whom this might not be a viable option, what is the option? if any. Without operating at a lower (higher?) level, this is one way to brick a Pico.

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Locked out of Pico after main runs?

Post by jimmo » Mon Jul 04, 2022 5:53 am

martincho wrote:
Mon Jul 04, 2022 3:02 am
I thought uploading a new UF2 would flash over any user python code on reboot. Clean slate. Not the case?
No, the UF2 uploading process only erases+writes to the flash regions that the uf2 includes data for. We specifically set a fixed boundary between code and filesystem, such that the filesystem always starts at a known offset (while giving the code some room to grow). The uf2 only touches the code region.

Raspberry Pi provide a uf2 file to erase the whole flash if necessary. Code here https://github.com/raspberrypi/pico-exa ... flash/nuke
I don't know if they provide an official binary, but here's one from adafruit. https://learn.adafruit.com/intro-to-rp2 ... f2-3083182

In general though, I'm not sure why Thonny isn't able to interrupt your program. It should be sending a Ctrl-C which will put the device back into the REPL. Does it work from a regular serial console (e.g. mpremote or screen or picocom).

I have seen a scenario where the second core is active that prevents Ctrl-C from working. I have sent a PR to fix this and will hopefully be merged soon -- https://github.com/micropython/micropython/pull/8845

martincho
Posts: 96
Joined: Mon May 16, 2022 9:59 pm

Re: Locked out of Pico after main runs?

Post by martincho » Mon Jul 04, 2022 6:20 am

What's happening is interesting. I think it also affects the conventional UARTS.

I have reduced the load sleep time down to 10 seconds and everything still works fine. I'll ignore Thonny for now. Don't need it for the real application. What I do need is to be able to connect to the USB serial port to watch diagnostics (just print() commands in the code).

I think what I am seeing is a mechanism that is causing at least the USB serial port to not initialize correctly. This app is too complex to serve as a tool with which to try and nail down what might be happening. I might see if I can reproduce this with something very simple.

The form this would take would be extreme and simple:

First, a file named "app.py" located in a subdirectory, say "v1". This file has a "run()" function that initializes UARTs and some I/O and then goes into a tight fast "while True" loop. Maybe toggle the LED without any sleep delays in the loop. Fast.

At the root directory, "main.py" just does:

Code: Select all

from v1 import app
app.run()
I am not suggesting anyone try this because, if it works, it could lock-up your Pico. I have a couple dozen available to me in the lab so I can afford to mess around. I'll see if I can try the above and reproduce the problem.

My current hypothesis is that the combination of quickly initializing peripherals and a tight loop might be messing with various interrupts. And this, in turn, is causing a reliability problem in getting the USB serial port to initialize and maybe even register with the host. It might even affect the UARTs. While I am not sure about that last part, I know that my application can't seem to communicate with the Pico at all unless I insert a delay somewhere in there.

Additionally, even with the delay, PuTTY (and other terminal programs) refuse to connect to the Pico's USB serial port unless I do it during the sleep() period. Once the code enters the tight loop I can't connect to the USB serial port. In case there's a bit of Windows-related funk in this process I'll try Linux and see what happens.

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Locked out of Pico after main runs?

Post by Roberthh » Mon Jul 04, 2022 6:26 am

There was a problem with RPI Pico and Tinyusb, that Ctrl-C would not interrupt running code any more after a character has been sent to the device and not being read. That was fixed in PR #8040 and should be fine now in MicroPython version 1.19.1. Also, if the keyboard interrupt character was changed by the code, then Ctrl-C does not interrupt the code any more.

martincho
Posts: 96
Joined: Mon May 16, 2022 9:59 pm

Re: Locked out of Pico after main runs?

Post by martincho » Mon Jul 04, 2022 6:33 am

Ah. I am running 1.18. I'll switch to 1.19.1 and see if anything changes. I didn't update just to avoid surprises...but now I have a surprise of my own, so it might be worth it.

Thanks. I'll report back once I get a chance to do it.

martincho
Posts: 96
Joined: Mon May 16, 2022 9:59 pm

Re: Locked out of Pico after main runs?

Post by martincho » Mon Jul 04, 2022 6:40 am

Perhaps related...

An interesting thing I've seen is that the very first print command issues might print all characters but one. It happens randomly.

The very first thing my program prints is a short tuple identifier:

Code: Select all

(230, 96, 145, 3, 195, 28, 111, 41)
Every so often the last parenthesis does not print.

When that happens, the very next print statement (say I print("hello world")), actually prints the missing parenthesis and then "hello world".

It's one of those strange things I ignored because it just didn't seem important enough. However, I think it hints that there might be an issue identifying when characters are in the buffer that need to be transmitted. This could happen in a few places.

Post Reply