-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
ports/esp32: Use shared/tinyusb integration. #15108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ports/esp32: Use shared/tinyusb integration. #15108
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #15108 +/- ##
=======================================
Coverage 98.57% 98.57%
=======================================
Files 164 164
Lines 21336 21336
=======================================
Hits 21031 21031
Misses 305 305 ☔ View full report in Codecov by Sentry. |
c5120d6
to
23cf623
Compare
2360143
to
9e54307
Compare
Code size report:
|
340212b
to
c17e1c6
Compare
722590c
to
c2691ee
Compare
This is now tested and working on both S2 and S3. I now consider it feature complete and ready for review. |
c2691ee
to
33facbd
Compare
ports/esp32/mpconfigport.h
Outdated
#endif | ||
|
||
#ifndef MICROPY_HW_USB_DESC_STR_MAX | ||
#define MICROPY_HW_USB_DESC_STR_MAX (16) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This now defaults to 40, so probably best left at that default and remove this setting here?
ports/esp32/mpconfigport.h
Outdated
#endif | ||
#endif | ||
|
||
#define MICROPY_HW_USBDEV_TASK_HOOK extern void mp_usbd_task(void); mp_usbd_task(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it need to poll tud_task()
like this? Surely it can be done by scheduling from a USB IRQ? That's how the rp2 port works.
How did the IDF handle calling tud_task()
prior to this PR, did it have a dedicated FreeRTOS thread to run TinyUSB?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I'm pretty sure IDF has a low priority tight loop task servicing the USB.
I'll have to look into whether we can use the interrupt, you're right it would certainly be a better option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to look at the source for that tight-loop task, and see what semaphore it waits on. Then see where that semaphore is set. That's the location we can schedule our tud task callback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, huh, the driver we're using here does that automatically for us!
I'll just want to confirm that this is definitely getting called to configure it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll need to wrap _dcd_int_handler
at the linker level, I guess.
ports/esp32/mphalport.h
Outdated
@@ -52,6 +52,7 @@ | |||
|
|||
extern TaskHandle_t mp_main_task_handle; | |||
|
|||
extern int mp_interrupt_char; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better to include shared/runtime/interrupt_char.h
rather than declare this variable.
shared/tinyusb/mp_usbd_cdc.c
Outdated
@@ -162,6 +172,15 @@ tud_cdc_line_state_cb | |||
tud_sof_cb_enable(true); | |||
} | |||
#endif | |||
#if MICROPY_HW_ESP_AUTOMATIC_BOOTLOADER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reckon this new config option should be called MICROPY_HW_USB_CDC_DTR_RTS_BOOTLOADER
, to indicate that it's part of the USB CDC code.
And then put a default value in shared/tinyusb/mp_usbd_cdc.h
of 0 (disabled) with a comment that this should only be used on ESP32 boards.
endif | ||
ifneq ($(BAUD),) | ||
BAUD_ARG := -b $(BAUD) | ||
endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this now leaves the selection of port and baud to idf.py
? Does that give a better user experience?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a default, yes. Esptool does have some auto detection logic that has worked very well for me during development.
33facbd
to
c80ed32
Compare
@andrewleech I see you made changes. Is this ready for re-review? |
Not quite sorry @dpgeorge I need to test them still. |
2372a32
to
c7d8651
Compare
Ok now it's re-tested on S2 and S3 with another rebase. I've fixed up based on review feedback and yes it all appears to work correctly without the polling of the USB task so that's great! Now ready for review thanks @dpgeorge |
Amazing work @andrewleech 👏 Will this allow us to use the existing USB HID classes (e.g. the keyboard)? |
@sebromero the intention is to support the runtime USB subsystem yes! However I haven't enabled or tested that yet as part of this PR. I'm not sure if I should just enable the runtime support defines here by default for the S2 and S3, what do you think @projectgus ? |
@andrewleech Nice! Let me know if / how I can help testing this. I can also get my students to run an experiment so we would have plenty of test data :-) |
Let's leave that for a separate PR. |
shared/tinyusb/mp_usbd.c
Outdated
@@ -49,12 +49,17 @@ void mp_usbd_task_callback(mp_sched_node_t *node) { | |||
|
|||
extern void __real_dcd_event_handler(dcd_event_t const *event, bool in_isr); | |||
|
|||
// Provide stub for ports that don't have/need the wake main task function. | |||
void __attribute((weak)) mp_hal_wake_main_task_from_isr(void) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to do this slightly differently and force all ports using these shared TinyUSB bindings to define this function. The ports can just add the following to their mphalport.h
:
static inline void mp_hal_wake_main_task_from_isr(void) {
// Nothing needs to be done here.
}
Reasons:
- Reduce code size and don't need to call a useless empty function (see rp2 code size report).
- Don't rely on weak linking, which may not be that portable and could lead to issues if the wrong function is linked instead.
- Make it explicit that a port doesn't need to implement anything for this MP HAL function, and provide a clear place to add it if needed (self documenting).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @dpgeorge I'm not a huge fan on boilerplate but yes it's true weak functions can be a little unclear / non-deterministic, it's hard to be certain which version is actually used.
I considered using a define instead to set if this function should be needed, but that's hard to document / describe as well.
This probably is the best compromise, I've implemented it for each of the TinyUSB ports now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered using a define instead to set if this function should be needed, but that's hard to document / describe as well.
Yeah, I had the same thoughts as you.
Thanks for updating!
I tested this on ESP32 S2 and S3 and it works, and it looks all good except the comment above about |
fae3ea7
to
67d9d67
Compare
Uses newer TinyUSB synopsys/dwc2 driver for esp32s2 and esp32s3 rather than the IDF tinyusb component. This allows re-use of other tinyusb integration code and features shared between ports. Signed-off-by: Andrew Leech <andrew@alelec.net>
No longer needed as shared tinyusb is now used by the esp32 port. Signed-off-by: Andrew Leech <andrew@alelec.net>
Enables support for the ESP standard DTR/RTS based reboot to bootloader. Switches from OTG to Serial/Jtag mode to workaround issue discussed in: espressif/arduino-esp32#6762 Signed-off-by: Andrew Leech <andrew@alelec.net>
Signed-off-by: Andrew Leech <andrew@alelec.net>
The custom line state handling is no longer needed as MicroPython runs it directly now. Signed-off-by: Andrew Leech <andrew@alelec.net>
Signed-off-by: Andrew Leech <andrew@alelec.net>
67d9d67
to
548f88d
Compare
Merged! Thanks very much @andrewleech for all your efforts on this, and everyone else who contributed and tested. |
@andrewleech Any hint on how to do this? 🙏 Would love to test this. |
@sebromero keep an eye on this: #15564 (comment) |
Hi, recently I can't compile micropython anymore. I came across this PR in my search and could it be that the errors are related to this? I Use an ESP32S3. I get errors like this:
Any ideas how to fix this? Thanks & Best regards |
For some reason, i needed to run this manually: make -f ../../py/mkrules.mk GIT_SUBMODULES="lib/berkeley-db-1.xx lib/tinyusb lib/micropython-lib" submodules This didn't do anything useful (probably this is a regression): make BOARD=ESP32_GENERIC_S3 submodules |
It checks out |
I found the issue: I needed to add |
Yes that's the correct / current pinned version of TinyUSB. Just to clarify, you were referring to building the |
Yes I used this only to initialize the submodules.
Thanks for pointing that out. Update: |
I had also problems while compiling on my board definition. This solved also my problem. Maybe on a fresh micropython repo-checkout, this is not needed, because the submodules are automatically registered and that is why the pipeline is passing, but on existing repos the submodule is not been registered automatically. |
Uses newer TinyUSB
synopsys/dwc2
driver for esp32s2 and esp32s3 rather than the IDF tinyusb component.This allows re-use of other tinyusb integration code / features shared between ports.
Also add / fix automatic bootloader handling for S2 and S3 by adding support for the ESP standard DTR/RTS based reboot to bootloader.
On S2 and S3 this requires esptool to be run twice (fails on first run as the chip resets and usb drops out) unless used with: espressif/esptool#980
This PR also switches from OTG to Serial/Jtag mode on S3 to workaround issue discussed in:
espressif/arduino-esp32#6762
Also, after flashing with esptool, auto-reboot back to application (micropython) works when used with new enough esptool containing espressif/esptool@0215786
This is not in the current release 4.8, so 4.9 beta release or install from GitHub url is needed.