Skip to content

extmod/machine: Add USB Host support.#7

Draft
andrewleech wants to merge 62 commits intoreview/machine-usbhostfrom
machine-usbhost
Draft

extmod/machine: Add USB Host support.#7
andrewleech wants to merge 62 commits intoreview/machine-usbhostfrom
machine-usbhost

Conversation

@andrewleech
Copy link
Owner

Summary

Adds machine.USBHost() which lets MicroPython act as a USB host, enumerating
and communicating with connected USB devices. Supports CDC (serial), MSC
(storage / block devices), and HID (keyboard/mouse) device classes. MSC devices
implement the block protocol so they can be mounted directly with vfs.mount().

Built on TinyUSB's host stack (submodule updated to 0.20.0 for host support) with a shared infrastructure
layer in shared/tinyusb/mp_usbh.c that handles enumeration, class dispatch,
and GC integration. Each port provides its own TinyUSB config and init glue.

Port support:

  • ESP32-S3: USBHOST variant of ESP32_GENERIC_S3 using native USB OTG
  • STM32F4: NUCLEO_F429ZI_USBHOST (host mode) and NUCLEO_F429ZI_TINYUSB
    (device mode, for testing against a host board) using USB OTG FS with DWC2 driver
  • RP2: WAVESHARE_RP2350_USB_A board using PIO USB for host mode on the
    USB-A receptacle (GPIO12/13) while native USB stays in device mode for REPL.
    System clock set to 120MHz (PIO USB needs 12MHz multiple).
  • MIMXRT: Host-only variants for RT1010/1060/1170 EVKs, plus a dual-port
    MIMXRT1170_EVK_USBHOST_DUAL variant running CDC device on USB_OTG1 and host
    on USB_OTG2 simultaneously

Testing

Multi-instance tests in tests/multi_usb/ cover CDC read/write, CDC with
usb.device library, CDC IRQ, HID keyboard/mouse reports, MSC block I/O,
MSC filesystem mount, device disconnect handling, and composite device enumeration.
These require two physical boards connected via USB cable, one running as host and
the other as device.

Tested with ESP32-S3 <-> NUCLEO-F429ZI in both host/device configurations,
MIMXRT1170-EVK in dual-port mode (CDC REPL on USB_OTG1, host on USB_OTG2),
MIMXRT1170-EVK in single-port host mode (UART REPL via dupterm, host on
USB_OTG1) with ESP32-S3 CDC device enumeration and bidirectional data transfer,
and Waveshare RP2350-USB-A with PIO USB host enumerating ESP32-S3 CDC device
(read/write verified).

Not yet tested:

  • MIMXRT RT1010/RT1060 single-port host variants: These use the only USB port
    for host mode so there's no CDC REPL. Builds compile but no hardware validation.
    The RT1170 single-port variant has been tested using UART REPL via dupterm.

Trade-offs and Alternatives

TinyUSB host mode requires a fair chunk of RAM for transfer buffers and
descriptor caches, particularly on memory-constrained chips like RT1010 where
EHCI data has to go in OCRAM instead of DTCM. Dual-mode configs (RT1170
dual-port, RP2350 PIO USB) need a linker wrap for hcd_event_handler to route
events to the correct stack when both device and host are active. PIO USB on
RP2350 also requires 120MHz clock (vs default 150MHz) since PIO USB needs a
12MHz multiple.

USB Host is opt-in per board variant so there's no size or RAM impact on
existing builds.

Generative AI

I used generative AI tools when creating this PR, but a human has checked the code and is responsible for the description above.

ant9000 and others added 30 commits February 24, 2026 18:18
Fixes a build issue on newer Zephyr versions.

Signed-off-by: Antonio Galea <antonio.galea@gmail.com>
The Pololu Zumo 2040 Robot is supported in pico-sdk now so we should not
include the header file here anymore, similarly to other boards.  This is
necessary for future changes from the SDK to be reflected in MicroPython
builds.

Signed-off-by: Paul Grayson <paul@pololu.com>
Replace the custom rosc_random_u8()/rosc_random_u32() implementation with
the pico_rand API from the Pico SDK. The RP2040 datasheet notes that ROSC
"does not meet the requirements of randomness for security systems because
it can be compromised", and the current 8-bit LFSR conditioning is not a
vetted algorithm under NIST SP 800-90B.

pico_rand uses various hardware RNG sources depending on the available
platform (including the RP2350 hardware TRNG) and is officially supported
and maintained as part of the Pico SDK.

This changes os.urandom(), the mbedTLS entropy source, the PRNG seed, and
the lwIP random function to all use pico_rand, and removes the custom ROSC
random functions from main.c.

Signed-off-by: Michel Le Bihan <michel@lebihan.pl>
When the timeout parameter of `esp32.RMT.wait_done()` is set to a non-zero
value, the underlying `rmt_tx_wait_all_done` blocks (it passes the timeout
to `xQueueReceive`).  Thus we should release the GIL so that other
MicroPython threads are not blocked from running.

Signed-off-by: Daniël van de Giessen <daniel@dvdgiessen.nl>
This commit lets the native emitter preserve the value of the index
register when performing register-indexed loads or stores of halfword or
word values on Thumb.

The original code was optimised too aggressively for a register-starved
architecture like Thumb, and the index value in the sequence to generate
was assumed to be allocated somewhere safe.  This is valid on other
architectures, but not on Thumb.

To solve this, load operations do clobber a temporary register that
should be safe to use, REG_TEMP2, to store the scaled register offset.
REG_TEMP2's value is only used within the scope of a single ASM API
instruction.  Save operations unfortunately use a register that is
aliased to REG_TEMP2, since they need to have three values in registers
to perform the operation.  This means the index register needs to be
pushed to the stack before performing the scale + store operation, and
then popped from the stack.  That's a 4 bytes penalty on each store and
a minor speed hit on generated code (plus a minor footprint increase of
the firmware image).

Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
This commit lets the native emitter preserve the value of the index
register when performing register-indexed loads or stores for halfword
or word values on RV32.

The original code was optimised too aggressively to reduce the generated
code's size, using compressed opcodes that alias the target register to
one of the operands.  In register-indexed load/store operations, the
index register was assumed to be allocated somewhere safe, but it was
not always the case.

To solve this, now all halfword and word register-indexed operations
will use REG_TEMP2 to store the scaled index register.  The size penalty
on generated code varies across operation sizes and enabled extensions:

- byte operations stay the same size with or without Zba
- halfword operations will be 2 bytes larger without Zba, and will stay
  the same size with Zba
- word operations will be 4 bytes larger without Zba, and 2 bytes larger
  with Zba

There is also a minor firmware footprint increase to hold the extra
logic needed for conditional register clobbering, but it shouldn't be
that large anyway.

Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
This commit introduces a test that should check whether viper load or
store operations won't clobber either the buffer address or the index
value being used.

Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
Call `mp_event_handle_nowait()` in the VFS reader buffer refill path so
that pending scheduled events (USB task, network poll, etc.) get processed
during long-running import/parse/compile operations.

Without this, importing a large Python module from the filesystem blocks
for too long causing TinyUSB event queue to overflow.  For example, on
renesas-ra, running a script that imports iperf3 via mpremote run, asserts,
most likely due to SOF interrupts not getting processing:

    queue_event at lib/tinyusb/src/device/usbd.c:382
    dcd_event_handler at lib/tinyusb/src/device/usbd.c:1318
    dcd_event_sof at lib/tinyusb/src/device/dcd.h:237
    dcd_int_handler at tinyusb/src/portable/renesas/rusb2/dcd_rusb2.c:964
    <signal handler called>
    disk_ioctl at extmod/vfs_fat_diskio.c:125
    validate at lib/oofatfs/ff.c:3359
    f_read at lib/oofatfs/ff.c:3625
    file_obj_read at extmod/vfs_fat_file.c:75
    mp_stream_rw at py/stream.c:60
    mp_reader_vfs_readbyte at extmod/vfs_reader.c:59
    next_char at py/lexer.c:174
    mp_lexer_to_next at py/lexer.c:713
    mp_parse at py/parse.c:1167

Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
The aim of this commit is to clarify the command line options available.
While they are available as well as in the CLI with --help, it's useful to
document them and provide a few examples.

Signed-off-by: Jos Verlinde <jos_verlinde@hotmail.com>
Factor out mp_os_urandom() of each port into extmod/modos.c, which then
calls the port-specific function mp_hal_get_random().

Move mp_hal_get_random() to mphalport where suitable. At the
MIMXRT and SAMD it is left in modos.c, since there are different
implementation depending on the MCU family.

At the ALIF, ESP32, CC3200 and RP2 port the file modos.c was removed,
since it was empty after moving mp_hal_get_random().

Tested for the cc3200, esp32, esp8266, mimxrt, nrf, rp2, samd, stm32
and unix ports. Compiled for the alif and the renesas port.

Signed-off-by: robert-hh <robert@hammelrath.com>
Fixes issue micropython#18825.

Signed-off-by: robert-hh <robert@hammelrath.com>
Signed-off-by: Damien George <damien@micropython.org>
This is a reproducer for micropython#17117.

Signed-off-by: Jeff Epler <jepler@unpythonic.net>
Signed-off-by: Jeff Epler <jepler@unpythonic.net>
This turns the reproducer into a sensible-ish crash:

    TypeError: exceptions must derive from BaseException

Closes: micropython#17117

Signed-off-by: Jeff Epler <jepler@unpythonic.net>
Signed-off-by: Jeff Epler <jepler@unpythonic.net>
This is convenient when trying to figure out the correct values
for --include/--exclude/--test-dirs/... arguments.

Signed-off-by: stijn <stijn@ignitron.net>
Test file paths which get passed to the run_tests function can be
absolute or relative and with or without leading slash in the latter
case, depending on the arguments to run-tests.py, but the skip_tests
list with tests to skip only contains relative paths so using simple
string equality comparison easily leads to false negatives.

Compare the full absolute path instead such that it doesn't matter
anymore in which form the tests are passed. Note:
- use realpath to resolve symlinks plus make the comparison case
  insensitive on windows
- the test_file passed to run_one_test is not altered by this commit,
  such that when the user inputs relative paths the tests are also
  still displayed with relative paths
- likewise the test_file_abspath is not modified because functions
  like run_micropython rely on it having forward slashes

In practice this means that it used to be so that the only forms
of running tests for which the skip_tests lists actually worked were:

 >python ./run-tests.py
 >python ./run-tests.py -d extmod

whereas it now works consistently so also for these invocations,
which in the end all point to the exact same path:

 >python ./run-tests.py -d ./extmod
 >python ./run-tests.py -d ../tests/extmod
 >python ./run-tests.py -d /full/path/to/tests/extmod

These examples used to not skip any of the tests in the extmod/
directory thereby leading to test failures.

Signed-off-by: stijn <stijn@ignitron.net>
Scan the --test-dirs argument for the main tests directory being
passed and if so do the same thing as if running from within that
main test directory.

In practice this makes the following (which used to counterintuitively
try and fail to run the .py files in the tests/ directory itself)

 >python micropython/tests/run-tests.py -d micropython/tests

do the same thing as

 >cd micropython/tests
 >python ./run-tests.py

which is logical and convenient.

Signed-off-by: stijn <stijn@ignitron.net>
Test file paths which get passed to the run_tests function can be
absolute or relative and with or without leading slash in the latter
case, depending on the arguments to run-tests.py, but since that path
is used to:
- display which tests run
- record which tests ran in the results.json
- craft the filename for the .exp/.out file for failed tests
it is desirable to always use the same file path irregardless of
how the user passed the path.

In practice this means that all forms of running our own tests like:

 >python ./run-tests.py -i extmod
 >python ./run-tests.py -d extmod
 >python ./run-tests.py -d ./extmod
 >python ./run-tests.py -d ../tests/extmod
 >python ./run-tests.py -d /full/path/to/tests/extmod

will now consistently all display the tests like

  pass  extmod/time_time_ns.py
  FAIL  extmod/some_failing_test.py

and produce output files like

  results/extmod_some_failing_test.py.exp
  results/extmod_some_failing_test.py.out

instead of displaying/using the exact path as passed.

For external tests, meaning not in the tests/ directory, we also want
to be consistent so there the choice was made to always use absolute
paths.

Signed-off-by: stijn <stijn@ignitron.net>
Fixes fatal crash if serial port access returns an error (for example: port
is native USB-CDC and the host hard faults during the test run). Instead of
crashing, have the runner mark this as a test run error and continue.

It's not certain the next test will run successfully, but this provides the
context of output showing what was happening when the communication error
occurred. Without this change, that output is lost when the fatal exception
terminates the runner process.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
This gives a more user-friendly name when the Python object (eg Pin) is
printed.  If the nodelabel is unavailable then it uses `dev->name` as a
fallback.

Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
Signed-off-by: Antonio Galea <antonio.galea@gmail.com>
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Goes along with
https://github.com/micropython/micropython/wiki/ContributorGuidelines#generative-ai-policy

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
Over the time, these are manufactured with different flash types.
All changed boards still build and run with the Giga Devices chip.
The ItsyBitsy M4 board was confirmed to work with the Winbond chip.

Signed-off-by: robert-hh <robert@hammelrath.com>
Previously, mpycert.der was the Intermediate certificate which is regularly
re-issued by Letsencrypt.

Also changes ssl_cert.py to load the cert data from the same file as
test_sslcontext_client.py, so the DER string doesn't have to be pasted
into the source.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
Occasionally, it's useful to be able to compare MicroPython's performance
figures to CPython's. This change adds the ability to run the internalbench
test runner with `--test-instance=cpython` in order to execute the same
test routines against CPython and produce a benchmark performance report in
the same format as MicroPython.

Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
dpgeorge and others added 29 commits March 4, 2026 00:58
Per the Alif example code and documentation for these functions.

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
It's now down to 80uA in `machine.deepsleep()`.

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
The buttons can now wake the device from deepsleep.

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
This allows `machine.deepsleep(N)` to wake the device after the timout N
seconds.

Could probably also do the same thing for lightsleep.

Note that this uses the LPTIMER0 resource, which would not work if
`MICROPY_HW_SYSTEM_TICK_USE_LPTIMER` was ever enabled (it's currently never
enabled, so OK for now).

Signed-off-by: Damien George <damien@micropython.org>
They can wake the device from deepsleep.

Signed-off-by: Damien George <damien@micropython.org>
This commit adds `machine.PWM` support to the alif port.  It uses the
existing common machine bindings and implements the standard set of
functionality: `freq()`, `duty_u16()`, `duty_ns()` and `invert`.

It uses the UTIMER peripheral and makes PWM available on all pins that have
an alt function connection to a UTIMER, which is 54 pins.  It does not use
UTIMER11 which is already in use by the HE core for its systick timer.  So
the following pins don't have PWM available because they need UTIMER11:
P2_6, P2_7, P7_6, P7_7, P12_6, P12_7.

Signed-off-by: Damien George <damien@micropython.org>
Tested on ALIF_ENSEMBLE and OPENMV_AE3 boards.

Signed-off-by: Damien George <damien@micropython.org>
Fixes rp2 issue where socket.getaddrinfo() could block indefinitely if an
interface goes down and still has a DNS server configured, as the LWIP
timer stops running and can't time out the DNS query.

Adds a regression test under multi_wlan that times out on rp2 without this
fix.

Fixes issue micropython#18797.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
As of CPython 3.7 `bytes.fromhex()` skips all ASCII whitespace.  And as of
CPython 3.8 `bytes.hex()` supports the optional separator argument.  So
this test no longer needs a .exp file.

Signed-off-by: Damien George <damien@micropython.org>
This reduces code duplication, and may help reduce code size.

Signed-off-by: Damien George <damien@micropython.org>
As per CPython behaviour, `b"".hex()` should return an empty str object
(not an empty bytes object).

Fixes issue micropython#18807.

Signed-off-by: Damien George <damien@micropython.org>
The rp2.asm_pio() decorator saves and temporarily replaces the globals
dictionary to allow the wrapped functions to reference PIO instructions
and register names in a natural way, restoring them before returning the
assembled program.

However, if an exception occurs while assembling the program, the globals
are not changed back, leaving them corrupted.

Wrap with try/finally to ensure they are always restored correctly.

Signed-off-by: Chris Webb <chris@arachsys.com>
Adds TinyUSB USB Host wrapper providing CDC/HID/MSC device management,
transfer handling, and GC integration. The implementation includes:

- mp_usbh.c: Core TinyUSB host wrapper with device enumeration,
  transfer management, and class-specific interfaces (CDC, HID, MSC)
- mp_usbh.h: Host configuration, init sequence, and device structs
- tusb_config.h: Extended configuration to support USB Host mode with
  fallback values when USB Device is disabled
- mp_usbd.h: Updated to include tusb_config.h unconditionally for
  macros used across device and host implementations

The mp_usbh_init_tuh() init sequence handles two edge cases:
- On shared-port boards (BOARD_TUH_RHPORT == TUD_OPT_RHPORT), calls
  tud_deinit() first to remove the device IRQ handler before the host
  resets the hardware.
- Pre-sets _tusb_rhport_role to TUSB_ROLE_HOST before tuh_init() to
  prevent an ISR race where a connected device triggers the host
  interrupt before the role is set, causing an infinite loop.

Updates lib/tinyusb submodule to version 0.20.0 which includes USB Host
driver improvements and bug fixes required for this implementation.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Implements the Python-facing machine.USBHost() class providing USB Host
functionality for MicroPython. The implementation includes:

- machine_usb_host.c: Complete USBHost class with device enumeration
  methods (cdc_devices(), hid_devices(), msc_devices()), connection
  management, and class-specific interfaces for CDC, HID, and MSC devices
- extmod.cmake: Build system registration for machine_usb_host.c
- modmachine.c: Integration of USBHost class into machine module

The class provides high-level Python access to USB devices with methods
for device discovery, data transfer, and device-specific operations
(e.g., HID report parsing, MSC block I/O, CDC read/write).

Builds on the shared/tinyusb USB Host infrastructure added in the
previous commit.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Adds USB Host support for ESP32-S3 with TinyUSB integration. The
implementation includes:

- esp32_common.cmake: Build integration for USB Host, including TinyUSB
  host stack configuration and source files
- main.c: USB Host task initialization on startup
- usb.c: ESP32-specific USB Host initialization and TinyUSB integration
- tinyusb_port/tusb_config.h: TinyUSB configuration for ESP32 USB stack
- tinyusb_port/tusb_config_host.h: USB Host specific TinyUSB configuration
  including HCD, CDC, MSC, and HID class support
- boards/ESP32_GENERIC_S3_USBHOST/: New board variant with
  USB Host enabled, configured for ESP32-S3's native USB
  peripheral on GPIO19/20

USB Host support requires ESP-IDF's TinyUSB component and is only
available on ESP32-S3 which has native USB OTG support.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Adds USB Host support for STM32F4 with TinyUSB integration. The
implementation includes:

- Makefile: Build integration for USB Host support, including TinyUSB
  port files and conditional compilation
- main.c: USB Host task initialization
- stm32_it.c: Interrupt handling for TinyUSB stack
- msc_disk.c: Updates to support TinyUSB MSC
- usbd_conf.c: USB configuration support for TinyUSB
- tinyusb_port/: TinyUSB port implementation for STM32
  - tusb_config.h: TinyUSB configuration for STM32 USB stack
  - tusb_config_host.h: USB Host specific configuration
  - tusb_port.c: STM32-specific USB initialization and interrupt handlers
- boards/NUCLEO_F429ZI/: Base board updates for TinyUSB compatibility
- boards/NUCLEO_F429ZI_USBHOST/: USB Host variant using TinyUSB host
  stack on USB OTG FS peripheral (CN13)
- boards/NUCLEO_F429ZI_TINYUSB/: TinyUSB device-only variant for
  testing USB Host/Device communication between two boards

USB Host support uses STM32's USB OTG FS peripheral with TinyUSB's
Synopsys DWC2 driver. The VBUS detection is disabled in the TinyUSB
device variant to allow device operation without external VBUS supply
(when connecting two self-powered boards).

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Adds USB Host support for RP2040/RP2350 with TinyUSB integration:

- CMakeLists.txt: Build integration for USB Host including TinyUSB host
  stack, PIO USB support (via tinyusb_pico_pio_usb when available for
  dual-mode boards), --wrap=hcd_event_handler linker flag, and -Werror
  suppression for third-party PIO USB sources
- mpconfigport.h: Feature enables for USB Host mode
- mpconfigport_usbhost.h: USB Host specific port configuration with
  defaults for MICROPY_HW_USB_HOST and class support (CDC, MSC, HID)
- tinyusb_port/tusb_config_host.h: TinyUSB USB Host configuration
  including FIFO sizing, class driver configuration, and #ifndef guard
  on BOARD_TUH_RHPORT so boards can override
- boards/RPI_PICO2_USBHOST/: USB Host variant for Pico2 with RP2350
- boards/WAVESHARE_RP2350_USB_A/: New board configuration for Waveshare
  RP2350-USB-A which has USB-A receptacle for USB Host mode

Updates lib/pico-sdk submodule to version with RP2350 USB Host support.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Adds USB Host support for the i.MX RT port via the shared TinyUSB host
infrastructure. Three board variants provided:

- MIMXRT1010_EVK_USBHOST: RT1010 with reduced TinyUSB config (max 2
  devices, no hub) due to limited memory. USB host data placed in OCRAM
  via custom linker script since DTCM is only 32KB.

- MIMXRT1060_EVK_USBHOST: RT1060 with standard host config using DTCM.

- MIMXRT1170_EVK_USBHOST: RT1170 with standard host config.

Includes linker-time assertion to catch USB host RAM section overflow
during build on memory-constrained boards.

Adds automatic UART dupterm in _boot.py when machine.USBHost is present
and machine.USBDevice is not, so single-port host boards (without USB
CDC REPL) have serial console access out of the box.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Adds simultaneous USB device (RHPORT0/USB_OTG1 for CDC REPL) and host
(RHPORT1/USB_OTG2) support for MIMXRT1170-EVK. Includes tusb_config_dual.h,
dual USB PHY init, unified IRQ handlers, EHCI data placement in OCRAM,
and hcd_event_handler linker wrap.

The MIMXRT1170_EVK_USBHOST_DUAL board config inherits from the base
MIMXRT1170_EVK with USB host overrides rather than duplicating the full
config.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Adds multi-instance tests for USB Host functionality, testing Host/Device
communication between two MicroPython boards. The test suite includes:

CDC (USB Serial) tests:
- cdc_basic.py: Basic CDC read/write operations between host and device
- cdc_custom_lib.py: CDC operations using usb.device library
- cdc_irq.py: CDC interrupt-driven I/O

HID (Human Interface Device) tests:
- hid_keyboard.py: HID keyboard report parsing and input
- hid_mouse.py: HID mouse report parsing and movement

MSC (Mass Storage Class) tests:
- msc_block_rw.py: Block-level read/write operations
- msc_mount_write.py: Filesystem mount and file operations

Device disconnect handling:
- disconnect_cdc.py: CDC device disconnect/reconnect handling
- disconnect_hid.py: HID device disconnect/reconnect handling
- disconnect_msc.py: MSC device disconnect/reconnect handling

Multi-interface enumeration:
- enum_multi_interface.py: Enumeration of composite USB devices

Each test includes a .py.exp file with expected output for automated
verification. Tests require two boards: one as USB Host (instance 0)
and one as USB Device (instance 1), connected via USB cable.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Adds API reference documentation for machine.USBHost class at
docs/library/machine.USBHost.rst.

The documentation covers:
- USBHost class constructor and activation
- Device enumeration methods (devices(), cdc_devices(), hid_devices(),
  msc_devices())
- Class-specific interfaces:
  - CDC: read(), write(), irq() for serial communication
  - HID: read_report() for input device data
  - MSC: block I/O and filesystem mount operations
- Device lifecycle and error handling
- Example usage for each device class

Provides complete reference for USB Host functionality available on
ESP32-S3, RP2040/RP2350, and STM32F4 ports.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Enable MICROPY_HW_ENABLE_USB_RUNTIME_DEVICE for all MIMXRT boards,
add mp_usbd_runtime.c to the build, and freeze the usb-device Python
modules (CDC, HID, keyboard, mouse).

Tested on MIMXRT1170-EVK with ESP32-S3 as USB host: built-in CDC
enumeration, Python CDC bidirectional data transfer, HID keyboard
and mouse reports all verified.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
When CFG_TUH_RPI_PIO_USB and MICROPY_HW_USB_HOST_DP_PIN are defined,
configure PIO USB pin mapping via tuh_configure() before tuh_init().

Use the default pico-sdk alarm pool (alarm_pool_get_default()) instead
of creating a new one. The default PIO USB alarm_pool_create(2, 1)
panics because MicroPython's soft timer already claims hardware alarm 2.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Reconfigure for dual-mode USB: native USB controller in device mode
(USB-C, REPL) on rhport 0, PIO USB in host mode (USB-A receptacle,
GPIO12/13) on rhport 1.

Set system clock to 120MHz (multiple of 12MHz required by PIO USB).
RP2350 default 150MHz doesn't divide evenly.

The original board config assumed native dual-controller host mode
which doesn't work as the RP2350 has only one USB controller. PIO USB
provides the second port via PIO state machines.

Tested on Waveshare RP2350-USB-A with ESP32-S3 native USB CDC device
connected to the USB-A receptacle. Host enumeration, CDC read/write
all verified.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Bump micropython-lib submodule to include usb-device-cdc fix for
default timeout in CDCInterface.init().

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.