For some reason bluetooth stack implementations send class requests
to device instead of interface.
To implement HCI interface over USB non device addressed requests
for class need to be handled.
The function is defined inside of a function body which generates a
warning. Circuit Python treats these warnings as errors, and so
refuses to build with debugging enabled:
../../lib/tinyusb/src/device/usbd_control.c: In function 'usbd_control_xfer_cb':
../../lib/tinyusb/src/device/usbd_control.c:195:19: error: nested extern declaration of 'usbd_driver_print_control_complete_name' [-Werror=nested-externs]
195 | extern void usbd_driver_print_control_complete_name(bool (*control_complete) (uint8_t, tusb_control_request_t const *));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
make: *** [../../py/mkrules.mk:55:
build-simmel/lib/tinyusb/src/device/usbd_control.o] Error 1
Move the declaration to the top of the function to silence this warning.
Signed-off-by: Sean Cross <sean@xobs.io>
For normal mynewt packages newt tool wants to have specific
folder structure. It wants to have src and include directories,
and only include (and arch related) directory is added to compiler
include search list.
Since TinyUSB has different folder structure newt tool will not
add anything to -I directives and those would need to be
specified as pkg.cflags: "-I@tinyusb/src"
Recent change to newt tool allowed to add specific include directories
for external (sdk) packages so just including package will add
necessary -I to build commands.
This commit changes package type to sdk and specifies src as include
root for TinyUSB.
For older newt tool adding sdk and include_dirs does not break build.
Code suggested that PLL with MSI is used resulting in 80MHz clock.
When in fact PLL was not configured and system clock was left at MSI 48MHz.
This happens because PLL configuration requires that SysTick interrupt
has interrupt priority level configured correctly.
As it seems ST code intentionally setups variable uwTickPrio to invalid
value and later when it is not setup by user code configuration
of oscillator will fail before PLL is configured.
This simple changes systick priority to some valid value that
allows clock to use PLL.
Field PLLState was not initialized in RCC_OscInitStruct.PLL in
function SystemClock_Config().
Value is used in HAL_RCC_OscConfig() regardless of oscillator.
In lucky case value would be 0 RCC_PLL_NONE and nothing would
happen.
If value was incorrect following line would end up in assert:
assert_param(IS_RCC_PLL(RCC_OscInitStruct->PLL.PLLState));
If value was valid but no RCC_PLL_NONE pll could be configured
with some other random values.
Setting PLLState to RCC_PLL_NONE eliminates potential problem.
setup packet can complete together with previous status (in & out).
Always make sure to prepare valid buffer for holding setup packet when
queuing control status.
Changes:
- checking if tx buffer empty interrupt is masked
- process more than one packet in isr
- mask tx buffer empty just after all bytes were written
- use of transmit_fifo_packet instead of transmit_packet
Busy flag was set to true after call to dcd_edpt_xfer().
In some cased it was possible that transfer finished before function
ended.
In this case busy flag could be set to false before it was set to
true.
Then setting it to true after dcd_edpt_xfer() made edpoint busy forever.
This change marks endpoint as busy before transfer is started to
avoid race condition.
For IN endpoints output FIFO is filled in interrupt, therefor before
endpoint is enabled, DIEPTSIZ is set with correct size of packet.
Then endpoint is enabled and FIFO empty interrupt is enabled.
This works fine except for the ZLP. Enabling FIFO empty interrupt
results in interrupt handler being called all the time because
there is nothing to put in the FIFO.
Eventually it ends when IN token is received and empty
packed is transmitted out.
This change does not enable FIFO empty interrupt for ZLP reducing
CPU load.
Larger SysEx transfers get corrupted by incoming packets.
This changes the FIFOs not to overwrite their data. MIDI should not be
a transport that drops packets. A potentially blocking device is easier
to detect and handle than a device that silently corrupts the packet
stream at random overflows, especially when SysEx messages are involved.
> If you notice my chain of events above, the bulk transfer was started BEFORE the SET_INTERFACE call. The USB device hardware swaps the order of them being delivered. On STM32, it gives priority to the lower-numbered EP index.
It shouldn't be a matter, control is 2+ stage, before sending the setup. Host should stop all communication to the endpoint that It wants to close.
This changes the internal buffering to the raw 4-byte messages. The
conversion of the messages to a byte-stream moved to the read/write
methods.
It adds a raw packet interface to send and retrieve the raw 4-byte
USB MIDI message:
static inline bool tud_midi_receive (uint8_t packet[4]);
static inline bool tud_midi_send (uint8_t const packet[4]);
MIDI USB packets carry virtual cable/wire/plug data in the packet header,
which cannot be exported in the byte-stream interface. The raw packet
interface allows to send and and receive the complete USB message.
This makes `rx_buffer` and `tx_buffer` *pointers*
volatile in order to avoid caching them in a register.
The original notation meant "a pointer to a volatile value"
(equivalent of `volatile uint8_t *`). This resulted in
`while(rx_buffer[ep_num] != NULL) ;` loop to get stuck
forever, even though the IRQ handler set the `rx_buffer[ep_num] = NULL`.
- nuc 121/125: add CFG_EXAMPLE_MSC_READONLY since it is not enough SRAM
to hold MSC disk
- nuc 126: drop i2c source files in compile list due to SDK driver
issue.
Since endpoint 0 is used for control requests, it doesn't have a class driver attached to it. As such, the corresponding `_usbd_dev.ep2drv` entry points to driver `0xFF`, which is invalid and this makes the `TU_ASSERT(drvid < USBD_CLASS_DRIVER_COUNT);` line fail, and eventually causes an endpoint stall. So as-is the stack cannot respond to any endpoint requests on endpoint 0.
However, standard requests on endpoint 0 do not need a class driver to produce a valid response. This commit changes the order of execution so that the assert is only checked if the endpoint is not 0.
Queue table has pointers instead of data os_event structs.
This resulted in crashes when elements were put to queue and
overwritten variables that were just after mpool desiged
for queue.
Due to an error, we were double-advancing the FIFO buffer. The end
result was that the second half of most reads were getting ignored.
This wasn't found during earlier testing because only 64-byte buffers
were tested.
This corrects this error by avoiding double-advancing the buffer.
Signed-off-by: Sean Cross <sean@xobs.io>
During development, the ROM address was at offset 0x2001a000
(due to the fact that the test program was located immediately
following the bitstream).
In normal Fomus, the ROM address is at offset 0x20040000, in order
to take into account additional bitstreams and bootloaders.
Correct the address to the offset in order to get examples working
with existing Fomus.
Signed-off-by: Sean Cross <sean@xobs.io>
When opening a USB port, we ensure the buffer is NULL and has
a length of 0.
Due to a mistake in specifying the endpoint type, we never actually
cleared the value when opening an IN endpoint. This patch fixes
the comparison when opening an IN endpoint.
This fixes issue #218.
Signed-off-by: Sean Cross <sean@xobs.io>
When BOARD=fomu, use the riscv cross-compiler. Otherwise, use the
default arm compiler. This can be overridden by passing
CROSS_COMIPLE on the command line.
Note that there are now three common risc-v prefixes:
- riscv32-unknown-elf- : Common for users who compile their own
- riscv64-unknown-elf- : Upstream multiarch toolchain from SiFive
- riscv-none-embed- : xPack embedded version of SiFive toolchain
Here we assume users are using the `riscv-none-embed-` toolchain from
xPack, because it appears to be growing more common. Additionally,
there is much confusion surrounding `riscv64-unknown-elf-`, which
actually includes both 32- and 64-bit runtimes and can generate software
for both.
Signed-off-by: Sean Cross <sean@xobs.io>
This toolchain seems popular in the embedded space, and is generally
preferred over the upstream SiFive toolchain. It can produce both
32- and 64-bit binaries, so its prefix is riscv-none-embed-.
Signed-off-by: Sean Cross <sean@xobs.io>
Use the name `valentyusb` as the vendor for the `valentyusb`
project, rather than the manufacturer name of the Fomu device.
This is because the `valentyusb` core can be used across multiple
vendors, much like how other cores can be used across chip vendors.
Signed-off-by: Sean Cross <sean@xobs.io>
While Fomu is produced by Foosn, the actual name of the hardware
block is `valentyusb`. Rename the module to match that.
Signed-off-by: Sean Cross <sean@xobs.io>
The Fomu bitstream now includes a `USB_NEXT_EV` register to
indicate which is the next logical event to process. Add this
register to the CSR definition.
Signed-off-by: Sean Cross <sean@xobs.io>
This is really just a few descriptors and then answering to the
request from the host to reboot into DFU mode.
That latter part is delegated to the app since this is platform
specific.
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
.. sending these as two 1-byte messages with CIN of 0xF is
misinterpreted by OSes including Windows 10 and (reportedly)
Mac.
Testing performed: Ran the reproducer script, which sends Program
Change (0xCx) messages. I did not check with Change Pressure (0xDx)
messages, but expect the same thing.
Closes: #98
2019-08-14 19:15:29 -05:00
759 changed files with 66267 additions and 112040 deletions
A clear and concise description of what you expected to happen.
3. See error
**Screenshots**
If applicable, add screenshots to help explain your problem.
If applicable, add screenshots, bus capture to help explain your problem.
**Additional context**
Add any other context about the problem here.
**Log**
Please provide the stack's log (uart/rtt/swo) where the issue occurred, best with comments to explain the actual events. To enable logging, add `LOG=2` to to the make command if building with stock examples or set `CFG_TUSB_DEBUG=2` in your tusb_config.h. More information can be found at [example's readme](/examples/readme.md)
TinyUSB is an open-source cross-platform USB Host/Device stack for embedded system. It is designed to be memory-safe with no dynamic allocation and thread-safe with all interrupt events are deferred then handled in the stack's task function.
TinyUSB is an open-source cross-platform USB Host/Device stack for embedded system, designed to be memory-safe with no dynamic allocation and thread-safe with all interrupt events are deferred then handled in the non-ISR task function.
[Here is the list of supported Boards](docs/boards.md) that can be used with provided examples.
## Device Stack
Support multiple device configurations by dynamically changing usb descriptors. Low power functions such as suspend, resume and remote wakeup. Following device classes are supported:
Supports multiple device configurations by dynamically changing usb descriptors. Low power functions such like suspend, resume, and remote wakeup. Following device classes are supported:
- Communication Class (CDC)
- Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ...
- Mass Storage Class (MSC): with multiple LUNs
- Musical Instrument Digital Interface (MIDI)
- Network with RNDIS, CDC-ECM (work in progress)
- USB Test and Measurement Class (USBTMC)
- Vendor-specific class support with generic In & Out endpoints. Can be used with MS OS 2.0 compatible descriptor to load winUSB driver without INF file.
- [WebUSB](https://github.com/WICG/webusb) with vendor-specific class
@ -38,34 +63,19 @@ Support multiple device configurations by dynamically changing usb descriptors.
- Human Interface Device (HID): Keyboard, Mouse, Generic
- Mass Storage Class (MSC)
- Hub currently only support 1 level of hub (due to my laziness)
- Hub currently only supports 1 level of hub (due to my laziness)
## OS Abtraction layer
## OS Abstraction layer
Currently the following OS are supported with tinyusb out of the box with a simple change of **CFG_TUSB_OS** macro.
TinyUSB is completely thread-safe by pushing all ISR events into a central queue, then process it later in the non-ISR context task function. It also uses semaphore/mutex to access shared resources such as CDC FIFO. Therefore the stack needs to use some of OS's basic APIs. Following OSes are already supported out of the box.
- **No OS**
- **No OS** : Disabling USB IRQ is used as way to provide mutex
- **FreeRTOS**
- **Mynewt** Due to the newt package build system, Mynewt examples are better to be on its [own repo](https://github.com/hathach/mynewt-tinyusb-example)
[Here is the list of supported Boards](docs/boards.md)
## Compiler & IDE
The stack is developed with GCC compiler, and should be compilable with others. Folder `examples` provide Makefile and Segger Embedded Studio build support.
## Getting Started
[Here is the details for getting started](docs/getting_started.md) with the stack.
[Here are the details for getting started](docs/getting_started.md) with the stack.
## Porting
@ -73,7 +83,7 @@ Want to help add TinyUSB support for a new MCU? Read [here](docs/porting.md) for
## License
MIT license for all TinyUSB sources `src` folder, [Full license is here](LICENSE). However each file is individually licensed especially those in `lib` and `hw/mcu` folder. Please make sure you understand all the license term for files you use in your project.
MIT license for all TinyUSB sources `src` folder, [Full license is here](LICENSE). However, each file is individually licensed especially those in `lib` and `hw/mcu` folder. Please make sure you understand all the license term for files you use in your project.
## Uses
@ -83,6 +93,7 @@ TinyUSB is currently used by these other projects:
- TinyUSB does not directly implement USB IRQ Handler function anymore. Application must implement IRQ Handler and invoke `tud_int_handler(rhport)`. This is due to:
- IRQ Handler name can be different across system depending on the startup
- Some OS need to execute enterISR()/exitISR() to work properly, also tracing tool may need to insert trace ISR enter/exit to record usb event
- Give application full control of IRQ handler, can be useful e.g signaling there is new usb event without constant polling
### MCU
- Added support for Espressif ESP32-S2 and saola-1 board
- All default IRQ Handler is renamed to `dcd_int_handler()`
- STM32 Synopsys
- Bus events disconnection/suspend/resume are supported
- Added `dcd_connect()` and `dcd_disconnect()` to enable/disable internal pullup on D+/D- on supported MCUs.
- Added `dcd_edpt_close()` for STM32 FSDev
### Device Stack
- tud_cdc_n_write_flush() return number of bytes forced to transfer instead of bool
- Support multiple configuration descriptors. `TUD_CONFIG_DESCRIPTOR()` template has extra config_num as 1st argument
- Added OPT_OS_CUMSTOM as hook for application to overwrite and/or add their own OS implementation
- Enhanced `net_lwip_webserver` example with multiple configuration: RNDIS for Windows, CDC-ECM for macOS (Linux will work with both)
## 0.6.0 - 2019.03.30
Added **CONTRIBUTORS.md** to give proper credit for contributors to the stack. Special thanks to [Nathan Conrad](https://github.com/pigrew), [Peter Lawrence](https://github.com/majbthrd) and [William D. Jones](https://github.com/cr1901) and others for spending their precious time to add lots of features and ports for this release.
### Added
**MCU**
- Added support for Microchip SAMG55
- Added support for Nordic nRF52833
- Added support for Nuvoton: NUC120, NUC121/NUC125, NUC126, NUC505
- Added support for NXP LPC: 51Uxx, 54xxx, 55xx
- Added support for NXP iMXRT: RT1011, RT1015, RT1021, RT1052, RT1062, RT1064
- Added support for Sony CXD56 (Spresense)
- Added support for STM32: L0, F0, F1, F2, F3, F4, F7, H7
- Added support for TI MSP430
- Added support for ValentyUSB's eptri
**Class Driver**
- Added DFU Runtime class driver
- Added Network class driver with RNDIS, CDC-ECM, CDC-EEM (work in progress)
- Added USBTMC class driver
- Added WebUSB class driver using vendor-specific class
- Added multiple instances support for CDC and MIDI
- Added a handful of unit test with Ceedling.
- Added LOG support for debugging with CFG_TUSB_DEBUG
- Added `tud_descriptor_bos_cb()` for BOS descriptor (required for USB 2.1)
- Added `dcd_edpt0_status_complete()` as optional API for DCD
**Examples**
Following examples are added:
- board_test
- cdc_dual_ports
- dfu_rt
- hid_composite
- net_lwip_webserver
- usbtmc
- webusb_serial
**Boards**
Following boards are added:
- adafruit_clue
- arduino_nano33_ble
- circuitplayground_bluefruit
- circuitplayground_express
- feather_m0_express
- feather_nrf52840_sense
- feather_stm32f405
- fomu
- itsybitsy_m0
- itsybitsy_m4
- lpcxpresso11u37
- lpcxpresso1549
- lpcxpresso51u68
- lpcxpresso54114
- lpcxpresso55s69
- mbed1768
- mimxrt1010_evk
- mimxrt1015_evk
- mimxrt1020_evk
- mimxrt1050_evkb
- mimxrt1060_evk
- mimxrt1064_evk
- msp_exp430f5529lp
- ngx4330
- nrf52840_mdk_dongle
- nutiny_nuc121s
- nutiny_nuc125s
- nutiny_nuc126v
- nutiny_sdk_nuc120
- nutiny_sdk_nuc505
- pca10059
- pca10100
- pyboardv11
- raytac_mdbt50q_rx
- samg55xplained
- seeeduino_xiao
- spresense
- stm32f070rbnucleo
- stm32f072disco
- stm32f103bluepill
- stm32f207nucleo
- stm32f401blackpill
- stm32f411blackpill
- stm32f411disco
- stm32f412disco
- stm32f767nucleo
- stm32h743nucleo
- stm32l0538disco
- stm32l476disco
- teensy_40
### Changed
- Changed `tud_descriptor_string_cb()` to have additional Language ID argument
- Merged hal_nrf5x.c into dcd_nrf5x.c
- Merged dcd_samd21.c and dcd_samd51.c into dcd_samd.c
- Generalized dcd_stm32f4.c to dcd_synopsys.c
- Changed cdc_msc_hid to cdc_msc (drop hid) due to limited endpoints number of some MCUs
The board support code is only used for self-contained examples and testing. It is not used when TinyUSB is part of a larger project. It is responsible for getting the MCU started and the USB peripheral clocked with minimal of on-board devices
- One LED for status
- One Button to get input from user
- One UART optionally, mostly for host examples
- One LED : for status
- One Button : to get input from user
- One UART : optional for device, but required for host examples
## Supported Boards
This code base already had supported for a handful of following boards
This code base already had supported for a handful of following boards (sorted alphabetically)
If you don't possess any of supported board above. Don't worry you can easily implemented your own one by following this guide as long as the mcu is supported.
- Create new makefile for your board at `hw/bsp/<board name>/board.mk` and linker file as well if needed.
- Create new source file for your board at `hw/bsp/<board name>/board_<board name>.c` and implement following APIs
- Create new source file for your board at `hw/bsp/<board name>/<board name>.c` and implement following APIs
The TinyUSB library is designed to operate on single-core MCUs with multi-threaded applications in mind. Interaction with interrupts is especially important to pay attention to.
It is compatible with optionally using a RTOS.
## General
When writing code, keep in mind that the OS (if using a RTOS) may swap out your code at any time. Also, your code can be preempted by an interrupt at any time.
## Application Code
The USB core does not execute application callbacks while in an interrupt context. Calls to application code are from within the USB core task context. Note that the application core will call class drivers from within their own task.
## Class Drivers
Class driver code should never be called from an interrupt context by the USB core, though the application is allowed to call class driver functions from interrupts. USB core functions may be called simultaneously by multiple tasks. Use care that proper locking is used to guard the USBD core functions from this case.
Class drivers are allowed to call `usbd_*` functions, but not `dcd_*` functions.
## USB Core
All functions that may be called from an (USB core) interrupt context have a `bool in_isr` parameter to remind the implementer that special care must be taken.
Interrupt handlers must not directly call class driver code, they must pass a message to the USB core's task.
`usbd_*` functions may be called from interrupts without any notice. They may also be called simultaneously by multiple tasks.
## Device Drivers
Much of the processing of the USB stack is done in an interrupt context, and care must be taken in order to ensure variables are handled in the appropriate ways by the compiler and optimizer.
In particular:
- Ensure that all memory-mapped registers (including packet memory) are marked as volatile. GCC's optimizer will even combine memory access (like two 16-bit to be a 32-bit) if you don't mark the pointers as volatile. On some architectures, this can use macros like `_I`, `_O`, or `_IO'.
- All defined global variables are marked as `static`.
*examples* is the folder where all the application & project files are located. There are demos for both device and hosts. For each, there are different projects for each of supported RTOS. Click to have more information on how to [build](../examples/readme.md) and run [device](../examples/device/readme.md) demos.
@ -17,11 +15,11 @@ It is relatively simple to incorporate tinyusb to your (existing) project
1. Copy or `git submodule` this repo into your project in a subfolder. Let's say it is *your_project/tinyusb*
2. Add all the .c in the src folder to your project settings (uvproj, ewp, makefile)
3. Add *your_project/tinysb* to your include path. Also make sure your current include path also contains the configuration file tusb_config.h. Or you could simply put the tusb_config.h into the tinyusb folder as well.
4. Make sure all required macros are all defined properly in tusb_config.h (configure file in demo application is sufficient, but you need to add a few more such as CFG_TUSB_MCU, CFG_TUSB_OS since they are passed by IDE/compiler to maintain a unique configure for all demo projects).
5. If you use the device stack, make sure you have created/modified usb descriptors for your own need. Ultimately you need to fill out required pointers in tusbd_descriptor_pointers for that stack to work.
4. Make sure all required macros are all defined properly in tusb_config.h (configure file in demo application is sufficient, but you need to add a few more such as CFG_TUSB_MCU, CFG_TUSB_OS since they are passed by IDE/compiler to maintain a unique configure for all boards).
5. If you use the device stack, make sure you have created/modified usb descriptors for your own need. Ultimately you need to implement all **tud_descriptor_** callbacks for that stack to work.
6. Add tusb_init() call to your reset initialization code.
7. Implement all enabled classes's callbacks.
8. If you don't use any RTOSes at all, you need to continuously and/or periodically call tud_task()/tuh_task() function. Most of the callbacks and functionality are handled and invoke within the call of that task runner.
8. If you don't use any RTOSes at all, you need to continuously and/or periodically call tud_task()/tuh_task() function. All of the callbacks and functionality are handled and invoke within the call of that task runner.
TinyUSB is designed to be a universal USB protocol stack for low-cost 32 bit microcontrollers. It
TinyUSB is designed to be a universal USB protocol stack for microcontrollers. It
handles most of the high level USB protocol and relies on the microcontroller's USB peripheral for
data transactions on different endpoints. Porting is the process of adding low-level support for
the rest of the common stack. Once the low-level is implemented, it is very easy to add USB support
for the microcontroller to other projects, especially those already using TinyUSB such as CircuitPython.
Below are instructions on how to get the cdc_msc_hid device example running on a new microcontroller. Doing so includes adding the common code necessary for other uses while minimizing other extra code. Whenever you see a phrase or word in <> it should be replaced.
Below are instructions on how to get the cdc_msc device example running on a new microcontroller. Doing so includes adding the common code necessary for other uses while minimizing other extra code. Whenever you see a phrase or word in <> it should be replaced.
## Register defs
@ -19,14 +19,12 @@ Once this is done, create a directory in `hw/bsp/<your board name>` for the spec
## Build
Now that those directories are in place, we can start our iteration process to get the example building successfully. To build, run from the root of TinyUSB:
Unless, you've read ahead, this will fail miserably. Now, lets get it to fail less by updating the files in the board directory. The code in the board's directory is responsible for setting up the microcontroller's clocks and pins so that USB works. TinyUSB itself only operates on the USB peripheral. The board directory also includes information what files are needed to build the example.
One of the first things to change is the `-DCFG_TUSB_MCU` cflag in the `board.mk` file. This is used to tell TinyUSB what platform is being built. So, add an entry to `src/tusb_option.h` and update the CFLAG to match.
Also, add an entry for the board in `hw/bsp/board.h`. The CFLAG is auto-added.
Update `board.mk`'s VENDOR and CHIP_FAMILY values when creating the directory for the struct files. Duplicate one of the other sources from `src/portable` into `src/portable/<vendor>/<chip_family>` and delete all of the implementation internals. We'll cover what everything there does later. For now, get it compiling.
## Implementation
@ -62,24 +60,34 @@ All of the code for the low-level device API is in `src/portable/<vendor>/<chip
#### Device Setup
##### dcd_init
Initializes the USB peripheral for device mode and enables it.
#### dcd_int_enable / dcd_int_disable
Initializes the USB peripheral for device mode and enables it.
This function should leave an internal D+/D- pull-up in its default power-on state. `dcd_connect` will be called by the USBD core following `dcd_init`.
##### dcd_int_enable / dcd_int_disable
Enables or disables the USB device interrupt(s). May be used to prevent concurrency issues when mutating data structures shared between main code and the interrupt handler.
##### dcd_int_handler
Processes all the hardware generated events e.g Bus reset, new data packet from host etc ... It will be called by application in the MCU USB interrupt handler.
##### dcd_set_address
Called when the device is given a new bus address.
If your peripheral automatically changes address during enumeration (like the nrf52) you may leave this empty and also no queue an event for the corresponding SETUP packet.
##### dcd_set_config
Called when the device received SET_CONFIG request, you can leave this empty if your peripheral does not require any specific action.
##### dcd_remote_wakeup
Called to remote wake up host when suspended (e.g hid keyboard)
##### dcd_connect / dcd_disconnect
Connect or disconnect the data-line pull-up resistor. Define only if MCU has an internal pull-up. (BSP may define for MCU without internal pull-up.)
#### Special events
You must let TinyUSB know when certain events occur so that it can continue its work. There are a few methods you can call to queue events for TinyUSB to process.
##### dcd_event_bus_signal
@ -98,13 +106,14 @@ The first `0` is the USB peripheral number. Statically saying 0 is common for si
The `true` indicates the call is from an interrupt handler and will always be the case when porting in this way.
##### dcd_setup_received
SETUP packets are a special type of transaction that can occur at any time on the control endpoint, numbered `0`. Since they are unique, most peripherals have special handling for them. Their data is always 8 bytes in length as well.
Calls to this look like:
dcd_event_setup_received(0, setup, true);
As before with `dcd_event_bus_signal` the first argument is the USB peripheral number and the third is true to signal its being called from an interrup handler. The middle argument is byte array of length 8 with the contents of the SETUP packet. It can be stack allocated because it is copied into the queue.
As before with `dcd_event_bus_signal` the first argument is the USB peripheral number and the third is true to signal its being called from an interrupt handler. The middle argument is byte array of length 8 with the contents of the SETUP packet. It can be stack allocated because it is copied into the queue.
#### Endpoints
@ -121,21 +130,39 @@ Opening an endpoint is done for all non-control endpoints once the host picks a
Also make sure to enable endpoint specific interrupts.
##### dcd_edpt_close
Close an endpoint. his function is used for implementing alternate settings.
After calling this, the device should not respond to any packets directed towards this endpoint. When called, this function must abort any transfers in progress through this endpoint, before returning.
Implementation is optional. Must be called from the USB task. Interrupts could be disabled or enabled during the call.
##### dcd_edpt_xfer
`dcd_edpt_xfer` is responsible for configuring the peripheral to send or receive data from the host. "xfer" is short for "transfer". **This is one of the core methods you must implement for TinyUSB to work (one other is the interrupt handler).** Data from the host is the OUT direction and data to the host is IN. In other words, direction is relative to the host.
`dcd_edpt_xfer` is responsible for configuring the peripheral to send or receive data from the host. "xfer" is short for "transfer". **This is one of the core methods you must implement for TinyUSB to work (one other is the interrupt handler).** Data from the host is the OUT direction and data to the host is IN. It is used for all endpoints including the control endpoint 0. Make sure to handle the zero-length packet STATUS packet on endpoint 0 correctly. It may be a special transaction to the peripheral.
`dcd_edpt_xfer` is used for all endpoints including the control endpoint 0. Make sure to handle the zero-length packet STATUS packet on endpoint 0 correctly. It may be a special transaction to the peripheral.
Besides that, all other transactions are relatively straight-forward. The endpoint address provides the endpoint
number and direction which usually determines where to write the buffer info. The buffer and its length are usually
written to a specific location in memory and the peripheral is told the data is valid. (Maybe by writing a 1 to a
register or setting a counter register to 0 for OUT or length for IN.)
Besides that, all other transactions are relatively straight-forward. The endpoint address provides the endpoint number and direction which usually determines where to write the buffer info. The buffer and its length are usually written to a specific location in memory and the peripheral is told the data is valid. (Maybe by writing a 1 to a register or setting a counter register to 0 for OUT or length for IN.)
The transmit buffer alignment is determined by `CFG_TUSB_MEM_ALIGN`.
TODO: can we promise the buffer is word aligned?
One potential pitfall is that the buffer may be longer than the maximum endpoint size of one USB packet. Some peripherals can handle transmitting multiple USB packets for a provided buffer (like the SAMD21). Others (like the nRF52) may need each USB packet queued individually. To make this work you'll need to track some state for yourself and queue up an intermediate USB packet from the interrupt handler.
One potential pitfall is that the buffer may be longer than the maximum endpoint size of one USB
packet. Some peripherals can handle transmitting multiple USB packets for a provided buffer (like the SAMD21).
Others (like the nRF52) may need each USB packet queued individually. To make this work you'll need to track
some state for yourself and queue up an intermediate USB packet from the interrupt handler.
Once the transaction is going, the interrupt handler will notify TinyUSB of transfer completion.
During transmission, the IN data buffer is guarenteed to remain unchanged in memory until the `dcd_xfer_complete` function is called.
TODO: who handles zero-length data packets?
The dcd_edpt_xfer function must never add zero-length-packets (ZLP) on its own to a transfer. If a ZLP is required,
then it must be explicitly sent by the stack calling dcd_edpt_xfer(), by calling dcd_edpt_xfer() a second time with len=0.
For control transfers, this is automatically done in `usbd_control.c`.
At the moment, only a single buffer can be transmitted at once. There is no provision for double-buffering. new dcd_edpt_xfer() will not
be called again on the same endpoint address until the driver calls dcd_xfer_complete() (except in cases of USB resets).