tinygo icon indicating copy to clipboard operation
tinygo copied to clipboard

Implement common USB 2.0 package

Open ardnew opened this issue 3 years ago • 9 comments

This PR serves as working area and development notes/discussion for a common USB 2.0 API and package implementation reusable by various TinyGo targets.

A functioning model — including a Device Controller driver with CDC-ACM device class support — is provided for Teensy 4 (NXP iMXRT1062). This can be used to iterate and evaluate changes to the architecture.

  1. The first step would be to document at a high-level the design of this functional prototype. From this, I think more developers could then be involved in discussing (and performing) what changes should be made, and it should help navigate the complexities of the implementation. I'll take this task.
  2. The next step should probably add support for another target. This process would help reveal which components of the existing architecture can be shared, and which components must be implemented on a per-target basis (e.g., USB PHY interaction, descriptor storage layout, etc.). I know TinyGo currently has USB (CDC-ACM) device support for SAMD21, SAMD51, and nRF52840, so one of these would be a good candidate to start with.

This is more than enough work for a single PR. But I feel it's all necessary to develop a robust baseline API for future USB targets.

ardnew avatar Apr 21 '21 18:04 ardnew

I really need this for something. Specifically I need HID keyboard support. So suddenly this PR is oh so very interesting again.

All kidding aside, @ardnew you have done a lot of work here. @sago35 I know you have done some testing with it.

It is pretty complex code for sure. Perhaps just the exercise of trying to implement some of these interfaces on SAMD21 would help clarify a process for getting it implemented on other hardware platforms? For sure I want to help out, what are the next steps?

deadprogram avatar Oct 01 '21 23:10 deadprogram

Bear with me, this is a rather long one...

@deadprogram getting some help is necessary at this point — specifically due to my personal time available to work on this. I'm currently finishing graduate school and have to dedicate my free time (outside my day job) to my master's thesis. So it probably won't be until 2022 before I can resume work on it.

To answer your question plainly, the next steps would be (in no particular order):

  • Have any other developer(s) add support for a new target (keep reading below!).
    • I can probably best support this effort in real-time on our Slack channel. But anywhere, such as this thread or via email works too. I will remain available for support until I can resume work myself next year.
  • Add high-level USB API documentation, perhaps integration procedures/checklists
    • The current package source code is thoroughly documented at a low-level with references, explanations, thought processes, clarifications, revisions, etc. It uses standard godoc conventions. This is generally very technical documentation
    • It would be extremely helpful for new developers to give an overview of the USB device protocol and how we realize this protocol in TinyGo
      1. (From a USB spec perspective) What are the important entities? How do they relate to one another? What are the important phases/lifetimes? How are these ideas combined to implement useful functionality?
      2. From this, we can then outline which of these concepts are used in TinyGo, the specific data structures and constructs we use to implement them, which of these are implemented by the generalized driver, and which of these need to be elaborated by the target device.
    • I would be happy to write an initial draft of this document, but, again, I can't begin work on it until next year (2022).

Current status

There has been a substantial amount of work on this package which is not shown in this branch. As you suggested, to exercise the API for another target, I've done just that and used it to add USB support for a completely different target (STM32). The only caveat is that it's an STM32 target not officially supported by TinyGo, the Arduino Portenta H7 (multi-core board support here).

The following branch uses this package to implement USB support for two different TinyGo targets — teensy40 (NXP iMXRT1062, USB High-Speed), arduino-portenta-h7-m7 (ST STM32H747, USB High-Speed, Cortex-M7 core only):

Repository Branch Package path
https://github.com/ardnew/tinygo feature/usb-common-arduino-portenta machine/usb

Since the USB hardware interfaces are so drastically different between these two targets, I feel this branch demonstrates the general requirements necessary to add support for any given target. I believe it also proves the package is versatile enough to support any TinyGo target.

Next target

For a new developer, I would recommend choosing nRF52 as the next target for adding support for a couple reasons. First, the baked-in firmware or hardware in that device does quite a few tasks for managing memory and USB protocol communication automatically (some of which are currently performed on-demand by this TinyGo USB package); e.g., SET_ADDRESS during device enumeration, DMA transfers to/from program memory to USB peripheral, etc. This may reduce the complexity required of adding support for this chip. Or, it may highlight problems with the current design that need to be addressed. Second, their documentation and SDK examples are pretty great.

More than any other target, there are perhaps more third-party and hobbyist implementations of a USB device library for the SAM D21/D51 families of MCUs. This variety would lend well to understanding different ways to integrate support for these targets with this USB package. Thus, these would also be very good choices for a new developer to use as their first target.

Each of these choices — nRF52 and SAM D21/D51 — also benefit from the fact that TinyGo currently has a minimal, functioning USB CDC serial implementation. These implementations are very stripped down and are not well-suited to generalization, but they are good references for understanding any TinyGo-specific nuances, bus/clock control, and necessary peripheral register configurations. A source-level debug probe is highly recommended.

ardnew avatar Oct 03 '21 18:10 ardnew

Hello @ardnew and @bgould I am trying to look into this myself just to try to catch up to where you both are at.

@bgould seems like https://github.com/bgould/tinygo/tree/usb-common-keyboard-firmware contains your latest work. I see comments there referring to "STM32H7 USB implemenetation" but do not actually see that implementation in that branch, for example in this directory: https://github.com/bgould/tinygo/tree/usb-common-keyboard-firmware/src/machine/usb

@ardnew I do see that you have done work on that board in the branch https://github.com/ardnew/tinygo/tree/feature/usb-common-arduino-portenta I see implementation in https://github.com/ardnew/tinygo/tree/feature/usb-common-arduino-portenta/src/machine/usb referring to stm32.

Basically I am just trying to figure out "what are the specific interfaces that need to be implemented to get a simple USB CDC working?"

Perhaps you both can help me out here? If I had a skeleton of what is needed to start with without all of the machine-specific implementation I would be able to get going more easily. I cannot really easily tell which parts are interface and which are implementation at the moment.

I see there is a core type that contains hcd and dcd types. The dcd type embeds dhw. My problem is I cannot easily determine what is required for the interface that dcd provides.

Same question for hcd and hhw. What is the required external implementation?

deadprogram avatar Apr 17 '22 12:04 deadprogram

Hello @ardnew and @bgould I am trying to look into this myself just to try to catch up to where you both are at.

@bgould seems like https://github.com/bgould/tinygo/tree/usb-common-keyboard-firmware contains your latest work. I see comments there referring to "STM32H7 USB implemenetation" but do not actually see that implementation in that branch, for example in this directory: https://github.com/bgould/tinygo/tree/usb-common-keyboard-firmware/src/machine/usb

@ardnew I do see that you have done work on that board in the branch https://github.com/ardnew/tinygo/tree/feature/usb-common-arduino-portenta I see implementation in https://github.com/ardnew/tinygo/tree/feature/usb-common-arduino-portenta/src/machine/usb referring to stm32.

Basically I am just trying to figure out "what are the specific interfaces that need to be implemented to get a simple USB CDC working?"

Perhaps you both can help me out here? If I had a skeleton of what is needed to start with without all of the machine-specific implementation I would be able to get going more easily. I cannot really easily tell which parts are interface and which are implementation at the moment.

I see there is a core type that contains hcd and dcd types. The dcd type embeds dhw. My problem is I cannot easily determine what is required for the interface that dcd provides.

Same question for hcd and hhw. What is the required external implementation?

deadprogram avatar Apr 17 '22 12:04 deadprogram

Hi @deadprogram:

Unfortunately I don't have a straightforward answer to that question because that interface hasn't been well-defined yet. The idea was that a well-defined interface would simply reveal itself after implementing this USB package for several different targets. However, so far, Teensy 4.0 is the only target that has fully implemented the package.

As you mentioned, the Portenta H7 (STM32) target made quite a bit of headway with the CDC device class (HID has not been started). But another target you may not have reviewed is for SAMD51:

  • https://github.com/ardnew/tinygo/tree/feature/usb-common-samd51

This implementation is actually much more complete than the STM32 target. CDC is fully implemented, HID registration is working for me on Linux, but not on Windows. This is as far as I've had time to get.

This branch should make the distinction between interface and implementation much clearer, as it supports two different targets: mimxrt1062 and atsamd51. Much of the machine-specific implementation code you saw in the Teensy 4.0 branch has been refactored into the generic interface code of this branch.

Note that hhw/hcd are merely placeholder stubs for USB host support. No work has been started on these for any target.

Hope this gives you a better idea of status on this effort.

ardnew avatar Apr 17 '22 21:04 ardnew

@ardnew thank you very much for the update. That branch is a lot easier for me to follow thus far, although I have not gotten too much time to look at it.

@bgould have you seen the branch at https://github.com/ardnew/tinygo/tree/feature/usb-common-samd51 ?

deadprogram avatar Apr 18 '22 11:04 deadprogram

Yes I looked at it, was going to see if I could use that to get RP2040 working. Things just freed up for me at work, and also finally got a hold of a couple RP2040 Feather boards to work on this.

bgould avatar Apr 20 '22 01:04 bgould

@ardnew @deadprogram @bgould USB-CDC for samd51 now works in Windows environment.

https://github.com/tinygo-org/tinygo/commit/51a5970171497e124326b1f0d6b467370a365573

$ tinygo flash --target wioterminal --size short --programmer cmsis-dap -tags usb.cdc ./src/examples/usb/serial/
   code    data     bss |   flash     ram
  12256     328    9428 |   12584    9756

sago35 avatar May 13 '22 11:05 sago35

Now that https://github.com/tinygo-org/tinygo/pull/2889 has been merged into dev I think this PR will require some updates.

Hopefully this will help simplify the process of getting this capability merged in!

deadprogram avatar Jun 11 '22 11:06 deadprogram