- Initial commit of base firmware - which is still very raw
This commit is contained in:
189
Firmware/build/Pico_Reset_And_Program.py
Normal file
189
Firmware/build/Pico_Reset_And_Program.py
Normal file
@@ -0,0 +1,189 @@
|
||||
import os
|
||||
import time
|
||||
import shutil
|
||||
import glob
|
||||
from pathlib import Path
|
||||
from string import ascii_uppercase
|
||||
from os import path
|
||||
import usb.core
|
||||
import usb.backend.libusb1
|
||||
|
||||
# Device configurations
|
||||
DEVICES = {
|
||||
'RP2040': {
|
||||
'vendor_id': 0x2E8A,
|
||||
'product_id': 0x000A,
|
||||
'name': 'RP2040'
|
||||
},
|
||||
'RP2350': {
|
||||
'vendor_id': 0x2E8A,
|
||||
'product_id': 0x0009,
|
||||
'name': 'RP2350'
|
||||
}
|
||||
}
|
||||
|
||||
# USB control constants
|
||||
RESET_INTERFACE = 2
|
||||
REQUEST_BOOTSEL = 0x01
|
||||
REQUEST_RESET = 0x02
|
||||
|
||||
# Timing constants
|
||||
TIMEOUT_THRESHOLD_s = 10
|
||||
TIMEOUT_INCREMENT_ms = 100
|
||||
|
||||
def detect_device():
|
||||
"""
|
||||
Detect which Pico device is connected.
|
||||
Returns device type string or None if no device found.
|
||||
"""
|
||||
print("Auto-detecting connected device...")
|
||||
|
||||
for device_type, config in DEVICES.items():
|
||||
device = usb.core.find(idVendor=config['vendor_id'], idProduct=config['product_id'])
|
||||
if device is not None:
|
||||
print(f"{config['name']} detected")
|
||||
return device_type
|
||||
|
||||
return None
|
||||
|
||||
def reset_device_to_bootloader(device_type):
|
||||
"""
|
||||
Reset the specified device type to bootloader mode.
|
||||
"""
|
||||
config = DEVICES[device_type]
|
||||
print(f"Resetting {config['name']} to bootloader mode...")
|
||||
|
||||
device = usb.core.find(idVendor=config['vendor_id'], idProduct=config['product_id'])
|
||||
|
||||
if device is None:
|
||||
print(f'No {config["name"]} device found')
|
||||
print(f'Make sure your {config["name"]} is connected and not in bootloader mode')
|
||||
return False
|
||||
|
||||
print(f"{config['name']} device found, attempting to enter bootloader mode...")
|
||||
|
||||
try:
|
||||
usb.util.claim_interface(device, RESET_INTERFACE)
|
||||
Request_Type = (0 << 6) | 1 # Standard Request Host-to-Device and to interface
|
||||
wIndex = RESET_INTERFACE
|
||||
wValue = 0 # No other data
|
||||
|
||||
device.ctrl_transfer(Request_Type, REQUEST_BOOTSEL, wValue, wIndex, [])
|
||||
print("Bootloader reset command sent successfully!")
|
||||
print(f"{config['name']} should now appear as a USB drive for programming")
|
||||
return True
|
||||
|
||||
except usb.core.USBError as e:
|
||||
# print(f"USB Error: {e}")
|
||||
# print("This is normal - the device resets and disconnects")
|
||||
return True # This is actually expected behavior
|
||||
except Exception as e:
|
||||
print(f"Unexpected error: {e}")
|
||||
return False
|
||||
finally:
|
||||
try:
|
||||
usb.util.release_interface(device, RESET_INTERFACE)
|
||||
except:
|
||||
pass # Device may have already disconnected
|
||||
|
||||
def find_uf2_drive():
|
||||
"""
|
||||
Find the UF2 bootloader drive by looking for characteristic files.
|
||||
Both RP2040 and RP2350 use the same UF2 bootloader mechanism.
|
||||
"""
|
||||
for drive in ascii_uppercase:
|
||||
if path.exists(drive + ":\\INDEX.HTM") and path.exists(drive + ":\\INFO_UF2.TXT"):
|
||||
return drive + ":\\"
|
||||
return ""
|
||||
|
||||
def copy_uf2_file(device_type):
|
||||
"""
|
||||
Copy the UF2 file to the detected bootloader drive.
|
||||
"""
|
||||
print("Looking for UF2 bootloader drive...")
|
||||
|
||||
TARGET_DRIVE = find_uf2_drive()
|
||||
Timeout_Counter = 0
|
||||
|
||||
# Wait for drive to appear
|
||||
while not TARGET_DRIVE:
|
||||
time.sleep(TIMEOUT_INCREMENT_ms/1000)
|
||||
TARGET_DRIVE = find_uf2_drive()
|
||||
|
||||
Timeout_Counter = Timeout_Counter + TIMEOUT_INCREMENT_ms
|
||||
if Timeout_Counter >= TIMEOUT_THRESHOLD_s * 1000:
|
||||
print(f"Error: Drive for {device_type} could not be found")
|
||||
return False
|
||||
|
||||
print(f"Found {device_type} drive at: {TARGET_DRIVE}")
|
||||
|
||||
# Change to script directory and find UF2 files
|
||||
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
uf2_files = glob.glob("./*.uf2")
|
||||
if len(uf2_files) == 0:
|
||||
print("Error: No uf2-file has been found")
|
||||
return False
|
||||
|
||||
print(f"Copying {uf2_files[0]} to {device_type}...")
|
||||
|
||||
try:
|
||||
shutil.copy(uf2_files[0], TARGET_DRIVE)
|
||||
print("Copy completed successfully!")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error copying file: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""
|
||||
Main function to orchestrate the programming process.
|
||||
"""
|
||||
print("=== Pico Programmer ===")
|
||||
|
||||
# Detect device
|
||||
device_type = detect_device()
|
||||
|
||||
if device_type:
|
||||
# Device found - attempt reset to bootloader
|
||||
print(f"\n-----------------------")
|
||||
print(f"Resetting {device_type}...")
|
||||
print(f"-----------------------")
|
||||
|
||||
# Reset to bootloader
|
||||
if not reset_device_to_bootloader(device_type):
|
||||
print("Failed to reset device to bootloader mode")
|
||||
os._exit(1)
|
||||
|
||||
print(f"\n-----------------------")
|
||||
print(f"Copying uf2-file...")
|
||||
print(f"-----------------------")
|
||||
|
||||
# Copy UF2 file
|
||||
if not copy_uf2_file(device_type):
|
||||
print("Failed to copy UF2 file")
|
||||
os._exit(1)
|
||||
|
||||
print(f"\nProgramming {device_type} completed successfully!")
|
||||
|
||||
else:
|
||||
# No device found - skip reset and try to find bootloader drive directly
|
||||
print("No supported Pico device found in normal mode")
|
||||
print("Skipping reset step and looking for existing bootloader drive...")
|
||||
|
||||
print(f"\n-----------------------")
|
||||
print(f"Looking for bootloader drive...")
|
||||
print(f"-----------------------")
|
||||
|
||||
# Try to find and copy to existing bootloader drive
|
||||
if not copy_uf2_file("RP2xxx"): # Generic name since we don't know the specific type
|
||||
print("No bootloader drive found and no device to reset")
|
||||
print("Make sure your device is:")
|
||||
print("1. Connected and in normal mode (for auto-reset), OR")
|
||||
print("2. Already in bootloader mode (showing as USB drive)")
|
||||
os._exit(1)
|
||||
|
||||
print(f"\nProgramming completed successfully!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user