Skip to content

Commit 5dafbf5

Browse files
Optimize and improve upload experience (#1136)
Stop the IDE from reporting large "Serial port not fount"-type errors after every upload by delaying a bit before the uploader exits to give the OS/Pico time to renegotiate. Fixes flashing problems on certain Linux distros by checking all possible mount locations instead of only the first one to be found. Make 1200bps reset tickle more robust Co-authored-by: Earle F. Philhower, III <[email protected]>
1 parent 09db2e6 commit 5dafbf5

File tree

2 files changed

+63
-20
lines changed

2 files changed

+63
-20
lines changed

cores/rp2040/SerialUSB.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "pico/mutex.h"
3434
#include "hardware/watchdog.h"
3535
#include "pico/unique_id.h"
36+
#include "hardware/resets.h"
3637

3738
#ifndef DISABLE_USB_SERIAL
3839
// Ensure we are installed in the USB chain
@@ -174,8 +175,18 @@ SerialUSB::operator bool() {
174175
static bool _dtr = false;
175176
static bool _rts = false;
176177
static int _bps = 115200;
178+
static bool _rebooting = false;
177179
static void CheckSerialReset() {
178-
if ((_bps == 1200) && (!_dtr)) {
180+
__holdUpPendSV = 1; // Ensure we don't get swapped out by FreeRTOS
181+
if (!_rebooting && (_bps == 1200) && (!_dtr)) {
182+
_rebooting = true;
183+
// Disable NVIC IRQ, so that we don't get bothered anymore
184+
irq_set_enabled(USBCTRL_IRQ, false);
185+
// Reset the whole USB hardware block
186+
reset_block(RESETS_RESET_USBCTRL_BITS);
187+
unreset_block(RESETS_RESET_USBCTRL_BITS);
188+
// Delay a bit, so the PC can figure out that we have disconnected.
189+
sleep_ms(3);
179190
reset_usb_boot(0, 0);
180191
while (1); // WDT will fire here
181192
}

tools/uf2conv.py

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,23 @@ def convert_from_hex_to_uf2(buf):
225225
def to_str(b):
226226
return b.decode("utf-8", "replace")
227227

228+
def possibly_add(p, q):
229+
if p not in q:
230+
if os.path.isdir(p):
231+
if os.access(p, os.W_OK):
232+
q.append(p)
233+
234+
def possibly_anydir(p, q):
235+
if os.path.isdir(p):
236+
if os.access(p, os.R_OK):
237+
r = glob.glob(p + "/*")
238+
for t in r:
239+
possibly_add(t, q)
240+
241+
def possibly_any(p, q, r):
242+
possibly_anydir(p, q)
243+
possibly_anydir(p + r, q)
244+
228245
def get_drives():
229246
drives = []
230247
if sys.platform == "win32":
@@ -240,10 +257,6 @@ def get_drives():
240257
"Format-Table -Property DeviceID, DriveType, Filesystem, VolumeName"],
241258
stdin = nul)
242259
nul.close()
243-
except FileNotFoundError:
244-
print("ERROR: Unable to execute powershell or wmic commands, can't continue.")
245-
print("ERROR: Please make sure either PowerShell or WMIC is installed and in your %PATH%.")
246-
sys.exit(1)
247260
except:
248261
print("Unable to build drive list");
249262
sys.exit(1)
@@ -252,21 +265,9 @@ def get_drives():
252265
if len(words) >= 3 and words[1] == "2" and words[2] == "FAT":
253266
drives.append(words[0])
254267
else:
255-
rootpath = "/run/media"
256-
if not os.path.isdir(rootpath):
257-
rootpath = "/media"
258-
if not os.path.isdir(rootpath):
259-
rootpath = "/opt/media"
260268
if sys.platform == "darwin":
261-
rootpath = "/Volumes"
269+
possibly_anydir("/Volumes", drives)
262270
elif sys.platform == "linux":
263-
tmp = rootpath + "/" + os.environ["USER"]
264-
if os.path.isdir(tmp):
265-
rootpath = tmp
266-
for d in os.listdir(rootpath):
267-
drives.append(os.path.join(rootpath, d))
268-
269-
if (len(drives) == 0) and (sys.platform == "linux"):
270271
globexpr = "/dev/disk/by-id/usb-RPI_RP2*-part1"
271272
rpidisk = glob.glob(globexpr)
272273
if len(rpidisk) > 0:
@@ -281,6 +282,19 @@ def get_drives():
281282
except Exception as ex:
282283
print("Exception executing udisksctl. Exception: {}".format(ex))
283284
# If it fails, no problem since it was a heroic attempt
285+
'''
286+
Generate a list and scan those too.
287+
First add the usual suspects.
288+
Then Scan a returned list.
289+
'''
290+
u="/" + os.environ["USER"]
291+
possibly_anydir("/mnt", drives)
292+
possibly_any("/media", drives, u)
293+
possibly_any("/opt/media", drives, u)
294+
possibly_any("/run/media", drives, u)
295+
possibly_any("/var/run/media", drives, u)
296+
# Add from udisksctl info?
297+
# Add from /proc/mounts?
284298

285299
def has_info(d):
286300
try:
@@ -351,8 +365,15 @@ def error(msg):
351365
try:
352366
print("Resetting " + str(args.serial))
353367
try:
354-
ser = serial.Serial(args.serial, 1200)
368+
ser = serial.Serial()
369+
ser.port = args.serial
370+
ser.open()
371+
ser.baudrate = 9600
372+
ser.dtr = True
373+
time.sleep(0.1)
355374
ser.dtr = False
375+
ser.baudrate = 1200
376+
ser.close()
356377
except:
357378
pass # Ignore error in the case it is already in upload mode
358379
except:
@@ -388,7 +409,7 @@ def error(msg):
388409
now = time.time()
389410
drives = []
390411
while (time.time() - now < 10.0) and (len(drives) == 0):
391-
time.sleep(0.5) # Avoid 100% CPU use while waiting for drive to appear
412+
time.sleep(1.0) # Avoid 100% CPU use while waiting for drive to appear
392413
drives = get_drives()
393414

394415
if args.output:
@@ -400,6 +421,17 @@ def error(msg):
400421
print("Flashing %s (%s)" % (d, board_id(d)))
401422
write_file(d + "/NEW.UF2", outbuf)
402423

424+
# Wait until serial port (if defined) re-appears, or 2s timeout unless UF2 drive direct upload
425+
try:
426+
if args.serial != "UF2 Board":
427+
timeout = time.time() + 2.0
428+
while time.time() < timeout:
429+
if os.access(args.serial, os.W_OK):
430+
break
431+
time.sleep(0.2)
432+
except:
433+
pass
434+
403435

404436
if __name__ == "__main__":
405437
main()

0 commit comments

Comments
 (0)