Repository navigation
Raspberry Pi Pico: Exposing USB device support #6811
Description
Activity
Unsure if this is the right place but anyone that lands here because they want to make a keyboard/macropad/whatever with the pico please note that you can install CircuitPython and the HID functions work fine under CircuitPython (as does the adafruit HID library). KMK is also likely to work but I haven't tested it.
Reacted by LennartPiro, Antony Nasce, Werner, Kot, Samveen and Thomas ChristliebI'd love to see USB host support in MicroPython for Pi Pico, I could help in implementation.
Reacted by Angainor Development, Antony Nasce, Jasnoor Singh, Chris Barth, Oz, freemstr, Trevor D'Arcy-Evans, Andrew Vasenev, Kevin, Kot and 3 moreAlso eagerly waiting for USB_HID to be available on micropython.
Is there someone actively working on this?
What would be needed?Since this works on circuit python, I guess mainly the core usb lib needs to be ported.
I'm not familiar with differences between circuitpython and micropython, but this seems a reasonable task.
How could I help?@AngainorDev there is a USB implementation for the pyboard in MicroPython:
Lines 366 to 392 in f305c62
// MicroPython bindings for USB /* Philosophy of USB driver and Python API: pyb.usb_mode(...) configures the USB on the board. The USB itself is not an entity, rather the interfaces are, and can be accessed by creating objects, such as pyb.USB_VCP() and pyb.USB_HID(). We have: pyb.usb_mode() # return the current usb mode pyb.usb_mode(None) # disable USB pyb.usb_mode('VCP') # enable with VCP interface pyb.usb_mode('VCP+MSC') # enable with VCP and MSC interfaces pyb.usb_mode('VCP+HID') # enable with VCP and HID, defaulting to mouse protocol pyb.usb_mode('VCP+HID', vid=0xf055, pid=0x9800) # specify VID and PID pyb.usb_mode('VCP+HID', hid=pyb.hid_mouse) pyb.usb_mode('VCP+HID', hid=pyb.hid_keyboard) pyb.usb_mode('VCP+HID', pid=0x1234, hid=(subclass, protocol, max_packet_len, polling_interval, report_desc)) vcp = pyb.USB_VCP() # get the VCP device for read/write hid = pyb.USB_HID() # get the HID device for write/poll Possible extensions: pyb.usb_mode('host', ...) pyb.usb_mode('OTG', ...) pyb.usb_mode(..., port=2) # for second USB port */
Maybe this is a good starting point in porting it to the Pico? I'm not good enough at C programming to make much sense of it.@LennartPiro
I had a look at adafruit implementation as well, and it's quite different (shared lib, for all ports)
I guess the way to go here would be to follow the existing pyboard implementation, since it's also tied to the existing, working VCP interface.
I also saw some PR or Issues about using the default tinyusb lib instead of the pico sdk provided one, things lying there as well probably.Someone with background on that low level code and USB implementation would be needed I'm afraid.
Is there any update on this?
Add me to the list here.
I just wanted to point out that one of my struggles using Circuitpython for usb hid is that it has no _thread support, which makes it difficult to perfrom concurrent functions. While Micropython does have minimal support for _thread, it will be more benificial to have usb hid device as well.
Reacted by Chleba and Max ReynoldsMicroPython really is the neglected younger sibling to C/C++ in the Pico world.
I struggle to see how a maker focused device could even be released without HID support. It is a huge part of the hobbyist microcontroller community. I really can't stomach going back to C, and hate switching between CircuitPython and MicroPython for every other product. Please can we have some traction on this.Reacted by Ofir Gaash, Ritik, Kevin and Thomas ChristliebYou might wanna look into my thread on the RPi forums
Its not an official library but it seems to work fine for HID :)I have been porting my MP code to CP just to findout that I need to create a new board in order to use it. CP is nice and all but I cant bear the fact that if you work on a custom board it need to be re-compiled. USB HID in MP is a must.
I have been porting my MP code to CP just to findout that I need to create a new board in order to use it. CP is nice and all but I cant bear the fact that if you work on a custom board it need to be re-compiled. USB HID in MP is a must.
Custom boards often use different flash chips. A generic build will have a slow but universal setup for the flash. Using a custom build allows for an optimal flash setup for a given board.
any word on this being added? (esp for pico w)
please, please add HID to MP
for tha love of god, add it
Reacted by Ofir Gaash, Tyler Williams, PTALTS-LK, Samveen, Thomas Christlieb, Chleba, Abdullah Osama, Venkat Naidu, Arya and aloneguid4 remaining items
Hoping it can't be bricked so I don't need to buy an external programmer or something
Yes, it is almost impossible to brick a device these days, and fortunately the Pico board has an easy "boot" button to get to the uf2 bootloader. The bootloader is in ROM so you can't overwrite it by accident.
(I have never bricked a single microcontroller while working on MicroPython)
You can also use a second Pico as an external (SWD) debugger for a Pico. Not sure if that supports uploading code though.
Once I get my code working, I would of course like to make the usb module.
There's a lot of scope here, and it impacts several ports (mimxrt, samd, rp2, esp32s*, nrf and potentially stm32). Also questions about how this works with host mode, and potentially whether we want to use the tinyusb device class implementations or something more Python-based.
So, great to experiment, but I don't have any specific advice to give here yet. Anything you find out will be useful though to help figure out how to approach this.
Thanks for the detailed info, once again
My next steps will be
- Of course, test the (allegdly) HID-enabled firmware i made the other day and get it working
- Try and build a
usbmodule which unifies all the pieces of configuration, and provides a standarized API (modemethod, keyboard/mouse/consumer classes, ...)
Actually, there is no point on adding a global module, since it would just be using the underlying API. Having port-specific modules would be harmless to other ports and eaiser to maintain&test
I'm by no means a software-engineer, I'm open to ideas but this feels like a decent way of approaching the problem.
Will be sharing updates as soon as i get back working on this project in a couple of days. (perhaps spamming this issue page isn't the best place to do so, should I move the convo elsewhere?)I'm by no means a software-engineer
I can't say I agree with you @elpekenin. This is exactly what I would consider software engineering to be all about.
perhaps spamming this issue page isn't the best place to do so, should I move the convo elsewhere?
I'd say this issue is the right place. The subscribers to the issue are the ones who are getting "spammed" and really do wish to stay up to date on anything that you can share. You might even get a few beta testers this way. The only other location I could suggest is the discussions section, but I would wait for someone to complain first.
Reacted by thoastbrot, LennartPiro, Thomas Christlieb and Abdullah OsamaThis is exactly what I would consider software engineering to be all about.
Thanks for the encouraing words :) I meant it in a "maybe there are some design patterns I'm missing" kind-off way
I've spent several hours trying (and failing), my findings so far:
⚠️ Maybe I got my head tangled during the several tests, so take this with a grain of salt)- Adding the
modusb_hid.ctoCMakeLists.txt, even when not trying to add the module tompconfigport.h: - The way in which modules are added in
mpconfigport.hhas changed since noobee made their code, and I'm unsure how should i add it, I'll double-check soon, but pretty sure none of this worked:
/* TESTING HID */ extern const struct _mp_obj_module_t mp_module_usb_hid; // #define MICROPY_PY_USB_HID (1) //useless config flag so far, just added so i don't forget // #define MICROPY_PY_USB_HID_INCLUDEFILE "ports/rp2/modusb_hid.c" // #define MICROPY_PY_USB_HID { MP_ROM_QSTR(MP_QSTR_USB_HID), MP_ROM_PTR(&mp_module_usb_hid) }, // #define MICROPY_PORT_BUILTIN_MODULES { MP_ROM_QSTR(MP_QSTR_USB_HID), MP_ROM_PTR(&mp_module_usb_hid) }, //noobee's way // MP_REGISTER_MODULE(MP_QSTR_usb_hid, &mp_module_usb_hid); #define MICROPY_PORT_BUILTIN_MODULES { MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid), (mp_obj_t)&mp_module_usb_hid },
- Adding the
Is there anything to be gained from looking at the circuit python implementation?
Added the
MP_REGISTER_MODULEline in the ownmodusb_hid.cfile and it worked, im now trying to get drivers working on Windows :))It is """working""" already, you can check my branch here
I'm not sure how/why the drivers were acting weird nor how i fixed it 😅
Changes made:
- Moved several defines to enums (im not sure i understood their meaning correctly, have some '??'s over the code)
- Added
#if CFG_TUD_HIDat all my pieces of code, so it can be disabled on compile. Also added checks for stuff related withCFG_TUD_MSCand didn't have it already USBD_DESC_LENis now dynamically computed (at compile) using a multiplication thanks to the CFG flags being 1/0 (should i add some extra code to avoid problems with other values? are they already forced to be 0/1?)
TODO list:
- Rename module to
usb - Rename stuff to match
pyb.USB_HID's API - Add some documentation
- Would like to add the module from
mpconfigport.hwith something like
#if CFG_TUD_HID # define MICROPY_PY_USB_HID_INCLUDEFILE "ports/rp2/modusb_hid.c" #endif
But not sure how to
If you have some time, please take a moment to check if you run into driver issues (as i did yesterday):
- Compile my code with
cd ports/rp2 && make submodules && make clean && make - Test on your board with this little program
import time import usb_hid report = bytearray(8) report[2] = 0x04 # register 'a' keycode usb_hid.report(usb_hid.KEYBOARD, report) # send event time.sleep(2) report[2] = 0x00 # unregister 'a' keycode usb_hid.report(usb_hid.KEYBOARD, report) # send event
And you should see a bunch fo
as being printed in your screenReacted by Celyn Walters, Taisuke Yamada and Arya@elpekenin did you delete that repo? can't find it, could use some HID in a project of mine
@CRImier sorry, nuked the repo a couple months back to make GitHub see it as a fork of CircuitPython instead.
I have just pushed that branch back up:https://github.com/elpekenin/circuitpython/tree/peke-devel
However, i ended up using QMK for HID stuff, so don't expect any further work on it. Also, be aware i made very minimal testing(and it was a year ago), i have no idea how good the code is nor how easy will it merge into current repo.
@elpekenin thank you so much, tinkering with it right now, works wonders!
Even after around 3 years of opening this issue, there's no official update....
Actually no attention from any of 541 contributors :))Reacted by Mikira Sora and Cameron TacklindEven after around 3 years of opening this issue, there's no official update.... Actually no attention from any of 541 contributors :))
There has been a lot of effort on this topic, see #9497.
This ticket should probably be closed since 9497 is under active development.
USB device support was added in MicroPython v1.23.0
Issue can be closed.#9497 was merged.

Is it possible or a reasonable to ask about exposing USB device support in MicroPython similar to the support for the PyBoard?
Beyond that, is it reasonable to expose even more support so that custom USB devices could be created? For example, a custom U2F token running from MicroPython or an OpenPGP card implementation. I'm sure someone can come up with examples that aren't security related.
Original issue: https://github.com/raspberrypi/micropython/issues/5