Description
CircuitPython version
Adafruit CircuitPython 9.2.1 on 2024-11-20; Adafruit Feather RP2040 USB Host with rp2040
Code/REPL
# A simplified (no UART output) version of
# examples/usb_host_midi_simpletest_rp2040usbfeather.py
# SPDX-FileCopyrightText: Copyright (c) 2023 Scott Shawcroft for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
# pylint: disable=unused-import
import usb.core
import adafruit_midi
# from adafruit_midi.note_on import NoteOn
# from adafruit_midi.note_off import NoteOff
# from adafruit_midi.control_change import ControlChange
# from adafruit_midi.pitch_bend import PitchBend
import adafruit_usb_host_midi
print("Looking for midi device")
raw_midi = None
while raw_midi is None:
for device in usb.core.find(find_all=True):
try:
raw_midi = adafruit_usb_host_midi.MIDI(device)
print("Found", hex(device.idVendor), hex(device.idProduct))
except ValueError:
continue
# output not needed for this demo/test
# # This setup is to use TX pin on Feather RP2040 with USB Type A Host as MIDI out
# # You must wire up the needed resistors and jack yourself
# # This will forward all MIDI messages from the device to hardware uart MIDI
# uart = busio.UART(rx=board.RX, tx=board.TX, baudrate=31250, timeout=0.001)
midi_device = adafruit_midi.MIDI(midi_in=raw_midi, in_channel=0)
# midi_uart = adafruit_midi.MIDI(midi_out=uart, midi_in=uart)
while True:
msg = midi_device.receive()
if msg:
print("midi msg:", msg)
# midi_uart.send(msg)
Behavior
Run the code with a Roland FP30X MIDI keyboard attached and you get the following output, but which never returns from the constructor to adafruit_usb_host_midi.MIDI:
soft reboot
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Looking for midi device
Found 0x582 0x29c
CTRL-C gets the following:
Traceback (most recent call last):
File "code.py", line 7, in
File "usb_host_midi_simpletest_rp2040usbfeather.py", line 40, in
File "adafruit_midi/init.py", line 128, in receive
File "/lib/adafruit_usb_host_midi.py", line 99, in read
KeyboardInterrupt:Code done running.
Press any key to enter the REPL. Use CTRL-D to reload.
Description
This error happens intermittently, along with succeeding perhaps 50% of the time. (It also gets a "usb.core.USBError: No configuration set" error, which is something else but perhaps a clue as to why nulls are being returned that cause the problem at hand.)
Here are 3 runs:
Success:
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Looking for midi device
Found 0x582 0x29c
midi msg: NoteOn(note=84, velocity=43, channel=0)
midi msg: NoteOn(note=86, velocity=42, channel=0)
...
Failure with usb**.core.USBError: No configuration set** error:
code.py output:
Looking for midi device
Found 0x582 0x29c
Traceback (most recent call last):
File "code.py", line 7, in
File "usb_host_midi_simpletest_rp2040usbfeather.py", line 40, in
File "adafruit_midi/init.py", line 128, in receive
File "/lib/adafruit_usb_host_midi.py", line 99, in read
usb.core.USBError: No configuration setCode done running.
Failure but with my added null catcher:
Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
Looking for midi device
Traceback (most recent call last):
File "code.py", line 7, in
File "usb_host_midi_simpletest_rp2040usbfeather.py", line 24, in
File "/lib/adafruit_usb_host_midi.py", line 55, in init
Exception: adafruit_usb_host_descriptors has a null!Code done running.
Additional information
If you make the following change to adafruit_usb_host_midi.py (starting at line 53, duplicated here)
descriptor_len = config_descriptor[i]
if descriptor_len == 0: # cran
raise Exception("adafruit_usb_host_descriptors has a null!") # cran
you will see that previously the constructor got stuck in an infinite loop because config_descriptor[0] (as well as all the others!) has a value of 0, and the code
i += descriptor_len
at the end of the loop here never increments.
I'm not sure what the best way to handle this null value from config_descriptor is, but this works for me.