- Initial commit of base firmware - which is still very raw
This commit is contained in:
4
Firmware/build/.gitignore
vendored
Normal file
4
Firmware/build/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
./*
|
||||
!./*.txt
|
||||
!./*.bat
|
||||
!./*.py
|
||||
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()
|
||||
1
Firmware/build/build_number.txt
Normal file
1
Firmware/build/build_number.txt
Normal file
@@ -0,0 +1 @@
|
||||
6
|
||||
1
Firmware/build/build_version.txt
Normal file
1
Firmware/build/build_version.txt
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
26
Firmware/build/increment_build_number.bat
Normal file
26
Firmware/build/increment_build_number.bat
Normal file
@@ -0,0 +1,26 @@
|
||||
@echo Off
|
||||
|
||||
echo.
|
||||
echo -----------------------
|
||||
echo Updating Build Number...
|
||||
echo -----------------------
|
||||
|
||||
set /p version=<build_version.txt
|
||||
@echo Major version number: %version%
|
||||
set /p old=< build_number.txt
|
||||
set /a new=%old%+1
|
||||
@echo New build number: %new%
|
||||
@echo Firmware Version: %version%.%new%
|
||||
echo.
|
||||
@echo %new% > build_number.txt
|
||||
|
||||
if %new% lss 10 set version_build_string=%version%.000%new%
|
||||
if %new% geq 10 if %new% lss 100 set version_build_string=%version%.00%new%
|
||||
if %new% geq 100 if %new% lss 1000 set version_build_string=%version%.0%new%
|
||||
if %new% geq 1000 set version_build_string=%version%.%new%
|
||||
|
||||
(
|
||||
echo #define VERSION %version%
|
||||
echo #define BUILD %new%
|
||||
echo #define VERSION_BUILD_STRING "%version_build_string%"
|
||||
) > ..\\Version.h
|
||||
49
Firmware/build/pico_program_auto.bat
Normal file
49
Firmware/build/pico_program_auto.bat
Normal file
@@ -0,0 +1,49 @@
|
||||
@echo Off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo.
|
||||
echo =========================
|
||||
echo Pico Auto-Programmer
|
||||
echo =========================
|
||||
|
||||
REM Read version and build number for file versioning
|
||||
set /p version=<build_version.txt
|
||||
set /p new=< build_number.txt
|
||||
|
||||
if %new% lss 10 set version_build_string=%version%.000%new%
|
||||
if %new% geq 10 if %new% lss 100 set version_build_string=%version%.00%new%
|
||||
if %new% geq 100 if %new% lss 1000 set version_build_string=%version%.0%new%
|
||||
if %new% geq 1000 set version_build_string=%version%.%new%
|
||||
|
||||
REM Create versions directory if it doesn't exist
|
||||
if not exist versions\ mkdir versions
|
||||
|
||||
REM Copy UF2 files with version numbers to versions folder
|
||||
for %%f in (*.uf2) do (
|
||||
set filename_base=%%~nf
|
||||
set filename_with_version=!filename_base!_!version_build_string!.uf2
|
||||
copy %%f versions\!filename_with_version! >nul 2>&1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo Running unified Pico programmer...
|
||||
echo.
|
||||
|
||||
REM Call the unified Python script
|
||||
call python ./Pico_Reset_And_Program.py
|
||||
|
||||
if %errorlevel% == 0 (
|
||||
echo.
|
||||
echo =========================
|
||||
echo Programming Success!
|
||||
echo =========================
|
||||
) else (
|
||||
echo.
|
||||
echo =========================
|
||||
echo Programming Error
|
||||
echo =========================
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
exit /b
|
||||
Reference in New Issue
Block a user