summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhathach <[email protected]>2025-10-09 12:27:30 +0700
committerhathach <[email protected]>2025-10-09 12:27:30 +0700
commit970384d6dbb012e5b27095b0f065fd73d00ebf4c (patch)
tree3f12ef5058f0e7772834b3bc98dceefdba25f8f1
parentb9378eb8e79691907aae40b3fc26cb57d4ffaeb4 (diff)
parent87523f2494109b45307644a36f035b5ad11d5ba9 (diff)
Merge branch 'master' into fork/ArcaneNibble/ohci-upstream
-rw-r--r--.github/copilot-instructions.md190
-rw-r--r--.github/workflows/build.yml25
-rwxr-xr-x.github/workflows/ci_set_matrix.py3
-rw-r--r--.gitignore1
-rw-r--r--.idea/debugServers/AT32F423VCT7.xml13
-rw-r--r--.idea/debugServers/ST_LINK.xml13
-rw-r--r--.idea/debugServers/at32f403acgu7.xml13
-rw-r--r--.idea/debugServers/max32690.xml13
-rw-r--r--.idea/debugServers/s3.xml6
-rw-r--r--.idea/debugServers/wch_riscv.xml14
-rw-r--r--CLAUDE.md78
-rw-r--r--README.rst17
-rw-r--r--docs/info/changelog.rst192
-rw-r--r--docs/reference/boards.rst31
-rw-r--r--docs/reference/dependencies.rst90
-rw-r--r--docs/reference/getting_started.rst2
-rw-r--r--examples/build_system/make/make.mk4
-rw-r--r--examples/device/CMakeLists.txt1
-rw-r--r--examples/device/audio_4_channel_mic/src/main.c4
-rw-r--r--examples/device/audio_4_channel_mic/src/tusb_config.h1
-rw-r--r--examples/device/audio_4_channel_mic_freertos/src/main.c6
-rw-r--r--examples/device/audio_4_channel_mic_freertos/src/tusb_config.h1
-rw-r--r--examples/device/audio_test/src/main.c4
-rw-r--r--examples/device/audio_test/src/tusb_config.h1
-rw-r--r--examples/device/audio_test_freertos/skip.txt1
-rw-r--r--examples/device/audio_test_freertos/src/main.c6
-rw-r--r--examples/device/audio_test_freertos/src/tusb_config.h1
-rw-r--r--examples/device/audio_test_multi_rate/src/main.c4
-rw-r--r--examples/device/audio_test_multi_rate/src/tusb_config.h1
-rw-r--r--examples/device/cdc_dual_ports/src/main.c8
-rw-r--r--examples/device/cdc_msc/src/main.c4
-rw-r--r--examples/device/cdc_msc/src/usb_descriptors.c2
-rw-r--r--examples/device/cdc_msc_freertos/src/main.c8
-rw-r--r--examples/device/cdc_msc_freertos/src/msc_disk.c2
-rw-r--r--examples/device/cdc_msc_freertos/src/usb_descriptors.c2
-rw-r--r--examples/device/cdc_uac2/src/tusb_config.h3
-rw-r--r--examples/device/cdc_uac2/src/usb_descriptors.c2
-rw-r--r--examples/device/dfu/src/main.c4
-rw-r--r--examples/device/dfu_runtime/src/main.c4
-rw-r--r--examples/device/dynamic_configuration/src/main.c4
-rw-r--r--examples/device/hid_boot_interface/src/main.c4
-rw-r--r--examples/device/hid_composite/src/main.c65
-rw-r--r--examples/device/hid_composite/src/usb_descriptors.c2
-rw-r--r--examples/device/hid_composite_freertos/src/main.c4
-rw-r--r--examples/device/hid_composite_freertos/src/usb_descriptors.c2
-rw-r--r--examples/device/hid_generic_inout/src/main.c4
-rw-r--r--examples/device/hid_multiple_interface/src/main.c4
-rw-r--r--examples/device/midi_test/src/main.c4
-rw-r--r--examples/device/midi_test_freertos/src/main.c6
-rw-r--r--examples/device/msc_dual_lun/src/main.c4
-rw-r--r--examples/device/mtp/CMakeLists.txt39
-rw-r--r--examples/device/mtp/CMakePresets.json6
-rw-r--r--examples/device/mtp/Makefile11
-rw-r--r--examples/device/mtp/prj.conf6
-rw-r--r--examples/device/mtp/skip.txt1
-rw-r--r--examples/device/mtp/src/main.c110
-rw-r--r--examples/device/mtp/src/mtp_fs_example.c624
-rw-r--r--examples/device/mtp/src/tinyusb_logo_png.h175
-rw-r--r--examples/device/mtp/src/tusb_config.h139
-rw-r--r--examples/device/mtp/src/usb_descriptors.c255
-rw-r--r--examples/device/net_lwip_webserver/src/main.c4
-rw-r--r--examples/device/uac2_headset/src/main.c4
-rw-r--r--examples/device/uac2_headset/src/tusb_config.h3
-rw-r--r--examples/device/uac2_speaker_fb/src/main.c4
-rw-r--r--examples/device/uac2_speaker_fb/src/quirk_os_guessing.c8
-rw-r--r--examples/device/uac2_speaker_fb/src/tusb_config.h5
-rw-r--r--examples/device/usbtmc/src/main.c4
-rw-r--r--examples/device/usbtmc/src/usbtmc_app.c4
-rw-r--r--examples/device/video_capture/src/main.c8
-rw-r--r--examples/device/video_capture_2ch/src/main.c8
-rw-r--r--examples/device/webusb_serial/src/main.c4
-rw-r--r--examples/dual/host_hid_to_device_cdc/src/main.c4
-rw-r--r--examples/dual/host_hid_to_device_cdc/src/usb_descriptors.c2
-rw-r--r--examples/dual/host_info_to_device_cdc/src/main.c4
-rw-r--r--examples/dual/host_info_to_device_cdc/src/usb_descriptors.c2
-rw-r--r--examples/host/bare_api/src/main.c4
-rw-r--r--examples/host/cdc_msc_hid/src/main.c4
-rw-r--r--examples/host/cdc_msc_hid_freertos/src/main.c4
-rw-r--r--examples/host/device_info/src/main.c4
-rw-r--r--examples/host/hid_controller/src/main.c4
-rw-r--r--examples/host/midi_rx/CMakePresets.json6
-rw-r--r--examples/host/msc_file_explorer/src/main.c4
-rw-r--r--hw/bsp/BoardPresets.json520
-rw-r--r--hw/bsp/at32f402_405/boards/at_start_f402/board.cmake8
-rw-r--r--hw/bsp/at32f402_405/boards/at_start_f402/board.h74
-rw-r--r--hw/bsp/at32f402_405/boards/at_start_f402/board.mk7
-rw-r--r--hw/bsp/at32f402_405/boards/at_start_f405/board.cmake9
-rw-r--r--hw/bsp/at32f402_405/boards/at_start_f405/board.h106
-rw-r--r--hw/bsp/at32f402_405/boards/at_start_f405/board.mk4
-rw-r--r--hw/bsp/at32f402_405/family.c36
-rw-r--r--hw/bsp/at32f402_405/family.cmake23
-rw-r--r--hw/bsp/at32f402_405/family.mk28
-rw-r--r--hw/bsp/at32f403a_407/boards/at32f403a_weact_blackpill/board.cmake8
-rw-r--r--hw/bsp/at32f403a_407/boards/at32f403a_weact_blackpill/board.h67
-rw-r--r--hw/bsp/at32f403a_407/boards/at32f403a_weact_blackpill/board.mk7
-rw-r--r--hw/bsp/at32f403a_407/boards/at_start_f403a/board.cmake2
-rw-r--r--hw/bsp/at32f403a_407/boards/at_start_f403a/board.h3
-rw-r--r--hw/bsp/at32f403a_407/boards/at_start_f403a/board.mk2
-rw-r--r--hw/bsp/at32f403a_407/boards/at_start_f407/board.cmake8
-rw-r--r--hw/bsp/at32f403a_407/boards/at_start_f407/board.h71
-rw-r--r--hw/bsp/at32f403a_407/boards/at_start_f407/board.mk7
-rw-r--r--hw/bsp/at32f403a_407/family.c4
-rw-r--r--hw/bsp/at32f413/boards/at_start_f413/board.h2
-rw-r--r--hw/bsp/at32f415/boards/at_start_f415/board.h2
-rw-r--r--hw/bsp/at32f423/boards/at_start_f423/board.h2
-rw-r--r--hw/bsp/at32f425/boards/at_start_f425/board.h2
-rw-r--r--hw/bsp/at32f435_437/boards/at_start_f435/board.cmake8
-rw-r--r--hw/bsp/at32f435_437/boards/at_start_f435/board.h74
-rw-r--r--hw/bsp/at32f435_437/boards/at_start_f435/board.mk7
-rw-r--r--hw/bsp/at32f435_437/boards/at_start_f437/board.h117
-rw-r--r--hw/bsp/at32f435_437/family.c40
-rw-r--r--hw/bsp/at32f435_437/family.cmake5
-rw-r--r--hw/bsp/at32f435_437/family.mk5
-rw-r--r--hw/bsp/board.c20
-rw-r--r--hw/bsp/board_api.h16
-rw-r--r--hw/bsp/espressif/boards/family.c14
-rw-r--r--hw/bsp/espressif/components/tinyusb_src/CMakeLists.txt1
-rw-r--r--hw/bsp/imxrt/boards/metro_m7_1011/board.h3
-rw-r--r--hw/bsp/imxrt/boards/metro_m7_1011_sd/board.h3
-rw-r--r--hw/bsp/imxrt/boards/mimxrt1010_evk/board.h3
-rw-r--r--hw/bsp/imxrt/boards/mimxrt1015_evk/board.h3
-rw-r--r--hw/bsp/imxrt/boards/mimxrt1020_evk/board.h3
-rw-r--r--hw/bsp/imxrt/boards/mimxrt1024_evk/board.h3
-rw-r--r--hw/bsp/imxrt/boards/mimxrt1050_evkb/board.h3
-rw-r--r--hw/bsp/imxrt/boards/mimxrt1060_evk/board.h3
-rw-r--r--hw/bsp/imxrt/boards/mimxrt1064_evk/board.h3
-rw-r--r--hw/bsp/imxrt/boards/mimxrt1170_evkb/board.h383
-rw-r--r--hw/bsp/imxrt/boards/teensy_40/board.h3
-rw-r--r--hw/bsp/imxrt/boards/teensy_41/board.h3
-rw-r--r--hw/bsp/imxrt/family.c389
-rw-r--r--hw/bsp/imxrt/family.cmake2
-rw-r--r--hw/bsp/imxrt/family.mk2
-rw-r--r--hw/bsp/rp2040/family.c8
-rw-r--r--hw/bsp/rp2040/family.cmake1
-rw-r--r--hw/bsp/samd11/family.cmake1
-rw-r--r--hw/bsp/samd11/family.mk1
-rw-r--r--hw/bsp/stm32f7/stm32f7xx_hal_conf.h2
-rw-r--r--hw/bsp/stm32h7/boards/stm32h745disco/board.cmake2
-rw-r--r--hw/bsp/stm32h7/boards/stm32h745disco/board.mk2
-rw-r--r--hw/bsp/stm32h7/linker/stm32h745xx_flash_CM7.ld184
-rw-r--r--hw/bsp/stm32h7/stm32h7xx_hal_conf.h81
-rw-r--r--hw/bsp/stm32h7rs/family.mk2
-rw-r--r--hw/bsp/stm32l4/family.c2
-rw-r--r--hw/bsp/stm32n6/boards/stm32n6570dk/STM32N657XX_AXISRAM2_fsbl.ld203
-rw-r--r--hw/bsp/stm32n6/boards/stm32n6570dk/board.cmake17
-rw-r--r--hw/bsp/stm32n6/boards/stm32n6570dk/board.h283
-rw-r--r--hw/bsp/stm32n6/boards/stm32n6570dk/board.mk17
-rw-r--r--hw/bsp/stm32u0/FreeRTOSConfig/FreeRTOSConfig.h149
-rw-r--r--hw/bsp/stm32u0/boards/stm32u083cdk/STM32U083MCTx_FLASH.ld176
-rw-r--r--hw/bsp/stm32u0/boards/stm32u083cdk/board.cmake12
-rw-r--r--hw/bsp/stm32u0/boards/stm32u083cdk/board.h129
-rw-r--r--hw/bsp/stm32u0/boards/stm32u083cdk/board.mk13
-rw-r--r--hw/bsp/stm32u0/boards/stm32u083cdk/stm32u083xx_flash.icf32
-rw-r--r--hw/bsp/stm32u0/family.c182
-rw-r--r--hw/bsp/stm32u0/family.cmake117
-rw-r--r--hw/bsp/stm32u0/family.mk50
-rw-r--r--hw/bsp/stm32u0/stm32u0xx_hal_conf.h337
-rw-r--r--hw/bsp/stm32wba/FreeRTOSConfig/FreeRTOSConfig.h153
-rw-r--r--hw/bsp/stm32wba/boards/stm32wba_nucleo/board.cmake8
-rw-r--r--hw/bsp/stm32wba/boards/stm32wba_nucleo/board.h136
-rw-r--r--hw/bsp/stm32wba/boards/stm32wba_nucleo/board.mk6
-rw-r--r--hw/bsp/stm32wba/family.c216
-rw-r--r--hw/bsp/stm32wba/family.cmake134
-rw-r--r--hw/bsp/stm32wba/family.mk59
-rw-r--r--hw/bsp/stm32wba/linker/STM32WBA65xx_FLASH_ns.ld188
-rw-r--r--hw/bsp/stm32wba/stm32wbaxx_hal_conf.h367
-rw-r--r--lib/rt-thread/SConscript2
-rw-r--r--library.json2
-rw-r--r--repository.yml3
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/class/audio/audio_device.c155
-rw-r--r--src/class/audio/audio_device.h15
-rwxr-xr-xsrc/class/bth/bth_device.c130
-rwxr-xr-xsrc/class/bth/bth_device.h8
-rw-r--r--src/class/cdc/cdc_device.c60
-rw-r--r--src/class/cdc/cdc_device.h14
-rw-r--r--src/class/cdc/cdc_host.c39
-rw-r--r--src/class/cdc/cdc_host.h8
-rw-r--r--src/class/cdc/cdc_rndis_host.c2
-rw-r--r--src/class/dfu/dfu_device.c27
-rw-r--r--src/class/dfu/dfu_device.h6
-rw-r--r--src/class/hid/hid.h591
-rw-r--r--src/class/hid/hid_device.h10
-rw-r--r--src/class/hid/hid_host.c87
-rw-r--r--src/class/hid/hid_host.h12
-rw-r--r--src/class/midi/midi_device.c12
-rw-r--r--src/class/midi/midi_device.h4
-rw-r--r--src/class/midi/midi_host.c10
-rw-r--r--src/class/msc/msc_device.c111
-rw-r--r--src/class/msc/msc_device.h16
-rw-r--r--src/class/msc/msc_host.c19
-rw-r--r--src/class/msc/msc_host.h4
-rw-r--r--src/class/mtp/mtp.h888
-rw-r--r--src/class/mtp/mtp_device.c540
-rw-r--r--src/class/mtp/mtp_device.h167
-rw-r--r--src/class/usbtmc/usbtmc_device.c29
-rw-r--r--src/class/usbtmc/usbtmc_device.h7
-rw-r--r--src/class/vendor/vendor_device.c22
-rw-r--r--src/class/vendor/vendor_device.h4
-rw-r--r--src/class/video/video_device.c33
-rw-r--r--src/class/video/video_device.h6
-rw-r--r--src/common/tusb_common.h21
-rw-r--r--src/common/tusb_fifo.c1
-rw-r--r--src/common/tusb_mcu.h12
-rw-r--r--src/common/tusb_verify.h8
-rw-r--r--src/device/dcd.h2
-rw-r--r--src/device/usbd.c32
-rw-r--r--src/device/usbd.h19
-rw-r--r--src/device/usbd_pvt.h2
-rw-r--r--src/host/usbh.c52
-rw-r--r--src/host/usbh.h6
-rw-r--r--src/host/usbh_pvt.h2
-rw-r--r--src/osal/osal_mynewt.h2
-rw-r--r--src/osal/osal_none.h9
-rw-r--r--src/portable/ehci/ehci.c79
-rw-r--r--src/portable/espressif/esp32sx/dcd_esp32sx.c889
-rw-r--r--src/portable/microchip/pic32mz/dcd_pic32mz.c8
-rw-r--r--src/portable/ohci/ohci.c18
-rw-r--r--src/portable/renesas/rusb2/rusb2_common.c4
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c48
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_at32.h5
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_ch32.h5
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_stm32.h49
-rw-r--r--src/portable/sunxi/dcd_sunxi_musb.c12
-rw-r--r--src/portable/synopsys/dwc2/dwc2_common.c45
-rw-r--r--src/portable/synopsys/dwc2/dwc2_esp32.h17
-rw-r--r--src/portable/synopsys/dwc2/dwc2_info.md116
-rwxr-xr-xsrc/portable/synopsys/dwc2/dwc2_info.py4
-rw-r--r--src/portable/synopsys/dwc2/dwc2_stm32.h23
-rw-r--r--src/portable/ti/msp430x5xx/dcd_msp430x5xx.c18
-rw-r--r--src/portable/wch/hcd_ch32_usbfs.c138
-rw-r--r--src/tinyusb.mk1
-rw-r--r--src/tusb.c8
-rw-r--r--src/tusb.h14
-rw-r--r--src/tusb_option.h10
-rw-r--r--src/typec/usbc.c25
-rw-r--r--src/typec/usbc.h4
-rw-r--r--test/fuzz/device/cdc/src/usb_descriptors.cc2
-rw-r--r--test/fuzz/device/msc/src/usb_descriptors.cc2
-rw-r--r--test/fuzz/device/net/src/usb_descriptors.cc2
-rw-r--r--test/fuzz/rules.mk1
-rwxr-xr-xtest/hil/hil_test.py119
-rw-r--r--test/hil/pymtp.py1290
-rw-r--r--tools/file2carray.py46
-rwxr-xr-xtools/get_deps.py92
-rwxr-xr-xtools/iar_gen.py2
-rw-r--r--tools/iar_template.ipcf5
-rwxr-xr-xtools/make_release.py2
248 files changed, 11398 insertions, 2647 deletions
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 000000000..9982583cd
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,190 @@
+# TinyUSB
+TinyUSB is an open-source cross-platform USB Host/Device stack for embedded systems, designed to be memory-safe with no dynamic allocation and thread-safe with all interrupt events deferred to non-ISR task functions.
+
+Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.
+
+## Working Effectively
+
+### Bootstrap and Build Setup
+- Install ARM GCC toolchain: `sudo apt-get update && sudo apt-get install -y gcc-arm-none-eabi`
+- Fetch core dependencies: `python3 tools/get_deps.py` -- takes <1 second. NEVER CANCEL.
+- For specific board families: `python3 tools/get_deps.py FAMILY_NAME` (e.g., rp2040, stm32f4)
+- Dependencies are cached in `lib/` and `hw/mcu/` directories
+
+### Build Examples
+Choose ONE of these approaches:
+
+**Option 1: Individual Example with CMake (RECOMMENDED)**
+```bash
+cd examples/device/cdc_msc
+mkdir -p build && cd build
+cmake -DBOARD=raspberry_pi_pico -DCMAKE_BUILD_TYPE=MinSizeRel ..
+cmake --build . -j4
+```
+-- takes 1-2 seconds. NEVER CANCEL. Set timeout to 5+ minutes.
+
+**CMake with Ninja (Alternative)**
+```bash
+cd examples/device/cdc_msc
+mkdir build && cd build
+cmake -G Ninja -DBOARD=raspberry_pi_pico ..
+ninja
+```
+
+**Option 2: Individual Example with Make**
+```bash
+cd examples/device/cdc_msc
+make BOARD=raspberry_pi_pico all
+```
+-- takes 2-3 seconds. NEVER CANCEL. Set timeout to 5+ minutes.
+
+**Option 3: All Examples for a Board**
+```bash
+python3 tools/build.py -b BOARD_NAME
+```
+-- takes 15-20 seconds, may have some objcopy failures that are non-critical. NEVER CANCEL. Set timeout to 30+ minutes.
+
+### Build Options
+- **Debug build**:
+ - CMake: `-DCMAKE_BUILD_TYPE=Debug`
+ - Make: `DEBUG=1`
+- **With logging**:
+ - CMake: `-DLOG=2`
+ - Make: `LOG=2`
+- **With RTT logger**:
+ - CMake: `-DLOG=2 -DLOGGER=rtt`
+ - Make: `LOG=2 LOGGER=rtt`
+- **RootHub port selection**:
+ - CMake: `-DRHPORT_DEVICE=1`
+ - Make: `RHPORT_DEVICE=1`
+- **Port speed**:
+ - CMake: `-DRHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED`
+ - Make: `RHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED`
+
+### Flashing and Deploymen
+- **Flash with JLink**:1
+ - CMake: `ninja cdc_msc-jlink`
+ - Make: `make BOARD=raspberry_pi_pico flash-jlink`
+- **Flash with OpenOCD**:
+ - CMake: `ninja cdc_msc-openocd`
+ - Make: `make BOARD=raspberry_pi_pico flash-openocd`
+- **Generate UF2**:
+ - CMake: `ninja cdc_msc-uf2`
+ - Make: `make BOARD=raspberry_pi_pico all uf2`
+- **List all targets** (CMake/Ninja): `ninja -t targets`
+
+### Unit Testing
+- Install Ceedling: `sudo gem install ceedling`
+- Run all unit tests: `cd test/unit-test && ceedling` or `cd test/unit-test && ceedling test:all` -- takes 4 seconds. NEVER CANCEL. Set timeout to 10+ minutes.
+- Run specific test: `cd test/unit-test && ceedling test:test_fifo`
+- Tests use Unity framework with CMock for mocking
+
+### Documentation
+- Install requirements: `pip install -r docs/requirements.txt`
+- Build docs: `cd docs && sphinx-build -b html . _build` -- takes 2-3 seconds. NEVER CANCEL. Set timeout to 10+ minutes.
+
+### Code Quality and Validation
+- Format code: `clang-format -i path/to/file.c` (uses `.clang-format` config)
+- Check spelling: `pip install codespell && codespell` (uses `.codespellrc` config)
+- Pre-commit hooks validate unit tests and code quality automatically
+
+## Validation
+
+### ALWAYS Run These After Making Changes
+1. **Pre-commit validation** (RECOMMENDED): `pre-commit run --all-files`
+ - Install pre-commit: `pip install pre-commit && pre-commit install`
+ - Runs all quality checks, unit tests, spell checking, and formatting
+ - Takes 10-15 seconds. NEVER CANCEL. Set timeout to 15+ minutes.
+2. **Build validation**: Build at least one example that exercises your changes
+ ```bash
+ cd examples/device/cdc_msc
+ make BOARD=raspberry_pi_pico all
+ ```
+
+### Manual Testing Scenarios
+- **Device examples**: Cannot be fully tested without real hardware, but must build successfully
+- **Unit tests**: Exercise core stack functionality - ALL tests must pass
+- **Build system**: Must be able to build examples for multiple board families
+
+### Board Selection for Testing
+- **STM32F4**: `stm32f407disco` - no external SDK required, good for testing
+- **RP2040**: `raspberry_pi_pico` - requires Pico SDK, commonly used
+- **Other families**: Check `hw/bsp/FAMILY/boards/` for available boards
+
+## Common Tasks and Time Expectations
+
+### Repository Structure Quick Reference
+```
+├── src/ # Core TinyUSB stack
+│ ├── class/ # USB device classes (CDC, HID, MSC, Audio, etc.)
+│ ├── portable/ # MCU-specific drivers (organized by vendor)
+│ ├── device/ # USB device stack core
+│ ├── host/ # USB host stack core
+│ └── common/ # Shared utilities (FIFO, etc.)
+├── examples/ # Example applications
+│ ├── device/ # Device examples (cdc_msc, hid_generic, etc.)
+│ ├── host/ # Host examples
+│ └── dual/ # Dual-role examples
+├── hw/bsp/ # Board Support Packages
+│ └── FAMILY/boards/ # Board-specific configurations
+├── test/unit-test/ # Unit tests using Ceedling
+├── tools/ # Build and utility scripts
+└── docs/ # Sphinx documentation
+```
+
+### Build Time Reference
+- **Dependency fetch**: <1 second
+- **Single example build**: 1-3 seconds
+- **Unit tests**: ~4 seconds
+- **Documentation build**: ~2.5 seconds
+- **Full board examples**: 15-20 seconds
+- **Toolchain installation**: 2-5 minutes (one-time)
+
+### Key Files to Know
+- `tools/get_deps.py`: Manages dependencies for MCU families
+- `tools/build.py`: Builds multiple examples, supports make/cmake
+- `src/tusb.h`: Main TinyUSB header file
+- `src/tusb_config.h`: Configuration template
+- `examples/device/cdc_msc/`: Most commonly used example for testing
+- `test/unit-test/project.yml`: Ceedling test configuration
+
+### Debugging Build Issues
+- **Missing compiler**: Install `gcc-arm-none-eabi` package
+- **Missing dependencies**: Run `python3 tools/get_deps.py FAMILY`
+- **Board not found**: Check `hw/bsp/FAMILY/boards/` for valid board names
+- **objcopy errors**: Often non-critical in full builds, try individual example builds
+
+### Working with USB Device Classes
+- **CDC (Serial)**: `src/class/cdc/` - Virtual serial port
+- **HID**: `src/class/hid/` - Human Interface Device (keyboard, mouse, etc.)
+- **MSC**: `src/class/msc/` - Mass Storage Class (USB drive)
+- **Audio**: `src/class/audio/` - USB Audio Class
+- Each class has device (`*_device.c`) and host (`*_host.c`) implementations
+
+### MCU Family Support
+- **STM32**: Largest support (F0, F1, F2, F3, F4, F7, G0, G4, H7, L4, U5, etc.)
+- **Raspberry Pi**: RP2040, RP2350 with PIO-USB host support
+- **NXP**: iMXRT, Kinetis, LPC families
+- **Microchip**: SAM D/E/G/L families
+- Check `hw/bsp/` for complete list and `docs/reference/boards.rst` for details
+
+## Code Style Guidelines
+
+### General Coding Standards
+- Use C99 standard
+- Memory-safe: no dynamic allocation
+- Thread-safe: defer all interrupt events to non-ISR task functions
+- 2-space indentation, no tabs
+- Use snake_case for variables/functions
+- Use UPPER_CASE for macros and constants
+- Follow existing variable naming patterns in files you're modifying
+- Include proper header comments with MIT license
+- Add descriptive comments for non-obvious functions
+
+### Best Practices
+- When including headers, group in order: C stdlib, tusb common, drivers, classes
+- Always check return values from functions that can fail
+- Use TU_ASSERT() for error checking with return statements
+- Follow the existing code patterns in the files you're modifying
+
+Remember: TinyUSB is designed for embedded systems - builds are fast, tests are focused, and the codebase is optimized for resource-constrained environments.
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index ff59421ce..16f906632 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -198,21 +198,27 @@ jobs:
needs: hil-build
runs-on: [self-hosted, X64, hathach, hardware-in-the-loop]
steps:
+ - name: Get Skip Boards from previous run
+ if: github.run_attempt != '1'
+ run: |
+ if [ -f "${{ env.HIL_JSON }}.skip" ]; then
+ SKIP_BOARDS=$(cat "${{ env.HIL_JSON }}.skip")
+ else
+ SKIP_BOARDS=""
+ fi
+ echo "SKIP_BOARDS=$SKIP_BOARDS"
+ echo "SKIP_BOARDS=$SKIP_BOARDS" >> $GITHUB_ENV
+
- name: Clean workspace
- if: github.run_attempt == '1'
run: |
echo "Cleaning up for the first run"
rm -rf "${{ github.workspace }}"
mkdir -p "${{ github.workspace }}"
- name: Checkout TinyUSB
- if: github.run_attempt == '1'
uses: actions/checkout@v4
- with:
- sparse-checkout: test/hil
- name: Download Artifacts
- if: github.run_attempt == '1'
uses: actions/download-artifact@v4
with:
path: cmake-build
@@ -220,15 +226,6 @@ jobs:
- name: Test on actual hardware
run: |
- ls cmake-build/
-
- # Skip boards that passed with previous run, file is generated by hil_test.py
- SKIP_BOARDS=""
- if [ -f ${{ env.HIL_JSON }}.skip ]; then
- SKIP_BOARDS=$(cat "${HIL_JSON}.skip")
- fi
- echo "SKIP_BOARDS=$SKIP_BOARDS"
-
python3 test/hil/hil_test.py ${{ env.HIL_JSON }} $SKIP_BOARDS
# ---------------------------------------
diff --git a/.github/workflows/ci_set_matrix.py b/.github/workflows/ci_set_matrix.py
index 40d51a7a2..e53998c66 100755
--- a/.github/workflows/ci_set_matrix.py
+++ b/.github/workflows/ci_set_matrix.py
@@ -44,7 +44,8 @@ family_list = {
"stm32h7 stm32h7rs": ["arm-gcc", "arm-clang", "arm-iar"],
"stm32l0 stm32l4": ["arm-gcc", "arm-clang", "arm-iar"],
"stm32n6": ["arm-gcc"],
- "stm32u5 stm32wb": ["arm-gcc", "arm-clang", "arm-iar"],
+ "stm32u0 stm32u5 stm32wb": ["arm-gcc", "arm-clang", "arm-iar"],
+ "stm32wba": ["arm-gcc", "arm-clang"],
"xmc4000": ["arm-gcc"],
"-bespressif_s2_devkitc": ["esp-idf"],
# S3, P4 will be built by hil test
diff --git a/.gitignore b/.gitignore
index 5638a09db..a4045f120 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,3 +52,4 @@ RelWithDebInfo
Release
BrowseInfo
.cmake_build
+README_processed.rst
diff --git a/.idea/debugServers/AT32F423VCT7.xml b/.idea/debugServers/AT32F423VCT7.xml
new file mode 100644
index 000000000..38b3d76ef
--- /dev/null
+++ b/.idea/debugServers/AT32F423VCT7.xml
@@ -0,0 +1,13 @@
+<component name="DebugServers">
+ <jlink-debug-target name="AT32F423VCT7" uniqueID="de4ea1de-6dcf-413e-a21f-aaeaeb0f3dbc">
+ <debugger version="1">
+ <debugger kind="GDB" isBundled="true" />
+ <env />
+ </debugger>
+ <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
+ <console port="19021" />
+ <target device="AT32F423VCT7" reset-before="false" frequency="16000" />
+ <connection extended-remote="false" port="4444" warmup-ms="500" />
+ <swo />
+ </jlink-debug-target>
+</component> \ No newline at end of file
diff --git a/.idea/debugServers/ST_LINK.xml b/.idea/debugServers/ST_LINK.xml
new file mode 100644
index 000000000..7c21d3879
--- /dev/null
+++ b/.idea/debugServers/ST_LINK.xml
@@ -0,0 +1,13 @@
+<component name="DebugServers">
+ <stlink-debug-target name="ST-LINK" uniqueID="300d1a6f-85c0-4eb3-9753-f033d01e2eff">
+ <debugger version="1">
+ <debugger kind="GDB" isBundled="true" />
+ <env />
+ </debugger>
+ <gdbserver exe="$USER_HOME$/st/stm32cubeide_1.16.1/plugins/com.st.stm32cube.ide.mcu.externaltools.stlink-gdb-server.linux64_2.1.400.202404281720/tools/bin/ST-LINK_gdbserver" programmer="$USER_HOME$/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin" />
+ <st-link />
+ <device interface="SWD" />
+ <connection port="61234" warmup-ms="500" />
+ <swo enabled="false" port="61235" />
+ </stlink-debug-target>
+</component> \ No newline at end of file
diff --git a/.idea/debugServers/at32f403acgu7.xml b/.idea/debugServers/at32f403acgu7.xml
new file mode 100644
index 000000000..9df65140f
--- /dev/null
+++ b/.idea/debugServers/at32f403acgu7.xml
@@ -0,0 +1,13 @@
+<component name="DebugServers">
+ <jlink-debug-target name="at32f403acgu7" uniqueID="13a1c815-97d7-4b16-8fcc-564bddfe2270">
+ <debugger version="1">
+ <debugger kind="GDB" isBundled="true" />
+ <env />
+ </debugger>
+ <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
+ <console port="19021" />
+ <target device="AT32F403ACGU7" reset-before="false" frequency="16000" />
+ <connection extended-remote="false" port="4444" warmup-ms="500" />
+ <swo />
+ </jlink-debug-target>
+</component> \ No newline at end of file
diff --git a/.idea/debugServers/max32690.xml b/.idea/debugServers/max32690.xml
new file mode 100644
index 000000000..3551f591e
--- /dev/null
+++ b/.idea/debugServers/max32690.xml
@@ -0,0 +1,13 @@
+<component name="DebugServers">
+ <jlink-debug-target name="max32690" uniqueID="cb5e7c25-cbda-4c6d-94e9-28a85a81ba66">
+ <debugger version="1">
+ <debugger kind="GDB" isBundled="true" />
+ <env />
+ </debugger>
+ <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
+ <console port="19021" />
+ <target device="MAX32690" reset-before="false" frequency="16000" />
+ <connection extended-remote="false" port="4444" warmup-ms="500" />
+ <swo />
+ </jlink-debug-target>
+</component> \ No newline at end of file
diff --git a/.idea/debugServers/s3.xml b/.idea/debugServers/s3.xml
new file mode 100644
index 000000000..a03abf744
--- /dev/null
+++ b/.idea/debugServers/s3.xml
@@ -0,0 +1,6 @@
+<component name="DebugServers">
+ <esp-idf-debug-target name="s3" uniqueID="e096f0d4-5923-482d-bcc3-169a2cfd7cdc">
+ <console enabled="false" />
+ <target />
+ </esp-idf-debug-target>
+</component> \ No newline at end of file
diff --git a/.idea/debugServers/wch_riscv.xml b/.idea/debugServers/wch_riscv.xml
new file mode 100644
index 000000000..2e147f1b6
--- /dev/null
+++ b/.idea/debugServers/wch_riscv.xml
@@ -0,0 +1,14 @@
+<component name="DebugServers">
+ <generic-debug-target name="wch-riscv" uniqueID="c471e2d0-3cb4-4e7e-aeb7-a33d0c8fdc08">
+ <debugger version="1">
+ <debugger kind="GDB" isBundled="true" />
+ <env />
+ </debugger>
+ <gdbserver dir="$CMakeProjectDir$" exe="$USER_HOME$/app/riscv-openocd-wch/src/openocd" args="-f hw/bsp/ch32v20x/wch-riscv.cfg">
+ <env />
+ </gdbserver>
+ <console enabled="true" port="4444" />
+ <target download-type="UPDATED_ONLY" reset-command="monitor reset init; resume 0x08000000" reset-before="false" />
+ <connection extended-remote="false" remote-string="tcp::3333" warmup-ms="500" />
+ </generic-debug-target>
+</component> \ No newline at end of file
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 000000000..6c6baa246
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,78 @@
+# TinyUSB Development Guide
+
+## Build Commands
+
+### CMake Build System (Preferred)
+CMake with Ninja is the preferred build method for TinyUSB development.
+
+- Build example with Ninja:
+ ```bash
+ cd examples/device/cdc_msc
+ mkdir build && cd build
+ cmake -G Ninja -DBOARD=raspberry_pi_pico ..
+ ninja
+ ```
+- Debug build: `cmake -G Ninja -DBOARD=raspberry_pi_pico -DCMAKE_BUILD_TYPE=Debug ..`
+- With logging: `cmake -G Ninja -DBOARD=raspberry_pi_pico -DLOG=2 ..`
+- With RTT logger: `cmake -G Ninja -DBOARD=raspberry_pi_pico -DLOG=2 -DLOGGER=rtt ..`
+- Flash with JLink: `ninja cdc_msc-jlink`
+- Flash with OpenOCD: `ninja cdc_msc-openocd`
+- Generate UF2: `ninja cdc_msc-uf2`
+- List all targets: `ninja -t targets`
+
+### Make Build System (Alternative)
+- Build example: `cd examples/device/cdc_msc && make BOARD=raspberry_pi_pico all`
+- For specific example: `cd examples/{device|host|dual}/{example_name} && make BOARD=raspberry_pi_pico all`
+- Flash with JLink: `make BOARD=raspberry_pi_pico flash-jlink`
+- Flash with OpenOCD: `make BOARD=raspberry_pi_pico flash-openocd`
+- Debug build: `make BOARD=raspberry_pi_pico DEBUG=1 all`
+- With logging: `make BOARD=raspberry_pi_pico LOG=2 all`
+- With RTT logger: `make BOARD=raspberry_pi_pico LOG=2 LOGGER=rtt all`
+- Generate UF2: `make BOARD=raspberry_pi_pico all uf2`
+
+### Additional Options
+- Select RootHub port: `RHPORT_DEVICE=1` (make) or `-DRHPORT_DEVICE=1` (cmake)
+- Set port speed: `RHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED` (make) or `-DRHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED` (cmake)
+
+### Dependencies
+- Get dependencies: `python tools/get_deps.py rp2040`
+- Or from example: `cd examples/device/cdc_msc && make BOARD=raspberry_pi_pico get-deps`
+
+### Testing
+- Run unit tests: `cd test/unit-test && ceedling test:all`
+- Run specific test: `cd test/unit-test && ceedling test:test_fifo`
+
+### Pre-commit Hooks
+Before building, it's recommended to run pre-commit to ensure code quality:
+- Run pre-commit on all files: `pre-commit run --all-files`
+- Run pre-commit on staged files: `pre-commit run`
+- Install pre-commit hook: `pre-commit install`
+
+## Code Style Guidelines
+- Use C99 standard
+- Memory-safe: no dynamic allocation
+- Thread-safe: defer all interrupt events to non-ISR task functions
+- 2-space indentation, no tabs
+- Use snake_case for variables/functions
+- Use UPPER_CASE for macros and constants
+- Follow existing variable naming patterns in files you're modifying
+- Include proper header comments with MIT license
+- Add descriptive comments for non-obvious functions
+- When including headers, group in order: C stdlib, tusb common, drivers, classes
+- Always check return values from functions that can fail
+- Use TU_ASSERT() for error checking with return statements
+
+## Project Structure
+- src/: Core TinyUSB stack code
+- hw/: Board support packages and MCU drivers
+- examples/: Reference examples for device/host/dual
+- test/: Unit tests and hardware integration tests
+
+## Release Process
+To prepare a new release:
+1. Update the `version` variable in `tools/make_release.py` to the new version number
+2. Run the release script: `python tools/make_release.py`
+ - This will update version numbers in `src/tusb_option.h`, `repository.yml`, and `library.json`
+ - It will also regenerate documentation
+3. Update `docs/info/changelog.rst` with release notes
+4. Commit changes and create release tag
diff --git a/README.rst b/README.rst
index d6830e707..03ad3744c 100644
--- a/README.rst
+++ b/README.rst
@@ -60,6 +60,7 @@ Supports multiple device configurations by dynamically changing USB descriptors,
- Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ...
- Mass Storage Class (MSC): with multiple LUNs
- Musical Instrument Digital Interface (MIDI)
+- Media Transfer Protocol (MTP/PTP)
- Network with RNDIS, Ethernet Control Model (ECM), Network Control Model (NCM)
- Test and Measurement Class (USBTMC)
- Video class 1.5 (UVC): work in progress
@@ -115,16 +116,18 @@ Supported CPUs
| +-----------------------------+--------+------+-----------+------------------------+-------------------+
| | F402_F405 | ✔ | ✔ | ✔ | dwc2 | F405 is HS |
+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+
-| Brigetek | FT90x | ✔ | | ✔ | ft9xx | 1-dir ep |
+| Bridgetek | FT90x | ✔ | | ✔ | ft9xx | 1-dir ep |
+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+
| Broadcom | BCM2711, BCM2837 | ✔ | | ✔ | dwc2 | |
+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+
| Dialog | DA1469x | ✔ | ✖ | ✖ | da146xx | |
+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+
-| Espressif | S2, S3 | ✔ | ✔ | ✖ | dwc2 or esp32sx | |
-| ESP32 +-----------------------------+--------+------+-----------+------------------------+-------------------+
+| Espressif | S2, S3 | ✔ | ✔ | ✖ | dwc2 | |
+| ESP32 +-----------------------------+--------+------+-----------+------------------------+-------------------+
| | P4 | ✔ | ✔ | ✔ | dwc2 | |
-+--------------+----+------------------------+--------+------+-----------+------------------------+-------------------+
+| +-----------------------------+--------+------+-----------+------------------------+-------------------+
+| | H4 | ✔ | ✔ | ✖ | dwc2 | |
++--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+
| GigaDevice | GD32VF103 | ✔ | | ✖ | dwc2 | |
+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+
| Infineon | XMC4500 | ✔ | ✔ | ✖ | dwc2 | |
@@ -145,7 +148,7 @@ Supported CPUs
| | +-----------------------+--------+------+-----------+------------------------+-------------------+
| | | 32mz | ✔ | | | pic32mz | musb variant |
+--------------+-----+-----------------------+--------+------+-----------+------------------------+-------------------+
-| Mind Montion | mm32 | ✔ | | ✖ | mm32f327x_otg | ci_fs variant |
+| MindMotion | mm32 | ✔ | | ✖ | mm32f327x_otg | ci_fs variant |
+--------------+-----+-----------------------+--------+------+-----------+------------------------+-------------------+
| NordicSemi | nRF 52833, 52840, 5340 | ✔ | ✖ | ✖ | nrf5x | only ep8 is ISO |
+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+
@@ -200,8 +203,6 @@ Supported CPUs
| | C0, G0, H5 | ✔ | | ✖ | stm32_fsdev | |
| +-----------------------------+--------+------+-----------+------------------------+-------------------+
| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | |
-| +-----------------------------+--------+------+-----------+------------------------+-------------------+
-| | L0, L1 | ✔ | ✖ | ✖ | stm32_fsdev | |
| +----+------------------------+--------+------+-----------+------------------------+-------------------+
| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | |
| | +------------------------+--------+------+-----------+------------------------+-------------------+
@@ -209,6 +210,8 @@ Supported CPUs
| +----+------------------------+--------+------+-----------+------------------------+-------------------+
| | N6 | ✔ | ✔ | ✔ | dwc2 | |
| +----+------------------------+--------+------+-----------+------------------------+-------------------+
+| | U0 | ✔ | ✖ | ✖ | stm32_fsdev | |
+| +----+------------------------+--------+------+-----------+------------------------+-------------------+
| | U5 | 535, 545 | ✔ | | ✖ | stm32_fsdev | |
| | +------------------------+--------+------+-----------+------------------------+-------------------+
| | | 575, 585 | ✔ | ✔ | ✖ | dwc2 | |
diff --git a/docs/info/changelog.rst b/docs/info/changelog.rst
index 6024bb9e3..b4423f81e 100644
--- a/docs/info/changelog.rst
+++ b/docs/info/changelog.rst
@@ -2,6 +2,198 @@
Changelog
*********
+0.19.0
+======
+
+General
+-------
+
+- New MCUs and Boards:
+
+ - Add ESP32-H4, ESP32-C5, ESP32-C61 support
+ - Add STM32U0, STM32WBA, STM32N6
+ - Add AT32F405, AT32F403A, AT32F415, AT32F423 support
+ - Add CH32V305 support and CH32V20x USB host support
+ - Add MCXA156 SDK 2.16 support and FRDM-MCXA156 board
+
+API Changes
+-----------
+
+- Core APIs
+ - Add weak callbacks with new syntax for better compiler compatibility
+ - Add ``tusb_deinit()`` to cleanup stack
+ - Add time functions: ``tusb_time_millis_api()`` and ``tusb_time_delay_ms_api()``
+ - Add ``osal_critical`` APIs for critical section handling
+ - Introduce ``xfer_isr()`` callback for ISO transfer optimization in device classes
+
+- Device APIs
+ - CDC: Add notification support ``tud_cdc_configure()``, ``tud_cdc_n_notify_uart_state()``,
+ ``tud_cdc_n_notify_conn_speed_change()``, ``tud_cdc_notify_complete_cb()``
+ - MSC: Add ``tud_msc_inquiry2_cb()`` with bufsize parameter, update ``tud_msc_async_io_done()``
+ with ``in_isr`` parameter
+ - Audio: Add ``tud_audio_n_mounted()`` and various FIFO access functions
+ - MTP: Add ``tud_mtp_mounted()``, ``tud_mtp_data_send()``, ``tud_mtp_data_receive()``,
+ ``tud_mtp_response_send()``, ``tud_mtp_event_send()``
+
+- Host APIs
+ - Core: Add ``tuh_edpt_close()``, ``tuh_address_set()``, ``tuh_descriptor_get_device_local()``,
+ ``tuh_descriptor_get_string_langid()``, ``tuh_connected()``, ``tuh_bus_info_get()``
+ - Add enumeration callbacks: ``tuh_enum_descriptor_device_cb()``,
+ ``tuh_enum_descriptor_configuration_cb()``
+ - CDC: Add ``tuh_cdc_get_control_line_state_local()``, ``tuh_cdc_get/set_dtr/rts()``,
+ ``tuh_cdc_connect/disconnect()`` and sync versions of all control APIs
+ - MIDI: Add ``tuh_midi_itf_get_info()``, ``tuh_midi_packet_read_n()``,
+ ``tuh_midi_packet_write_n()``, ``tuh_midi_read_available()``, ``tuh_midi_write_flush()``,
+ ``tuh_midi_descriptor_cb()``
+
+Controller Driver (DCD & HCD)
+-----------------------------
+
+- DWC2
+ - Support DWC2 v4.30a with improved reset procedure
+ - Fix core reset: wait for AHB idle before reset
+ - Add STM32 DWC2 data cache support with proper alignment
+ - Host improvements:
+ - Fix disconnect detection and SOF flag handling
+ - Fix HFIR timing off-by-one error
+ - Retry IN token immediately for bInterval=1
+ - Proper attach debouncing (200ms)
+ - Fix all retry intervals
+ - Resume OUT transfer when PING ACKed
+ - Fix enumeration racing conditions
+ - Refactor bitfields for better code generation
+
+- FSDEV (STM32)
+ - Fix AT32 compile issues after single-buffered endpoint changes
+ - Add configurable single-buffered isochronous endpoints
+ - Fix STM32H7 recurrent suspend ISR
+ - Fix STM32L4 GPIOD clock enable for variants without GPIOD
+ - Fix STM32 PHYC PLL stability wait
+ - Improve PMA size handling for STM32U0
+
+- EHCI
+ - Fix removed QHD getting reused
+ - Fix NXP USBPHY disconnection detection
+
+- Chipidea/NXP
+ - Fix race condition with spinlock
+ - Improve iMXRT support: fix build, disable BOARD_ConfigMPU, fix attach debouncing on port1 highspeed
+ - Fix iMXRT1064 and add to HIL test pool
+
+- MAX3421E
+ - Use spinlock for thread safety instead of atomic flag
+ - Implement ``hcd_edpt_close()``
+
+- RP2040
+ - Fix audio ISO transfer: reset state before notifying stack
+ - Fix CMake RTOS cache variable
+ - Abort transfer if active in ``iso_activate()``
+
+- SAMD
+ - Add host controller driver support
+
+Device Stack
+------------
+
+- USBD Core
+ - Introduce ``xfer_isr()`` callback for interrupt-time transfer handling
+ - Add ``usbd_edpt_xfer_fifo()`` stub
+ - Revert endpoint busy/claim status if ``xfer_isr()`` defers to ``xfer_cb()``
+
+- Audio
+ - Major simplification of UAC driver and alt settings management
+ - Move ISO transfers into ``xfer_isr()`` for better performance
+ - Remove FIFO mutex (single producer/consumer optimization)
+ - Add implicit feedback support for data IN endpoints
+ - Fix alignment issues
+ - Update buffer macros with cache line size alignment
+
+- CDC
+ - Add notification support: ``CFG_TUD_CDC_NOTIFY``, ``tud_cdc_n_notify_conn_speed_change()``, ``tud_cdc_notify_complete_cb()``
+ - Reduce default bInterval from 16ms to 1ms for better responsiveness
+ - Rename ``tud_cdc_configure_fifo()`` to ``tud_cdc_configure()`` and add ``tx_overwritable_if_not_connected`` option
+ - Fix web serial robustness with major overhaul and logic cleanup
+
+- HID
+ - Add Usage Page and Table for Power Devices (0x84 - 0x85)
+ - Fix HID descriptor parser variable size and 4-byte item handling
+ - Add consumer page configurations
+
+- MIDI
+ - Fix MIDI interface descriptor handling after audio streaming interface
+ - Skip RX data with all zeroes
+
+- MSC
+ - Add async I/O support for MSC using ``tud_msc_async_io_done()``
+ - Add ``tud_msc_inquiry2_cb()`` with bufsize for full inquiry response
+
+- MTP
+ - Add new Media Transfer Protocol (MTP) device class driver
+ - Support MTP operations: GetDeviceInfo, SendObjectInfo, SendObject
+ - Add MTP event support with ``tud_mtp_event_send()``
+ - Implement filesystem example with callbacks
+ - Add hardware-in-the-loop testing support
+
+- NCM
+ - Add USB NCM link state control support
+ - Fix DHCP offer/ACK destination
+
+- USBTMC
+ - Add vendor-specific message support
+
+- Vendor
+ - Fix vendor device reset and open issues
+ - Fix descriptor parsing for ``CFG_TUD_VENDOR > 1``
+ - Fix vendor FIFO argument calculation
+
+Host Stack
+----------
+
+- USBH Core
+ - Major enumeration improvements:
+ - Fix enumeration racing conditions
+ - Add proper attach debouncing with hub/rootport handling (200ms delay)
+ - Reduce ``ENUM_DEBOUNCING_DELAY_MS`` to 200ms
+ - Always get language ID, manufacturer, product, and serial strings during enumeration
+ - Always get first 2 bytes of string descriptor to determine length (prevents buffer overflow)
+ - Support devices with multiple configurations
+ - Add ``tuh_enum_descriptor_device_cb()`` and ``tuh_enum_descriptor_configuration_cb()`` callbacks
+ - Add ``tuh_descriptor_get_string_langid()`` API
+ - Hub improvements:
+ - Check status before getting first device descriptor
+ - Properly handle port status and change detection
+ - Queue status endpoint for detach/remove events
+ - Fix hub status change endpoint handling
+ - Fix endpoint management:
+ - ``hcd_edpt_open()`` returns false if endpoint already opened
+ - Add ``hcd_edpt_close()`` implementation
+ - Abort pending transfers on close
+ - Add roothub debouncing flag to ignore attach/remove during debouncing
+ - Move address setting and bus info management to separate structures
+ - Force removed devices in same bus info before setting address
+
+- CDC Serial Host
+ - Major refactor to generalize CDC serial drivers (FTDI, CP210x, CH34x, PL2303, ACM)
+ - Add explicit ``sync()`` API with ``TU_API_SYNC()`` returning ``tusb_xfer_result_t``
+ - Rename ``tuh_cdc_get_local_line_coding()`` to ``tuh_cdc_get_line_coding_local()``
+ - Add ``tuh_cdc_get_control_line_state_local()``
+ - Implement ``tuh_cdc_get/set_dtr/rts()`` as inline functions
+
+- MIDI Host
+ - Major API changes:
+ - Rename ``tuh_midi_stream_flush()`` to ``tuh_midi_write_flush()``
+ - Add ``tuh_midi_packet_read_n()`` and ``tuh_midi_packet_write_n()``
+ - Add ``CFG_TUH_MIDI_STREAM_API`` to opt out of stream API
+ - Change API to use index instead of device address (supports multiple MIDI per device)
+ - Rename ``tuh_midi_get_num_rx/tx_cables()`` to ``tuh_midi_get_rx/tx_cable_count()``
+ - Add ``tuh_midi_descriptor_cb()`` and ``tuh_midi_itf_get_info()``
+
+- MSC Host
+ - Continue async I/O improvements
+
+- HID Host
+ - Fix version string to actually show version
+
0.18.0
======
diff --git a/docs/reference/boards.rst b/docs/reference/boards.rst
index 289ec543a..3f8277247 100644
--- a/docs/reference/boards.rst
+++ b/docs/reference/boards.rst
@@ -28,19 +28,23 @@ max78002evkit MAX78002 EVKIT maxim https://www.analog.com/en/resources/e
============= ================ ======== ================================================================================================================= ======
Artery
------
+------
-============== ============== ============= ================================================== ======
-Board Name Family URL Note
-============== ============== ============= ================================================== ======
-at_start_f405 AT-START-F405 at32f402_405 https://www.arterychip.com/en/product/AT32F405.jsp
-at_start_f403a AT-START-F403a at32f403a_407 https://www.arterychip.com/en/product/AT32F403.jsp
-at_start_f413 AT-START-F413 at32f413 https://www.arterychip.com/en/product/AT32F413.jsp
-at_start_f415 AT-START-F415 at32f415 https://www.arterychip.com/en/product/AT32F415.jsp
-at_start_f423 AT-START-F423 at32f423 https://www.arterychip.com/en/product/AT32F423.jsp
-at_start_f425 AT-START-F425 at32f425 https://www.arterychip.com/en/product/AT32F425.jsp
-at_start_f437 AT-START-F437 at32f435_437 https://www.arterychip.com/en/product/AT32F437.jsp
-============== ============== ============= ================================================== ======
+========================= ============================= ============= ==================================================== ======
+Board Name Family URL Note
+========================= ============================= ============= ==================================================== ======
+at_start_f402 AT-START-F402 at32f402_405 https://www.arterychip.com/en/product/AT32F402.jsp
+at_start_f405 AT-START-F405 at32f402_405 https://www.arterychip.com/en/product/AT32F405.jsp
+at32f403a_weact_blackpill WeAct BlackPill AT32F403ACGU7 at32f403a_407 https://github.com/WeActStudio/WeActStudio.BlackPill
+at_start_f403a AT-START-F403a at32f403a_407 https://www.arterychip.com/en/product/AT32F403.jsp
+at_start_f407 AT-START-F407 at32f403a_407 https://www.arterychip.com/en/product/AT32F407.jsp
+at_start_f413 AT-START-F413 at32f413 https://www.arterychip.com/en/product/AT32F413.jsp
+at_start_f415 AT-START-F415 at32f415 https://www.arterychip.com/en/product/AT32F415.jsp
+at_start_f423 AT-START-F423 at32f423 https://www.arterychip.com/en/product/AT32F423.jsp
+at_start_f425 AT-START-F425 at32f425 https://www.arterychip.com/en/product/AT32F425.jsp
+at_start_f435 AT-START-F435 at32f435_437 https://www.arterychip.com/en/product/AT32F435.jsp
+at_start_f437 AT-START-F437 at32f435_437 https://www.arterychip.com/en/product/AT32F437.jsp
+========================= ============================= ============= ==================================================== ======
Bridgetek
---------
@@ -292,13 +296,16 @@ stm32l412nucleo STM32 L412 Nucleo stm32l4 https://www.s
stm32l476disco STM32 L476 Disco stm32l4 https://www.st.com/en/evaluation-tools/32l476gdiscovery.html
stm32l4p5nucleo STM32 L4P5 Nucleo stm32l4 https://www.st.com/en/evaluation-tools/nucleo-l4p5zg.html
stm32l4r5nucleo STM32 L4R5 Nucleo stm32l4 https://www.st.com/en/evaluation-tools/nucleo-l4r5zi.html
+stm32n6570dk STM32 N6570-DK stm32n6 https://www.st.com/en/evaluation-tools/stm32n6570-dk.html
stm32n657nucleo STM32 N657X0-Q Nucleo stm32n6 https://www.st.com/en/evaluation-tools/nucleo-n657x0-q.html
b_u585i_iot2a STM32 B-U585i IOT2A Discovery kit stm32u5 https://www.st.com/en/evaluation-tools/b-u585i-iot02a.html
+stm32u083cdk STM32 U083C Discovery Kit stm32u0 https://www.st.com/en/evaluation-tools/stm32u083c-dk.html
stm32u545nucleo STM32 U545 Nucleo stm32u5 https://www.st.com/en/evaluation-tools/nucleo-u545re-q.html
stm32u575eval STM32 U575 Eval stm32u5 https://www.st.com/en/evaluation-tools/stm32u575i-ev.html
stm32u575nucleo STM32 U575 Nucleo stm32u5 https://www.st.com/en/evaluation-tools/nucleo-u575zi-q.html
stm32u5a5nucleo STM32 U5a5 Nucleo stm32u5 https://www.st.com/en/evaluation-tools/nucleo-u5a5zj-q.html
stm32wb55nucleo STM32 P-NUCLEO-WB55 stm32wb https://www.st.com/en/evaluation-tools/p-nucleo-wb55.html
+stm32wba_nucleo STM32 NUCLEO-WBA65RI stm32wba https://www.st.com/en/evaluation-tools/nucleo-wba65ri.html
=================== ================================= ========= ================================================================= ======
Sunxi
diff --git a/docs/reference/dependencies.rst b/docs/reference/dependencies.rst
index d75139aae..1a088c989 100644
--- a/docs/reference/dependencies.rst
+++ b/docs/reference/dependencies.rst
@@ -4,9 +4,9 @@ Dependencies
MCU low-level peripheral driver and external libraries for building TinyUSB examples
-======================================== ================================================================ ======================================== ======================================================================================================================================================================================================================================================================================================================================================
+======================================== ================================================================ ======================================== ======================================================================================================================================================================================================================================================================================================================================================================
Local Path Repo Commit Required by
-======================================== ================================================================ ======================================== ======================================================================================================================================================================================================================================================================================================================================================
+======================================== ================================================================ ======================================== ======================================================================================================================================================================================================================================================================================================================================================================
hw/mcu/allwinner https://github.com/hathach/allwinner_driver.git 8e5e89e8e132c0fd90e72d5422e5d3d68232b756 fc100s
hw/mcu/analog/msdk https://github.com/analogdevicesinc/msdk.git b20b398d3e5e2007594e54a74ba3d2a2e50ddd75 maxim
hw/mcu/artery/at32f402_405 https://github.com/ArteryTek/AT32F402_405_Firmware_Library.git 4424515c2663e82438654e0947695295df2abdfe at32f402_405
@@ -26,60 +26,64 @@ hw/mcu/nordic/nrfx https://github.com/NordicSemiconductor
hw/mcu/nuvoton https://github.com/majbthrd/nuc_driver.git 2204191ec76283371419fbcec207da02e1bc22fa nuc
hw/mcu/nxp/lpcopen https://github.com/hathach/nxp_lpcopen.git b41cf930e65c734d8ec6de04f1d57d46787c76ae lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43
hw/mcu/nxp/mcux-sdk https://github.com/nxp-mcuxpresso/mcux-sdk a1bdae309a14ec95a4f64a96d3315a4f89c397c6 kinetis_k kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx imxrt
-hw/mcu/raspberry_pi/Pico-PIO-USB https://github.com/sekigon-gonnoc/Pico-PIO-USB.git 3c1eec341a5232640e4c00628b889b641af34b28 rp2040
+hw/mcu/raspberry_pi/Pico-PIO-USB https://github.com/sekigon-gonnoc/Pico-PIO-USB.git 675543bcc9baa8170f868ab7ba316d418dbcf41f rp2040
hw/mcu/renesas/fsp https://github.com/renesas/fsp.git edcc97d684b6f716728a60d7a6fea049d9870bd6 ra
hw/mcu/renesas/rx https://github.com/kkitayam/rx_device.git 706b4e0cf485605c32351e2f90f5698267996023 rx
hw/mcu/silabs/cmsis-dfp-efm32gg12b https://github.com/cmsis-packs/cmsis-dfp-efm32gg12b.git f1c31b7887669cb230b3ea63f9b56769078960bc efm32
hw/mcu/sony/cxd56/spresense-exported-sdk https://github.com/sonydevworld/spresense-exported-sdk.git 2ec2a1538362696118dc3fdf56f33dacaf8f4067 spresense
-hw/mcu/st/cmsis_device_c0 https://github.com/STMicroelectronics/cmsis_device_c0.git fb56b1b70c73b74eacda2a4bcc36886444364ab3 stm32c0
-hw/mcu/st/cmsis_device_f0 https://github.com/STMicroelectronics/cmsis_device_f0.git 2fc25ee22264bc27034358be0bd400b893ef837e stm32f0
-hw/mcu/st/cmsis_device_f1 https://github.com/STMicroelectronics/cmsis_device_f1.git 6601104a6397299b7304fd5bcd9a491f56cb23a6 stm32f1
-hw/mcu/st/cmsis_device_f2 https://github.com/STMicroelectronics/cmsis_device_f2.git 182fcb3681ce116816feb41b7764f1b019ce796f stm32f2
-hw/mcu/st/cmsis_device_f3 https://github.com/STMicroelectronics/cmsis_device_f3.git 5e4ee5ed7a7b6c85176bb70a9fd3c72d6eb99f1b stm32f3
-hw/mcu/st/cmsis_device_f4 https://github.com/STMicroelectronics/cmsis_device_f4.git 2615e866fa48fe1ff1af9e31c348813f2b19e7ec stm32f4
-hw/mcu/st/cmsis_device_f7 https://github.com/STMicroelectronics/cmsis_device_f7.git 25b0463439303b7a38f0d27b161f7d2f3c096e79 stm32f7
-hw/mcu/st/cmsis_device_g0 https://github.com/STMicroelectronics/cmsis_device_g0.git 3a23e1224417f3f2d00300ecd620495e363f2094 stm32g0
-hw/mcu/st/cmsis_device_g4 https://github.com/STMicroelectronics/cmsis_device_g4.git ce822adb1dc552b3aedd13621edbc7fdae124878 stm32g4
-hw/mcu/st/cmsis_device_h5 https://github.com/STMicroelectronics/cmsis_device_h5.git cd2d1d579743de57b88ccaf61a968b9c05848ffc stm32h5
-hw/mcu/st/cmsis_device_h7 https://github.com/STMicroelectronics/cmsis_device_h7.git 60dc2c913203dc8629dc233d4384dcc41c91e77f stm32h7
-hw/mcu/st/cmsis_device_h7rs https://github.com/STMicroelectronics/cmsis_device_h7rs.git 832649d1fd09bd901e9f68e979522e5c209ebf20 stm32h7rs
-hw/mcu/st/cmsis_device_l0 https://github.com/STMicroelectronics/cmsis_device_l0.git 69cd5999fd40ae6e546d4905b21635c6ca1bcb92 stm32l0
-hw/mcu/st/cmsis_device_l1 https://github.com/STMicroelectronics/cmsis_device_l1.git 7f16ec0a1c4c063f84160b4cc6bf88ad554a823e stm32l1
-hw/mcu/st/cmsis_device_l4 https://github.com/STMicroelectronics/cmsis_device_l4.git 6ca7312fa6a5a460b5a5a63d66da527fdd8359a6 stm32l4
-hw/mcu/st/cmsis_device_l5 https://github.com/STMicroelectronics/cmsis_device_l5.git d922865fc0326a102c26211c44b8e42f52c1e53d stm32l5
-hw/mcu/st/cmsis_device_n6 https://github.com/STMicroelectronics/cmsis-device-n6.git f818b00f775444e8d19ef6cad822534c345e054f stm32n6
-hw/mcu/st/cmsis_device_u5 https://github.com/STMicroelectronics/cmsis_device_u5.git 5ad9797c54ec3e55eff770fc9b3cd4a1aefc1309 stm32u5
-hw/mcu/st/cmsis_device_wb https://github.com/STMicroelectronics/cmsis_device_wb.git d6a7fa2e7de084f5e5e47f2ab88b022fe9b50e5a stm32wb
+hw/mcu/st/cmsis-device-u0 https://github.com/STMicroelectronics/cmsis-device-u0.git e3a627c6a5bc4eb2388e1885a95cc155e1672253 stm32u0
+hw/mcu/st/cmsis-device-wba https://github.com/STMicroelectronics/cmsis-device-wba.git 647d8522e5fd15049e9a1cc30ed19d85e5911eaf stm32wba
+hw/mcu/st/cmsis_device_c0 https://github.com/STMicroelectronics/cmsis_device_c0.git 517611273f835ffe95318947647bc1408f69120d stm32c0
+hw/mcu/st/cmsis_device_f0 https://github.com/STMicroelectronics/cmsis_device_f0.git cbb5da5d48b4b5f2efacdc2f033be30f9d29889f stm32f0
+hw/mcu/st/cmsis_device_f1 https://github.com/STMicroelectronics/cmsis_device_f1.git c8e9a4a4f16b6d2cb2a2083cbe5161025280fb22 stm32f1
+hw/mcu/st/cmsis_device_f2 https://github.com/STMicroelectronics/cmsis_device_f2.git 49321f1e4d2bd3e65687b37f2652a28ea7983674 stm32f2
+hw/mcu/st/cmsis_device_f3 https://github.com/STMicroelectronics/cmsis_device_f3.git 5558e64e3675a1e1fcb1c71f468c7c407c1b1134 stm32f3
+hw/mcu/st/cmsis_device_f4 https://github.com/STMicroelectronics/cmsis_device_f4.git 3c77349ce04c8af401454cc51f85ea9a50e34fc1 stm32f4
+hw/mcu/st/cmsis_device_f7 https://github.com/STMicroelectronics/cmsis_device_f7.git 2352e888e821aa0f4fe549bd5ea81d29c67a3222 stm32f7
+hw/mcu/st/cmsis_device_g0 https://github.com/STMicroelectronics/cmsis_device_g0.git f484fe852535f913a02ee79787eafa74dd7f9488 stm32g0
+hw/mcu/st/cmsis_device_g4 https://github.com/STMicroelectronics/cmsis_device_g4.git 7c39c32593b03764aaa57531588b8bf7cdd443a5 stm32g4
+hw/mcu/st/cmsis_device_h5 https://github.com/STMicroelectronics/cmsis_device_h5.git 5273b8f134ba65f5b8174c4141b711b5c0d295b2 stm32h5
+hw/mcu/st/cmsis_device_h7 https://github.com/STMicroelectronics/cmsis_device_h7.git 45b818cab6ee2806e3a27c80e330957223424392 stm32h7
+hw/mcu/st/cmsis_device_h7rs https://github.com/STMicroelectronics/cmsis_device_h7rs.git 57ea11f70ebf1850e1048989d665c9070f0bb863 stm32h7rs
+hw/mcu/st/cmsis_device_l0 https://github.com/STMicroelectronics/cmsis_device_l0.git 7b7ae8cd71437331e1d7824f157d00c7bb4a5044 stm32l0
+hw/mcu/st/cmsis_device_l1 https://github.com/STMicroelectronics/cmsis_device_l1.git a23ade4ccf14012085fedf862e33a536ab7ed8be stm32l1
+hw/mcu/st/cmsis_device_l4 https://github.com/STMicroelectronics/cmsis_device_l4.git a2530753e86dd326a75467d28feb92e2ba7d0df2 stm32l4
+hw/mcu/st/cmsis_device_l5 https://github.com/STMicroelectronics/cmsis_device_l5.git 7d9a51481f0e6c376e62c3c849e6caf652c66482 stm32l5
+hw/mcu/st/cmsis_device_n6 https://github.com/STMicroelectronics/cmsis-device-n6.git 7bcdc944fbf7cf5928d3c1d14054ca13261d33ec stm32n6
+hw/mcu/st/cmsis_device_u5 https://github.com/STMicroelectronics/cmsis_device_u5.git 6e67187dec98035893692ab2923914cb5f4e0117 stm32u5
+hw/mcu/st/cmsis_device_wb https://github.com/STMicroelectronics/cmsis_device_wb.git cda2cb9fc4a5232ab18efece0bb06b0b60910083 stm32wb
hw/mcu/st/stm32-mfxstm32l152 https://github.com/STMicroelectronics/stm32-mfxstm32l152.git 7f4389efee9c6a655b55e5df3fceef5586b35f9b stm32h7
hw/mcu/st/stm32-tcpp0203 https://github.com/STMicroelectronics/stm32-tcpp0203.git 9918655bff176ac3046ccf378b5c7bbbc6a38d15 stm32h7rs stm32n6
-hw/mcu/st/stm32c0xx_hal_driver https://github.com/STMicroelectronics/stm32c0xx_hal_driver.git 41253e2f1d7ae4a4d0c379cf63f5bcf71fcf8eb3 stm32c0
-hw/mcu/st/stm32f0xx_hal_driver https://github.com/STMicroelectronics/stm32f0xx_hal_driver.git 0e95cd88657030f640a11e690a8a5186c7712ea5 stm32f0
-hw/mcu/st/stm32f1xx_hal_driver https://github.com/STMicroelectronics/stm32f1xx_hal_driver.git 1dd9d3662fb7eb2a7f7d3bc0a4c1dc7537915a29 stm32f1
-hw/mcu/st/stm32f2xx_hal_driver https://github.com/STMicroelectronics/stm32f2xx_hal_driver.git c75ace9b908a9aca631193ebf2466963b8ea33d0 stm32f2
-hw/mcu/st/stm32f3xx_hal_driver https://github.com/STMicroelectronics/stm32f3xx_hal_driver.git 1761b6207318ede021706e75aae78f452d72b6fa stm32f3
-hw/mcu/st/stm32f4xx_hal_driver https://github.com/STMicroelectronics/stm32f4xx_hal_driver.git 04e99fbdabd00ab8f370f377c66b0a4570365b58 stm32f4
-hw/mcu/st/stm32f7xx_hal_driver https://github.com/STMicroelectronics/stm32f7xx_hal_driver.git f7ffdf6bf72110e58b42c632b0a051df5997e4ee stm32f7
-hw/mcu/st/stm32g0xx_hal_driver https://github.com/STMicroelectronics/stm32g0xx_hal_driver.git e911b12c7f67084d7f6b76157a4c0d4e2ec3779c stm32g0
-hw/mcu/st/stm32g4xx_hal_driver https://github.com/STMicroelectronics/stm32g4xx_hal_driver.git 8b4518417706d42eef5c14e56a650005abf478a8 stm32g4
-hw/mcu/st/stm32h5xx_hal_driver https://github.com/STMicroelectronics/stm32h5xx_hal_driver.git 2cf77de584196d619cec1b4586c3b9e2820a254e stm32h5
-hw/mcu/st/stm32h7rsxx_hal_driver https://github.com/STMicroelectronics/stm32h7rsxx-hal-driver.git 7ca2e07ca21bc66b53654e845b4c85c884343b60 stm32h7rs
-hw/mcu/st/stm32h7xx_hal_driver https://github.com/STMicroelectronics/stm32h7xx_hal_driver.git d8461b980b59b1625207d8c4f2ce0a9c2a7a3b04 stm32h7
-hw/mcu/st/stm32l0xx_hal_driver https://github.com/STMicroelectronics/stm32l0xx_hal_driver.git fbdacaf6f8c82a4e1eb9bd74ba650b491e97e17b stm32l0
-hw/mcu/st/stm32l1xx_hal_driver https://github.com/STMicroelectronics/stm32l1xx_hal_driver.git 44efc446fa69ed8344e7fd966e68ed11043b35d9 stm32l1
-hw/mcu/st/stm32l4xx_hal_driver https://github.com/STMicroelectronics/stm32l4xx_hal_driver.git aee3d5bf283ae5df87532b781bdd01b7caf256fc stm32l4
-hw/mcu/st/stm32l5xx_hal_driver https://github.com/STMicroelectronics/stm32l5xx_hal_driver.git 675c32a75df37f39d50d61f51cb0dcf53f07e1cb stm32l5
-hw/mcu/st/stm32n6xx_hal_driver https://github.com/STMicroelectronics/stm32n6xx-hal-driver.git 49f9989d10cf6817d4b07ac01848956b46bd0fd6 stm32n6
-hw/mcu/st/stm32u5xx_hal_driver https://github.com/STMicroelectronics/stm32u5xx_hal_driver.git 4d93097a67928e9377e655ddd14622adc31b9770 stm32u5
-hw/mcu/st/stm32wbxx_hal_driver https://github.com/STMicroelectronics/stm32wbxx_hal_driver.git 2c5f06638be516c1b772f768456ba637f077bac8 stm32wb
+hw/mcu/st/stm32c0xx_hal_driver https://github.com/STMicroelectronics/stm32c0xx_hal_driver.git c283b143bef6bdaacf64240ee6f15eb61dad6125 stm32c0
+hw/mcu/st/stm32f0xx_hal_driver https://github.com/STMicroelectronics/stm32f0xx_hal_driver.git 94399697cb5eeaf8511b81b7f50dc62f0a5a3f6c stm32f0
+hw/mcu/st/stm32f1xx_hal_driver https://github.com/STMicroelectronics/stm32f1xx_hal_driver.git 18074e3e5ecad0b380a5cf5a9131fe4b5ed1b2b7 stm32f1
+hw/mcu/st/stm32f2xx_hal_driver https://github.com/STMicroelectronics/stm32f2xx_hal_driver.git ae7b47fe41cf75ccaf65cbf8ee8749b18ba0e0f3 stm32f2
+hw/mcu/st/stm32f3xx_hal_driver https://github.com/STMicroelectronics/stm32f3xx_hal_driver.git e098c8c8ce6f426bcee7db3a37c0932ea881eb0b stm32f3
+hw/mcu/st/stm32f4xx_hal_driver https://github.com/STMicroelectronics/stm32f4xx_hal_driver.git b6f0ed3829f3829eb358a2e7417d80bba1a42db7 stm32f4
+hw/mcu/st/stm32f7xx_hal_driver https://github.com/STMicroelectronics/stm32f7xx_hal_driver.git e1446fa12ffda80ea1016faf349e45b2047fff12 stm32f7
+hw/mcu/st/stm32g0xx_hal_driver https://github.com/STMicroelectronics/stm32g0xx_hal_driver.git a248a9e484d58943b46c68f6c49b4b276778bd59 stm32g0
+hw/mcu/st/stm32g4xx_hal_driver https://github.com/STMicroelectronics/stm32g4xx_hal_driver.git 10138a41749ea62d53ecab65b2bc2a950acc04d2 stm32g4
+hw/mcu/st/stm32h5xx_hal_driver https://github.com/STMicroelectronics/stm32h5xx_hal_driver.git 3c84eaa6000ab620be01afbcfba2735389afe09b stm32h5
+hw/mcu/st/stm32h7rsxx_hal_driver https://github.com/STMicroelectronics/stm32h7rsxx-hal-driver.git 9e83b95ae0f70faa067eddce2da617d180937f9b stm32h7rs
+hw/mcu/st/stm32h7xx_hal_driver https://github.com/STMicroelectronics/stm32h7xx_hal_driver.git dbfb749f229e1aa89e50b54229ca87766e180d2d stm32h7
+hw/mcu/st/stm32l0xx_hal_driver https://github.com/STMicroelectronics/stm32l0xx_hal_driver.git 65da4cd8a10ad859ec8d9cd71f3f6c50735bd473 stm32l0
+hw/mcu/st/stm32l1xx_hal_driver https://github.com/STMicroelectronics/stm32l1xx_hal_driver.git 54f0b7568ce2acb33d090c70c897ee32229c1d32 stm32l1
+hw/mcu/st/stm32l4xx_hal_driver https://github.com/STMicroelectronics/stm32l4xx_hal_driver.git 3e039bbf62f54bbd834d578185521cff80596efe stm32l4
+hw/mcu/st/stm32l5xx_hal_driver https://github.com/STMicroelectronics/stm32l5xx_hal_driver.git 3340b9a597bcf75cc173345a90a74aa2a4a37510 stm32l5
+hw/mcu/st/stm32n6xx_hal_driver https://github.com/STMicroelectronics/stm32n6xx-hal-driver.git bc6c41f8f67d61b47af26695d0bf67762a000666 stm32n6
+hw/mcu/st/stm32u0xx_hal_driver https://github.com/STMicroelectronics/stm32u0xx-hal-driver.git cbfb5ac654256445237fd32b3587ac6a238d24f1 stm32u0
+hw/mcu/st/stm32u5xx_hal_driver https://github.com/STMicroelectronics/stm32u5xx_hal_driver.git 2c5e2568fbdb1900a13ca3b2901fdd302cac3444 stm32u5
+hw/mcu/st/stm32wbaxx_hal_driver https://github.com/STMicroelectronics/stm32wbaxx_hal_driver.git 9442fbb71f855ff2e64fbf662b7726beba511a24 stm32wba
+hw/mcu/st/stm32wbxx_hal_driver https://github.com/STMicroelectronics/stm32wbxx_hal_driver.git d60dd46996876506f1d2e9abd6b1cc110c8004cd stm32wb
hw/mcu/ti https://github.com/hathach/ti_driver.git 143ed6cc20a7615d042b03b21e070197d473e6e5 msp430 msp432e4 tm4c
hw/mcu/wch/ch32f20x https://github.com/openwch/ch32f20x.git 77c4095087e5ed2c548ec9058e655d0b8757663b ch32f20x
hw/mcu/wch/ch32v103 https://github.com/openwch/ch32v103.git 7578cae0b21f86dd053a1f781b2fc6ab99d0ec17 ch32v10x
hw/mcu/wch/ch32v20x https://github.com/openwch/ch32v20x.git c4c38f507e258a4e69b059ccc2dc27dde33cea1b ch32v20x
hw/mcu/wch/ch32v307 https://github.com/openwch/ch32v307.git 184f21b852cb95eed58e86e901837bc9fff68775 ch32v30x
-lib/CMSIS_5 https://github.com/ARM-software/CMSIS_5.git 2b7495b8535bdcb306dac29b9ded4cfb679d7e5c imxrt kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx mm32 msp432e4 nrf saml2x lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43 stm32c0 stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32g0 stm32g4 stm32h5 stm32h7 stm32h7rs stm32l0 stm32l1 stm32l4 stm32l5 stm32n6 stm32u5 stm32wb sam3x samd11 samd21 samd51 samd5x_e5x same5x same7x saml2x samg tm4c
+lib/CMSIS_5 https://github.com/ARM-software/CMSIS_5.git 2b7495b8535bdcb306dac29b9ded4cfb679d7e5c imxrt kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx mm32 msp432e4 nrf saml2x lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43 stm32c0 stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32g0 stm32g4 stm32h5 stm32h7 stm32h7rs stm32l0 stm32l1 stm32l4 stm32l5 stm32n6 stm32u0 stm32u5 stm32wb stm32wbasam3x samd11 samd21 samd51 samd5x_e5x same5x same7x saml2x samg tm4c
lib/CMSIS_6 https://github.com/ARM-software/CMSIS_6.git b0bbb0423b278ca632cfe1474eb227961d835fd2 ra
lib/FreeRTOS-Kernel https://github.com/FreeRTOS/FreeRTOS-Kernel.git cc0e0707c0c748713485b870bb980852b210877f all
lib/lwip https://github.com/lwip-tcpip/lwip.git 159e31b689577dbf69cf0683bbaffbd71fa5ee10 all
lib/sct_neopixel https://github.com/gsteiert/sct_neopixel.git e73e04ca63495672d955f9268e003cffe168fcd8 lpc55
tools/uf2 https://github.com/microsoft/uf2.git c594542b2faa01cc33a2b97c9fbebc38549df80a all
-======================================== ================================================================ ======================================== ======================================================================================================================================================================================================================================================================================================================================================
+======================================== ================================================================ ======================================== ======================================================================================================================================================================================================================================================================================================================================================================
diff --git a/docs/reference/getting_started.rst b/docs/reference/getting_started.rst
index bb9ff1cb4..f1a755804 100644
--- a/docs/reference/getting_started.rst
+++ b/docs/reference/getting_started.rst
@@ -178,7 +178,7 @@ By default log message is printed via on-board UART which is slow and take lots
* Pros: work with most if not all MCUs
* Software viewer is JLink RTT Viewer/Client/Logger which is bundled with JLink driver package.
-* ``LOGGER=swo``\ : Use dedicated SWO pin of ARM Cortex SWD debug header.
+* ``LOGGER=swo`` : Use dedicated SWO pin of ARM Cortex SWD debug header.
* Cons: only work with ARM Cortex MCUs minus M0
* Pros: should be compatible with more debugger that support SWO.
diff --git a/examples/build_system/make/make.mk b/examples/build_system/make/make.mk
index f70748d34..4f5d3242e 100644
--- a/examples/build_system/make/make.mk
+++ b/examples/build_system/make/make.mk
@@ -134,8 +134,8 @@ endif
ifeq ($(LOGGER),rtt)
CFLAGS += -DLOGGER_RTT
#CFLAGS += -DSEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL
- INC += $(TOP)/$(lib/SEGGER_RTT)/RTT
- SRC_C += $(lib/SEGGER_RTT)/RTT/SEGGER_RTT.c
+ INC += $(TOP)/lib/SEGGER_RTT/RTT
+ SRC_C += lib/SEGGER_RTT/RTT/SEGGER_RTT.c
endif
ifeq ($(LOGGER),swo)
CFLAGS += -DLOGGER_SWO
diff --git a/examples/device/CMakeLists.txt b/examples/device/CMakeLists.txt
index bb7dd0a0f..eb625ea51 100644
--- a/examples/device/CMakeLists.txt
+++ b/examples/device/CMakeLists.txt
@@ -26,6 +26,7 @@ family_add_subdirectory(hid_generic_inout)
family_add_subdirectory(hid_multiple_interface)
family_add_subdirectory(midi_test)
family_add_subdirectory(msc_dual_lun)
+family_add_subdirectory(mtp)
family_add_subdirectory(net_lwip_webserver)
family_add_subdirectory(uac2_headset)
family_add_subdirectory(uac2_speaker_fb)
diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c
index 9b169e77e..3e0f03a20 100644
--- a/examples/device/audio_4_channel_mic/src/main.c
+++ b/examples/device/audio_4_channel_mic/src/main.c
@@ -85,9 +85,7 @@ int main(void) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// Init values
sampFreq = AUDIO_SAMPLE_RATE;
diff --git a/examples/device/audio_4_channel_mic/src/tusb_config.h b/examples/device/audio_4_channel_mic/src/tusb_config.h
index 446a7a32a..0ee3ba2d0 100644
--- a/examples/device/audio_4_channel_mic/src/tusb_config.h
+++ b/examples/device/audio_4_channel_mic/src/tusb_config.h
@@ -107,7 +107,6 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_FOUR_CH_DESC_LEN
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
diff --git a/examples/device/audio_4_channel_mic_freertos/src/main.c b/examples/device/audio_4_channel_mic_freertos/src/main.c
index 9c76380a2..96eca0be9 100644
--- a/examples/device/audio_4_channel_mic_freertos/src/main.c
+++ b/examples/device/audio_4_channel_mic_freertos/src/main.c
@@ -184,9 +184,7 @@ void usb_device_task(void *param) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// RTOS forever loop
while (1) {
@@ -476,13 +474,11 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p
//--------------------------------------------------------------------+
void led_blinking_task(void *param) {
(void) param;
- static uint32_t start_ms = 0;
static bool led_state = false;
while (1) {
// Blink every interval ms
vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS);
- start_ms += blink_interval_ms;
board_led_write(led_state);
led_state = 1 - led_state;// toggle
diff --git a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h b/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h
index f7c0efe08..d973be2af 100644
--- a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h
+++ b/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h
@@ -113,7 +113,6 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_FOUR_CH_DESC_LEN
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c
index ec47de7b8..5b3beec24 100644
--- a/examples/device/audio_test/src/main.c
+++ b/examples/device/audio_test/src/main.c
@@ -83,9 +83,7 @@ int main(void) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// Init values
sampFreq = CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE;
diff --git a/examples/device/audio_test/src/tusb_config.h b/examples/device/audio_test/src/tusb_config.h
index b38958d7c..10bf53809 100644
--- a/examples/device/audio_test/src/tusb_config.h
+++ b/examples/device/audio_test/src/tusb_config.h
@@ -109,7 +109,6 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
diff --git a/examples/device/audio_test_freertos/skip.txt b/examples/device/audio_test_freertos/skip.txt
index 650bf355b..1f3d4281a 100644
--- a/examples/device/audio_test_freertos/skip.txt
+++ b/examples/device/audio_test_freertos/skip.txt
@@ -14,3 +14,4 @@ mcu:VALENTYUSB_EPTRI
mcu:RAXXX
family:broadcom_32bit
family:broadcom_64bit
+board:stm32l0538disco
diff --git a/examples/device/audio_test_freertos/src/main.c b/examples/device/audio_test_freertos/src/main.c
index b2bed295f..1eab5dab8 100644
--- a/examples/device/audio_test_freertos/src/main.c
+++ b/examples/device/audio_test_freertos/src/main.c
@@ -167,9 +167,7 @@ void usb_device_task(void *param) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// RTOS forever loop
while (1) {
@@ -470,13 +468,11 @@ bool tud_audio_set_itf_close_ep_cb(uint8_t rhport, tusb_control_request_t const
//--------------------------------------------------------------------+
void led_blinking_task(void *param) {
(void) param;
- static uint32_t start_ms = 0;
static bool led_state = false;
while (1) {
// Blink every interval ms
vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS);
- start_ms += blink_interval_ms;
board_led_write(led_state);
led_state = 1 - led_state;// toggle
diff --git a/examples/device/audio_test_freertos/src/tusb_config.h b/examples/device/audio_test_freertos/src/tusb_config.h
index b708e2541..c9dc50082 100644
--- a/examples/device/audio_test_freertos/src/tusb_config.h
+++ b/examples/device/audio_test_freertos/src/tusb_config.h
@@ -115,7 +115,6 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
diff --git a/examples/device/audio_test_multi_rate/src/main.c b/examples/device/audio_test_multi_rate/src/main.c
index 87f56f4b5..9d467991e 100644
--- a/examples/device/audio_test_multi_rate/src/main.c
+++ b/examples/device/audio_test_multi_rate/src/main.c
@@ -100,9 +100,7 @@ int main(void) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// Init values
sampFreq = sampleRatesList[0];
diff --git a/examples/device/audio_test_multi_rate/src/tusb_config.h b/examples/device/audio_test_multi_rate/src/tusb_config.h
index d9b925dcf..b48c0a0be 100644
--- a/examples/device/audio_test_multi_rate/src/tusb_config.h
+++ b/examples/device/audio_test_multi_rate/src/tusb_config.h
@@ -123,7 +123,6 @@ extern "C" {
// Have a look into audio_device.h for all configurations
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_2_FORMAT_DESC_LEN
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
diff --git a/examples/device/cdc_dual_ports/src/main.c b/examples/device/cdc_dual_ports/src/main.c
index 5a3e18358..8fe003f21 100644
--- a/examples/device/cdc_dual_ports/src/main.c
+++ b/examples/device/cdc_dual_ports/src/main.c
@@ -58,9 +58,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
@@ -141,9 +139,7 @@ void tud_cdc_line_state_cb(uint8_t instance, bool dtr, bool rts) {
cdc_line_coding_t coding;
tud_cdc_get_line_coding(&coding);
if (coding.bit_rate == 1200) {
- if (board_reset_to_bootloader) {
- board_reset_to_bootloader();
- }
+ board_reset_to_bootloader();
}
}
}
diff --git a/examples/device/cdc_msc/src/main.c b/examples/device/cdc_msc/src/main.c
index 5cd93e7dd..4e7aa989e 100644
--- a/examples/device/cdc_msc/src/main.c
+++ b/examples/device/cdc_msc/src/main.c
@@ -57,9 +57,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
diff --git a/examples/device/cdc_msc/src/usb_descriptors.c b/examples/device/cdc_msc/src/usb_descriptors.c
index edcee0462..597a6b1e6 100644
--- a/examples/device/cdc_msc/src/usb_descriptors.c
+++ b/examples/device/cdc_msc/src/usb_descriptors.c
@@ -184,7 +184,7 @@ uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
- // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
+ // Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG
memcpy(desc_other_speed_config,
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration,
CONFIG_TOTAL_LEN);
diff --git a/examples/device/cdc_msc_freertos/src/main.c b/examples/device/cdc_msc_freertos/src/main.c
index 09ccc9bf3..69f2435ba 100644
--- a/examples/device/cdc_msc_freertos/src/main.c
+++ b/examples/device/cdc_msc_freertos/src/main.c
@@ -119,9 +119,7 @@ static void usb_device_task(void *param) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
msc_disk_init();
// RTOS forever loop
@@ -229,13 +227,11 @@ void tud_cdc_rx_cb(uint8_t itf) {
//--------------------------------------------------------------------+
void led_blinking_task(void* param) {
(void) param;
- static uint32_t start_ms = 0;
- static bool led_state = false;
+ static bool led_state = false;
while (1) {
// Blink every interval ms
vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS);
- start_ms += blink_interval_ms;
board_led_write(led_state);
led_state = 1 - led_state; // toggle
diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c
index 3602c991d..849712e6a 100644
--- a/examples/device/cdc_msc_freertos/src/msc_disk.c
+++ b/examples/device/cdc_msc_freertos/src/msc_disk.c
@@ -150,7 +150,7 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
};
#if CFG_EXAMPLE_MSC_ASYNC_IO
-void msc_disk_init() {
+void msc_disk_init(void) {
#if configSUPPORT_STATIC_ALLOCATION
io_queue = xQueueCreateStatic(1, sizeof(io_ops_t), io_queue_buf, &io_queue_static);
diff --git a/examples/device/cdc_msc_freertos/src/usb_descriptors.c b/examples/device/cdc_msc_freertos/src/usb_descriptors.c
index a55fa3675..cb440c209 100644
--- a/examples/device/cdc_msc_freertos/src/usb_descriptors.c
+++ b/examples/device/cdc_msc_freertos/src/usb_descriptors.c
@@ -186,7 +186,7 @@ uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
- // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
+ // Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG
memcpy(desc_other_speed_config,
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration,
CONFIG_TOTAL_LEN);
diff --git a/examples/device/cdc_uac2/src/tusb_config.h b/examples/device/cdc_uac2/src/tusb_config.h
index 2318ccf73..2e744f8d2 100644
--- a/examples/device/cdc_uac2/src/tusb_config.h
+++ b/examples/device/cdc_uac2/src/tusb_config.h
@@ -157,9 +157,6 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT) // Maximum EP IN size for all AS alternate settings used
#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX // Example read FIFO every 1ms, so it should be 8 times larger for HS device
-// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 2
-
// Size of control request buffer
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
diff --git a/examples/device/cdc_uac2/src/usb_descriptors.c b/examples/device/cdc_uac2/src/usb_descriptors.c
index 22d3cf05a..da55bdb5a 100644
--- a/examples/device/cdc_uac2/src/usb_descriptors.c
+++ b/examples/device/cdc_uac2/src/usb_descriptors.c
@@ -176,7 +176,7 @@ uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
- // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
+ // Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG
memcpy(desc_other_speed_config,
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration,
CONFIG_TOTAL_LEN);
diff --git a/examples/device/dfu/src/main.c b/examples/device/dfu/src/main.c
index af9e99857..c0c848837 100644
--- a/examples/device/dfu/src/main.c
+++ b/examples/device/dfu/src/main.c
@@ -81,9 +81,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/dfu_runtime/src/main.c b/examples/device/dfu_runtime/src/main.c
index 4740c18c4..37cb80093 100644
--- a/examples/device/dfu_runtime/src/main.c
+++ b/examples/device/dfu_runtime/src/main.c
@@ -76,9 +76,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/dynamic_configuration/src/main.c b/examples/device/dynamic_configuration/src/main.c
index 32ff58232..258cfcd02 100644
--- a/examples/device/dynamic_configuration/src/main.c
+++ b/examples/device/dynamic_configuration/src/main.c
@@ -63,9 +63,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/hid_boot_interface/src/main.c b/examples/device/hid_boot_interface/src/main.c
index 570e4e801..45712cede 100644
--- a/examples/device/hid_boot_interface/src/main.c
+++ b/examples/device/hid_boot_interface/src/main.c
@@ -63,9 +63,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/hid_composite/src/main.c b/examples/device/hid_composite/src/main.c
index a58107b6f..89dab0bdc 100644
--- a/examples/device/hid_composite/src/main.c
+++ b/examples/device/hid_composite/src/main.c
@@ -64,9 +64,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
@@ -197,41 +195,30 @@ static void send_hid_report(uint8_t report_id, uint32_t btn)
}
}
break;
- default: break;
- }
-}
-
-/* use this to send stylus touch signal through USB. */
-static void send_stylus_touch(uint16_t x, uint16_t y, bool state)
-{
- // skip if hid is not ready yet
- if ( !tud_hid_ready() ) return;
-
- static bool has_stylus_pen = false;
-
- hid_stylus_report_t report =
- {
- .attr = 0,
- .x = 0,
- .y = 0
- };
- report.x = x;
- report.y = y;
-
- if (state)
- {
- report.attr = STYLUS_ATTR_TIP_SWITCH | STYLUS_ATTR_IN_RANGE;
- tud_hid_report(REPORT_ID_STYLUS_PEN, &report, sizeof(report));
+ case REPORT_ID_STYLUS_PEN: {
+ static bool touch_state = false;
+ hid_stylus_report_t report = {
+ .attr = 0,
+ .x = 0,
+ .y = 0
+ };
- has_stylus_pen = true;
- }else
- {
- report.attr = 0;
- if (has_stylus_pen) tud_hid_report(REPORT_ID_STYLUS_PEN, &report, sizeof(report));
- has_stylus_pen = false;
+ if (btn) {
+ report.attr = STYLUS_ATTR_TIP_SWITCH | STYLUS_ATTR_IN_RANGE;
+ report.x = 100;
+ report.y = 100;
+ tud_hid_report(REPORT_ID_STYLUS_PEN, &report, sizeof(report));
+ touch_state = true;
+ } else {
+ report.attr = 0;
+ if (touch_state) tud_hid_report(REPORT_ID_STYLUS_PEN, &report, sizeof(report));
+ touch_state = false;
+ }
+ }
+ break;
+ default: break;
}
-
}
// Every 10ms, we will sent 1 report for each HID profile (keyboard, mouse etc ..)
@@ -241,14 +228,6 @@ void hid_task(void)
// Poll every 10ms
const uint32_t interval_ms = 10;
static uint32_t start_ms = 0;
- static uint32_t touch_ms = 0;
- static bool touch_state = false;
-
- if (board_millis() - touch_ms < 100) {
- touch_ms = board_millis();
- send_stylus_touch(0, 0, touch_state = !touch_state);
- return;
- }
if ( board_millis() - start_ms < interval_ms) return; // not enough time
start_ms += interval_ms;
diff --git a/examples/device/hid_composite/src/usb_descriptors.c b/examples/device/hid_composite/src/usb_descriptors.c
index 15c6e1f73..ce7fbd13f 100644
--- a/examples/device/hid_composite/src/usb_descriptors.c
+++ b/examples/device/hid_composite/src/usb_descriptors.c
@@ -154,7 +154,7 @@ uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
- // other speed config is basically configuration with type = OHER_SPEED_CONFIG
+ // other speed config is basically configuration with type = OTHER_SPEED_CONFIG
memcpy(desc_other_speed_config, desc_configuration, CONFIG_TOTAL_LEN);
desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
diff --git a/examples/device/hid_composite_freertos/src/main.c b/examples/device/hid_composite_freertos/src/main.c
index 3f5e8a91c..0eb13add3 100644
--- a/examples/device/hid_composite_freertos/src/main.c
+++ b/examples/device/hid_composite_freertos/src/main.c
@@ -141,9 +141,7 @@ void usb_device_task(void* param)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// RTOS forever loop
while (1)
diff --git a/examples/device/hid_composite_freertos/src/usb_descriptors.c b/examples/device/hid_composite_freertos/src/usb_descriptors.c
index 85820de55..3f231fecc 100644
--- a/examples/device/hid_composite_freertos/src/usb_descriptors.c
+++ b/examples/device/hid_composite_freertos/src/usb_descriptors.c
@@ -153,7 +153,7 @@ uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
- // other speed config is basically configuration with type = OHER_SPEED_CONFIG
+ // other speed config is basically configuration with type = OTHER_SPEED_CONFIG
memcpy(desc_other_speed_config, desc_configuration, CONFIG_TOTAL_LEN);
desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
diff --git a/examples/device/hid_generic_inout/src/main.c b/examples/device/hid_generic_inout/src/main.c
index 73f51002d..9837a47d9 100644
--- a/examples/device/hid_generic_inout/src/main.c
+++ b/examples/device/hid_generic_inout/src/main.c
@@ -87,9 +87,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/hid_multiple_interface/src/main.c b/examples/device/hid_multiple_interface/src/main.c
index 92c7e8332..0bccd13c1 100644
--- a/examples/device/hid_multiple_interface/src/main.c
+++ b/examples/device/hid_multiple_interface/src/main.c
@@ -68,9 +68,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/midi_test/src/main.c b/examples/device/midi_test/src/main.c
index e5c47bdb2..fd58e3021 100644
--- a/examples/device/midi_test/src/main.c
+++ b/examples/device/midi_test/src/main.c
@@ -68,9 +68,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
diff --git a/examples/device/midi_test_freertos/src/main.c b/examples/device/midi_test_freertos/src/main.c
index 3e406d38d..9dd66c526 100644
--- a/examples/device/midi_test_freertos/src/main.c
+++ b/examples/device/midi_test_freertos/src/main.c
@@ -123,9 +123,7 @@ void usb_device_task(void *param) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// RTOS forever loop
while (1) {
@@ -225,13 +223,11 @@ void midi_task(void* param) {
//--------------------------------------------------------------------+
void led_blinking_task(void* param) {
(void) param;
- static uint32_t start_ms = 0;
static bool led_state = false;
while (1) {
// Blink every interval ms
vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS);
- start_ms += blink_interval_ms;
board_led_write(led_state);
led_state = 1 - led_state; // toggle
diff --git a/examples/device/msc_dual_lun/src/main.c b/examples/device/msc_dual_lun/src/main.c
index 012095dca..62b1c872a 100644
--- a/examples/device/msc_dual_lun/src/main.c
+++ b/examples/device/msc_dual_lun/src/main.c
@@ -60,9 +60,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
diff --git a/examples/device/mtp/CMakeLists.txt b/examples/device/mtp/CMakeLists.txt
new file mode 100644
index 000000000..e91eb8fd9
--- /dev/null
+++ b/examples/device/mtp/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 3.20)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
+
+# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
+family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
+
+project(${PROJECT} C CXX ASM)
+
+# Checks this example is valid for the family and initializes the project
+family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
+
+if (RTOS STREQUAL zephyr)
+ set(EXE_NAME app)
+else()
+ set(EXE_NAME ${PROJECT})
+ add_executable(${EXE_NAME})
+endif()
+
+# Example source
+target_sources(${EXE_NAME} PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/mtp_fs_example.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
+
+# Example include
+target_include_directories(${EXE_NAME} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
+
+# Configure compilation flags and libraries for the example without RTOS.
+# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
+family_configure_device_example(${EXE_NAME} ${RTOS})
diff --git a/examples/device/mtp/CMakePresets.json b/examples/device/mtp/CMakePresets.json
new file mode 100644
index 000000000..5cd8971e9
--- /dev/null
+++ b/examples/device/mtp/CMakePresets.json
@@ -0,0 +1,6 @@
+{
+ "version": 6,
+ "include": [
+ "../../../hw/bsp/BoardPresets.json"
+ ]
+}
diff --git a/examples/device/mtp/Makefile b/examples/device/mtp/Makefile
new file mode 100644
index 000000000..7fa475da5
--- /dev/null
+++ b/examples/device/mtp/Makefile
@@ -0,0 +1,11 @@
+include ../../build_system/make/make.mk
+
+INC += \
+ src \
+ $(TOP)/hw \
+
+# Example source
+EXAMPLE_SOURCE += $(wildcard src/*.c)
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
+
+include ../../build_system/make/rules.mk
diff --git a/examples/device/mtp/prj.conf b/examples/device/mtp/prj.conf
new file mode 100644
index 000000000..2f5139d9d
--- /dev/null
+++ b/examples/device/mtp/prj.conf
@@ -0,0 +1,6 @@
+CONFIG_GPIO=y
+CONFIG_FPU=y
+CONFIG_NO_OPTIMIZATIONS=y
+CONFIG_UART_INTERRUPT_DRIVEN=y
+CONFIG_NRFX_POWER=y
+CONFIG_NRFX_UARTE0=y
diff --git a/examples/device/mtp/skip.txt b/examples/device/mtp/skip.txt
new file mode 100644
index 000000000..37a4485d7
--- /dev/null
+++ b/examples/device/mtp/skip.txt
@@ -0,0 +1 @@
+board:cynthion_d11
diff --git a/examples/device/mtp/src/main.c b/examples/device/mtp/src/main.c
new file mode 100644
index 000000000..57d1535b2
--- /dev/null
+++ b/examples/device/mtp/src/main.c
@@ -0,0 +1,110 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bsp/board_api.h"
+#include "tusb.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+
+/* Blink pattern
+ * - 250 ms : device not mounted
+ * - 1000 ms : device mounted
+ * - 2500 ms : device is suspended
+ */
+enum {
+ BLINK_NOT_MOUNTED = 250,
+ BLINK_MOUNTED = 1000,
+ BLINK_SUSPENDED = 2500,
+};
+
+static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
+
+void led_blinking_task(void);
+
+/*------------- MAIN -------------*/
+int main(void) {
+ board_init();
+
+ // init device stack on configured roothub port
+ tusb_rhport_init_t dev_init = {
+ .role = TUSB_ROLE_DEVICE,
+ .speed = TUSB_SPEED_AUTO
+ };
+ tusb_init(BOARD_TUD_RHPORT, &dev_init);
+ board_init_after_tusb();
+
+ while (1) {
+ tud_task(); // tinyusb device task
+ led_blinking_task();
+ }
+}
+
+//--------------------------------------------------------------------+
+// Device callbacks
+//--------------------------------------------------------------------+
+
+// Invoked when device is mounted
+void tud_mount_cb(void) {
+ blink_interval_ms = BLINK_MOUNTED;
+}
+
+// Invoked when device is unmounted
+void tud_umount_cb(void) {
+ blink_interval_ms = BLINK_NOT_MOUNTED;
+}
+
+// Invoked when usb bus is suspended
+// remote_wakeup_en : if host allow us to perform remote wakeup
+// Within 7ms, device must draw an average of current less than 2.5 mA from bus
+void tud_suspend_cb(bool remote_wakeup_en) {
+ (void) remote_wakeup_en;
+ blink_interval_ms = BLINK_SUSPENDED;
+}
+
+// Invoked when usb bus is resumed
+void tud_resume_cb(void) {
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
+}
+
+//--------------------------------------------------------------------+
+// BLINKING TASK
+//--------------------------------------------------------------------+
+void led_blinking_task(void) {
+ static uint32_t start_ms = 0;
+ static bool led_state = false;
+
+ // Blink every interval ms
+ if (board_millis() - start_ms < blink_interval_ms) return; // not enough time
+ start_ms += blink_interval_ms;
+
+ board_led_write(led_state);
+ led_state = 1 - led_state; // toggle
+}
diff --git a/examples/device/mtp/src/mtp_fs_example.c b/examples/device/mtp/src/mtp_fs_example.c
new file mode 100644
index 000000000..b4772f146
--- /dev/null
+++ b/examples/device/mtp/src/mtp_fs_example.c
@@ -0,0 +1,624 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "bsp/board_api.h"
+#include "tusb.h"
+
+#include "tinyusb_logo_png.h"
+
+//--------------------------------------------------------------------+
+// Dataset
+//--------------------------------------------------------------------+
+
+//------------- device info -------------//
+#define DEV_INFO_MANUFACTURER "TinyUSB"
+#define DEV_INFO_MODEL "MTP Example"
+#define DEV_INFO_VERSION "1.0"
+#define DEV_PROP_FRIENDLY_NAME "TinyUSB MTP"
+
+//------------- storage info -------------//
+#define STORAGE_DESCRIPTRION { 'd', 'i', 's', 'k', 0 }
+#define VOLUME_IDENTIFIER { 'v', 'o', 'l', 0 }
+
+typedef MTP_STORAGE_INFO_STRUCT(TU_ARRAY_SIZE((uint16_t[]) STORAGE_DESCRIPTRION),
+ TU_ARRAY_SIZE(((uint16_t[])VOLUME_IDENTIFIER))
+) storage_info_t;
+
+storage_info_t storage_info = {
+ #ifdef CFG_EXAMPLE_MTP_READONLY
+ .storage_type = MTP_STORAGE_TYPE_FIXED_ROM,
+ #else
+ .storage_type = MTP_STORAGE_TYPE_FIXED_RAM,
+ #endif
+
+ .filesystem_type = MTP_FILESYSTEM_TYPE_GENERIC_HIERARCHICAL,
+ .access_capability = MTP_ACCESS_CAPABILITY_READ_WRITE,
+ .max_capacity_in_bytes = 0, // calculated at runtime
+ .free_space_in_bytes = 0, // calculated at runtime
+ .free_space_in_objects = 0, // calculated at runtime
+ .storage_description = {
+ .count = (TU_FIELD_SIZE(storage_info_t, storage_description)-1) / sizeof(uint16_t),
+ .utf16 = STORAGE_DESCRIPTRION
+ },
+ .volume_identifier = {
+ .count = (TU_FIELD_SIZE(storage_info_t, volume_identifier)-1) / sizeof(uint16_t),
+ .utf16 = VOLUME_IDENTIFIER
+ }
+};
+
+//--------------------------------------------------------------------+
+// MTP FILESYSTEM
+//--------------------------------------------------------------------+
+// only allow to add 1 more object to make it simpler to manage memory
+#define FS_MAX_FILE_COUNT 3UL
+#define FS_MAX_FILENAME_LEN 16
+
+#ifdef CFG_EXAMPLE_MTP_READONLY
+ #define FS_MAX_CAPACITY_BYTES 0
+#else
+ #define FS_MAX_CAPACITY_BYTES (4 * 1024UL)
+
+ // object data buffer (excluding 2 predefined files) with simple allocation pointer
+ uint8_t fs_buf[FS_MAX_CAPACITY_BYTES];
+#endif
+
+#define FS_FIXED_DATETIME "20250808T173500.0" // "YYYYMMDDTHHMMSS.s"
+#define README_TXT_CONTENT "TinyUSB MTP Filesystem example"
+
+typedef struct {
+ uint16_t name[FS_MAX_FILENAME_LEN];
+ uint16_t object_format;
+ uint16_t protection_status;
+ uint32_t image_pix_width;
+ uint32_t image_pix_height;
+ uint32_t image_bit_depth;
+ uint32_t parent;
+ uint16_t association_type;
+ uint32_t size;
+ uint8_t* data;
+} fs_file_t;
+
+// Files system, handle is index + 1
+static fs_file_t fs_objects[FS_MAX_FILE_COUNT] = {
+ {
+ .name = { 'r', 'e', 'a', 'd', 'm', 'e', '.', 't', 'x', 't', 0 }, // readme.txt
+ .object_format = MTP_OBJ_FORMAT_TEXT,
+ .protection_status = MTP_PROTECTION_STATUS_READ_ONLY,
+ .image_pix_width = 0,
+ .image_pix_height = 0,
+ .image_bit_depth = 0,
+ .parent = 0,
+ .association_type = MTP_ASSOCIATION_UNDEFINED,
+ .size = sizeof(README_TXT_CONTENT)-1,
+ .data = (uint8_t*) (uintptr_t) README_TXT_CONTENT,
+ },
+ {
+ .name = { 't', 'i', 'n', 'y', 'u', 's', 'b', '.', 'p', 'n', 'g', 0 }, // "tinyusb.png"
+ .object_format = MTP_OBJ_FORMAT_PNG,
+ .protection_status = MTP_PROTECTION_STATUS_READ_ONLY,
+ .image_pix_width = 128,
+ .image_pix_height = 64,
+ .image_bit_depth = 32,
+ .parent = 0,
+ .association_type = MTP_ASSOCIATION_UNDEFINED,
+ .size = LOGO_LEN,
+ .data = (uint8_t*) (uintptr_t) logo_bin
+ }
+};
+
+enum {
+ SUPPORTED_STORAGE_ID = 0x00010001u // physical = 1, logical = 1
+};
+
+static int32_t fs_get_device_info(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_open_close_session(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_get_storage_ids(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_get_storage_info(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_get_device_properties(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_get_object_handles(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_get_object_info(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_get_object(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_delete_object(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_send_object_info(tud_mtp_cb_data_t* cb_data);
+static int32_t fs_send_object(tud_mtp_cb_data_t* cb_data);
+
+typedef int32_t (*fs_op_handler_t)(tud_mtp_cb_data_t* cb_data);
+typedef struct {
+ uint32_t op_code;
+ fs_op_handler_t handler;
+}fs_op_handler_dict_t;
+
+fs_op_handler_dict_t fs_op_handler_dict[] = {
+ { MTP_OP_GET_DEVICE_INFO, fs_get_device_info },
+ { MTP_OP_OPEN_SESSION, fs_open_close_session },
+ { MTP_OP_CLOSE_SESSION, fs_open_close_session },
+ { MTP_OP_GET_STORAGE_IDS, fs_get_storage_ids },
+ { MTP_OP_GET_STORAGE_INFO, fs_get_storage_info },
+ { MTP_OP_GET_DEVICE_PROP_DESC, fs_get_device_properties },
+ { MTP_OP_GET_DEVICE_PROP_VALUE, fs_get_device_properties },
+ { MTP_OP_GET_OBJECT_HANDLES, fs_get_object_handles },
+ { MTP_OP_GET_OBJECT_INFO, fs_get_object_info },
+ { MTP_OP_GET_OBJECT, fs_get_object },
+ { MTP_OP_DELETE_OBJECT, fs_delete_object },
+ { MTP_OP_SEND_OBJECT_INFO, fs_send_object_info },
+ { MTP_OP_SEND_OBJECT, fs_send_object },
+};
+
+static bool is_session_opened = false;
+static uint32_t send_obj_handle = 0;
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+// Get pointer to object info from handle
+static inline fs_file_t* fs_get_file(uint32_t handle) {
+ if (handle == 0 || handle > FS_MAX_FILE_COUNT) {
+ return NULL;
+ }
+ return &fs_objects[handle-1];
+}
+
+static inline bool fs_file_exist(fs_file_t* f) {
+ return f->name[0] != 0;
+}
+
+// Get the number of allocated nodes in filesystem
+static uint32_t fs_get_file_count(void) {
+ uint32_t count = 0;
+ for (size_t i = 0; i < FS_MAX_FILE_COUNT; i++) {
+ if (fs_file_exist(&fs_objects[i])) {
+ count++;
+ }
+ }
+ return count;
+}
+
+static inline fs_file_t* fs_create_file(void) {
+ for (size_t i = 0; i < FS_MAX_FILE_COUNT; i++) {
+ fs_file_t* f = &fs_objects[i];
+ if (!fs_file_exist(f)) {
+ send_obj_handle = i + 1;
+ return f;
+ }
+ }
+ return NULL;
+}
+
+// simple malloc
+static inline uint8_t* fs_malloc(size_t size) {
+#ifdef CFG_EXAMPLE_MTP_READONLY
+ (void) size;
+ return NULL;
+#else
+ if (size > FS_MAX_CAPACITY_BYTES) {
+ return NULL;
+ }
+ return fs_buf;
+#endif
+}
+
+//--------------------------------------------------------------------+
+// Control Request callback
+//--------------------------------------------------------------------+
+bool tud_mtp_request_cancel_cb(tud_mtp_request_cb_data_t* cb_data) {
+ mtp_request_reset_cancel_data_t cancel_data;
+ memcpy(&cancel_data, cb_data->buf, sizeof(cancel_data));
+ (void) cancel_data.code;
+ (void ) cancel_data.transaction_id;
+ return true;
+}
+
+// Invoked when received Device Reset request
+// return false to stall the request
+bool tud_mtp_request_device_reset_cb(tud_mtp_request_cb_data_t* cb_data) {
+ (void) cb_data;
+ return true;
+}
+
+// Invoked when received Get Extended Event request. Application fill callback data's buffer for response
+// return negative to stall the request
+int32_t tud_mtp_request_get_extended_event_cb(tud_mtp_request_cb_data_t* cb_data) {
+ (void) cb_data;
+ return false; // not implemented yet
+}
+
+// Invoked when received Get DeviceStatus request. Application fill callback data's buffer for response
+// return negative to stall the request
+int32_t tud_mtp_request_get_device_status_cb(tud_mtp_request_cb_data_t* cb_data) {
+ uint16_t* buf16 = (uint16_t*)(uintptr_t) cb_data->buf;
+ buf16[0] = 4; // length
+ buf16[1] = MTP_RESP_OK; // status
+ return 4;
+}
+
+//--------------------------------------------------------------------+
+// Bulk Only Protocol
+//--------------------------------------------------------------------+
+int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ fs_op_handler_t handler = NULL;
+ for (size_t i = 0; i < TU_ARRAY_SIZE(fs_op_handler_dict); i++) {
+ if (fs_op_handler_dict[i].op_code == command->header.code) {
+ handler = fs_op_handler_dict[i].handler;
+ break;
+ }
+ }
+
+ int32_t resp_code;
+ if (handler == NULL) {
+ resp_code = MTP_RESP_OPERATION_NOT_SUPPORTED;
+ } else {
+ resp_code = handler(cb_data);
+ if (resp_code > MTP_RESP_UNDEFINED) {
+ // send response if needed
+ io_container->header->code = (uint16_t)resp_code;
+ tud_mtp_response_send(io_container);
+ }
+ }
+
+ return resp_code;
+}
+
+int32_t tud_mtp_data_xfer_cb(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+
+ fs_op_handler_t handler = NULL;
+ for (size_t i = 0; i < TU_ARRAY_SIZE(fs_op_handler_dict); i++) {
+ if (fs_op_handler_dict[i].op_code == command->header.code) {
+ handler = fs_op_handler_dict[i].handler;
+ break;
+ }
+ }
+
+ int32_t resp_code;
+ if (handler == NULL) {
+ resp_code = MTP_RESP_OPERATION_NOT_SUPPORTED;
+ } else {
+ resp_code = handler(cb_data);
+ if (resp_code > MTP_RESP_UNDEFINED) {
+ // send response if needed
+ io_container->header->code = (uint16_t)resp_code;
+ tud_mtp_response_send(io_container);
+ }
+ }
+
+ return 0;
+}
+
+int32_t tud_mtp_data_complete_cb(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* resp = &cb_data->io_container;
+ switch (command->header.code) {
+ case MTP_OP_SEND_OBJECT_INFO: {
+ fs_file_t* f = fs_get_file(send_obj_handle);
+ if (f == NULL) {
+ resp->header->code = MTP_RESP_GENERAL_ERROR;
+ break;
+ }
+ // parameter is: storage id, parent handle, new handle
+ mtp_container_add_uint32(resp, SUPPORTED_STORAGE_ID);
+ mtp_container_add_uint32(resp, f->parent);
+ mtp_container_add_uint32(resp, send_obj_handle);
+ resp->header->code = MTP_RESP_OK;
+ break;
+ }
+
+ default:
+ resp->header->code = (cb_data->xfer_result == XFER_RESULT_SUCCESS) ? MTP_RESP_OK : MTP_RESP_GENERAL_ERROR;
+ break;
+ }
+
+ tud_mtp_response_send(resp);
+ return 0;
+}
+
+int32_t tud_mtp_response_complete_cb(tud_mtp_cb_data_t* cb_data) {
+ (void) cb_data;
+ return 0; // nothing to do
+}
+
+//--------------------------------------------------------------------+
+// File System Handlers
+//--------------------------------------------------------------------+
+static int32_t fs_get_device_info(tud_mtp_cb_data_t* cb_data) {
+ // Device info is already prepared up to playback formats. Application only need to add string fields
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ mtp_container_add_cstring(io_container, DEV_INFO_MANUFACTURER);
+ mtp_container_add_cstring(io_container, DEV_INFO_MODEL);
+ mtp_container_add_cstring(io_container, DEV_INFO_VERSION);
+
+ enum { MAX_SERIAL_NCHARS = 32 };
+ uint16_t serial_utf16[MAX_SERIAL_NCHARS+1];
+ size_t nchars = board_usb_get_serial(serial_utf16, MAX_SERIAL_NCHARS);
+ serial_utf16[tu_min32(nchars, MAX_SERIAL_NCHARS)] = 0; // ensure null termination
+ mtp_container_add_string(io_container, serial_utf16);
+
+ tud_mtp_data_send(io_container);
+ return 0;
+}
+
+static int32_t fs_open_close_session(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ if (command->header.code == MTP_OP_OPEN_SESSION) {
+ if (is_session_opened) {
+ return MTP_RESP_SESSION_ALREADY_OPEN;
+ }
+ is_session_opened = true;
+ } else { // close session
+ if (!is_session_opened) {
+ return MTP_RESP_SESSION_NOT_OPEN;
+ }
+ is_session_opened = false;
+ }
+ return MTP_RESP_OK;
+}
+
+static int32_t fs_get_storage_ids(tud_mtp_cb_data_t* cb_data) {
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ uint32_t storage_ids [] = { SUPPORTED_STORAGE_ID };
+ mtp_container_add_auint32(io_container, 1, storage_ids);
+ tud_mtp_data_send(io_container);
+ return 0;
+}
+
+static int32_t fs_get_storage_info(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ const uint32_t storage_id = command->params[0];
+ TU_VERIFY(SUPPORTED_STORAGE_ID == storage_id, -1);
+ // update storage info with current free space
+ storage_info.max_capacity_in_bytes = sizeof(README_TXT_CONTENT) + LOGO_LEN + FS_MAX_CAPACITY_BYTES;
+ storage_info.free_space_in_objects = FS_MAX_FILE_COUNT - fs_get_file_count();
+ storage_info.free_space_in_bytes = storage_info.free_space_in_objects ? FS_MAX_CAPACITY_BYTES : 0;
+ mtp_container_add_raw(io_container, &storage_info, sizeof(storage_info));
+ tud_mtp_data_send(io_container);
+ return 0;
+}
+
+static int32_t fs_get_device_properties(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ const uint16_t dev_prop_code = (uint16_t) command->params[0];
+
+ if (command->header.code == MTP_OP_GET_DEVICE_PROP_DESC) {
+ // get describing dataset
+ mtp_device_prop_desc_header_t device_prop_header;
+ device_prop_header.device_property_code = dev_prop_code;
+ switch (dev_prop_code) {
+ case MTP_DEV_PROP_DEVICE_FRIENDLY_NAME:
+ device_prop_header.datatype = MTP_DATA_TYPE_STR;
+ device_prop_header.get_set = MTP_MODE_GET;
+ mtp_container_add_raw(io_container, &device_prop_header, sizeof(device_prop_header));
+ mtp_container_add_cstring(io_container, DEV_PROP_FRIENDLY_NAME); // factory
+ mtp_container_add_cstring(io_container, DEV_PROP_FRIENDLY_NAME); // current
+ mtp_container_add_uint8(io_container, 0); // no form
+ tud_mtp_data_send(io_container);
+ break;
+
+ default:
+ return MTP_RESP_PARAMETER_NOT_SUPPORTED;
+ }
+ } else {
+ // get value
+ switch (dev_prop_code) {
+ case MTP_DEV_PROP_DEVICE_FRIENDLY_NAME:
+ mtp_container_add_cstring(io_container, DEV_PROP_FRIENDLY_NAME);
+ tud_mtp_data_send(io_container);
+ break;
+
+ default:
+ return MTP_RESP_PARAMETER_NOT_SUPPORTED;
+ }
+ }
+ return 0;
+}
+
+static int32_t fs_get_object_handles(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+
+ const uint32_t storage_id = command->params[0];
+ const uint32_t obj_format = command->params[1]; // optional
+ const uint32_t parent_handle = command->params[2]; // folder handle, 0xFFFFFFFF is root
+ (void)obj_format;
+
+ if (storage_id != 0xFFFFFFFF && storage_id != SUPPORTED_STORAGE_ID) {
+ return MTP_RESP_INVALID_STORAGE_ID;
+ }
+
+ uint32_t handles[FS_MAX_FILE_COUNT] = { 0 };
+ uint32_t count = 0;
+ for (uint8_t i = 0; i < FS_MAX_FILE_COUNT; i++) {
+ fs_file_t* f = &fs_objects[i];
+ if (fs_file_exist(f) &&
+ (parent_handle == f->parent || (parent_handle == 0xFFFFFFFF && f->parent == 0))) {
+ handles[count++] = i + 1; // handle is index + 1
+ }
+ }
+ mtp_container_add_auint32(io_container, count, handles);
+ tud_mtp_data_send(io_container);
+
+ return 0;
+}
+
+static int32_t fs_get_object_info(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ const uint32_t obj_handle = command->params[0];
+ fs_file_t* f = fs_get_file(obj_handle);
+ if (f == NULL) {
+ return MTP_RESP_INVALID_OBJECT_HANDLE;
+ }
+ mtp_object_info_header_t obj_info_header = {
+ .storage_id = SUPPORTED_STORAGE_ID,
+ .object_format = f->object_format,
+ .protection_status = f->protection_status,
+ .object_compressed_size = f->size,
+ .thumb_format = MTP_OBJ_FORMAT_UNDEFINED,
+ .thumb_compressed_size = 0,
+ .thumb_pix_width = 0,
+ .thumb_pix_height = 0,
+ .image_pix_width = f->image_pix_width,
+ .image_pix_height = f->image_pix_height,
+ .image_bit_depth = f->image_bit_depth,
+ .parent_object = f->parent,
+ .association_type = f->association_type,
+ .association_desc = 0,
+ .sequence_number = 0
+ };
+ mtp_container_add_raw(io_container, &obj_info_header, sizeof(obj_info_header));
+ mtp_container_add_string(io_container, f->name);
+ mtp_container_add_cstring(io_container, FS_FIXED_DATETIME);
+ mtp_container_add_cstring(io_container, FS_FIXED_DATETIME);
+ mtp_container_add_cstring(io_container, ""); // keywords, not used
+ tud_mtp_data_send(io_container);
+
+ return 0;
+}
+
+static int32_t fs_get_object(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ const uint32_t obj_handle = command->params[0];
+ const fs_file_t* f = fs_get_file(obj_handle);
+ if (f == NULL) {
+ return MTP_RESP_INVALID_OBJECT_HANDLE;
+ }
+
+ if (cb_data->phase == MTP_PHASE_COMMAND) {
+ // If file contents is larger than CFG_TUD_MTP_EP_BUFSIZE, data may only partially is added here
+ // the rest will be sent in tud_mtp_data_more_cb
+ mtp_container_add_raw(io_container, f->data, f->size);
+ tud_mtp_data_send(io_container);
+ } else if (cb_data->phase == MTP_PHASE_DATA) {
+ // continue sending remaining data: file contents offset is xferred byte minus header size
+ const uint32_t offset = cb_data->total_xferred_bytes - sizeof(mtp_container_header_t);
+ const uint32_t xact_len = tu_min32(f->size - offset, io_container->payload_bytes);
+ if (xact_len > 0) {
+ memcpy(io_container->payload, f->data + offset, xact_len);
+ tud_mtp_data_send(io_container);
+ }
+ }
+
+ return 0;
+}
+
+static int32_t fs_send_object_info(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ const uint32_t storage_id = command->params[0];
+ const uint32_t parent_handle = command->params[1]; // folder handle, 0xFFFFFFFF is root
+ (void) parent_handle;
+
+ if (!is_session_opened) {
+ return MTP_RESP_SESSION_NOT_OPEN;
+ }
+ if (storage_id != 0xFFFFFFFF && storage_id != SUPPORTED_STORAGE_ID) {
+ return MTP_RESP_INVALID_STORAGE_ID;
+ }
+
+ if (cb_data->phase == MTP_PHASE_COMMAND) {
+ tud_mtp_data_receive(io_container);
+ } else if (cb_data->phase == MTP_PHASE_DATA) {
+ mtp_object_info_header_t* obj_info = (mtp_object_info_header_t*) io_container->payload;
+ if (obj_info->storage_id != 0 && obj_info->storage_id != SUPPORTED_STORAGE_ID) {
+ return MTP_RESP_INVALID_STORAGE_ID;
+ }
+
+ if (obj_info->parent_object) {
+ fs_file_t* parent = fs_get_file(obj_info->parent_object);
+ if (parent == NULL || !parent->association_type) {
+ return MTP_RESP_INVALID_PARENT_OBJECT;
+ }
+ }
+
+ uint8_t* f_buf = fs_malloc(obj_info->object_compressed_size);
+ if (f_buf == NULL) {
+ return MTP_RESP_STORE_FULL;
+ }
+ fs_file_t* f = fs_create_file();
+ if (f == NULL) {
+ return MTP_RESP_STORE_FULL;
+ }
+
+ f->object_format = obj_info->object_format;
+ f->protection_status = obj_info->protection_status;
+ f->image_pix_width = obj_info->image_pix_width;
+ f->image_pix_height = obj_info->image_pix_height;
+ f->image_bit_depth = obj_info->image_bit_depth;
+ f->parent = obj_info->parent_object;
+ f->association_type = obj_info->association_type;
+ f->size = obj_info->object_compressed_size;
+ f->data = f_buf;
+ uint8_t* buf = io_container->payload + sizeof(mtp_object_info_header_t);
+ mtp_container_get_string(buf, f->name);
+ // ignore date created/modified/keywords
+ }
+
+ return 0;
+}
+
+static int32_t fs_send_object(tud_mtp_cb_data_t* cb_data) {
+ mtp_container_info_t* io_container = &cb_data->io_container;
+ fs_file_t* f = fs_get_file(send_obj_handle);
+ if (f == NULL) {
+ return MTP_RESP_INVALID_OBJECT_HANDLE;
+ }
+
+ if (cb_data->phase == MTP_PHASE_COMMAND) {
+ io_container->header->len += f->size;
+ tud_mtp_data_receive(io_container);
+ } else {
+ // file contents offset is total xferred minus header size minus last received chunk
+ const uint32_t offset = cb_data->total_xferred_bytes - sizeof(mtp_container_header_t) - io_container->payload_bytes;
+ memcpy(f->data + offset, io_container->payload, io_container->payload_bytes);
+ if (cb_data->total_xferred_bytes - sizeof(mtp_container_header_t) < f->size) {
+ tud_mtp_data_receive(io_container);
+ }
+ }
+
+ return 0;
+}
+
+static int32_t fs_delete_object(tud_mtp_cb_data_t* cb_data) {
+ const mtp_container_command_t* command = cb_data->command_container;
+ const uint32_t obj_handle = command->params[0];
+ const uint32_t obj_format = command->params[1]; // optional
+ (void) obj_format;
+
+ if (!is_session_opened) {
+ return MTP_RESP_SESSION_NOT_OPEN;
+ }
+ fs_file_t* f = fs_get_file(obj_handle);
+ if (f == NULL) {
+ return MTP_RESP_INVALID_OBJECT_HANDLE;
+ }
+
+ // delete object by clear the name
+ f->name[0] = 0;
+ return MTP_RESP_OK;
+}
diff --git a/examples/device/mtp/src/tinyusb_logo_png.h b/examples/device/mtp/src/tinyusb_logo_png.h
new file mode 100644
index 000000000..f8a9bde4e
--- /dev/null
+++ b/examples/device/mtp/src/tinyusb_logo_png.h
@@ -0,0 +1,175 @@
+// convert using tools/file2carray.py
+enum { LOGO_LEN = 2733 };
+static const uint8_t logo_bin[] __attribute__((aligned(16))) = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0xd2, 0xd6, 0x7f,
+ 0x7f, 0x00, 0x00, 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xa0,
+ 0xbd, 0xa7, 0x93, 0x00, 0x00, 0x0a, 0x62, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0xed, 0x9c, 0x7d,
+ 0x54, 0x54, 0x65, 0x1a, 0xc0, 0x7f, 0xc3, 0x00, 0x29, 0x1f, 0x31, 0x88, 0x61, 0x90, 0xd6, 0xa1,
+ 0xb3, 0xba, 0x1a, 0x18, 0x7e, 0xf2, 0xad, 0x40, 0x82, 0xb8, 0x9b, 0x2b, 0x43, 0x1e, 0xd2, 0x00,
+ 0x53, 0xc0, 0xea, 0xec, 0xc9, 0x70, 0x18, 0x3d, 0x5b, 0xb1, 0x9e, 0x4a, 0x6d, 0x13, 0x2d, 0xcb,
+ 0x76, 0xcd, 0x00, 0xf3, 0x8b, 0x10, 0x8a, 0x8e, 0xd6, 0xee, 0xda, 0x8a, 0x96, 0x30, 0x66, 0xa2,
+ 0xa0, 0x91, 0x64, 0xae, 0x16, 0x98, 0x45, 0x9d, 0x2c, 0x93, 0x8f, 0x05, 0x11, 0x92, 0x81, 0xbb,
+ 0x7f, 0xa8, 0x93, 0x33, 0x23, 0xcc, 0xdc, 0x61, 0x60, 0x46, 0xb8, 0xbf, 0xbf, 0x78, 0xdf, 0xfb,
+ 0x3c, 0xcf, 0xfb, 0xc0, 0x7d, 0xee, 0x73, 0xdf, 0xf7, 0xb9, 0xef, 0x8b, 0x8c, 0x6b, 0x08, 0x82,
+ 0x90, 0x08, 0x2c, 0x03, 0x02, 0x81, 0x21, 0x48, 0x0c, 0x44, 0xda, 0x81, 0x6a, 0xe0, 0x55, 0x99,
+ 0x4c, 0x56, 0x0c, 0x20, 0x03, 0x10, 0x04, 0x61, 0x35, 0xb0, 0xc2, 0x86, 0x8e, 0x49, 0xf4, 0x3f,
+ 0x6b, 0x64, 0x32, 0x59, 0x96, 0x4c, 0x10, 0x84, 0x19, 0xc0, 0x47, 0x5c, 0x0b, 0x06, 0x89, 0x41,
+ 0x45, 0xac, 0x03, 0xa0, 0x42, 0xba, 0xf9, 0x83, 0x15, 0x95, 0x4c, 0x10, 0x84, 0x8b, 0x80, 0x97,
+ 0xad, 0x3d, 0x91, 0xb0, 0x09, 0x4d, 0x32, 0x41, 0x10, 0x3a, 0x01, 0x07, 0x5b, 0x7b, 0x22, 0x61,
+ 0x1b, 0x1c, 0x90, 0xd2, 0xff, 0xa0, 0x46, 0x7a, 0xf2, 0x07, 0x39, 0x52, 0x00, 0x0c, 0x72, 0x1c,
+ 0x2d, 0x55, 0x3c, 0x52, 0x5e, 0x4e, 0x53, 0x63, 0x93, 0x28, 0x9d, 0x49, 0x93, 0x27, 0x31, 0xe2,
+ 0xce, 0x3b, 0x4d, 0xca, 0x5d, 0xba, 0x74, 0x89, 0xea, 0x13, 0xd5, 0x26, 0xe5, 0x46, 0x8c, 0xf0,
+ 0xe6, 0x77, 0xa3, 0x47, 0x8b, 0xf2, 0x41, 0x42, 0x1f, 0x99, 0x20, 0x08, 0x5d, 0x58, 0x30, 0x0f,
+ 0x48, 0x7c, 0x68, 0x2e, 0x9f, 0x57, 0x55, 0x89, 0xd2, 0xd9, 0x94, 0x9b, 0xc3, 0xcc, 0xb8, 0x38,
+ 0x93, 0x72, 0x27, 0xbf, 0x38, 0x49, 0xc2, 0x9c, 0x39, 0x78, 0x78, 0x78, 0x74, 0x2b, 0xd3, 0xd6,
+ 0xd6, 0x46, 0xbc, 0x52, 0xc9, 0x9a, 0x75, 0x6b, 0x45, 0xf9, 0x20, 0xa1, 0x8f, 0xc5, 0x19, 0xa0,
+ 0x3f, 0xa8, 0xfc, 0xec, 0x38, 0x72, 0xc7, 0x9b, 0xbb, 0xb8, 0x22, 0x2b, 0x8b, 0x4e, 0x6d, 0x67,
+ 0x3f, 0x7b, 0x34, 0xf0, 0x90, 0xe6, 0x00, 0x83, 0x1c, 0xbb, 0x0e, 0x80, 0xb6, 0xb6, 0x36, 0x5e,
+ 0x5c, 0xb5, 0x8a, 0x0f, 0x76, 0xbf, 0x0f, 0x40, 0xdd, 0x77, 0xdf, 0xf1, 0xe2, 0xaa, 0x55, 0x1c,
+ 0xfe, 0xf4, 0xb0, 0x8d, 0x3d, 0x1b, 0x38, 0xd8, 0x75, 0x00, 0x68, 0xb5, 0x5a, 0x34, 0xa5, 0x65,
+ 0x9c, 0x3a, 0x75, 0x0a, 0x80, 0xa6, 0xa6, 0xff, 0xa1, 0x29, 0x2d, 0xa3, 0xae, 0xee, 0x3b, 0x1b,
+ 0x7b, 0x36, 0x70, 0xb0, 0xeb, 0x39, 0x80, 0xbb, 0xbb, 0x3b, 0x1f, 0x6b, 0xca, 0x74, 0xed, 0xfb,
+ 0x03, 0xef, 0xd7, 0xb5, 0x57, 0x64, 0x65, 0xd9, 0xca, 0xad, 0x01, 0x85, 0x5d, 0x07, 0x80, 0xbd,
+ 0x70, 0xb9, 0xf5, 0x32, 0x3f, 0x5f, 0xf8, 0x19, 0xb9, 0x83, 0x03, 0x6e, 0xee, 0xee, 0x28, 0x14,
+ 0x0a, 0x1c, 0x1c, 0xec, 0x3a, 0x79, 0x9a, 0x8d, 0xd9, 0xcb, 0xc0, 0x8e, 0x8e, 0x0e, 0x56, 0x3e,
+ 0xff, 0xbc, 0xae, 0xfd, 0xf1, 0xfe, 0x8f, 0xb8, 0x78, 0xf1, 0xa2, 0xa8, 0xc1, 0x22, 0xa6, 0x4d,
+ 0x63, 0xe4, 0xa8, 0x91, 0x7a, 0x7d, 0xa1, 0x61, 0x61, 0x3c, 0x38, 0x7b, 0xb6, 0xae, 0xfd, 0xf7,
+ 0x0d, 0x1b, 0x38, 0x73, 0xfa, 0x0c, 0xfb, 0xf7, 0xed, 0xe3, 0xe1, 0xf9, 0xf3, 0xba, 0xfd, 0x43,
+ 0x1f, 0xab, 0x3c, 0x86, 0xd0, 0xd5, 0x45, 0x50, 0x48, 0x30, 0x69, 0x8b, 0x17, 0x73, 0xef, 0xbd,
+ 0xf7, 0xea, 0xae, 0x7d, 0xb4, 0x7f, 0x3f, 0x07, 0x35, 0x1a, 0x51, 0xbe, 0xad, 0x5c, 0xbd, 0x1a,
+ 0xb9, 0x5c, 0x0e, 0x5c, 0x9d, 0x6b, 0x94, 0xec, 0x2d, 0xe1, 0xa0, 0x46, 0x43, 0xf5, 0x89, 0x13,
+ 0xb4, 0xb7, 0xb7, 0xeb, 0xc9, 0xba, 0xb9, 0xb9, 0xe1, 0x1f, 0x10, 0x40, 0x4c, 0x6c, 0x0c, 0xf1,
+ 0x09, 0x09, 0x0c, 0x1b, 0x36, 0x4c, 0x77, 0xed, 0xc7, 0x1f, 0x7f, 0x64, 0xd3, 0xc6, 0x8d, 0xa2,
+ 0xc6, 0x06, 0x70, 0x90, 0x39, 0xf0, 0xec, 0x5f, 0xb3, 0x18, 0xea, 0xe2, 0x22, 0x4a, 0xef, 0xdd,
+ 0xa2, 0x77, 0x38, 0x79, 0xf2, 0x0b, 0xbd, 0xbe, 0xe4, 0x94, 0x14, 0xc6, 0xdd, 0x77, 0x9f, 0x59,
+ 0xfa, 0x66, 0x07, 0x40, 0x5b, 0x5b, 0x1b, 0xe3, 0xc7, 0x99, 0x67, 0x54, 0x0c, 0x8b, 0xd2, 0x52,
+ 0x59, 0xf1, 0xdc, 0x73, 0xba, 0x76, 0x5c, 0x4c, 0x2c, 0x67, 0x6b, 0x6b, 0x45, 0xd9, 0x28, 0x28,
+ 0x2a, 0x24, 0x24, 0x34, 0x54, 0xd7, 0x5e, 0xff, 0xf2, 0x2b, 0xbc, 0xf9, 0xc6, 0x1b, 0xa2, 0x6c,
+ 0x9c, 0xa9, 0xad, 0xa1, 0xa1, 0xa1, 0x81, 0x7f, 0x6c, 0x78, 0x9d, 0xe2, 0xe2, 0x77, 0xcd, 0x5e,
+ 0x62, 0x0e, 0x19, 0x32, 0x84, 0xa5, 0x99, 0x99, 0xa4, 0xa5, 0xa7, 0xe9, 0x96, 0xac, 0x73, 0xe3,
+ 0x95, 0x54, 0x57, 0x9b, 0x2e, 0x64, 0x19, 0xf2, 0xf4, 0xb3, 0xcf, 0xf2, 0xd8, 0x13, 0x8f, 0x9b,
+ 0x2d, 0xdf, 0xdc, 0xdc, 0x4c, 0x44, 0x68, 0x28, 0x97, 0x5b, 0x2f, 0xeb, 0xfa, 0x14, 0x0a, 0x05,
+ 0x87, 0xca, 0x0f, 0x9b, 0x1d, 0x48, 0x03, 0x23, 0x8f, 0x59, 0x81, 0xea, 0x13, 0x27, 0x98, 0x3d,
+ 0xeb, 0x0f, 0x14, 0x15, 0x16, 0x8a, 0xaa, 0x2f, 0xb4, 0xb7, 0xb7, 0xb3, 0x76, 0xcd, 0x1a, 0x32,
+ 0x96, 0x3c, 0x45, 0xa7, 0x56, 0x0b, 0xc0, 0x53, 0xaa, 0xa5, 0x16, 0xf9, 0x90, 0x97, 0x9b, 0xa3,
+ 0x77, 0x33, 0x4d, 0x51, 0xb4, 0xb3, 0xd0, 0x48, 0x3e, 0xe5, 0xd1, 0x05, 0xa2, 0xb2, 0x88, 0x14,
+ 0x00, 0xd7, 0x78, 0xe2, 0xb1, 0xc7, 0x69, 0x68, 0x68, 0xb0, 0x58, 0x7f, 0x5f, 0x49, 0x09, 0x6b,
+ 0xb3, 0xaf, 0x56, 0x25, 0xa3, 0xa2, 0xa3, 0x09, 0x9c, 0x30, 0x41, 0xb4, 0x8d, 0xc6, 0x86, 0x46,
+ 0x76, 0x16, 0x14, 0x98, 0x25, 0xab, 0xd5, 0x6a, 0x29, 0xc8, 0xcf, 0xd7, 0xeb, 0x73, 0x72, 0x72,
+ 0x22, 0x29, 0x25, 0x45, 0xd4, 0x98, 0x66, 0x4f, 0x02, 0x9d, 0x9d, 0x9d, 0xd9, 0x71, 0x83, 0x73,
+ 0xab, 0x57, 0xae, 0xa4, 0xb6, 0xa6, 0x46, 0xd4, 0x60, 0x19, 0x2a, 0x15, 0x93, 0xa7, 0x4c, 0xd1,
+ 0xeb, 0xf3, 0xf1, 0xf5, 0x11, 0x65, 0xa3, 0xaf, 0x68, 0x6a, 0x6c, 0xec, 0xb5, 0x8d, 0x1d, 0xdb,
+ 0xb7, 0x91, 0xf8, 0x70, 0x22, 0xa3, 0xc7, 0x8c, 0x61, 0x69, 0xa6, 0x8a, 0xb4, 0x85, 0x8b, 0x44,
+ 0xdb, 0xc8, 0xcb, 0xcd, 0x21, 0x39, 0x25, 0x05, 0x17, 0xd7, 0x9e, 0x9f, 0xe2, 0x0f, 0xf7, 0xec,
+ 0xe1, 0xfc, 0xf9, 0xf3, 0x7a, 0x7d, 0x73, 0xe2, 0xe3, 0xf1, 0xf6, 0xf6, 0x16, 0x35, 0x9e, 0xd9,
+ 0x01, 0x20, 0x97, 0xcb, 0x09, 0x8f, 0x08, 0xd7, 0xb5, 0xdd, 0xdd, 0xdd, 0x45, 0x0d, 0x04, 0x30,
+ 0x76, 0xdc, 0x58, 0x3d, 0x1b, 0xf6, 0xc4, 0x5d, 0x77, 0xdd, 0x45, 0x70, 0x48, 0x08, 0x23, 0x47,
+ 0x8d, 0xa4, 0xab, 0xab, 0x8b, 0xe3, 0xc7, 0x8e, 0x73, 0xf4, 0xc8, 0x11, 0x51, 0x36, 0x3a, 0xb5,
+ 0x9d, 0x14, 0x15, 0x16, 0xf2, 0xdc, 0x0b, 0x2f, 0x30, 0x3d, 0x32, 0x92, 0x29, 0x53, 0xa7, 0x70,
+ 0xfc, 0xd8, 0x71, 0x51, 0x36, 0xae, 0x67, 0x01, 0x53, 0x73, 0x81, 0xfc, 0x6d, 0xdb, 0x8d, 0xfa,
+ 0x16, 0xa5, 0xa5, 0x8a, 0x1a, 0x0b, 0xa4, 0x57, 0x80, 0x8e, 0x98, 0x99, 0xb1, 0xac, 0x5b, 0xff,
+ 0x0a, 0x19, 0x2a, 0x15, 0x2a, 0xb5, 0x9a, 0x82, 0xa2, 0x42, 0xfe, 0xfc, 0xe4, 0x93, 0xa2, 0xed,
+ 0x94, 0x95, 0xfe, 0x56, 0xb7, 0x58, 0x92, 0x91, 0x61, 0x91, 0x2f, 0xa6, 0xe6, 0x02, 0x95, 0x15,
+ 0x15, 0x46, 0x93, 0xcc, 0xb0, 0xf0, 0x70, 0xb3, 0x67, 0xfe, 0x37, 0x22, 0x05, 0x40, 0x0f, 0x2c,
+ 0x4a, 0x4b, 0xd5, 0x2d, 0x0d, 0xcd, 0xe5, 0xfb, 0xba, 0x3a, 0x9a, 0x9a, 0xae, 0x7e, 0x26, 0x8f,
+ 0x98, 0x36, 0x8d, 0xa9, 0x41, 0x53, 0x45, 0x8f, 0x6b, 0x6a, 0x2e, 0xb0, 0xe5, 0xad, 0xb7, 0x8c,
+ 0xfa, 0x52, 0xd3, 0xd3, 0x44, 0x8f, 0x03, 0x52, 0x00, 0xf4, 0x88, 0x97, 0x97, 0x17, 0x0a, 0x85,
+ 0x42, 0xb4, 0x5e, 0x7d, 0x7d, 0xbd, 0xee, 0xe7, 0x25, 0x19, 0xd6, 0x5d, 0x11, 0x7c, 0x7b, 0xee,
+ 0x5b, 0xca, 0x0e, 0x94, 0xea, 0xf5, 0xf9, 0xf9, 0xf9, 0x11, 0x19, 0x15, 0x65, 0xd1, 0x38, 0x76,
+ 0x1b, 0x00, 0x81, 0x81, 0x81, 0x6c, 0xdc, 0xb4, 0x89, 0xdc, 0xcd, 0x9b, 0x89, 0x57, 0x2a, 0x01,
+ 0x58, 0x98, 0xba, 0x88, 0x3d, 0x25, 0x7b, 0xd9, 0xf5, 0xcf, 0x0f, 0x48, 0x4d, 0x4b, 0x43, 0x26,
+ 0xeb, 0xfb, 0xed, 0x8c, 0xb7, 0xdf, 0x7e, 0xbb, 0x68, 0x9d, 0xc6, 0x86, 0xdf, 0x26, 0x94, 0xe1,
+ 0x11, 0xe1, 0x4c, 0x0d, 0x0a, 0xb2, 0xc8, 0xc6, 0xcd, 0xb2, 0xc0, 0xb6, 0xad, 0x5b, 0xe9, 0xea,
+ 0xea, 0xd2, 0xeb, 0x4b, 0x7b, 0x6c, 0xb1, 0xc5, 0x95, 0x49, 0xbb, 0x2c, 0x05, 0xfb, 0xfa, 0xfa,
+ 0x52, 0x50, 0x54, 0xa8, 0x5b, 0xcf, 0xce, 0x88, 0x8d, 0x61, 0x7a, 0x64, 0x24, 0xf1, 0x09, 0x4a,
+ 0x9d, 0x4c, 0x60, 0x60, 0x20, 0x1d, 0x37, 0x59, 0x0a, 0x59, 0x1b, 0x4b, 0x82, 0xac, 0xab, 0x4b,
+ 0xbf, 0x8e, 0x90, 0xa1, 0x5a, 0xca, 0x82, 0xa4, 0x64, 0xd1, 0x76, 0x0c, 0x57, 0x04, 0x4d, 0x4d,
+ 0x4d, 0xec, 0xde, 0xb5, 0x4b, 0x4f, 0x46, 0xa1, 0x50, 0xa0, 0x54, 0x2a, 0x6f, 0xa6, 0x6e, 0x16,
+ 0x76, 0x99, 0x01, 0xe6, 0x28, 0x95, 0x0c, 0x75, 0x71, 0x61, 0x5d, 0x76, 0x36, 0xe1, 0x21, 0xa1,
+ 0xe4, 0x6f, 0xdf, 0x41, 0x7c, 0x82, 0x92, 0xa3, 0x47, 0x8e, 0x70, 0xbf, 0xbf, 0x3f, 0x33, 0x1f,
+ 0x98, 0x41, 0x4b, 0x4b, 0x0b, 0xf3, 0x93, 0x1e, 0xb1, 0xb5, 0xab, 0x66, 0x11, 0x1a, 0x16, 0x46,
+ 0x50, 0x70, 0xb0, 0x68, 0x3d, 0xc3, 0x2c, 0x50, 0x58, 0x50, 0x40, 0xdb, 0x65, 0xfd, 0xd7, 0x42,
+ 0xf2, 0x82, 0x14, 0xd1, 0xe5, 0xe3, 0x1b, 0xb1, 0xcb, 0x00, 0x18, 0x35, 0x6a, 0x14, 0x70, 0x75,
+ 0x69, 0xf6, 0xe8, 0xc2, 0x85, 0xb8, 0xb9, 0xbb, 0x01, 0x57, 0x9f, 0xc6, 0x27, 0x97, 0x3c, 0xc5,
+ 0xdc, 0xc4, 0x44, 0x5a, 0x2f, 0xb5, 0x72, 0xcf, 0xdd, 0x77, 0xdb, 0xd2, 0x4d, 0x51, 0xa8, 0x97,
+ 0x2f, 0xb7, 0x48, 0xef, 0xfa, 0x5c, 0x40, 0xab, 0xd5, 0x52, 0xb8, 0x73, 0xa7, 0xde, 0x35, 0x27,
+ 0x27, 0x27, 0x92, 0x17, 0x2c, 0xe8, 0x95, 0x5f, 0x76, 0xf9, 0x0a, 0x70, 0x76, 0x76, 0x06, 0x30,
+ 0xfa, 0xe5, 0x82, 0x43, 0x42, 0x08, 0x0e, 0x09, 0xd1, 0xb5, 0xaf, 0x97, 0x5e, 0x6f, 0x05, 0xa6,
+ 0x4c, 0x9d, 0x42, 0x70, 0x48, 0x08, 0x15, 0x47, 0x8f, 0x8a, 0xd2, 0xbb, 0x9e, 0x05, 0xbc, 0x86,
+ 0x7b, 0xf1, 0xd3, 0xf9, 0x9f, 0xf4, 0xae, 0x59, 0x52, 0xf8, 0x31, 0xc4, 0x2e, 0x03, 0xa0, 0x20,
+ 0x3f, 0x9f, 0xd2, 0xd2, 0x03, 0x26, 0xe5, 0x04, 0x41, 0xe8, 0x07, 0x6f, 0xac, 0x87, 0x4a, 0x9d,
+ 0xc9, 0x23, 0x0f, 0xcf, 0x13, 0xad, 0xf7, 0x56, 0x5e, 0x1e, 0xc3, 0xef, 0x18, 0x6e, 0xd4, 0x6f,
+ 0x49, 0xe1, 0xc7, 0x10, 0xbb, 0x0c, 0x80, 0xea, 0xea, 0xea, 0x9b, 0x7e, 0x4d, 0xf3, 0xf0, 0xf0,
+ 0x20, 0x2a, 0x3a, 0x9a, 0xdb, 0x86, 0xdc, 0x46, 0xd5, 0x67, 0x55, 0xa2, 0x4b, 0xd1, 0xb6, 0x66,
+ 0x6a, 0x50, 0x10, 0xa1, 0x61, 0x61, 0x1c, 0x29, 0x2f, 0x17, 0xa5, 0x57, 0x5f, 0x5f, 0xaf, 0xb7,
+ 0xb4, 0x04, 0xcb, 0x0b, 0x3f, 0x86, 0xd8, 0xe5, 0x1c, 0xe0, 0x99, 0xac, 0x2c, 0x6a, 0xbf, 0x3d,
+ 0x47, 0x4c, 0x6c, 0xac, 0xae, 0x2f, 0x6e, 0xd6, 0x2c, 0x0e, 0x68, 0xca, 0x58, 0xbf, 0xe1, 0x35,
+ 0x5e, 0xca, 0xce, 0xe6, 0xc3, 0x92, 0xbd, 0x24, 0xce, 0x13, 0xff, 0x34, 0xd9, 0x9a, 0xcc, 0x65,
+ 0x6a, 0xab, 0xd8, 0xb1, 0xb4, 0xf0, 0x63, 0x88, 0x5d, 0x06, 0xc0, 0xdd, 0xf7, 0x5c, 0x9d, 0xdc,
+ 0xd5, 0xd6, 0xd4, 0x20, 0x93, 0xc9, 0xc8, 0x50, 0xa9, 0xd8, 0xf8, 0xe6, 0x26, 0x14, 0x9e, 0x9e,
+ 0x1c, 0xd4, 0x68, 0x78, 0x79, 0xed, 0x5a, 0xae, 0x5c, 0xb9, 0xc2, 0x5f, 0x9e, 0x7e, 0xda, 0xc6,
+ 0x9e, 0x8a, 0x67, 0xd2, 0xe4, 0xc9, 0xbd, 0xfe, 0x1e, 0xd2, 0x9b, 0xc2, 0x8f, 0x21, 0x76, 0xf9,
+ 0x0a, 0xa8, 0xad, 0xa9, 0x61, 0x66, 0x5c, 0x1c, 0x1b, 0x73, 0xde, 0xa4, 0x53, 0xab, 0xc5, 0x3f,
+ 0x20, 0x00, 0xad, 0x56, 0x4b, 0xf6, 0x4b, 0x2f, 0xb1, 0x7d, 0xeb, 0x36, 0x00, 0x66, 0xc4, 0xc4,
+ 0x30, 0x61, 0xe2, 0x44, 0x9c, 0x9c, 0x9c, 0x6c, 0xec, 0xad, 0x78, 0x54, 0x6a, 0x75, 0xaf, 0x76,
+ 0x36, 0xa7, 0x2e, 0x4e, 0xb7, 0xda, 0x96, 0x34, 0xbb, 0xcc, 0x00, 0x9b, 0x73, 0xf3, 0xa8, 0xac,
+ 0xa8, 0x60, 0xec, 0xd8, 0xb1, 0xf8, 0x07, 0x04, 0xf0, 0x7d, 0x5d, 0x1d, 0x49, 0xf3, 0xe6, 0xeb,
+ 0x6e, 0xbe, 0xe7, 0x30, 0x4f, 0xc6, 0x8d, 0x1b, 0x47, 0xcd, 0xd7, 0x35, 0x74, 0x74, 0x74, 0xd8,
+ 0xd8, 0x5b, 0xf1, 0x4c, 0x9c, 0x34, 0x89, 0x88, 0x69, 0xd3, 0x2c, 0xd2, 0x55, 0x28, 0x14, 0x24,
+ 0x24, 0x24, 0x58, 0xcd, 0x17, 0x8b, 0x33, 0x80, 0x25, 0x25, 0x52, 0x73, 0x69, 0x69, 0x69, 0x21,
+ 0x69, 0xde, 0x7c, 0x7c, 0x7c, 0x7c, 0x70, 0x75, 0x73, 0xe3, 0xdc, 0x37, 0xdf, 0xd0, 0xd9, 0xf9,
+ 0x5b, 0x75, 0xad, 0xa5, 0xb9, 0x85, 0x88, 0xd0, 0x30, 0xae, 0xdc, 0x82, 0x37, 0xff, 0x3a, 0x2a,
+ 0x75, 0x26, 0x9f, 0x1e, 0x3a, 0x24, 0x5a, 0xaf, 0xb7, 0x85, 0x1f, 0x43, 0x2c, 0x0e, 0x80, 0x61,
+ 0x5e, 0xc3, 0x4c, 0x0b, 0x19, 0xf0, 0xeb, 0xaf, 0xbf, 0x9a, 0x25, 0xf7, 0xc7, 0xd9, 0x0f, 0xe2,
+ 0xef, 0x1f, 0xd0, 0xed, 0xf5, 0x96, 0xe6, 0x66, 0xaa, 0xaa, 0xaa, 0xa8, 0xac, 0xa8, 0x10, 0xed,
+ 0x83, 0xbd, 0x30, 0x61, 0xe2, 0x44, 0xa6, 0x47, 0x46, 0xf2, 0xc9, 0xc1, 0x83, 0x66, 0xeb, 0x38,
+ 0x3a, 0x3a, 0x92, 0x94, 0x2c, 0xbe, 0xa4, 0xdc, 0xa3, 0x4d, 0x4b, 0x15, 0xc7, 0x8c, 0xf9, 0xbd,
+ 0x68, 0x1d, 0xc3, 0x42, 0x46, 0x77, 0x44, 0x47, 0x3f, 0x40, 0xc2, 0xdc, 0x87, 0x4c, 0xca, 0xe5,
+ 0xe5, 0xe4, 0xb2, 0x2e, 0x3b, 0x5b, 0xb4, 0x1f, 0xf6, 0x82, 0x7a, 0xf9, 0x32, 0x0e, 0x7d, 0xf2,
+ 0x89, 0xd9, 0xf5, 0x8c, 0x39, 0xf1, 0xf1, 0x66, 0x9d, 0xae, 0x16, 0x83, 0xc5, 0x01, 0x10, 0x33,
+ 0x33, 0x96, 0xb5, 0x6b, 0xd6, 0x88, 0xd2, 0x29, 0x7e, 0xe7, 0x1d, 0x62, 0x66, 0xc6, 0xe2, 0xe7,
+ 0xe7, 0xd7, 0xa3, 0x5c, 0x5e, 0x6e, 0x2e, 0x1f, 0xbc, 0xbf, 0xbb, 0xdb, 0xeb, 0x1e, 0x0a, 0x05,
+ 0xea, 0x65, 0xcb, 0x49, 0x5f, 0x9c, 0xce, 0xeb, 0xaf, 0xbd, 0x26, 0xca, 0x07, 0x7b, 0x22, 0x60,
+ 0xfc, 0x78, 0x22, 0xa3, 0xa2, 0xd0, 0x94, 0x95, 0x99, 0x16, 0xc6, 0x7a, 0x4b, 0xbf, 0x1b, 0xb1,
+ 0x38, 0x00, 0xfc, 0xfc, 0xfc, 0x88, 0x9b, 0x35, 0x8b, 0x7d, 0x25, 0x25, 0x66, 0xeb, 0x9c, 0x3b,
+ 0x77, 0x8e, 0xb8, 0x19, 0x31, 0x78, 0x8f, 0xf0, 0xc6, 0xd5, 0xc5, 0x95, 0xfa, 0x86, 0x06, 0x94,
+ 0x09, 0x4a, 0xbd, 0x6d, 0xe1, 0x00, 0x0d, 0xf5, 0xf5, 0x46, 0x7b, 0xf1, 0x6f, 0x64, 0xc8, 0x85,
+ 0x5f, 0x68, 0x6e, 0x6e, 0xc6, 0x41, 0x2e, 0xc7, 0xb1, 0x9b, 0xd3, 0xc3, 0xb7, 0x0a, 0x2a, 0x75,
+ 0x26, 0x07, 0x35, 0x1a, 0x93, 0x59, 0xc0, 0x5a, 0x85, 0x1f, 0x43, 0x7a, 0xf5, 0xd7, 0x7b, 0x7e,
+ 0xe5, 0x0b, 0x9c, 0xfa, 0xf2, 0x4b, 0x7e, 0xf8, 0xe1, 0x07, 0xb3, 0x75, 0xba, 0xba, 0xba, 0x4c,
+ 0xbe, 0x0a, 0x9e, 0xc9, 0xca, 0x32, 0xeb, 0x15, 0xb0, 0xf7, 0xc3, 0xff, 0xd0, 0xda, 0xda, 0x6a,
+ 0xf6, 0xd8, 0xf6, 0x48, 0xc0, 0xf8, 0xf1, 0x44, 0x45, 0x47, 0x53, 0x56, 0x5a, 0xda, 0xa3, 0x5c,
+ 0x5f, 0x3c, 0xfd, 0xd0, 0xcb, 0x00, 0xf0, 0x1e, 0x31, 0x82, 0xe2, 0xdd, 0xbb, 0x58, 0x9e, 0xa9,
+ 0xa6, 0xfc, 0xb0, 0xf5, 0x4e, 0xec, 0xd6, 0xd4, 0x7c, 0xdd, 0xe3, 0x3a, 0xf9, 0xe2, 0xc5, 0x5f,
+ 0xf8, 0xec, 0xd8, 0x71, 0xde, 0x2b, 0x2e, 0xb6, 0xda, 0x98, 0xb6, 0x44, 0xa5, 0xce, 0x44, 0x53,
+ 0x56, 0xd6, 0x6d, 0x16, 0xb0, 0x66, 0xe1, 0xc7, 0x90, 0x5e, 0xe7, 0x4f, 0x6f, 0x6f, 0x6f, 0xf2,
+ 0x77, 0x16, 0x70, 0xac, 0xb2, 0x92, 0x3d, 0xff, 0xfa, 0x37, 0xe5, 0x87, 0x0f, 0x53, 0xf7, 0x7d,
+ 0x5d, 0x8f, 0x87, 0x2b, 0xe4, 0x72, 0x39, 0xc3, 0xef, 0xb8, 0x03, 0x1f, 0x1f, 0x1f, 0x46, 0x8f,
+ 0x1e, 0x63, 0x74, 0x3d, 0x2f, 0x27, 0x97, 0xbc, 0x9c, 0xdc, 0xde, 0xba, 0x76, 0xcb, 0xe0, 0x1f,
+ 0x10, 0x40, 0xf4, 0x8c, 0x07, 0x28, 0xfd, 0xf8, 0xe6, 0x1f, 0xc0, 0xac, 0x59, 0xf8, 0x31, 0xc4,
+ 0xe2, 0x7f, 0x11, 0xd3, 0x13, 0x9d, 0x5a, 0x2d, 0x3f, 0x5f, 0xb8, 0x40, 0x73, 0x73, 0x33, 0xda,
+ 0x6b, 0x6b, 0xf5, 0xa1, 0x2e, 0x2e, 0x38, 0x3b, 0x39, 0x31, 0xd4, 0xc5, 0x05, 0x4f, 0x4f, 0x4f,
+ 0xd1, 0x9b, 0x2d, 0x07, 0x3a, 0xff, 0x3d, 0x75, 0x8a, 0xf8, 0xd9, 0x7f, 0x32, 0xca, 0x02, 0x62,
+ 0x8f, 0x7a, 0x89, 0xa5, 0x4f, 0x66, 0x50, 0x72, 0x47, 0x47, 0x7c, 0x7d, 0x7d, 0xf1, 0xf5, 0xf5,
+ 0xed, 0x0b, 0xf3, 0x03, 0x92, 0xfb, 0xfc, 0xfd, 0x09, 0x09, 0x0d, 0x35, 0xfa, 0x52, 0xf8, 0x48,
+ 0x72, 0x72, 0x9f, 0xdd, 0x7c, 0xb0, 0xd3, 0x52, 0xf0, 0x60, 0xa4, 0xad, 0xad, 0x8d, 0xd3, 0xa7,
+ 0x4f, 0xeb, 0xf5, 0x39, 0x3a, 0x3a, 0x92, 0x2c, 0xf2, 0xa8, 0x97, 0x58, 0xa4, 0x00, 0xb0, 0x13,
+ 0x76, 0xbd, 0xf7, 0x9e, 0xd1, 0xf1, 0xb4, 0x39, 0xf1, 0xf1, 0xdc, 0xe9, 0x63, 0xdd, 0xc2, 0x8f,
+ 0x21, 0x52, 0x00, 0xd8, 0x01, 0x82, 0x20, 0xf0, 0xf6, 0x0e, 0xe3, 0xdd, 0xcd, 0x7d, 0xb5, 0xf4,
+ 0xbb, 0x11, 0x29, 0x00, 0xec, 0x80, 0xb2, 0x03, 0xa5, 0x9c, 0x3d, 0x7b, 0x56, 0xaf, 0x2f, 0x34,
+ 0x2c, 0xac, 0x4f, 0x0a, 0x3f, 0x86, 0x48, 0x01, 0x60, 0x07, 0x6c, 0xdd, 0xb2, 0xc5, 0xa8, 0x2f,
+ 0x35, 0x3d, 0xbd, 0x5f, 0xc6, 0x96, 0x02, 0xc0, 0xc6, 0x7c, 0x75, 0xe6, 0x2b, 0xa3, 0x9d, 0xc2,
+ 0x7e, 0x7e, 0x7e, 0x44, 0x45, 0x47, 0xf5, 0xcb, 0xf8, 0x52, 0x00, 0xd8, 0x98, 0x2d, 0x9b, 0x37,
+ 0x1b, 0xad, 0xfd, 0xfb, 0xb2, 0xf0, 0x63, 0x48, 0x9f, 0x14, 0x82, 0x24, 0xcc, 0xa3, 0xbe, 0xbe,
+ 0x9e, 0xe9, 0x61, 0xe1, 0x7a, 0xfb, 0x24, 0xfa, 0xba, 0xf0, 0x63, 0x88, 0x94, 0x01, 0x6c, 0xc8,
+ 0xdb, 0x3b, 0x76, 0x18, 0x6d, 0x92, 0x49, 0x4a, 0xb1, 0xee, 0x8e, 0x1f, 0x53, 0x48, 0x19, 0xc0,
+ 0x86, 0xb4, 0xb6, 0xb6, 0xa2, 0x35, 0x38, 0xdd, 0xe4, 0xea, 0xea, 0xda, 0xaf, 0x9f, 0xb8, 0xa5,
+ 0x00, 0x18, 0xe4, 0x38, 0x00, 0xb7, 0xd6, 0xf9, 0x2a, 0x09, 0xab, 0xe2, 0x00, 0xf4, 0xfe, 0xdf,
+ 0x63, 0x49, 0xdc, 0xaa, 0x34, 0x3a, 0x00, 0xe2, 0x0e, 0xaa, 0x49, 0x0c, 0x24, 0xca, 0x65, 0x82,
+ 0x20, 0x44, 0x03, 0x07, 0x90, 0xe6, 0x01, 0x83, 0x0d, 0x01, 0x88, 0x75, 0x90, 0xc9, 0x64, 0x65,
+ 0xc0, 0x8b, 0xb6, 0xf6, 0x46, 0xa2, 0xdf, 0xf9, 0x9b, 0x4c, 0x26, 0x3b, 0xa0, 0x7b, 0xea, 0x05,
+ 0x41, 0x98, 0x0b, 0xa8, 0x81, 0x89, 0xc0, 0x50, 0x9b, 0xb9, 0x25, 0xd1, 0x97, 0xb4, 0x03, 0x9f,
+ 0x03, 0xeb, 0x65, 0x32, 0xd9, 0x2e, 0x80, 0xff, 0x03, 0xff, 0x08, 0x81, 0xdd, 0xa8, 0xcb, 0xf5,
+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
+};
diff --git a/examples/device/mtp/src/tusb_config.h b/examples/device/mtp/src/tusb_config.h
new file mode 100644
index 000000000..4d166aa63
--- /dev/null
+++ b/examples/device/mtp/src/tusb_config.h
@@ -0,0 +1,139 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Board Specific Configuration
+//--------------------------------------------------------------------+
+
+// RHPort number used for device can be defined by board.mk, default to port 0
+#ifndef BOARD_TUD_RHPORT
+#define BOARD_TUD_RHPORT 0
+#endif
+
+// RHPort max operational speed can defined by board.mk
+#ifndef BOARD_TUD_MAX_SPEED
+#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
+#endif
+
+//--------------------------------------------------------------------
+// COMMON CONFIGURATION
+//--------------------------------------------------------------------
+
+// defined by compiler flags for flexibility
+#ifndef CFG_TUSB_MCU
+#error CFG_TUSB_MCU must be defined
+#endif
+
+#ifndef CFG_TUSB_OS
+#define CFG_TUSB_OS OPT_OS_NONE
+#endif
+
+#ifndef CFG_TUSB_DEBUG
+#define CFG_TUSB_DEBUG 0
+#endif
+
+// Enable Device stack
+#define CFG_TUD_ENABLED 1
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
+
+/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
+ * Tinyusb use follows macros to declare transferring memory so that they can be put
+ * into those specific section.
+ * e.g
+ * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
+ * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
+ */
+#ifndef CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_SECTION
+#endif
+
+#ifndef CFG_TUSB_MEM_ALIGN
+#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// DEVICE CONFIGURATION
+//--------------------------------------------------------------------
+
+#ifndef CFG_TUD_ENDPOINT0_SIZE
+#define CFG_TUD_ENDPOINT0_SIZE 64
+#endif
+
+//------------- CLASS -------------//
+#define CFG_TUD_MTP 1
+#define CFG_TUD_MTP_EP_BUFSIZE 512
+#define CFG_TUD_MTP_EP_CONTROL_BUFSIZE 16 // should be enough to hold data in MTP control request
+
+//------------- MTP device info -------------//
+#define CFG_TUD_MTP_DEVICEINFO_EXTENSIONS "microsoft.com: 1.0; "
+#define CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS \
+ MTP_OP_GET_DEVICE_INFO, \
+ MTP_OP_OPEN_SESSION, \
+ MTP_OP_CLOSE_SESSION, \
+ MTP_OP_GET_STORAGE_IDS, \
+ MTP_OP_GET_STORAGE_INFO, \
+ MTP_OP_GET_OBJECT_HANDLES, \
+ MTP_OP_GET_OBJECT_INFO, \
+ MTP_OP_GET_OBJECT, \
+ MTP_OP_DELETE_OBJECT, \
+ MTP_OP_SEND_OBJECT_INFO, \
+ MTP_OP_SEND_OBJECT, \
+ MTP_OP_RESET_DEVICE, \
+ MTP_OP_GET_DEVICE_PROP_DESC, \
+ MTP_OP_GET_DEVICE_PROP_VALUE, \
+ MTP_OP_SET_DEVICE_PROP_VALUE
+
+#define CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS \
+ MTP_EVENT_OBJECT_ADDED
+
+#define CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES \
+ MTP_DEV_PROP_DEVICE_FRIENDLY_NAME
+
+#define CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS \
+ MTP_OBJ_FORMAT_UNDEFINED, \
+ MTP_OBJ_FORMAT_ASSOCIATION, \
+ MTP_OBJ_FORMAT_TEXT, \
+ MTP_OBJ_FORMAT_PNG
+
+#define CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS \
+ MTP_OBJ_FORMAT_UNDEFINED, \
+ MTP_OBJ_FORMAT_ASSOCIATION, \
+ MTP_OBJ_FORMAT_TEXT, \
+ MTP_OBJ_FORMAT_PNG
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */
diff --git a/examples/device/mtp/src/usb_descriptors.c b/examples/device/mtp/src/usb_descriptors.c
new file mode 100644
index 000000000..80345d8f8
--- /dev/null
+++ b/examples/device/mtp/src/usb_descriptors.c
@@ -0,0 +1,255 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "bsp/board_api.h"
+#include "tusb.h"
+
+/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
+ * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
+ *
+ * Auto ProductID layout's Bitmap:
+ * [MSB] MTP | VENDOR | MIDI | HID | MSC | CDC [LSB]
+ */
+#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
+#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
+ _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) | _PID_MAP(MTP, 5))
+
+#define USB_VID 0xCafe
+#define USB_BCD 0x0200
+
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
+tusb_desc_device_t const desc_device =
+{
+ .bLength = sizeof(tusb_desc_device_t),
+ .bDescriptorType = TUSB_DESC_DEVICE,
+ .bcdUSB = USB_BCD,
+ .bDeviceClass = TUSB_CLASS_UNSPECIFIED,
+ .bDeviceSubClass = 0x00,
+ .bDeviceProtocol = 0x00,
+ .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+
+ .idVendor = USB_VID,
+ .idProduct = USB_PID,
+ .bcdDevice = 0x0100,
+
+ .iManufacturer = 0x01,
+ .iProduct = 0x02,
+ .iSerialNumber = 0x03,
+
+ .bNumConfigurations = 0x01
+};
+
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const *tud_descriptor_device_cb(void)
+{
+ return (uint8_t const *) &desc_device;
+}
+
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+
+enum
+{
+ ITF_NUM_MTP = 0,
+ ITF_NUM_TOTAL
+};
+
+#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
+ // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
+ // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ...
+ #define EPNUM_MTP_EVT 0x81
+ #define EPNUM_MTP_OUT 0x02
+ #define EPNUM_MTP_IN 0x82
+
+#elif CFG_TUSB_MCU == OPT_MCU_CXD56
+ // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number
+ // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN)
+ #define EPNUM_MTP_EVT 0x83
+ #define EPNUM_MTP_OUT 0x02
+ #define EPNUM_MTP_IN 0x81
+
+#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY)
+ // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h
+ // e.g EP1 OUT & EP1 IN cannot exist together
+ #define EPNUM_MTP_EVT 0x81
+ #define EPNUM_MTP_OUT 0x03
+ #define EPNUM_MTP_IN 0x82
+
+#else
+ #define EPNUM_MTP_EVT 0x81
+ #define EPNUM_MTP_OUT 0x02
+ #define EPNUM_MTP_IN 0x82
+#endif
+
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MTP_DESC_LEN)
+
+// full speed configuration
+const uint8_t desc_fs_configuration[] = {
+ // Config number, interface count, string index, total length, attribute, power in mA
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
+ // Interface number, string index, EP event, EP event size, EP event polling, EP Out & EP In address, EP size
+ TUD_MTP_DESCRIPTOR(ITF_NUM_MTP, 4, EPNUM_MTP_EVT, 64, 1, EPNUM_MTP_OUT, EPNUM_MTP_IN, 64),
+};
+
+#if TUD_OPT_HIGH_SPEED
+// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration
+
+// high speed configuration
+uint8_t const desc_hs_configuration[] = {
+ // Config number, interface count, string index, total length, attribute, power in mA
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
+ // Interface number, string index, EP event, EP event size, EP event polling, EP Out & EP In address, EP size
+ TUD_MTP_DESCRIPTOR(ITF_NUM_MTP, 4, EPNUM_MTP_EVT, 64, 1, EPNUM_MTP_OUT, EPNUM_MTP_IN, 512),
+};
+
+// other speed configuration
+uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
+
+// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
+tusb_desc_device_qualifier_t const desc_device_qualifier = {
+ .bLength = sizeof(tusb_desc_device_qualifier_t),
+ .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
+ .bcdUSB = USB_BCD,
+
+ .bDeviceClass = TUSB_CLASS_MISC,
+ .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+ .bDeviceProtocol = MISC_PROTOCOL_IAD,
+
+ .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+ .bNumConfigurations = 0x01,
+ .bReserved = 0x00
+};
+
+// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
+// device_qualifier descriptor describes information about a high-speed capable device that would
+// change if the device were operating at the other speed. If not highspeed capable stall this request.
+uint8_t const *tud_descriptor_device_qualifier_cb(void) {
+ return (uint8_t const *) &desc_device_qualifier;
+}
+
+// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
+uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
+ (void) index; // for multiple configurations
+
+ // if link speed is high return fullspeed config, and vice versa
+ // Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG
+ memcpy(desc_other_speed_config,
+ (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration,
+ CONFIG_TOTAL_LEN);
+ desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
+ return desc_other_speed_config;
+}
+
+#endif // highspeed
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+const uint8_t*tud_descriptor_configuration_cb(uint8_t index) {
+ (void) index; // for multiple configurations
+#if TUD_OPT_HIGH_SPEED
+ // Although we are highspeed, host may be fullspeed.
+ return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
+#else
+ return desc_fs_configuration;
+#endif
+}
+
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+ STRID_MTP,
+};
+
+// array of pointer to string descriptors
+char const *string_desc_arr[] =
+{
+ (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
+ "TinyUsb", // 1: Manufacturer
+ "TinyUsb Device", // 2: Product
+ NULL, // 3: Serials will use unique ID if possible
+ "TinyUSB MTP", // 4: MTP Interface
+};
+
+static uint16_t _desc_str[32 + 1];
+
+// Invoked when received GET STRING DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
+ (void) langid;
+ size_t chr_count;
+
+ switch ( index ) {
+ case STRID_LANGID:
+ memcpy(&_desc_str[1], string_desc_arr[0], 2);
+ chr_count = 1;
+ break;
+
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
+
+ default:
+ // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
+ // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
+
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) {
+ return NULL;
+ }
+
+ const char *str = string_desc_arr[index];
+ // Cap at max char
+ chr_count = strlen(str);
+ const size_t max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
+ if ( chr_count > max_count ) {
+ chr_count = max_count;
+ }
+
+ // Convert ASCII string into UTF-16
+ for ( size_t i = 0; i < chr_count; i++ ) {
+ _desc_str[1 + i] = str[i];
+ }
+ break;
+ }
+
+ // first byte is length (including header), second byte is string type
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
+
+ return _desc_str;
+}
diff --git a/examples/device/net_lwip_webserver/src/main.c b/examples/device/net_lwip_webserver/src/main.c
index 4bdddf6c5..dd9f213ae 100644
--- a/examples/device/net_lwip_webserver/src/main.c
+++ b/examples/device/net_lwip_webserver/src/main.c
@@ -250,9 +250,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
/* initialize lwip, dhcp-server, dns-server, and http */
init_lwip();
diff --git a/examples/device/uac2_headset/src/main.c b/examples/device/uac2_headset/src/main.c
index d4c2b41d9..102a6eef1 100644
--- a/examples/device/uac2_headset/src/main.c
+++ b/examples/device/uac2_headset/src/main.c
@@ -102,9 +102,7 @@ int main(void) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
TU_LOG1("Headset running\r\n");
diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h
index e738a09af..e9165163b 100644
--- a/examples/device/uac2_headset/src/tusb_config.h
+++ b/examples/device/uac2_headset/src/tusb_config.h
@@ -158,9 +158,6 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_OUT) // Maximum EP IN size for all AS alternate settings used
#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX // Example read FIFO every 1ms, so it should be 8 times larger for HS device
-// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 2
-
// Size of control request buffer
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
diff --git a/examples/device/uac2_speaker_fb/src/main.c b/examples/device/uac2_speaker_fb/src/main.c
index d9f6e9259..ed9e7716d 100644
--- a/examples/device/uac2_speaker_fb/src/main.c
+++ b/examples/device/uac2_speaker_fb/src/main.c
@@ -108,9 +108,7 @@ int main(void) {
.speed = TUSB_SPEED_AUTO};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
TU_LOG1("Speaker running\r\n");
diff --git a/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c
index 965bbd6cf..92b9ab6ee 100644
--- a/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c
+++ b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c
@@ -29,12 +29,12 @@ static tusb_desc_type_t desc_req_buf[2];
static int desc_req_idx = 0;
// Place at the start of tud_descriptor_device_cb()
-void quirk_os_guessing_desc_device_cb() {
+void quirk_os_guessing_desc_device_cb(void) {
desc_req_idx = 0;
}
// Place at the start of tud_descriptor_configuration_cb()
-void quirk_os_guessing_desc_configuration_cb() {
+void quirk_os_guessing_desc_configuration_cb(void) {
// Skip redundant request
if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_CONFIGURATION)) {
desc_req_buf[desc_req_idx++] = TUSB_DESC_CONFIGURATION;
@@ -42,7 +42,7 @@ void quirk_os_guessing_desc_configuration_cb() {
}
// Place at the start of tud_descriptor_bos_cb()
-void quirk_os_guessing_desc_bos_cb() {
+void quirk_os_guessing_desc_bos_cb(void) {
// Skip redundant request
if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_BOS)) {
desc_req_buf[desc_req_idx++] = TUSB_DESC_BOS;
@@ -50,7 +50,7 @@ void quirk_os_guessing_desc_bos_cb() {
}
// Place at the start of tud_descriptor_string_cb()
-void quirk_os_guessing_desc_string_cb() {
+void quirk_os_guessing_desc_string_cb(void) {
// Skip redundant request
if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_STRING)) {
desc_req_buf[desc_req_idx++] = TUSB_DESC_STRING;
diff --git a/examples/device/uac2_speaker_fb/src/tusb_config.h b/examples/device/uac2_speaker_fb/src/tusb_config.h
index fd4925c7f..18ab2ff96 100644
--- a/examples/device/uac2_speaker_fb/src/tusb_config.h
+++ b/examples/device/uac2_speaker_fb/src/tusb_config.h
@@ -130,7 +130,7 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_SPEAKER_STEREO_FB_DESC_LEN
-// Enable if Full-Speed on OSX, also set feedback EP size to 3
+// Can be enabled with Full-Speed device on OSX, which forces feedback EP size to 3, in this case CFG_QUIRK_OS_GUESSING can be disabled
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0
// Audio format type I specifications
@@ -155,9 +155,6 @@ extern "C" {
// Enable feedback EP
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 1
-// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1
-
// Size of control request buffer
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
diff --git a/examples/device/usbtmc/src/main.c b/examples/device/usbtmc/src/main.c
index aa7902a15..f78cce91f 100644
--- a/examples/device/usbtmc/src/main.c
+++ b/examples/device/usbtmc/src/main.c
@@ -61,9 +61,7 @@ int main(void)
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/device/usbtmc/src/usbtmc_app.c b/examples/device/usbtmc/src/usbtmc_app.c
index fb25982c7..e738f1008 100644
--- a/examples/device/usbtmc/src/usbtmc_app.c
+++ b/examples/device/usbtmc/src/usbtmc_app.c
@@ -99,7 +99,7 @@ usbtmc_response_capabilities_488_t const *
#else
usbtmc_response_capabilities_t const *
#endif
-tud_usbtmc_get_capabilities_cb()
+tud_usbtmc_get_capabilities_cb(void)
{
return &tud_usbtmc_app_capabilities;
}
@@ -161,7 +161,7 @@ bool tud_usbtmc_msg_data_cb(void *data, size_t len, bool transfer_complete)
return true;
}
-bool tud_usbtmc_msgBulkIn_complete_cb()
+bool tud_usbtmc_msgBulkIn_complete_cb(void)
{
if((buffer_tx_ix == buffer_len) || idnQuery) // done
{
diff --git a/examples/device/video_capture/src/main.c b/examples/device/video_capture/src/main.c
index 0406279fd..29656e944 100644
--- a/examples/device/video_capture/src/main.c
+++ b/examples/device/video_capture/src/main.c
@@ -74,9 +74,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
@@ -329,9 +327,7 @@ void usb_device_task(void *param) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// RTOS forever loop
while (1) {
diff --git a/examples/device/video_capture_2ch/src/main.c b/examples/device/video_capture_2ch/src/main.c
index dc616e3fa..f56738f67 100644
--- a/examples/device/video_capture_2ch/src/main.c
+++ b/examples/device/video_capture_2ch/src/main.c
@@ -74,9 +74,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
@@ -337,9 +335,7 @@ void usb_device_task(void *param) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
// RTOS forever loop
while (1) {
diff --git a/examples/device/webusb_serial/src/main.c b/examples/device/webusb_serial/src/main.c
index d189af91f..4a724f45e 100644
--- a/examples/device/webusb_serial/src/main.c
+++ b/examples/device/webusb_serial/src/main.c
@@ -97,9 +97,7 @@ int main(void) {
};
tusb_init(BOARD_TUD_RHPORT, &dev_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
diff --git a/examples/dual/host_hid_to_device_cdc/src/main.c b/examples/dual/host_hid_to_device_cdc/src/main.c
index 6f30ca381..8c53588c3 100644
--- a/examples/dual/host_hid_to_device_cdc/src/main.c
+++ b/examples/dual/host_hid_to_device_cdc/src/main.c
@@ -91,9 +91,7 @@ int main(void) {
};
tusb_init(BOARD_TUH_RHPORT, &host_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
diff --git a/examples/dual/host_hid_to_device_cdc/src/usb_descriptors.c b/examples/dual/host_hid_to_device_cdc/src/usb_descriptors.c
index 9d57737fb..b7cffe23d 100644
--- a/examples/dual/host_hid_to_device_cdc/src/usb_descriptors.c
+++ b/examples/dual/host_hid_to_device_cdc/src/usb_descriptors.c
@@ -175,7 +175,7 @@ uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
- // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
+ // Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG
memcpy(desc_other_speed_config,
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration,
CONFIG_TOTAL_LEN);
diff --git a/examples/dual/host_info_to_device_cdc/src/main.c b/examples/dual/host_info_to_device_cdc/src/main.c
index a2a505952..67e905b9d 100644
--- a/examples/dual/host_info_to_device_cdc/src/main.c
+++ b/examples/dual/host_info_to_device_cdc/src/main.c
@@ -113,9 +113,7 @@ int main(void) {
};
tusb_init(BOARD_TUH_RHPORT, &host_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
tud_task(); // tinyusb device task
diff --git a/examples/dual/host_info_to_device_cdc/src/usb_descriptors.c b/examples/dual/host_info_to_device_cdc/src/usb_descriptors.c
index 9d57737fb..b7cffe23d 100644
--- a/examples/dual/host_info_to_device_cdc/src/usb_descriptors.c
+++ b/examples/dual/host_info_to_device_cdc/src/usb_descriptors.c
@@ -175,7 +175,7 @@ uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
- // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
+ // Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG
memcpy(desc_other_speed_config,
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration,
CONFIG_TOTAL_LEN);
diff --git a/examples/host/bare_api/src/main.c b/examples/host/bare_api/src/main.c
index 0c76ff0c9..c693d6b00 100644
--- a/examples/host/bare_api/src/main.c
+++ b/examples/host/bare_api/src/main.c
@@ -67,9 +67,7 @@ int main(void) {
};
tusb_init(BOARD_TUH_RHPORT, &host_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1) {
// tinyusb host task
diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c
index 7b02e238e..e2dd6e5d2 100644
--- a/examples/host/cdc_msc_hid/src/main.c
+++ b/examples/host/cdc_msc_hid/src/main.c
@@ -50,9 +50,7 @@ int main(void) {
};
tusb_init(BOARD_TUH_RHPORT, &host_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
// FeatherWing MAX3421E use MAX3421E's GPIO0 for VBUS enable
diff --git a/examples/host/cdc_msc_hid_freertos/src/main.c b/examples/host/cdc_msc_hid_freertos/src/main.c
index 0bcb355ec..d498c1b57 100644
--- a/examples/host/cdc_msc_hid_freertos/src/main.c
+++ b/examples/host/cdc_msc_hid_freertos/src/main.c
@@ -116,9 +116,7 @@ static void usb_host_task(void *param) {
vTaskSuspend(NULL);
}
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
// FeatherWing MAX3421E use MAX3421E's GPIO0 for VBUS enable
diff --git a/examples/host/device_info/src/main.c b/examples/host/device_info/src/main.c
index 7189972d6..419806551 100644
--- a/examples/host/device_info/src/main.c
+++ b/examples/host/device_info/src/main.c
@@ -89,9 +89,7 @@ static void init_tinyusb(void) {
};
tusb_init(BOARD_TUH_RHPORT, &host_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
}
int main(void) {
diff --git a/examples/host/hid_controller/src/main.c b/examples/host/hid_controller/src/main.c
index ba12774bd..f3244db95 100644
--- a/examples/host/hid_controller/src/main.c
+++ b/examples/host/hid_controller/src/main.c
@@ -58,9 +58,7 @@ int main(void)
};
tusb_init(BOARD_TUH_RHPORT, &host_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
while (1)
{
diff --git a/examples/host/midi_rx/CMakePresets.json b/examples/host/midi_rx/CMakePresets.json
new file mode 100644
index 000000000..5cd8971e9
--- /dev/null
+++ b/examples/host/midi_rx/CMakePresets.json
@@ -0,0 +1,6 @@
+{
+ "version": 6,
+ "include": [
+ "../../../hw/bsp/BoardPresets.json"
+ ]
+}
diff --git a/examples/host/msc_file_explorer/src/main.c b/examples/host/msc_file_explorer/src/main.c
index 8197c3c8d..506c3b015 100644
--- a/examples/host/msc_file_explorer/src/main.c
+++ b/examples/host/msc_file_explorer/src/main.c
@@ -82,9 +82,7 @@ int main(void) {
};
tusb_init(BOARD_TUH_RHPORT, &host_init);
- if (board_init_after_tusb) {
- board_init_after_tusb();
- }
+ board_init_after_tusb();
msc_app_init();
diff --git a/hw/bsp/BoardPresets.json b/hw/bsp/BoardPresets.json
index 24da362da..335546837 100644
--- a/hw/bsp/BoardPresets.json
+++ b/hw/bsp/BoardPresets.json
@@ -13,30 +13,32 @@
}
},
{
- "name": "default single",
- "hidden": true,
- "description": "Configure preset for the ${presetName} board",
- "generator": "Ninja",
- "binaryDir": "${sourceDir}/build/${presetName}",
- "cacheVariables": {
- "BOARD": "${presetName}"
- }
- },
- {
"name": "adafruit_clue",
"inherits": "default"
},
{
"name": "adafruit_feather_esp32_v2",
- "inherits": "default single"
+ "inherits": "default"
+ },
+ {
+ "name": "adafruit_feather_esp32c6",
+ "inherits": "default"
},
{
"name": "adafruit_feather_esp32s2",
- "inherits": "default single"
+ "inherits": "default"
},
{
"name": "adafruit_feather_esp32s3",
- "inherits": "default single"
+ "inherits": "default"
+ },
+ {
+ "name": "adafruit_feather_rp2040_usb_host",
+ "inherits": "default"
+ },
+ {
+ "name": "adafruit_fruit_jam",
+ "inherits": "default"
},
{
"name": "adafruit_magtag_29gray",
@@ -44,7 +46,11 @@
},
{
"name": "adafruit_metro_esp32s2",
- "inherits": "default single"
+ "inherits": "default"
+ },
+ {
+ "name": "adafruit_metro_rp2350",
+ "inherits": "default"
},
{
"name": "apard32690",
@@ -55,6 +61,50 @@
"inherits": "default"
},
{
+ "name": "at32f403a_weact_blackpill",
+ "inherits": "default"
+ },
+ {
+ "name": "at_start_f402",
+ "inherits": "default"
+ },
+ {
+ "name": "at_start_f403a",
+ "inherits": "default"
+ },
+ {
+ "name": "at_start_f405",
+ "inherits": "default"
+ },
+ {
+ "name": "at_start_f407",
+ "inherits": "default"
+ },
+ {
+ "name": "at_start_f413",
+ "inherits": "default"
+ },
+ {
+ "name": "at_start_f415",
+ "inherits": "default"
+ },
+ {
+ "name": "at_start_f423",
+ "inherits": "default"
+ },
+ {
+ "name": "at_start_f425",
+ "inherits": "default"
+ },
+ {
+ "name": "at_start_f435",
+ "inherits": "default"
+ },
+ {
+ "name": "at_start_f437",
+ "inherits": "default"
+ },
+ {
"name": "atsamd21_xpro",
"inherits": "default"
},
@@ -140,39 +190,39 @@
},
{
"name": "espressif_addax_1",
- "inherits": "default single"
+ "inherits": "default"
},
{
"name": "espressif_c3_devkitc",
- "inherits": "default single"
+ "inherits": "default"
},
{
"name": "espressif_c6_devkitc",
- "inherits": "default single"
+ "inherits": "default"
},
{
"name": "espressif_kaluga_1",
- "inherits": "default single"
+ "inherits": "default"
},
{
"name": "espressif_p4_function_ev",
- "inherits": "default single"
+ "inherits": "default"
},
{
"name": "espressif_s2_devkitc",
- "inherits": "default single"
+ "inherits": "default"
},
{
"name": "espressif_s3_devkitc",
- "inherits": "default single"
+ "inherits": "default"
},
{
"name": "espressif_s3_devkitm",
- "inherits": "default single"
+ "inherits": "default"
},
{
"name": "espressif_saola_1",
- "inherits": "default single"
+ "inherits": "default"
},
{
"name": "f1c100s",
@@ -227,6 +277,10 @@
"inherits": "default"
},
{
+ "name": "frdm_mcxa156",
+ "inherits": "default"
+ },
+ {
"name": "frdm_mcxn947",
"inherits": "default"
},
@@ -411,6 +465,10 @@
"inherits": "default"
},
{
+ "name": "nanoch32v305",
+ "inherits": "default"
+ },
+ {
"name": "pca10056",
"inherits": "default"
},
@@ -483,6 +541,10 @@
"inherits": "default"
},
{
+ "name": "raspberry_pi_pico_w",
+ "inherits": "default"
+ },
+ {
"name": "raspberrypi_cm4",
"inherits": "default"
},
@@ -695,6 +757,18 @@
"inherits": "default"
},
{
+ "name": "stm32n6570dk",
+ "inherits": "default"
+ },
+ {
+ "name": "stm32n657nucleo",
+ "inherits": "default"
+ },
+ {
+ "name": "stm32u083cdk",
+ "inherits": "default"
+ },
+ {
"name": "stm32u545nucleo",
"inherits": "default"
},
@@ -715,6 +789,10 @@
"inherits": "default"
},
{
+ "name": "stm32wba_nucleo",
+ "inherits": "default"
+ },
+ {
"name": "teensy_35",
"inherits": "default"
},
@@ -759,6 +837,11 @@
"configurePreset": "adafruit_feather_esp32_v2"
},
{
+ "name": "adafruit_feather_esp32c6",
+ "description": "Build preset for the adafruit_feather_esp32c6 board",
+ "configurePreset": "adafruit_feather_esp32c6"
+ },
+ {
"name": "adafruit_feather_esp32s2",
"description": "Build preset for the adafruit_feather_esp32s2 board",
"configurePreset": "adafruit_feather_esp32s2"
@@ -769,6 +852,16 @@
"configurePreset": "adafruit_feather_esp32s3"
},
{
+ "name": "adafruit_feather_rp2040_usb_host",
+ "description": "Build preset for the adafruit_feather_rp2040_usb_host board",
+ "configurePreset": "adafruit_feather_rp2040_usb_host"
+ },
+ {
+ "name": "adafruit_fruit_jam",
+ "description": "Build preset for the adafruit_fruit_jam board",
+ "configurePreset": "adafruit_fruit_jam"
+ },
+ {
"name": "adafruit_magtag_29gray",
"description": "Build preset for the adafruit_magtag_29gray board",
"configurePreset": "adafruit_magtag_29gray"
@@ -779,6 +872,11 @@
"configurePreset": "adafruit_metro_esp32s2"
},
{
+ "name": "adafruit_metro_rp2350",
+ "description": "Build preset for the adafruit_metro_rp2350 board",
+ "configurePreset": "adafruit_metro_rp2350"
+ },
+ {
"name": "apard32690",
"description": "Build preset for the apard32690 board",
"configurePreset": "apard32690"
@@ -789,6 +887,61 @@
"configurePreset": "arduino_nano33_ble"
},
{
+ "name": "at32f403a_weact_blackpill",
+ "description": "Build preset for the at32f403a_weact_blackpill board",
+ "configurePreset": "at32f403a_weact_blackpill"
+ },
+ {
+ "name": "at_start_f402",
+ "description": "Build preset for the at_start_f402 board",
+ "configurePreset": "at_start_f402"
+ },
+ {
+ "name": "at_start_f403a",
+ "description": "Build preset for the at_start_f403a board",
+ "configurePreset": "at_start_f403a"
+ },
+ {
+ "name": "at_start_f405",
+ "description": "Build preset for the at_start_f405 board",
+ "configurePreset": "at_start_f405"
+ },
+ {
+ "name": "at_start_f407",
+ "description": "Build preset for the at_start_f407 board",
+ "configurePreset": "at_start_f407"
+ },
+ {
+ "name": "at_start_f413",
+ "description": "Build preset for the at_start_f413 board",
+ "configurePreset": "at_start_f413"
+ },
+ {
+ "name": "at_start_f415",
+ "description": "Build preset for the at_start_f415 board",
+ "configurePreset": "at_start_f415"
+ },
+ {
+ "name": "at_start_f423",
+ "description": "Build preset for the at_start_f423 board",
+ "configurePreset": "at_start_f423"
+ },
+ {
+ "name": "at_start_f425",
+ "description": "Build preset for the at_start_f425 board",
+ "configurePreset": "at_start_f425"
+ },
+ {
+ "name": "at_start_f435",
+ "description": "Build preset for the at_start_f435 board",
+ "configurePreset": "at_start_f435"
+ },
+ {
+ "name": "at_start_f437",
+ "description": "Build preset for the at_start_f437 board",
+ "configurePreset": "at_start_f437"
+ },
+ {
"name": "atsamd21_xpro",
"description": "Build preset for the atsamd21_xpro board",
"configurePreset": "atsamd21_xpro"
@@ -1004,6 +1157,11 @@
"configurePreset": "frdm_mcxa153"
},
{
+ "name": "frdm_mcxa156",
+ "description": "Build preset for the frdm_mcxa156 board",
+ "configurePreset": "frdm_mcxa156"
+ },
+ {
"name": "frdm_mcxn947",
"description": "Build preset for the frdm_mcxn947 board",
"configurePreset": "frdm_mcxn947"
@@ -1234,6 +1392,11 @@
"configurePreset": "nanoch32v203"
},
{
+ "name": "nanoch32v305",
+ "description": "Build preset for the nanoch32v305 board",
+ "configurePreset": "nanoch32v305"
+ },
+ {
"name": "pca10056",
"description": "Build preset for the pca10056 board",
"configurePreset": "pca10056"
@@ -1324,6 +1487,11 @@
"configurePreset": "raspberry_pi_pico2"
},
{
+ "name": "raspberry_pi_pico_w",
+ "description": "Build preset for the raspberry_pi_pico_w board",
+ "configurePreset": "raspberry_pi_pico_w"
+ },
+ {
"name": "raspberrypi_cm4",
"description": "Build preset for the raspberrypi_cm4 board",
"configurePreset": "raspberrypi_cm4"
@@ -1589,6 +1757,21 @@
"configurePreset": "stm32l4r5nucleo"
},
{
+ "name": "stm32n6570dk",
+ "description": "Build preset for the stm32n6570dk board",
+ "configurePreset": "stm32n6570dk"
+ },
+ {
+ "name": "stm32n657nucleo",
+ "description": "Build preset for the stm32n657nucleo board",
+ "configurePreset": "stm32n657nucleo"
+ },
+ {
+ "name": "stm32u083cdk",
+ "description": "Build preset for the stm32u083cdk board",
+ "configurePreset": "stm32u083cdk"
+ },
+ {
"name": "stm32u545nucleo",
"description": "Build preset for the stm32u545nucleo board",
"configurePreset": "stm32u545nucleo"
@@ -1614,6 +1797,11 @@
"configurePreset": "stm32wb55nucleo"
},
{
+ "name": "stm32wba_nucleo",
+ "description": "Build preset for the stm32wba_nucleo board",
+ "configurePreset": "stm32wba_nucleo"
+ },
+ {
"name": "teensy_35",
"description": "Build preset for the teensy_35 board",
"configurePreset": "teensy_35"
@@ -1682,6 +1870,19 @@
]
},
{
+ "name": "adafruit_feather_esp32c6",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "adafruit_feather_esp32c6"
+ },
+ {
+ "type": "build",
+ "name": "adafruit_feather_esp32c6"
+ }
+ ]
+ },
+ {
"name": "adafruit_feather_esp32s2",
"steps": [
{
@@ -1708,6 +1909,32 @@
]
},
{
+ "name": "adafruit_feather_rp2040_usb_host",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "adafruit_feather_rp2040_usb_host"
+ },
+ {
+ "type": "build",
+ "name": "adafruit_feather_rp2040_usb_host"
+ }
+ ]
+ },
+ {
+ "name": "adafruit_fruit_jam",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "adafruit_fruit_jam"
+ },
+ {
+ "type": "build",
+ "name": "adafruit_fruit_jam"
+ }
+ ]
+ },
+ {
"name": "adafruit_magtag_29gray",
"steps": [
{
@@ -1734,6 +1961,19 @@
]
},
{
+ "name": "adafruit_metro_rp2350",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "adafruit_metro_rp2350"
+ },
+ {
+ "type": "build",
+ "name": "adafruit_metro_rp2350"
+ }
+ ]
+ },
+ {
"name": "apard32690",
"steps": [
{
@@ -1760,6 +2000,149 @@
]
},
{
+ "name": "at32f403a_weact_blackpill",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "at32f403a_weact_blackpill"
+ },
+ {
+ "type": "build",
+ "name": "at32f403a_weact_blackpill"
+ }
+ ]
+ },
+ {
+ "name": "at_start_f402",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "at_start_f402"
+ },
+ {
+ "type": "build",
+ "name": "at_start_f402"
+ }
+ ]
+ },
+ {
+ "name": "at_start_f403a",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "at_start_f403a"
+ },
+ {
+ "type": "build",
+ "name": "at_start_f403a"
+ }
+ ]
+ },
+ {
+ "name": "at_start_f405",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "at_start_f405"
+ },
+ {
+ "type": "build",
+ "name": "at_start_f405"
+ }
+ ]
+ },
+ {
+ "name": "at_start_f407",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "at_start_f407"
+ },
+ {
+ "type": "build",
+ "name": "at_start_f407"
+ }
+ ]
+ },
+ {
+ "name": "at_start_f413",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "at_start_f413"
+ },
+ {
+ "type": "build",
+ "name": "at_start_f413"
+ }
+ ]
+ },
+ {
+ "name": "at_start_f415",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "at_start_f415"
+ },
+ {
+ "type": "build",
+ "name": "at_start_f415"
+ }
+ ]
+ },
+ {
+ "name": "at_start_f423",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "at_start_f423"
+ },
+ {
+ "type": "build",
+ "name": "at_start_f423"
+ }
+ ]
+ },
+ {
+ "name": "at_start_f425",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "at_start_f425"
+ },
+ {
+ "type": "build",
+ "name": "at_start_f425"
+ }
+ ]
+ },
+ {
+ "name": "at_start_f435",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "at_start_f435"
+ },
+ {
+ "type": "build",
+ "name": "at_start_f435"
+ }
+ ]
+ },
+ {
+ "name": "at_start_f437",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "at_start_f437"
+ },
+ {
+ "type": "build",
+ "name": "at_start_f437"
+ }
+ ]
+ },
+ {
"name": "atsamd21_xpro",
"steps": [
{
@@ -2319,6 +2702,19 @@
]
},
{
+ "name": "frdm_mcxa156",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "frdm_mcxa156"
+ },
+ {
+ "type": "build",
+ "name": "frdm_mcxa156"
+ }
+ ]
+ },
+ {
"name": "frdm_mcxn947",
"steps": [
{
@@ -2917,6 +3313,19 @@
]
},
{
+ "name": "nanoch32v305",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "nanoch32v305"
+ },
+ {
+ "type": "build",
+ "name": "nanoch32v305"
+ }
+ ]
+ },
+ {
"name": "pca10056",
"steps": [
{
@@ -3151,6 +3560,19 @@
]
},
{
+ "name": "raspberry_pi_pico_w",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "raspberry_pi_pico_w"
+ },
+ {
+ "type": "build",
+ "name": "raspberry_pi_pico_w"
+ }
+ ]
+ },
+ {
"name": "raspberrypi_cm4",
"steps": [
{
@@ -3840,6 +4262,45 @@
]
},
{
+ "name": "stm32n6570dk",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "stm32n6570dk"
+ },
+ {
+ "type": "build",
+ "name": "stm32n6570dk"
+ }
+ ]
+ },
+ {
+ "name": "stm32n657nucleo",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "stm32n657nucleo"
+ },
+ {
+ "type": "build",
+ "name": "stm32n657nucleo"
+ }
+ ]
+ },
+ {
+ "name": "stm32u083cdk",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "stm32u083cdk"
+ },
+ {
+ "type": "build",
+ "name": "stm32u083cdk"
+ }
+ ]
+ },
+ {
"name": "stm32u545nucleo",
"steps": [
{
@@ -3905,6 +4366,19 @@
]
},
{
+ "name": "stm32wba_nucleo",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "stm32wba_nucleo"
+ },
+ {
+ "type": "build",
+ "name": "stm32wba_nucleo"
+ }
+ ]
+ },
+ {
"name": "teensy_35",
"steps": [
{
diff --git a/hw/bsp/at32f402_405/boards/at_start_f402/board.cmake b/hw/bsp/at32f402_405/boards/at_start_f402/board.cmake
new file mode 100644
index 000000000..4e7755c0f
--- /dev/null
+++ b/hw/bsp/at32f402_405/boards/at_start_f402/board.cmake
@@ -0,0 +1,8 @@
+set(MCU_VARIANT AT32F402RCT7)
+set(MCU_LINKER_NAME AT32F402xC)
+
+set(JLINK_DEVICE ${MCU_VARIANT})
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC ${MCU_VARIANT})
+endfunction()
diff --git a/hw/bsp/at32f402_405/boards/at_start_f402/board.h b/hw/bsp/at32f402_405/boards/at_start_f402/board.h
new file mode 100644
index 000000000..01b78f101
--- /dev/null
+++ b/hw/bsp/at32f402_405/boards/at_start_f402/board.h
@@ -0,0 +1,74 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ name: AT-START-F402
+ url: https://www.arterychip.com/en/product/AT32F402.jsp
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define USB_VBUS_IGNORE
+//#define USB_SOF_OUTPUT_ENABLE
+
+// LED
+#define LED_PORT GPIOF
+#define LED_PIN GPIO_PINS_4
+#define LED_STATE_ON 0 // Active Low
+#define LED_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOF_PERIPH_CLOCK, TRUE)
+
+// Button
+#define BUTTON_PORT GPIOA
+#define BUTTON_PIN GPIO_PINS_0
+#define BUTTON_STATE_ACTIVE 1
+#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
+
+//USART
+#define PRINT_UART USART1
+#define PRINT_UART_CRM_CLK CRM_USART1_PERIPH_CLOCK
+#define PRINT_UART_TX_PIN GPIO_PINS_9
+#define PRINT_UART_TX_GPIO GPIOA
+#define PRINT_UART_TX_GPIO_CRM_CLK CRM_GPIOA_PERIPH_CLOCK
+#define PRINT_UART_TX_PIN_SOURCE GPIO_PINS_SOURCE9
+#define PRINT_UART_TX_PIN_MUX_NUM GPIO_MUX_7
+
+//Vbus
+static inline void board_vbus_sense_init(void)
+{
+ *(int*)(0x50000038) |= (1<<21);
+ *(int*)(0x40040038) |= (1<<21);
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* BOARD_H_ */
diff --git a/hw/bsp/at32f402_405/boards/at_start_f402/board.mk b/hw/bsp/at32f402_405/boards/at_start_f402/board.mk
new file mode 100644
index 000000000..f1082247b
--- /dev/null
+++ b/hw/bsp/at32f402_405/boards/at_start_f402/board.mk
@@ -0,0 +1,7 @@
+MCU_VARIANT = AT32F402RCT7
+MCU_LINKER_NAME = AT32F402xC
+
+JLINK_DEVICE = ${MCU_VARIANT}
+
+CFLAGS += \
+ -D${MCU_VARIANT}
diff --git a/hw/bsp/at32f402_405/boards/at_start_f405/board.cmake b/hw/bsp/at32f402_405/boards/at_start_f405/board.cmake
index 0d09680a1..39c5cd905 100644
--- a/hw/bsp/at32f402_405/boards/at_start_f405/board.cmake
+++ b/hw/bsp/at32f402_405/boards/at_start_f405/board.cmake
@@ -3,6 +3,15 @@ set(MCU_LINKER_NAME AT32F405xC)
set(JLINK_DEVICE ${MCU_VARIANT})
+set(RHPORT_SPEED OPT_MODE_FULL_SPEED OPT_MODE_HIGH_SPEED)
+
+if (NOT DEFINED RHPORT_DEVICE)
+ set(RHPORT_DEVICE 1)
+endif()
+if (NOT DEFINED RHPORT_HOST)
+ set(RHPORT_HOST 0)
+endif()
+
function(update_board TARGET)
target_compile_definitions(${TARGET} PUBLIC ${MCU_VARIANT})
endfunction()
diff --git a/hw/bsp/at32f402_405/boards/at_start_f405/board.h b/hw/bsp/at32f402_405/boards/at_start_f405/board.h
index 2d6cc3e57..b11b7a80f 100644
--- a/hw/bsp/at32f402_405/boards/at_start_f405/board.h
+++ b/hw/bsp/at32f402_405/boards/at_start_f405/board.h
@@ -48,7 +48,7 @@
// Button
#define BUTTON_PORT GPIOA
#define BUTTON_PIN GPIO_PINS_0
-#define BUTTON_STATE_ACTIVE 0
+#define BUTTON_STATE_ACTIVE 1
#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
//USART
@@ -60,111 +60,11 @@
#define PRINT_UART_TX_PIN_SOURCE GPIO_PINS_SOURCE9
#define PRINT_UART_TX_PIN_MUX_NUM GPIO_MUX_7
-//USB
-#ifdef BOARD_TUD_RHPORT
- #if BOARD_TUD_RHPORT == 0
- #define USB_ID USB_OTG1_ID
- #define OTG_CLOCK CRM_OTGFS1_PERIPH_CLOCK
- #define OTG_IRQ OTGFS1_IRQn
- #define OTG_IRQ_HANDLER OTGFS1_IRQHandler
- #define OTG_WKUP_IRQ OTGFS1_WKUP_IRQn
- #define OTG_WKUP_HANDLER OTGFS1_WKUP_IRQHandler
- #define OTG_WKUP_EXINT_LINE EXINT_LINE_18
- #define OTG_PIN_GPIO GPIOA
- #define OTG_PIN_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
- #define OTG_PIN_VBUS GPIO_PINS_9
- #define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE9
- #define OTG_PIN_ID GPIO_PINS_10
- #define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE10
- #define OTG_PIN_SOF_GPIO GPIOA
- #define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
- #define OTG_PIN_SOF GPIO_PINS_8
- #define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE8
- #define OTG_PIN_MUX GPIO_MUX_10
- #define USB_SPEED_CORE_ID USB_FULL_SPEED_CORE_ID
- #elif BOARD_TUD_RHPORT == 1
- #define USB_ID USB_OTG2_ID
- #define OTG_CLOCK CRM_OTGHS_PERIPH_CLOCK
- #define OTG_IRQ OTGHS_IRQn
- #define OTG_IRQ_HANDLER OTGHS_IRQHandler
- #define OTG_WKUP_IRQ OTGHS_WKUP_IRQn
- #define OTG_WKUP_HANDLER OTGHS_WKUP_IRQHandler
- #define OTG_WKUP_EXINT_LINE EXINT_LINE_20
- #define OTG_PIN_GPIO GPIOB
- #define OTG_PIN_GPIO_CLOCK CRM_GPIOB_PERIPH_CLOCK
- #define OTG_PIN_VBUS GPIO_PINS_13
- #define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE13
- #define OTG_PIN_ID GPIO_PINS_12
- #define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE12
- #define OTG_PIN_SOF_GPIO GPIOA
- #define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
- #define OTG_PIN_SOF GPIO_PINS_4
- #define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE4
- #define OTG_PIN_MUX GPIO_MUX_10
- #define USB_SPEED_CORE_ID USB_HIGH_SPEED_CORE_ID
- #endif
-#endif
-#ifdef BOARD_TUH_RHPORT
- #if BOARD_TUH_RHPORT == 0
- #define USB_ID USB_OTG1_ID
- #define OTG_CLOCK CRM_OTGFS1_PERIPH_CLOCK
- #define OTG_IRQ OTGFS1_IRQn
- #define OTG_IRQ_HANDLER OTGFS1_IRQHandler
- #define OTG_WKUP_IRQ OTGFS1_WKUP_IRQn
- #define OTG_WKUP_HANDLER OTGFS1_WKUP_IRQHandler
- #define OTG_WKUP_EXINT_LINE EXINT_LINE_18
- #define OTG_PIN_GPIO GPIOA
- #define OTG_PIN_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
- #define OTG_PIN_VBUS GPIO_PINS_9
- #define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE9
- #define OTG_PIN_ID GPIO_PINS_10
- #define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE10
- #define OTG_PIN_SOF_GPIO GPIOA
- #define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
- #define OTG_PIN_SOF GPIO_PINS_8
- #define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE8
- #define OTG_PIN_MUX GPIO_MUX_10
- #define USB_SPEED_CORE_ID USB_FULL_SPEED_CORE_ID
- #elif BOARD_TUH_RHPORT == 1
- #define USB_ID USB_OTG2_ID
- #define OTG_CLOCK CRM_OTGHS_PERIPH_CLOCK
- #define OTG_IRQ OTGHS_IRQn
- #define OTG_IRQ_HANDLER OTGHS_IRQHandler
- #define OTG_WKUP_IRQ OTGHS_WKUP_IRQn
- #define OTG_WKUP_HANDLER OTGHS_WKUP_IRQHandler
- #define OTG_WKUP_EXINT_LINE EXINT_LINE_20
- #define OTG_PIN_GPIO GPIOB
- #define OTG_PIN_GPIO_CLOCK CRM_GPIOB_PERIPH_CLOCK
- #define OTG_PIN_VBUS GPIO_PINS_13
- #define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE13
- #define OTG_PIN_ID GPIO_PINS_12
- #define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE12
- #define OTG_PIN_SOF_GPIO GPIOA
- #define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
- #define OTG_PIN_SOF GPIO_PINS_4
- #define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE4
- #define OTG_PIN_MUX GPIO_MUX_10
- #define USB_SPEED_CORE_ID USB_HIGH_SPEED_CORE_ID
- #endif
-#endif
-
//Vbus
static inline void board_vbus_sense_init(void)
{
- #ifdef BOARD_TUD_RHPORT
- #if BOARD_TUD_RHPORT == 0
- *(int*)(0x50000038) |= (1<<21);
- #elif BOARD_TUD_RHPORT == 1
- *(int*)(0x40040038) |= (1<<21);
- #endif
- #endif
- #ifdef BOARD_TUH_RHPORT
- #if BOARD_TUH_RHPORT == 0
- *(int*)(0x50000038) |= (1<<21);
- #elif BOARD_TUH_RHPORT == 1
- *(int*)(0x40040038) |= (1<<21);
- #endif
- #endif
+ *(int*)(0x50000038) |= (1<<21);
+ *(int*)(0x40040038) |= (1<<21);
}
#ifdef __cplusplus
diff --git a/hw/bsp/at32f402_405/boards/at_start_f405/board.mk b/hw/bsp/at32f402_405/boards/at_start_f405/board.mk
index 25a719ccf..b4d55ca8f 100644
--- a/hw/bsp/at32f402_405/boards/at_start_f405/board.mk
+++ b/hw/bsp/at32f402_405/boards/at_start_f405/board.mk
@@ -3,5 +3,9 @@ MCU_LINKER_NAME = AT32F405xC
JLINK_DEVICE = ${MCU_VARIANT}
+RHPORT_SPEED = OPT_MODE_FULL_SPEED OPT_MODE_HIGH_SPEED
+RHPORT_DEVICE ?= 1
+RHPORT_HOST ?= 0
+
CFLAGS += \
-D${MCU_VARIANT}
diff --git a/hw/bsp/at32f402_405/family.c b/hw/bsp/at32f402_405/family.c
index 7d94f2564..cb5987cd4 100644
--- a/hw/bsp/at32f402_405/family.c
+++ b/hw/bsp/at32f402_405/family.c
@@ -66,10 +66,11 @@ void board_init(void)
system_clock_config();
/* config usb io*/
- usb_gpio_config();
+ //usb_gpio_config();
/* enable usb clock */
- crm_periph_clock_enable(OTG_CLOCK, TRUE);
+ crm_periph_clock_enable(CRM_OTGFS1_PERIPH_CLOCK, TRUE);
+ crm_periph_clock_enable(CRM_OTGHS_PERIPH_CLOCK, TRUE);
/* select usb 48m clcok source */
usb_clock48m_select(USB_CLK_HEXT);
@@ -82,9 +83,11 @@ void board_init(void)
#if CFG_TUSB_OS == OPT_OS_FREERTOS
// If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
- NVIC_SetPriority(OTG_IRQ, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
+ NVIC_SetPriority(OTGHS_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
+ NVIC_SetPriority(OTGFS1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
#else
- NVIC_SetPriority(OTG_IRQ, 0);
+ NVIC_SetPriority(OTGHS_IRQn, 0);
+ NVIC_SetPriority(OTGFS1_IRQn, 0);
#endif
/* config led and key */
@@ -160,26 +163,11 @@ void usb_clock48m_select(usb_clk48_s clk_s)
void usb_gpio_config(void)
{
- gpio_init_type gpio_init_struct;
- crm_periph_clock_enable(OTG_PIN_GPIO_CLOCK, TRUE);
- gpio_default_para_init(&gpio_init_struct);
- gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
- gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
- gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
- gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
- #ifdef USB_SOF_OUTPUT_ENABLE
- crm_periph_clock_enable(OTG_PIN_SOF_GPIO_CLOCK, TRUE);
- gpio_init_struct.gpio_pins = OTG_PIN_SOF;
- gpio_init(OTG_PIN_SOF_GPIO, &gpio_init_struct);
- gpio_pin_mux_config(OTG_PIN_SOF_GPIO, OTG_PIN_SOF_SOURCE, OTG_PIN_MUX);
- #endif
- /* otgfs use vbus pin */
- #ifndef USB_VBUS_IGNORE
- gpio_init_struct.gpio_pins = OTG_PIN_VBUS;
- gpio_init_struct.gpio_pull = GPIO_PULL_DOWN;
- gpio_pin_mux_config(OTG_PIN_GPIO, OTG_PIN_VBUS_SOURCE, OTG_PIN_MUX);
- gpio_init(OTG_PIN_GPIO, &gpio_init_struct);
- #endif
+ /* When the USB clock is enabled, the hardware will automatically
+ configure the pins; but other special pins that need to be used,
+ such as the pins used to detect VBUS or the pins that output the
+ SOF signal, still need to be configured separately, and these pins
+ are usually not required */
}
/**
diff --git a/hw/bsp/at32f402_405/family.cmake b/hw/bsp/at32f402_405/family.cmake
index 010e36b88..b10760cef 100644
--- a/hw/bsp/at32f402_405/family.cmake
+++ b/hw/bsp/at32f402_405/family.cmake
@@ -14,6 +14,23 @@ set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOL
set(FAMILY_MCUS ${AT32_FAMILY_UPPER} CACHE INTERNAL "")
+if (NOT DEFINED RHPORT_DEVICE)
+ set(RHPORT_DEVICE 0)
+endif ()
+if (NOT DEFINED RHPORT_HOST)
+ set(RHPORT_HOST 0)
+endif ()
+
+if (NOT DEFINED RHPORT_SPEED)
+ set(RHPORT_SPEED OPT_MODE_FULL_SPEED OPT_MODE_FULL_SPEED)
+endif ()
+if (NOT DEFINED RHPORT_DEVICE_SPEED)
+ list(GET RHPORT_SPEED ${RHPORT_DEVICE} RHPORT_DEVICE_SPEED)
+endif ()
+if (NOT DEFINED RHPORT_HOST_SPEED)
+ list(GET RHPORT_SPEED ${RHPORT_HOST} RHPORT_HOST_SPEED)
+endif ()
+
#------------------------------------
# BOARD_TARGET
#------------------------------------
@@ -50,8 +67,10 @@ function(add_board_target BOARD_TARGET)
${AT32_SDK_LIB}/drivers/inc
)
target_compile_definitions(${BOARD_TARGET} PUBLIC
- BOARD_TUD_RHPORT=0
- BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
+ BOARD_TUD_RHPORT=${RHPORT_DEVICE}
+ BOARD_TUD_MAX_SPEED=${RHPORT_DEVICE_SPEED}
+ BOARD_TUH_RHPORT=${RHPORT_HOST}
+ BOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED}
)
update_board(${BOARD_TARGET})
diff --git a/hw/bsp/at32f402_405/family.mk b/hw/bsp/at32f402_405/family.mk
index 60a0f93e9..09b2f1139 100644
--- a/hw/bsp/at32f402_405/family.mk
+++ b/hw/bsp/at32f402_405/family.mk
@@ -8,10 +8,32 @@ CPU_CORE ?= cortex-m4
CFLAGS_GCC += \
-flto
+RHPORT_SPEED ?= OPT_MODE_FULL_SPEED OPT_MODE_FULL_SPEED
+RHPORT_DEVICE ?= 0
+RHPORT_HOST ?= 0
+
+ifndef RHPORT_DEVICE_SPEED
+ifeq ($(RHPORT_DEVICE), 0)
+ RHPORT_DEVICE_SPEED = $(firstword $(RHPORT_SPEED))
+else
+ RHPORT_DEVICE_SPEED = $(lastword $(RHPORT_SPEED))
+endif
+endif
+
+ifndef RHPORT_HOST_SPEED
+ifeq ($(RHPORT_HOST), 0)
+ RHPORT_HOST_SPEED = $(firstword $(RHPORT_SPEED))
+else
+ RHPORT_HOST_SPEED = $(lastword $(RHPORT_SPEED))
+endif
+endif
+
CFLAGS += \
- -DCFG_TUSB_MCU=OPT_MCU_AT32F402_405 \
- -DBOARD_TUD_RHPORT=0 \
- -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
+ -DCFG_TUSB_MCU=OPT_MCU_AT32F402_405 \
+ -DBOARD_TUD_RHPORT=${RHPORT_DEVICE} \
+ -DBOARD_TUD_MAX_SPEED=${RHPORT_DEVICE_SPEED} \
+ -DBOARD_TUH_RHPORT=${RHPORT_HOST} \
+ -DBOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED} \
LDFLAGS_GCC += \
-flto --specs=nosys.specs -nostdlib -nostartfiles
diff --git a/hw/bsp/at32f403a_407/boards/at32f403a_weact_blackpill/board.cmake b/hw/bsp/at32f403a_407/boards/at32f403a_weact_blackpill/board.cmake
new file mode 100644
index 000000000..25c9558f9
--- /dev/null
+++ b/hw/bsp/at32f403a_407/boards/at32f403a_weact_blackpill/board.cmake
@@ -0,0 +1,8 @@
+set(MCU_VARIANT AT32F403ACGU7)
+set(MCU_LINKER_NAME AT32F403AxG)
+
+set(JLINK_DEVICE ${MCU_VARIANT})
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC ${MCU_VARIANT})
+endfunction()
diff --git a/hw/bsp/at32f403a_407/boards/at32f403a_weact_blackpill/board.h b/hw/bsp/at32f403a_407/boards/at32f403a_weact_blackpill/board.h
new file mode 100644
index 000000000..2dac9bc56
--- /dev/null
+++ b/hw/bsp/at32f403a_407/boards/at32f403a_weact_blackpill/board.h
@@ -0,0 +1,67 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ name: WeAct BlackPill AT32F403ACGU7
+ url: https://github.com/WeActStudio/WeActStudio.BlackPill
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// LED
+#define LED_PORT GPIOC
+#define LED_PIN GPIO_PINS_13
+#define LED_STATE_ON 0 // Active Low
+#define LED_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE)
+
+// Button
+#define BUTTON_PORT GPIOA
+#define BUTTON_PIN GPIO_PINS_0
+#define BUTTON_PULL GPIO_PULL_UP
+#define BUTTON_STATE_ACTIVE 0
+#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
+
+// UART
+#define PRINT_UART USART1
+#define PRINT_UART_CRM_CLK CRM_USART1_PERIPH_CLOCK
+#define PRINT_UART_TX_PIN GPIO_PINS_9
+#define PRINT_UART_TX_GPIO GPIOA
+#define PRINT_UART_TX_GPIO_CRM_CLK CRM_GPIOA_PERIPH_CLOCK
+
+static inline void board_vbus_sense_init(void)
+{
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* BOARD_H_ */
diff --git a/hw/bsp/at32f403a_407/boards/at32f403a_weact_blackpill/board.mk b/hw/bsp/at32f403a_407/boards/at32f403a_weact_blackpill/board.mk
new file mode 100644
index 000000000..9bb6843aa
--- /dev/null
+++ b/hw/bsp/at32f403a_407/boards/at32f403a_weact_blackpill/board.mk
@@ -0,0 +1,7 @@
+MCU_VARIANT = AT32F403ACGU7
+MCU_LINKER_NAME = AT32F403AxG
+
+JLINK_DEVICE = ${MCU_VARIANT}
+
+CFLAGS += \
+ -D${MCU_VARIANT}
diff --git a/hw/bsp/at32f403a_407/boards/at_start_f403a/board.cmake b/hw/bsp/at32f403a_407/boards/at_start_f403a/board.cmake
index 25c9558f9..ce26fd244 100644
--- a/hw/bsp/at32f403a_407/boards/at_start_f403a/board.cmake
+++ b/hw/bsp/at32f403a_407/boards/at_start_f403a/board.cmake
@@ -1,4 +1,4 @@
-set(MCU_VARIANT AT32F403ACGU7)
+set(MCU_VARIANT AT32F403AVGT7)
set(MCU_LINKER_NAME AT32F403AxG)
set(JLINK_DEVICE ${MCU_VARIANT})
diff --git a/hw/bsp/at32f403a_407/boards/at_start_f403a/board.h b/hw/bsp/at32f403a_407/boards/at_start_f403a/board.h
index 472901cfe..758ab5e5c 100644
--- a/hw/bsp/at32f403a_407/boards/at_start_f403a/board.h
+++ b/hw/bsp/at32f403a_407/boards/at_start_f403a/board.h
@@ -50,7 +50,8 @@
// Button
#define BUTTON_PORT GPIOA
#define BUTTON_PIN GPIO_PINS_0
-#define BUTTON_STATE_ACTIVE 0
+#define BUTTON_PULL GPIO_PULL_DOWN
+#define BUTTON_STATE_ACTIVE 1
#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
// UART
diff --git a/hw/bsp/at32f403a_407/boards/at_start_f403a/board.mk b/hw/bsp/at32f403a_407/boards/at_start_f403a/board.mk
index 9bb6843aa..d9f360360 100644
--- a/hw/bsp/at32f403a_407/boards/at_start_f403a/board.mk
+++ b/hw/bsp/at32f403a_407/boards/at_start_f403a/board.mk
@@ -1,4 +1,4 @@
-MCU_VARIANT = AT32F403ACGU7
+MCU_VARIANT = AT32F403AVGT7
MCU_LINKER_NAME = AT32F403AxG
JLINK_DEVICE = ${MCU_VARIANT}
diff --git a/hw/bsp/at32f403a_407/boards/at_start_f407/board.cmake b/hw/bsp/at32f403a_407/boards/at_start_f407/board.cmake
new file mode 100644
index 000000000..f76c46f21
--- /dev/null
+++ b/hw/bsp/at32f403a_407/boards/at_start_f407/board.cmake
@@ -0,0 +1,8 @@
+set(MCU_VARIANT AT32F407VGT7)
+set(MCU_LINKER_NAME AT32F407xG)
+
+set(JLINK_DEVICE ${MCU_VARIANT})
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC ${MCU_VARIANT})
+endfunction()
diff --git a/hw/bsp/at32f403a_407/boards/at_start_f407/board.h b/hw/bsp/at32f403a_407/boards/at_start_f407/board.h
new file mode 100644
index 000000000..c490d7ed6
--- /dev/null
+++ b/hw/bsp/at32f403a_407/boards/at_start_f407/board.h
@@ -0,0 +1,71 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ name: AT-START-F407
+ url: https://www.arterychip.com/en/product/AT32F407.jsp
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// LED
+#define LED_PORT GPIOD
+#define LED_PIN GPIO_PINS_13
+#define LED_STATE_ON 0 // Active Low
+#define LED_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE)
+
+// #define LED_PORT GPIOA
+// #define LED_PIN GPIO_PINS_1
+// #define LED_STATE_ON 0 // Active Low
+// #define LED_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
+
+// Button
+#define BUTTON_PORT GPIOA
+#define BUTTON_PIN GPIO_PINS_0
+#define BUTTON_STATE_ACTIVE 1
+#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
+
+// UART
+#define PRINT_UART USART1
+#define PRINT_UART_CRM_CLK CRM_USART1_PERIPH_CLOCK
+#define PRINT_UART_TX_PIN GPIO_PINS_9
+#define PRINT_UART_TX_GPIO GPIOA
+#define PRINT_UART_TX_GPIO_CRM_CLK CRM_GPIOA_PERIPH_CLOCK
+
+static inline void board_vbus_sense_init(void)
+{
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* BOARD_H_ */
diff --git a/hw/bsp/at32f403a_407/boards/at_start_f407/board.mk b/hw/bsp/at32f403a_407/boards/at_start_f407/board.mk
new file mode 100644
index 000000000..714cbaec2
--- /dev/null
+++ b/hw/bsp/at32f403a_407/boards/at_start_f407/board.mk
@@ -0,0 +1,7 @@
+MCU_VARIANT = AT32F407VGT7
+MCU_LINKER_NAME = AT32F407xG
+
+JLINK_DEVICE = ${MCU_VARIANT}
+
+CFLAGS += \
+ -D${MCU_VARIANT}
diff --git a/hw/bsp/at32f403a_407/family.c b/hw/bsp/at32f403a_407/family.c
index b05a0435f..8c8329323 100644
--- a/hw/bsp/at32f403a_407/family.c
+++ b/hw/bsp/at32f403a_407/family.c
@@ -29,8 +29,8 @@
*/
#include "at32f403a_407_clock.h"
-#include "board.h"
#include "bsp/board_api.h"
+#include "board.h"
void usb_clock48m_select(usb_clk48_s clk_s);
void uart_print_init(uint32_t baudrate);
@@ -198,7 +198,7 @@ void board_led_write(bool state) {
}
uint32_t board_button_read(void) {
- return gpio_input_data_bit_read(BUTTON_PORT, BUTTON_PIN);
+ return gpio_input_data_bit_read(BUTTON_PORT, BUTTON_PIN) == BUTTON_STATE_ACTIVE;
}
size_t board_get_unique_id(uint8_t id[], size_t max_len) {
diff --git a/hw/bsp/at32f413/boards/at_start_f413/board.h b/hw/bsp/at32f413/boards/at_start_f413/board.h
index 4b386a2f4..290400658 100644
--- a/hw/bsp/at32f413/boards/at_start_f413/board.h
+++ b/hw/bsp/at32f413/boards/at_start_f413/board.h
@@ -45,7 +45,7 @@
// Button
#define BUTTON_PORT GPIOA
#define BUTTON_PIN GPIO_PINS_0
-#define BUTTON_STATE_ACTIVE 0
+#define BUTTON_STATE_ACTIVE 1
#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
// UART
diff --git a/hw/bsp/at32f415/boards/at_start_f415/board.h b/hw/bsp/at32f415/boards/at_start_f415/board.h
index 0464d383e..b3c2c1aea 100644
--- a/hw/bsp/at32f415/boards/at_start_f415/board.h
+++ b/hw/bsp/at32f415/boards/at_start_f415/board.h
@@ -47,7 +47,7 @@
// Button
#define BUTTON_PORT GPIOA
#define BUTTON_PIN GPIO_PINS_0
-#define BUTTON_STATE_ACTIVE 0
+#define BUTTON_STATE_ACTIVE 1
#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
// Usart
diff --git a/hw/bsp/at32f423/boards/at_start_f423/board.h b/hw/bsp/at32f423/boards/at_start_f423/board.h
index ef85b4977..24def1ee7 100644
--- a/hw/bsp/at32f423/boards/at_start_f423/board.h
+++ b/hw/bsp/at32f423/boards/at_start_f423/board.h
@@ -47,7 +47,7 @@
// Button
#define BUTTON_PORT GPIOA
#define BUTTON_PIN GPIO_PINS_0
-#define BUTTON_STATE_ACTIVE 0
+#define BUTTON_STATE_ACTIVE 1
#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
// UART
diff --git a/hw/bsp/at32f425/boards/at_start_f425/board.h b/hw/bsp/at32f425/boards/at_start_f425/board.h
index 145eab3b9..2a4d98237 100644
--- a/hw/bsp/at32f425/boards/at_start_f425/board.h
+++ b/hw/bsp/at32f425/boards/at_start_f425/board.h
@@ -47,7 +47,7 @@
// Button
#define BUTTON_PORT GPIOA
#define BUTTON_PIN GPIO_PINS_0
-#define BUTTON_STATE_ACTIVE 0
+#define BUTTON_STATE_ACTIVE 1
#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
// Usart
diff --git a/hw/bsp/at32f435_437/boards/at_start_f435/board.cmake b/hw/bsp/at32f435_437/boards/at_start_f435/board.cmake
new file mode 100644
index 000000000..6d9024f4f
--- /dev/null
+++ b/hw/bsp/at32f435_437/boards/at_start_f435/board.cmake
@@ -0,0 +1,8 @@
+set(MCU_VARIANT AT32F435ZMT7)
+set(MCU_LINKER_NAME AT32F435xM)
+
+set(JLINK_DEVICE ${MCU_VARIANT})
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC ${MCU_VARIANT})
+endfunction()
diff --git a/hw/bsp/at32f435_437/boards/at_start_f435/board.h b/hw/bsp/at32f435_437/boards/at_start_f435/board.h
new file mode 100644
index 000000000..25fd81450
--- /dev/null
+++ b/hw/bsp/at32f435_437/boards/at_start_f435/board.h
@@ -0,0 +1,74 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ name: AT-START-F435
+ url: https://www.arterychip.com/en/product/AT32F435.jsp
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//#define USB_VBUS_IGNORE
+//#define USB_SOF_OUTPUT_ENABLE
+
+// LED
+#define LED_PORT GPIOD
+#define LED_PIN GPIO_PINS_13
+#define LED_STATE_ON 0 // Active Low
+#define LED_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE)
+
+// Button
+#define BUTTON_PORT GPIOA
+#define BUTTON_PIN GPIO_PINS_0
+#define BUTTON_STATE_ACTIVE 1
+#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
+
+// USART
+#define PRINT_UART USART1
+#define PRINT_UART_CRM_CLK CRM_USART1_PERIPH_CLOCK
+#define PRINT_UART_TX_PIN GPIO_PINS_9
+#define PRINT_UART_TX_GPIO GPIOA
+#define PRINT_UART_TX_GPIO_CRM_CLK CRM_GPIOA_PERIPH_CLOCK
+#define PRINT_UART_TX_PIN_SOURCE GPIO_PINS_SOURCE9
+#define PRINT_UART_TX_PIN_MUX_NUM GPIO_MUX_7
+
+// VBUS
+static inline void board_vbus_sense_init(void)
+{
+ *(int*)(0x50000038) |= (1<<21);
+ *(int*)(0x40040038) |= (1<<21);
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* BOARD_H_ */
diff --git a/hw/bsp/at32f435_437/boards/at_start_f435/board.mk b/hw/bsp/at32f435_437/boards/at_start_f435/board.mk
new file mode 100644
index 000000000..5fe56ce77
--- /dev/null
+++ b/hw/bsp/at32f435_437/boards/at_start_f435/board.mk
@@ -0,0 +1,7 @@
+MCU_VARIANT = AT32F435ZMT7
+MCU_LINKER_NAME = AT32F435xM
+
+JLINK_DEVICE = ${MCU_VARIANT}
+
+CFLAGS += \
+ -D${MCU_VARIANT}
diff --git a/hw/bsp/at32f435_437/boards/at_start_f437/board.h b/hw/bsp/at32f435_437/boards/at_start_f437/board.h
index b6de119bc..3522e759a 100644
--- a/hw/bsp/at32f435_437/boards/at_start_f437/board.h
+++ b/hw/bsp/at32f435_437/boards/at_start_f437/board.h
@@ -60,124 +60,11 @@
#define PRINT_UART_TX_PIN_SOURCE GPIO_PINS_SOURCE9
#define PRINT_UART_TX_PIN_MUX_NUM GPIO_MUX_7
-// USB
-#ifdef BOARD_TUD_RHPORT
- #if BOARD_TUD_RHPORT == 0
- #define USB_ID 0
- #define OTG_CLOCK CRM_OTGFS1_PERIPH_CLOCK
- #define OTG_IRQ OTGFS1_IRQn
- #define OTG_IRQ_HANDLER OTGFS1_IRQHandler
- #define OTG_WKUP_IRQ OTGFS1_WKUP_IRQn
- #define OTG_WKUP_HANDLER OTGFS1_WKUP_IRQHandler
- #define OTG_WKUP_EXINT_LINE EXINT_LINE_18
- #define OTG_PIN_GPIO GPIOA
- #define OTG_PIN_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
- #define OTG_PIN_DP GPIO_PINS_12
- #define OTG_PIN_DP_SOURCE GPIO_PINS_SOURCE12
- #define OTG_PIN_DM GPIO_PINS_11
- #define OTG_PIN_DM_SOURCE GPIO_PINS_SOURCE11
- #define OTG_PIN_VBUS GPIO_PINS_9
- #define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE9
- #define OTG_PIN_ID GPIO_PINS_10
- #define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE12
- #define OTG_PIN_SOF_GPIO GPIOA
- #define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
- #define OTG_PIN_SOF GPIO_PINS_8
- #define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE8
- #define OTG_PIN_MUX GPIO_MUX_10
- #elif BOARD_TUD_RHPORT == 1
- #define USB_ID 1
- #define OTG_CLOCK CRM_OTGFS2_PERIPH_CLOCK
- #define OTG_IRQ OTGFS2_IRQn
- #define OTG_IRQ_HANDLER OTGFS2_IRQHandler
- #define OTG_WKUP_IRQ OTGFS2_WKUP_IRQn
- #define OTG_WKUP_HANDLER OTGFS2_WKUP_IRQHandler
- #define OTG_WKUP_EXINT_LINE EXINT_LINE_20
- #define OTG_PIN_GPIO GPIOB
- #define OTG_PIN_GPIO_CLOCK CRM_GPIOB_PERIPH_CLOCK
- #define OTG_PIN_DP GPIO_PINS_15
- #define OTG_PIN_DP_SOURCE GPIO_PINS_SOURCE15
- #define OTG_PIN_DM GPIO_PINS_14
- #define OTG_PIN_DM_SOURCE GPIO_PINS_SOURCE14
- #define OTG_PIN_VBUS GPIO_PINS_13
- #define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE13
- #define OTG_PIN_ID GPIO_PINS_12
- #define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE10
- #define OTG_PIN_SOF_GPIO GPIOA
- #define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
- #define OTG_PIN_SOF GPIO_PINS_4
- #define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE4
- #define OTG_PIN_MUX GPIO_MUX_12
- #endif
-#endif
-
-#ifdef BOARD_TUH_RHPORT
- #if BOARD_TUH_RHPORT == 0
- #define USB_ID 0
- #define OTG_CLOCK CRM_OTGFS1_PERIPH_CLOCK
- #define OTG_IRQ OTGFS1_IRQn
- #define OTG_IRQ_HANDLER OTGFS1_IRQHandler
- #define OTG_WKUP_IRQ OTGFS1_WKUP_IRQn
- #define OTG_WKUP_HANDLER OTGFS1_WKUP_IRQHandler
- #define OTG_WKUP_EXINT_LINE EXINT_LINE_18
- #define OTG_PIN_GPIO GPIOA
- #define OTG_PIN_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
- #define OTG_PIN_DP GPIO_PINS_12
- #define OTG_PIN_DP_SOURCE GPIO_PINS_SOURCE12
- #define OTG_PIN_DM GPIO_PINS_11
- #define OTG_PIN_DM_SOURCE GPIO_PINS_SOURCE11
- #define OTG_PIN_VBUS GPIO_PINS_9
- #define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE9
- #define OTG_PIN_ID GPIO_PINS_10
- #define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE12
- #define OTG_PIN_SOF_GPIO GPIOA
- #define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
- #define OTG_PIN_SOF GPIO_PINS_8
- #define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE8
- #define OTG_PIN_MUX GPIO_MUX_10
- #elif BOARD_TUH_RHPORT == 1
- #define USB_ID 1
- #define OTG_CLOCK CRM_OTGFS2_PERIPH_CLOCK
- #define OTG_IRQ OTGFS2_IRQn
- #define OTG_IRQ_HANDLER OTGFS2_IRQHandler
- #define OTG_WKUP_IRQ OTGFS2_WKUP_IRQn
- #define OTG_WKUP_HANDLER OTGFS2_WKUP_IRQHandler
- #define OTG_WKUP_EXINT_LINE EXINT_LINE_20
- #define OTG_PIN_GPIO GPIOB
- #define OTG_PIN_GPIO_CLOCK CRM_GPIOB_PERIPH_CLOCK
- #define OTG_PIN_DP GPIO_PINS_15
- #define OTG_PIN_DP_SOURCE GPIO_PINS_SOURCE15
- #define OTG_PIN_DM GPIO_PINS_14
- #define OTG_PIN_DM_SOURCE GPIO_PINS_SOURCE14
- #define OTG_PIN_VBUS GPIO_PINS_13
- #define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE13
- #define OTG_PIN_ID GPIO_PINS_12
- #define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE10
- #define OTG_PIN_SOF_GPIO GPIOA
- #define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
- #define OTG_PIN_SOF GPIO_PINS_4
- #define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE4
- #define OTG_PIN_MUX GPIO_MUX_12
- #endif
-#endif
-
// VBUS
static inline void board_vbus_sense_init(void)
{
- #ifdef BOARD_TUD_RHPORT
- #if BOARD_TUD_RHPORT == 0
- *(int*)(0x50000038) |= (1<<21);
- #elif BOARD_TUD_RHPORT == 1
- *(int*)(0x40040038) |= (1<<21);
- #endif
- #endif
- #ifdef BOARD_TUH_RHPORT
- #if BOARD_TUH_RHPORT == 0
- *(int*)(0x50000038) |= (1<<21);
- #elif BOARD_TUH_RHPORT == 1
- *(int*)(0x40040038) |= (1<<21);
- #endif
- #endif
+ *(int*)(0x50000038) |= (1<<21);
+ *(int*)(0x40040038) |= (1<<21);
}
#ifdef __cplusplus
diff --git a/hw/bsp/at32f435_437/family.c b/hw/bsp/at32f435_437/family.c
index 702fdd2a8..a65116729 100644
--- a/hw/bsp/at32f435_437/family.c
+++ b/hw/bsp/at32f435_437/family.c
@@ -64,21 +64,23 @@ void board_init(void) {
usb_gpio_config();
/* enable usb clock */
- crm_periph_clock_enable(OTG_CLOCK, TRUE);
+ crm_periph_clock_enable(CRM_OTGFS1_PERIPH_CLOCK, TRUE);
+ crm_periph_clock_enable(CRM_OTGFS2_PERIPH_CLOCK, TRUE);
/* select usb 48m clcok source */
usb_clock48m_select(USB_CLK_HEXT);
- /* enable otgfs irq */
- //nvic_irq_enable(OTG_IRQ, 0, 0);
-
/* vbus ignore */
board_vbus_sense_init();
SysTick_Config(SystemCoreClock / 1000);
#if CFG_TUSB_OS == OPT_OS_FREERTOS
// If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
- NVIC_SetPriority(OTG_IRQ, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
+ NVIC_SetPriority(OTGFS1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
+ NVIC_SetPriority(OTGFS2_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
+#else
+ NVIC_SetPriority(OTGFS1_IRQn, 0);
+ NVIC_SetPriority(OTGFS2_IRQn, 0);
#endif
/* config led and key */
@@ -271,30 +273,22 @@ int inHandlerMode(void) {
void usb_gpio_config(void) {
gpio_init_type gpio_init_struct;
- crm_periph_clock_enable(OTG_PIN_GPIO_CLOCK, TRUE);
+ crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
+ crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
/* dp and dm */
- gpio_init_struct.gpio_pins = OTG_PIN_DP | OTG_PIN_DM;
- gpio_init(OTG_PIN_GPIO, &gpio_init_struct);
- gpio_pin_mux_config(OTG_PIN_GPIO, OTG_PIN_DP_SOURCE, OTG_PIN_MUX);
- gpio_pin_mux_config(OTG_PIN_GPIO, OTG_PIN_DM_SOURCE, OTG_PIN_MUX);
-#ifdef USB_SOF_OUTPUT_ENABLE
- crm_periph_clock_enable(OTG_PIN_SOF_GPIO_CLOCK, TRUE);
- gpio_init_struct.gpio_pins = OTG_PIN_SOF;
- gpio_init(OTG_PIN_SOF_GPIO, &gpio_init_struct);
- gpio_pin_mux_config(OTG_PIN_SOF_GPIO, OTG_PIN_SOF_SOURCE, OTG_PIN_MUX);
-#endif
- /* otgfs use vbus pin */
-#ifndef USB_VBUS_IGNORE
- gpio_init_struct.gpio_pins = OTG_PIN_VBUS;
- gpio_init_struct.gpio_pull = GPIO_PULL_DOWN;
- gpio_pin_mux_config(OTG_PIN_GPIO, OTG_PIN_VBUS_SOURCE, OTG_PIN_MUX);
- gpio_init(OTG_PIN_GPIO, &gpio_init_struct);
-#endif
+ gpio_init_struct.gpio_pins = GPIO_PINS_11 | GPIO_PINS_12;
+ gpio_init(GPIOA, &gpio_init_struct);
+ gpio_init_struct.gpio_pins = GPIO_PINS_14 | GPIO_PINS_15;
+ gpio_init(GPIOB, &gpio_init_struct);
+ gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE11, GPIO_MUX_10);
+ gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE12, GPIO_MUX_10);
+ gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE14, GPIO_MUX_12);
+ gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE15, GPIO_MUX_12);
}
void board_led_write(bool state) {
diff --git a/hw/bsp/at32f435_437/family.cmake b/hw/bsp/at32f435_437/family.cmake
index c85b58ae4..085e5462b 100644
--- a/hw/bsp/at32f435_437/family.cmake
+++ b/hw/bsp/at32f435_437/family.cmake
@@ -51,7 +51,10 @@ function(add_board_target BOARD_TARGET)
${AT32_SDK_LIB}/drivers/inc
)
target_compile_definitions(${BOARD_TARGET} PUBLIC
- BOARD_TUD_RHPORT=0
+ BOARD_TUD_RHPORT=1
+ BOARD_TUH_RHPORT=0
+ BOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED
+ BOARD_TUH_MAX_SPEED=OPT_MODE_FULL_SPEED
)
update_board(${BOARD_TARGET})
diff --git a/hw/bsp/at32f435_437/family.mk b/hw/bsp/at32f435_437/family.mk
index b33be1180..ba22f5420 100644
--- a/hw/bsp/at32f435_437/family.mk
+++ b/hw/bsp/at32f435_437/family.mk
@@ -10,7 +10,10 @@ CFLAGS_GCC += \
CFLAGS += \
-DCFG_TUSB_MCU=OPT_MCU_AT32F435_437 \
- -DBOARD_TUD_RHPORT=0
+ -DBOARD_TUD_RHPORT=1 \
+ -DBOARD_TUH_RHPORT=0 \
+ -DBOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED \
+ -DBOARD_TUH_MAX_SPEED=OPT_MODE_FULL_SPEED \
LDFLAGS_GCC += \
-flto --specs=nosys.specs -nostdlib -nostartfiles
diff --git a/hw/bsp/board.c b/hw/bsp/board.c
index 1ba5a1b9d..e141664da 100644
--- a/hw/bsp/board.c
+++ b/hw/bsp/board.c
@@ -141,6 +141,26 @@ __strong_reference(stdin, stderr);
#endif
//--------------------------------------------------------------------+
+// Weak board API (to be optionally implemented by board)
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK size_t board_get_unique_id(uint8_t id[], size_t max_len) {
+ (void) max_len;
+ // fixed serial string is 01234567889ABCDEF
+ uint32_t* uid32 = (uint32_t*) (uintptr_t)id;
+ uid32[0] = 0x67452301;
+ uid32[1] = 0xEFCDAB89;
+ return 8;
+}
+
+TU_ATTR_WEAK void board_init_after_tusb(void) {
+ // nothing to do
+}
+
+TU_ATTR_WEAK void board_reset_to_bootloader(void) {
+ // not implemented
+}
+
+//--------------------------------------------------------------------+
// Board API
//--------------------------------------------------------------------+
int board_getchar(void) {
diff --git a/hw/bsp/board_api.h b/hw/bsp/board_api.h
index 328fe9363..5ecd7797a 100644
--- a/hw/bsp/board_api.h
+++ b/hw/bsp/board_api.h
@@ -72,10 +72,10 @@ extern "C" {
void board_init(void);
// Init board after tinyusb is initialized
-void board_init_after_tusb(void) TU_ATTR_WEAK;
+void board_init_after_tusb(void);
// Jump to bootloader
-void board_reset_to_bootloader(void) TU_ATTR_WEAK;
+void board_reset_to_bootloader(void);
// Turn LED on or off
void board_led_write(bool state);
@@ -89,7 +89,7 @@ void board_led_write(bool state);
uint32_t board_button_read(void);
// Get board unique ID for USB serial number. Return number of bytes. Note max_len is typically 16
-TU_ATTR_WEAK size_t board_get_unique_id(uint8_t id[], size_t max_len);
+size_t board_get_unique_id(uint8_t id[], size_t max_len);
// Get characters from UART. Return number of read bytes
int board_uart_read(uint8_t *buf, int len);
@@ -152,15 +152,7 @@ static inline size_t board_usb_get_serial(uint16_t desc_str1[], size_t max_chars
size_t uid_len;
// TODO work with make, but not working with esp32s3 cmake
- if ( board_get_unique_id ) {
- uid_len = board_get_unique_id(uid, sizeof(uid));
- }else {
- // fixed serial string is 01234567889ABCDEF
- uint32_t* uid32 = (uint32_t*) (uintptr_t) uid;
- uid32[0] = 0x67452301;
- uid32[1] = 0xEFCDAB89;
- uid_len = 8;
- }
+ uid_len = board_get_unique_id(uid, sizeof(uid));
if ( uid_len > max_chars / 2 ) uid_len = max_chars / 2;
diff --git a/hw/bsp/espressif/boards/family.c b/hw/bsp/espressif/boards/family.c
index 2a5deed26..a837417f4 100644
--- a/hw/bsp/espressif/boards/family.c
+++ b/hw/bsp/espressif/boards/family.c
@@ -49,7 +49,7 @@ static led_strip_handle_t led_strip;
static void max3421_init(void);
#endif
-#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_ESP32P4)
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_ESP32H4, OPT_MCU_ESP32P4)
static bool usb_init(void);
#endif
@@ -105,7 +105,7 @@ void board_init(void) {
#endif
}
-#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_ESP32H4)
#endif
@@ -160,11 +160,19 @@ void board_putchar(int c) {
putchar(c);
}
+void board_init_after_tusb(void) {
+ // nothing to do
+}
+
+void board_reset_to_bootloader(void) {
+ // not implemented
+}
+
//--------------------------------------------------------------------
// PHY Init
//--------------------------------------------------------------------
-#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_ESP32P4)
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_ESP32H4, OPT_MCU_ESP32P4)
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
#include "esp_private/usb_phy.h"
diff --git a/hw/bsp/espressif/components/tinyusb_src/CMakeLists.txt b/hw/bsp/espressif/components/tinyusb_src/CMakeLists.txt
index 00e288bad..beabcad9c 100644
--- a/hw/bsp/espressif/components/tinyusb_src/CMakeLists.txt
+++ b/hw/bsp/espressif/components/tinyusb_src/CMakeLists.txt
@@ -37,6 +37,7 @@ list(APPEND srcs
${tusb_src}/class/hid/hid_device.c
${tusb_src}/class/midi/midi_device.c
${tusb_src}/class/msc/msc_device.c
+ ${tusb_src}/class/mtp/mtp_device.c
${tusb_src}/class/net/ecm_rndis_device.c
${tusb_src}/class/net/ncm_device.c
${tusb_src}/class/usbtmc/usbtmc_device.c
diff --git a/hw/bsp/imxrt/boards/metro_m7_1011/board.h b/hw/bsp/imxrt/boards/metro_m7_1011/board.h
index ccc4d6b9a..908b9b87c 100644
--- a/hw/bsp/imxrt/boards/metro_m7_1011/board.h
+++ b/hw/bsp/imxrt/boards/metro_m7_1011/board.h
@@ -49,4 +49,7 @@
#define UART_PORT LPUART1
#define UART_CLK_ROOT BOARD_BOOTCLOCKRUN_UART_CLK_ROOT
+static inline void BOARD_ConfigMPU(void) {
+}
+
#endif
diff --git a/hw/bsp/imxrt/boards/metro_m7_1011_sd/board.h b/hw/bsp/imxrt/boards/metro_m7_1011_sd/board.h
index 04d5b01b5..8f100284a 100644
--- a/hw/bsp/imxrt/boards/metro_m7_1011_sd/board.h
+++ b/hw/bsp/imxrt/boards/metro_m7_1011_sd/board.h
@@ -49,4 +49,7 @@
#define UART_PORT LPUART1
#define UART_CLK_ROOT BOARD_BOOTCLOCKRUN_UART_CLK_ROOT
+static inline void BOARD_ConfigMPU(void) {
+}
+
#endif
diff --git a/hw/bsp/imxrt/boards/mimxrt1010_evk/board.h b/hw/bsp/imxrt/boards/mimxrt1010_evk/board.h
index 6b9ec0ae1..eda185fe4 100644
--- a/hw/bsp/imxrt/boards/mimxrt1010_evk/board.h
+++ b/hw/bsp/imxrt/boards/mimxrt1010_evk/board.h
@@ -49,4 +49,7 @@
#define UART_PORT LPUART1
#define UART_CLK_ROOT BOARD_BOOTCLOCKRUN_UART_CLK_ROOT
+static inline void BOARD_ConfigMPU(void) {
+}
+
#endif
diff --git a/hw/bsp/imxrt/boards/mimxrt1015_evk/board.h b/hw/bsp/imxrt/boards/mimxrt1015_evk/board.h
index e2ec4e627..697b9c30b 100644
--- a/hw/bsp/imxrt/boards/mimxrt1015_evk/board.h
+++ b/hw/bsp/imxrt/boards/mimxrt1015_evk/board.h
@@ -53,4 +53,7 @@
#define UART_RX_PINMUX IOMUXC_GPIO_AD_B0_07_LPUART1_RX
#define UART_TX_PINMUX IOMUXC_GPIO_AD_B0_06_LPUART1_TX
+static inline void BOARD_ConfigMPU(void) {
+}
+
#endif
diff --git a/hw/bsp/imxrt/boards/mimxrt1020_evk/board.h b/hw/bsp/imxrt/boards/mimxrt1020_evk/board.h
index 3f9c97e11..5028a6239 100644
--- a/hw/bsp/imxrt/boards/mimxrt1020_evk/board.h
+++ b/hw/bsp/imxrt/boards/mimxrt1020_evk/board.h
@@ -49,4 +49,7 @@
#define UART_PORT LPUART1
#define UART_CLK_ROOT BOARD_BOOTCLOCKRUN_UART_CLK_ROOT
+static inline void BOARD_ConfigMPU(void) {
+}
+
#endif
diff --git a/hw/bsp/imxrt/boards/mimxrt1024_evk/board.h b/hw/bsp/imxrt/boards/mimxrt1024_evk/board.h
index 39e63c472..f6a97815e 100644
--- a/hw/bsp/imxrt/boards/mimxrt1024_evk/board.h
+++ b/hw/bsp/imxrt/boards/mimxrt1024_evk/board.h
@@ -50,4 +50,7 @@
#define UART_PORT LPUART1
#define UART_CLK_ROOT BOARD_BOOTCLOCKRUN_UART_CLK_ROOT
+static inline void BOARD_ConfigMPU(void) {
+}
+
#endif
diff --git a/hw/bsp/imxrt/boards/mimxrt1050_evkb/board.h b/hw/bsp/imxrt/boards/mimxrt1050_evkb/board.h
index de7ab0535..47678e9fe 100644
--- a/hw/bsp/imxrt/boards/mimxrt1050_evkb/board.h
+++ b/hw/bsp/imxrt/boards/mimxrt1050_evkb/board.h
@@ -49,4 +49,7 @@
#define UART_PORT LPUART1
#define UART_CLK_ROOT BOARD_BOOTCLOCKRUN_UART_CLK_ROOT
+static inline void BOARD_ConfigMPU(void) {
+}
+
#endif
diff --git a/hw/bsp/imxrt/boards/mimxrt1060_evk/board.h b/hw/bsp/imxrt/boards/mimxrt1060_evk/board.h
index 5bbacadaf..e24b6dcdc 100644
--- a/hw/bsp/imxrt/boards/mimxrt1060_evk/board.h
+++ b/hw/bsp/imxrt/boards/mimxrt1060_evk/board.h
@@ -49,4 +49,7 @@
#define UART_PORT LPUART1
#define UART_CLK_ROOT BOARD_BOOTCLOCKRUN_UART_CLK_ROOT
+static inline void BOARD_ConfigMPU(void) {
+}
+
#endif
diff --git a/hw/bsp/imxrt/boards/mimxrt1064_evk/board.h b/hw/bsp/imxrt/boards/mimxrt1064_evk/board.h
index 6dc01e3e7..8bdb0561b 100644
--- a/hw/bsp/imxrt/boards/mimxrt1064_evk/board.h
+++ b/hw/bsp/imxrt/boards/mimxrt1064_evk/board.h
@@ -49,4 +49,7 @@
#define UART_PORT LPUART1
#define UART_CLK_ROOT BOARD_BOOTCLOCKRUN_UART_CLK_ROOT
+static inline void BOARD_ConfigMPU(void) {
+}
+
#endif
diff --git a/hw/bsp/imxrt/boards/mimxrt1170_evkb/board.h b/hw/bsp/imxrt/boards/mimxrt1170_evkb/board.h
index c5d54b7a7..a6332d896 100644
--- a/hw/bsp/imxrt/boards/mimxrt1170_evkb/board.h
+++ b/hw/bsp/imxrt/boards/mimxrt1170_evkb/board.h
@@ -49,4 +49,387 @@
#define UART_PORT LPUART1
#define UART_CLK_ROOT BOARD_BOOTCLOCKRUN_LPUART10_CLK_ROOT
+//--------------------------------------------------------------------
+// MPU configuration
+//--------------------------------------------------------------------
+#if __CORTEX_M == 7
+static inline void BOARD_ConfigMPU(void) {
+ #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
+ extern uint32_t Image$$RW_m_ncache$$Base[];
+ /* RW_m_ncache_unused is a auxiliary region which is used to get the whole size of noncache section */
+ extern uint32_t Image$$RW_m_ncache_unused$$Base[];
+ extern uint32_t Image$$RW_m_ncache_unused$$ZI$$Limit[];
+ uint32_t nonCacheStart = (uint32_t) Image$$RW_m_ncache$$Base;
+ uint32_t size = ((uint32_t) Image$$RW_m_ncache_unused$$Base == nonCacheStart) ? 0 : ((uint32_t) Image$$RW_m_ncache_unused$$ZI$$Limit - nonCacheStart);
+ #elif defined(__MCUXPRESSO)
+ #if defined(__USE_SHMEM)
+ extern uint32_t __base_rpmsg_sh_mem;
+ extern uint32_t __top_rpmsg_sh_mem;
+ uint32_t nonCacheStart = (uint32_t) (&__base_rpmsg_sh_mem);
+ uint32_t size = (uint32_t) (&__top_rpmsg_sh_mem) - nonCacheStart;
+ #else
+ extern uint32_t __base_NCACHE_REGION;
+ extern uint32_t __top_NCACHE_REGION;
+ uint32_t nonCacheStart = (uint32_t) (&__base_NCACHE_REGION);
+ uint32_t size = (uint32_t) (&__top_NCACHE_REGION) - nonCacheStart;
+ #endif
+ #elif defined(__ICCARM__) || defined(__GNUC__)
+ extern uint32_t __NCACHE_REGION_START[];
+ extern uint32_t __NCACHE_REGION_SIZE[];
+ uint32_t nonCacheStart = (uint32_t) __NCACHE_REGION_START;
+ uint32_t size = (uint32_t) __NCACHE_REGION_SIZE;
+ #endif
+ volatile uint32_t i = 0;
+
+ #if defined(__ICACHE_PRESENT) && __ICACHE_PRESENT
+ /* Disable I cache and D cache */
+ if (SCB_CCR_IC_Msk == (SCB_CCR_IC_Msk & SCB->CCR)) {
+ SCB_DisableICache();
+ }
+ #endif
+ #if defined(__DCACHE_PRESENT) && __DCACHE_PRESENT
+ if (SCB_CCR_DC_Msk == (SCB_CCR_DC_Msk & SCB->CCR)) {
+ SCB_DisableDCache();
+ }
+ #endif
+
+ /* Disable MPU */
+ ARM_MPU_Disable();
+
+ /* MPU configure:
+ * Use ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable,
+ * SubRegionDisable, Size)
+ * API in mpu_armv7.h.
+ * param DisableExec Instruction access (XN) disable bit,0=instruction fetches enabled, 1=instruction fetches
+ * disabled.
+ * param AccessPermission Data access permissions, allows you to configure read/write access for User and
+ * Privileged mode.
+ * Use MACROS defined in mpu_armv7.h:
+ * ARM_MPU_AP_NONE/ARM_MPU_AP_PRIV/ARM_MPU_AP_URO/ARM_MPU_AP_FULL/ARM_MPU_AP_PRO/ARM_MPU_AP_RO
+ * Combine TypeExtField/IsShareable/IsCacheable/IsBufferable to configure MPU memory access attributes.
+ * TypeExtField IsShareable IsCacheable IsBufferable Memory Attribute Shareability Cache
+ * 0 x 0 0 Strongly Ordered shareable
+ * 0 x 0 1 Device shareable
+ * 0 0 1 0 Normal not shareable Outer and inner write
+ * through no write allocate
+ * 0 0 1 1 Normal not shareable Outer and inner write
+ * back no write allocate
+ * 0 1 1 0 Normal shareable Outer and inner write
+ * through no write allocate
+ * 0 1 1 1 Normal shareable Outer and inner write
+ * back no write allocate
+ * 1 0 0 0 Normal not shareable outer and inner
+ * noncache
+ * 1 1 0 0 Normal shareable outer and inner
+ * noncache
+ * 1 0 1 1 Normal not shareable outer and inner write
+ * back write/read acllocate
+ * 1 1 1 1 Normal shareable outer and inner write
+ * back write/read acllocate
+ * 2 x 0 0 Device not shareable
+ * Above are normal use settings, if your want to see more details or want to config different inner/outer cache
+ * policy.
+ * please refer to Table 4-55 /4-56 in arm cortex-M7 generic user guide <dui0646b_cortex_m7_dgug.pdf>
+ * param SubRegionDisable Sub-region disable field. 0=sub-region is enabled, 1=sub-region is disabled.
+ * param Size Region size of the region to be configured. use ARM_MPU_REGION_SIZE_xxx MACRO in
+ * mpu_armv7.h.
+ */
+
+ /*
+ * Add default region to deny access to whole address space to workaround speculative prefetch.
+ * Refer to Arm errata 1013783-B for more details.
+ *
+ */
+ /* Region 0 setting: Instruction access disabled, No data access permission. */
+ MPU->RBAR = ARM_MPU_RBAR(0, 0x00000000U);
+ MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_NONE, 0, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_4GB);
+
+ /* Region 1 setting: Memory with Device type, not shareable, non-cacheable. */
+ MPU->RBAR = ARM_MPU_RBAR(1, 0x80000000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB);
+
+ /* Region 2 setting: Memory with Device type, not shareable, non-cacheable. */
+ MPU->RBAR = ARM_MPU_RBAR(2, 0x60000000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB);
+
+ /* Region 3 setting: Memory with Device type, not shareable, non-cacheable. */
+ MPU->RBAR = ARM_MPU_RBAR(3, 0x00000000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1GB);
+
+ /* Region 4 setting: Memory with Normal type, not shareable, outer/inner write back */
+ MPU->RBAR = ARM_MPU_RBAR(4, 0x00000000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_256KB);
+
+ /* Region 5 setting: Memory with Normal type, not shareable, outer/inner write back */
+ MPU->RBAR = ARM_MPU_RBAR(5, 0x20000000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_256KB);
+
+ #if defined(CACHE_MODE_WRITE_THROUGH) && CACHE_MODE_WRITE_THROUGH
+ /* Region 6 setting: Memory with Normal type, not shareable, write through */
+ MPU->RBAR = ARM_MPU_RBAR(6, 0x20200000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_1MB);
+
+ /* Region 7 setting: Memory with Normal type, not shareable, write through */
+ MPU->RBAR = ARM_MPU_RBAR(7, 0x20300000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_512KB);
+ #else
+ /* Region 6 setting: Memory with Normal type, not shareable, outer/inner write back */
+ MPU->RBAR = ARM_MPU_RBAR(6, 0x20200000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_1MB);
+
+ /* Region 7 setting: Memory with Normal type, not shareable, outer/inner write back */
+ MPU->RBAR = ARM_MPU_RBAR(7, 0x20300000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_512KB);
+ #endif
+
+ #if defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1)
+ /* Region 8 setting: Memory with Normal type, not shareable, outer/inner write back. */
+ MPU->RBAR = ARM_MPU_RBAR(8, 0x30000000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_RO, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_16MB);
+ #endif
+
+ #ifdef USE_SDRAM
+ #if defined(CACHE_MODE_WRITE_THROUGH) && CACHE_MODE_WRITE_THROUGH
+ /* Region 9 setting: Memory with Normal type, not shareable, write through */
+ MPU->RBAR = ARM_MPU_RBAR(9, 0x80000000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_64MB);
+ #else
+ /* Region 9 setting: Memory with Normal type, not shareable, outer/inner write back */
+ MPU->RBAR = ARM_MPU_RBAR(9, 0x80000000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_64MB);
+ #endif
+ #endif
+
+ while ((size >> i) > 0x1U) {
+ i++;
+ }
+
+ if (i != 0) {
+ /* The MPU region size should be 2^N, 5<=N<=32, region base should be multiples of size. */
+ assert(!(nonCacheStart % size));
+ assert(size == (uint32_t) (1 << i));
+ assert(i >= 5);
+
+ /* Region 10 setting: Memory with Normal type, not shareable, non-cacheable */
+ MPU->RBAR = ARM_MPU_RBAR(10, nonCacheStart);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 0, 0, 0, 0, i - 1);
+ }
+
+ /* Region 11 setting: Memory with Device type, not shareable, non-cacheable */
+ MPU->RBAR = ARM_MPU_RBAR(11, 0x40000000);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_16MB);
+
+ /* Region 12 setting: Memory with Device type, not shareable, non-cacheable */
+ MPU->RBAR = ARM_MPU_RBAR(12, 0x41000000);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_2MB);
+
+ /* Region 13 setting: Memory with Device type, not shareable, non-cacheable */
+ MPU->RBAR = ARM_MPU_RBAR(13, 0x41400000);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1MB);
+
+ /* Region 14 setting: Memory with Device type, not shareable, non-cacheable */
+ MPU->RBAR = ARM_MPU_RBAR(14, 0x41800000);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_2MB);
+
+ /* Region 15 setting: Memory with Device type, not shareable, non-cacheable */
+ MPU->RBAR = ARM_MPU_RBAR(15, 0x42000000);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1MB);
+
+ /* Enable MPU */
+ ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
+
+ /* Enable I cache and D cache */
+ #if defined(__DCACHE_PRESENT) && __DCACHE_PRESENT
+ SCB_EnableDCache();
+ #endif
+ #if defined(__ICACHE_PRESENT) && __ICACHE_PRESENT
+ SCB_EnableICache();
+ #endif
+}
+
+#elif __CORTEX_M == 4
+
+static void BOARD_ConfigMPU(void) {
+ #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
+ extern uint32_t Image$$RW_m_ncache$$Base[];
+ /* RW_m_ncache_unused is a auxiliary region which is used to get the whole size of noncache section */
+ extern uint32_t Image$$RW_m_ncache_unused$$Base[];
+ extern uint32_t Image$$RW_m_ncache_unused$$ZI$$Limit[];
+ uint32_t nonCacheStart = (uint32_t) Image$$RW_m_ncache$$Base;
+ uint32_t nonCacheSize = ((uint32_t) Image$$RW_m_ncache_unused$$Base == nonCacheStart) ? 0 : ((uint32_t) Image$$RW_m_ncache_unused$$ZI$$Limit - nonCacheStart);
+ #elif defined(__MCUXPRESSO)
+ extern uint32_t __base_NCACHE_REGION;
+ extern uint32_t __top_NCACHE_REGION;
+ uint32_t nonCacheStart = (uint32_t) (&__base_NCACHE_REGION);
+ uint32_t nonCacheSize = (uint32_t) (&__top_NCACHE_REGION) - nonCacheStart;
+ #elif defined(__ICCARM__) || defined(__GNUC__)
+ extern uint32_t __NCACHE_REGION_START[];
+ extern uint32_t __NCACHE_REGION_SIZE[];
+ uint32_t nonCacheStart = (uint32_t) __NCACHE_REGION_START;
+ uint32_t nonCacheSize = (uint32_t) __NCACHE_REGION_SIZE;
+ #endif
+ #if defined(__USE_SHMEM)
+ #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
+ extern uint32_t Image$$RPMSG_SH_MEM$$Base[];
+ /* RPMSG_SH_MEM_unused is a auxiliary region which is used to get the whole size of RPMSG_SH_MEM section */
+ extern uint32_t Image$$RPMSG_SH_MEM_unused$$Base[];
+ extern uint32_t Image$$RPMSG_SH_MEM_unused$$ZI$$Limit[];
+ uint32_t rpmsgShmemStart = (uint32_t) Image$$RPMSG_SH_MEM$$Base;
+ uint32_t rpmsgShmemSize = (uint32_t) Image$$RPMSG_SH_MEM_unused$$ZI$$Limit - rpmsgShmemStart;
+ #elif defined(__MCUXPRESSO)
+ extern uint32_t __base_rpmsg_sh_mem;
+ extern uint32_t __top_rpmsg_sh_mem;
+ uint32_t rpmsgShmemStart = (uint32_t) (&__base_rpmsg_sh_mem);
+ uint32_t rpmsgShmemSize = (uint32_t) (&__top_rpmsg_sh_mem) - rpmsgShmemStart;
+ #elif defined(__ICCARM__) || defined(__GNUC__)
+ extern uint32_t __RPMSG_SH_MEM_START[];
+ extern uint32_t __RPMSG_SH_MEM_SIZE[];
+ uint32_t rpmsgShmemStart = (uint32_t) __RPMSG_SH_MEM_START;
+ uint32_t rpmsgShmemSize = (uint32_t) __RPMSG_SH_MEM_SIZE;
+ #endif
+ #endif
+ uint32_t i = 0;
+
+ /* Only config non-cacheable region on system bus */
+ assert(nonCacheStart >= 0x20000000);
+
+ /* Disable code bus cache */
+ if (LMEM_PCCCR_ENCACHE_MASK == (LMEM_PCCCR_ENCACHE_MASK & LMEM->PCCCR)) {
+ /* Enable the processor code bus to push all modified lines. */
+ LMEM->PCCCR |= LMEM_PCCCR_PUSHW0_MASK | LMEM_PCCCR_PUSHW1_MASK | LMEM_PCCCR_GO_MASK;
+ /* Wait until the cache command completes. */
+ while ((LMEM->PCCCR & LMEM_PCCCR_GO_MASK) != 0U) {
+ }
+ /* As a precaution clear the bits to avoid inadvertently re-running this command. */
+ LMEM->PCCCR &= ~(LMEM_PCCCR_PUSHW0_MASK | LMEM_PCCCR_PUSHW1_MASK);
+ /* Now disable the cache. */
+ LMEM->PCCCR &= ~LMEM_PCCCR_ENCACHE_MASK;
+ }
+
+ /* Disable system bus cache */
+ if (LMEM_PSCCR_ENCACHE_MASK == (LMEM_PSCCR_ENCACHE_MASK & LMEM->PSCCR)) {
+ /* Enable the processor system bus to push all modified lines. */
+ LMEM->PSCCR |= LMEM_PSCCR_PUSHW0_MASK | LMEM_PSCCR_PUSHW1_MASK | LMEM_PSCCR_GO_MASK;
+ /* Wait until the cache command completes. */
+ while ((LMEM->PSCCR & LMEM_PSCCR_GO_MASK) != 0U) {
+ }
+ /* As a precaution clear the bits to avoid inadvertently re-running this command. */
+ LMEM->PSCCR &= ~(LMEM_PSCCR_PUSHW0_MASK | LMEM_PSCCR_PUSHW1_MASK);
+ /* Now disable the cache. */
+ LMEM->PSCCR &= ~LMEM_PSCCR_ENCACHE_MASK;
+ }
+
+ /* Disable MPU */
+ ARM_MPU_Disable();
+
+ #if defined(CACHE_MODE_WRITE_THROUGH) && CACHE_MODE_WRITE_THROUGH
+ /* Region 0 setting: Memory with Normal type, not shareable, write through */
+ MPU->RBAR = ARM_MPU_RBAR(0, 0x20200000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_1MB);
+
+ /* Region 1 setting: Memory with Normal type, not shareable, write through */
+ MPU->RBAR = ARM_MPU_RBAR(1, 0x20300000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_512KB);
+
+ /* Region 2 setting: Memory with Normal type, not shareable, write through */
+ MPU->RBAR = ARM_MPU_RBAR(2, 0x80000000U);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_64MB);
+
+ while ((nonCacheSize >> i) > 0x1U) {
+ i++;
+ }
+
+ if (i != 0) {
+ /* The MPU region size should be 2^N, 5<=N<=32, region base should be multiples of size. */
+ assert(!(nonCacheStart % nonCacheSize));
+ assert(nonCacheSize == (uint32_t) (1 << i));
+ assert(i >= 5);
+
+ /* Region 3 setting: Memory with device type, not shareable, non-cacheable */
+ MPU->RBAR = ARM_MPU_RBAR(3, nonCacheStart);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, i - 1);
+ }
+
+ #if defined(__USE_SHMEM)
+ i = 0;
+
+ while ((rpmsgShmemSize >> i) > 0x1U) {
+ i++;
+ }
+
+ if (i != 0) {
+ /* The MPU region size should be 2^N, 5<=N<=32, region base should be multiples of size. */
+ assert(!(rpmsgShmemStart % rpmsgShmemSize));
+ assert(rpmsgShmemSize == (uint32_t) (1 << i));
+ assert(i >= 5);
+
+ /* Region 4 setting: Memory with device type, not shareable, non-cacheable */
+ MPU->RBAR = ARM_MPU_RBAR(4, rpmsgShmemStart);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, i - 1);
+ }
+ #endif
+ #else
+ while ((nonCacheSize >> i) > 0x1U) {
+ i++;
+ }
+
+ if (i != 0) {
+ /* The MPU region size should be 2^N, 5<=N<=32, region base should be multiples of size. */
+ assert(!(nonCacheStart % nonCacheSize));
+ assert(nonCacheSize == (uint32_t) (1 << i));
+ assert(i >= 5);
+
+ /* Region 0 setting: Memory with device type, not shareable, non-cacheable */
+ MPU->RBAR = ARM_MPU_RBAR(0, nonCacheStart);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, i - 1);
+ }
+
+ #if defined(__USE_SHMEM)
+ i = 0;
+
+ while ((rpmsgShmemSize >> i) > 0x1U) {
+ i++;
+ }
+
+ if (i != 0) {
+ /* The MPU region size should be 2^N, 5<=N<=32, region base should be multiples of size. */
+ assert(!(rpmsgShmemStart % rpmsgShmemSize));
+ assert(rpmsgShmemSize == (uint32_t) (1 << i));
+ assert(i >= 5);
+
+ /* Region 1 setting: Memory with device type, not shareable, non-cacheable */
+ MPU->RBAR = ARM_MPU_RBAR(1, rpmsgShmemStart);
+ MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, i - 1);
+ }
+ #endif
+ #endif
+
+ /* Enable MPU */
+ ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
+
+ /* Enables the processor system bus to invalidate all lines in both ways.
+ and Initiate the processor system bus cache command. */
+ LMEM->PSCCR |= LMEM_PSCCR_INVW0_MASK | LMEM_PSCCR_INVW1_MASK | LMEM_PSCCR_GO_MASK;
+ /* Wait until the cache command completes */
+ while ((LMEM->PSCCR & LMEM_PSCCR_GO_MASK) != 0U) {
+ }
+ /* As a precaution clear the bits to avoid inadvertently re-running this command. */
+ LMEM->PSCCR &= ~(LMEM_PSCCR_INVW0_MASK | LMEM_PSCCR_INVW1_MASK);
+ /* Now enable the system bus cache. */
+ LMEM->PSCCR |= LMEM_PSCCR_ENCACHE_MASK;
+
+ /* Enables the processor code bus to invalidate all lines in both ways.
+ and Initiate the processor code bus code cache command. */
+ LMEM->PCCCR |= LMEM_PCCCR_INVW0_MASK | LMEM_PCCCR_INVW1_MASK | LMEM_PCCCR_GO_MASK;
+ /* Wait until the cache command completes. */
+ while ((LMEM->PCCCR & LMEM_PCCCR_GO_MASK) != 0U) {
+ }
+ /* As a precaution clear the bits to avoid inadvertently re-running this command. */
+ LMEM->PCCCR &= ~(LMEM_PCCCR_INVW0_MASK | LMEM_PCCCR_INVW1_MASK);
+ /* Now enable the code bus cache. */
+ LMEM->PCCCR |= LMEM_PCCCR_ENCACHE_MASK;
+}
+#endif
+
+
#endif
diff --git a/hw/bsp/imxrt/boards/teensy_40/board.h b/hw/bsp/imxrt/boards/teensy_40/board.h
index ae749e894..7b8754a97 100644
--- a/hw/bsp/imxrt/boards/teensy_40/board.h
+++ b/hw/bsp/imxrt/boards/teensy_40/board.h
@@ -49,4 +49,7 @@
#define UART_PORT LPUART6
#define UART_CLK_ROOT BOARD_BOOTCLOCKRUN_UART_CLK_ROOT
+static inline void BOARD_ConfigMPU(void) {
+}
+
#endif /* BOARD_H_ */
diff --git a/hw/bsp/imxrt/boards/teensy_41/board.h b/hw/bsp/imxrt/boards/teensy_41/board.h
index 1bc022c54..91ae3debd 100644
--- a/hw/bsp/imxrt/boards/teensy_41/board.h
+++ b/hw/bsp/imxrt/boards/teensy_41/board.h
@@ -49,4 +49,7 @@
#define UART_PORT LPUART6
#define UART_CLK_ROOT BOARD_BOOTCLOCKRUN_UART_CLK_ROOT
+static inline void BOARD_ConfigMPU(void) {
+}
+
#endif /* BOARD_H_ */
diff --git a/hw/bsp/imxrt/family.c b/hw/bsp/imxrt/family.c
index 7e4734a66..9cd59b7d7 100644
--- a/hw/bsp/imxrt/family.c
+++ b/hw/bsp/imxrt/family.c
@@ -61,8 +61,6 @@
- Define CFG_TUSB_MEM_SECTION=__attribute__((section("NonCacheable")))
*/
-// static void BOARD_ConfigMPU(void);
-
// needed by fsl_flexspi_nor_boot
TU_ATTR_USED const uint8_t dcd_data[] = {0x00};
@@ -109,11 +107,12 @@ static void init_usb_phy(uint8_t usb_id) {
}
void board_init(void) {
- // BOARD_ConfigMPU();
BOARD_InitBootPins();
BOARD_BootClockRUN();
SystemCoreClockUpdate();
+ BOARD_ConfigMPU(); // defined in board.h
+
#ifdef TRACE_ETM
//CLOCK_EnableClock(kCLOCK_Trace);
#endif
@@ -254,387 +253,3 @@ void _exit(int __status) {
}
#endif
#endif
-
-//--------------------------------------------------------------------
-// MPU configuration
-//--------------------------------------------------------------------
-#if 0 // TODO move to per board specific
-#if __CORTEX_M == 7
-static void BOARD_ConfigMPU(void) {
- #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
- extern uint32_t Image$$RW_m_ncache$$Base[];
- /* RW_m_ncache_unused is a auxiliary region which is used to get the whole size of noncache section */
- extern uint32_t Image$$RW_m_ncache_unused$$Base[];
- extern uint32_t Image$$RW_m_ncache_unused$$ZI$$Limit[];
- uint32_t nonCacheStart = (uint32_t) Image$$RW_m_ncache$$Base;
- uint32_t size = ((uint32_t) Image$$RW_m_ncache_unused$$Base == nonCacheStart) ? 0 : ((uint32_t) Image$$RW_m_ncache_unused$$ZI$$Limit - nonCacheStart);
- #elif defined(__MCUXPRESSO)
- #if defined(__USE_SHMEM)
- extern uint32_t __base_rpmsg_sh_mem;
- extern uint32_t __top_rpmsg_sh_mem;
- uint32_t nonCacheStart = (uint32_t) (&__base_rpmsg_sh_mem);
- uint32_t size = (uint32_t) (&__top_rpmsg_sh_mem) - nonCacheStart;
- #else
- extern uint32_t __base_NCACHE_REGION;
- extern uint32_t __top_NCACHE_REGION;
- uint32_t nonCacheStart = (uint32_t) (&__base_NCACHE_REGION);
- uint32_t size = (uint32_t) (&__top_NCACHE_REGION) - nonCacheStart;
- #endif
- #elif defined(__ICCARM__) || defined(__GNUC__)
- extern uint32_t __NCACHE_REGION_START[];
- extern uint32_t __NCACHE_REGION_SIZE[];
- uint32_t nonCacheStart = (uint32_t) __NCACHE_REGION_START;
- uint32_t size = (uint32_t) __NCACHE_REGION_SIZE;
- #endif
- volatile uint32_t i = 0;
-
- #if defined(__ICACHE_PRESENT) && __ICACHE_PRESENT
- /* Disable I cache and D cache */
- if (SCB_CCR_IC_Msk == (SCB_CCR_IC_Msk & SCB->CCR)) {
- SCB_DisableICache();
- }
- #endif
- #if defined(__DCACHE_PRESENT) && __DCACHE_PRESENT
- if (SCB_CCR_DC_Msk == (SCB_CCR_DC_Msk & SCB->CCR)) {
- SCB_DisableDCache();
- }
- #endif
-
- /* Disable MPU */
- ARM_MPU_Disable();
-
- /* MPU configure:
- * Use ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable,
- * SubRegionDisable, Size)
- * API in mpu_armv7.h.
- * param DisableExec Instruction access (XN) disable bit,0=instruction fetches enabled, 1=instruction fetches
- * disabled.
- * param AccessPermission Data access permissions, allows you to configure read/write access for User and
- * Privileged mode.
- * Use MACROS defined in mpu_armv7.h:
- * ARM_MPU_AP_NONE/ARM_MPU_AP_PRIV/ARM_MPU_AP_URO/ARM_MPU_AP_FULL/ARM_MPU_AP_PRO/ARM_MPU_AP_RO
- * Combine TypeExtField/IsShareable/IsCacheable/IsBufferable to configure MPU memory access attributes.
- * TypeExtField IsShareable IsCacheable IsBufferable Memory Attribute Shareability Cache
- * 0 x 0 0 Strongly Ordered shareable
- * 0 x 0 1 Device shareable
- * 0 0 1 0 Normal not shareable Outer and inner write
- * through no write allocate
- * 0 0 1 1 Normal not shareable Outer and inner write
- * back no write allocate
- * 0 1 1 0 Normal shareable Outer and inner write
- * through no write allocate
- * 0 1 1 1 Normal shareable Outer and inner write
- * back no write allocate
- * 1 0 0 0 Normal not shareable outer and inner
- * noncache
- * 1 1 0 0 Normal shareable outer and inner
- * noncache
- * 1 0 1 1 Normal not shareable outer and inner write
- * back write/read acllocate
- * 1 1 1 1 Normal shareable outer and inner write
- * back write/read acllocate
- * 2 x 0 0 Device not shareable
- * Above are normal use settings, if your want to see more details or want to config different inner/outer cache
- * policy.
- * please refer to Table 4-55 /4-56 in arm cortex-M7 generic user guide <dui0646b_cortex_m7_dgug.pdf>
- * param SubRegionDisable Sub-region disable field. 0=sub-region is enabled, 1=sub-region is disabled.
- * param Size Region size of the region to be configured. use ARM_MPU_REGION_SIZE_xxx MACRO in
- * mpu_armv7.h.
- */
-
- /*
- * Add default region to deny access to whole address space to workaround speculative prefetch.
- * Refer to Arm errata 1013783-B for more details.
- *
- */
- /* Region 0 setting: Instruction access disabled, No data access permission. */
- MPU->RBAR = ARM_MPU_RBAR(0, 0x00000000U);
- MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_NONE, 0, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_4GB);
-
- /* Region 1 setting: Memory with Device type, not shareable, non-cacheable. */
- MPU->RBAR = ARM_MPU_RBAR(1, 0x80000000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB);
-
- /* Region 2 setting: Memory with Device type, not shareable, non-cacheable. */
- MPU->RBAR = ARM_MPU_RBAR(2, 0x60000000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB);
-
- /* Region 3 setting: Memory with Device type, not shareable, non-cacheable. */
- MPU->RBAR = ARM_MPU_RBAR(3, 0x00000000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1GB);
-
- /* Region 4 setting: Memory with Normal type, not shareable, outer/inner write back */
- MPU->RBAR = ARM_MPU_RBAR(4, 0x00000000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_256KB);
-
- /* Region 5 setting: Memory with Normal type, not shareable, outer/inner write back */
- MPU->RBAR = ARM_MPU_RBAR(5, 0x20000000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_256KB);
-
- #if defined(CACHE_MODE_WRITE_THROUGH) && CACHE_MODE_WRITE_THROUGH
- /* Region 6 setting: Memory with Normal type, not shareable, write through */
- MPU->RBAR = ARM_MPU_RBAR(6, 0x20200000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_1MB);
-
- /* Region 7 setting: Memory with Normal type, not shareable, write through */
- MPU->RBAR = ARM_MPU_RBAR(7, 0x20300000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_512KB);
- #else
- /* Region 6 setting: Memory with Normal type, not shareable, outer/inner write back */
- MPU->RBAR = ARM_MPU_RBAR(6, 0x20200000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_1MB);
-
- /* Region 7 setting: Memory with Normal type, not shareable, outer/inner write back */
- MPU->RBAR = ARM_MPU_RBAR(7, 0x20300000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_512KB);
- #endif
-
- #if defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1)
- /* Region 8 setting: Memory with Normal type, not shareable, outer/inner write back. */
- MPU->RBAR = ARM_MPU_RBAR(8, 0x30000000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_RO, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_16MB);
- #endif
-
- #ifdef USE_SDRAM
- #if defined(CACHE_MODE_WRITE_THROUGH) && CACHE_MODE_WRITE_THROUGH
- /* Region 9 setting: Memory with Normal type, not shareable, write through */
- MPU->RBAR = ARM_MPU_RBAR(9, 0x80000000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_64MB);
- #else
- /* Region 9 setting: Memory with Normal type, not shareable, outer/inner write back */
- MPU->RBAR = ARM_MPU_RBAR(9, 0x80000000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_64MB);
- #endif
- #endif
-
- while ((size >> i) > 0x1U) {
- i++;
- }
-
- if (i != 0) {
- /* The MPU region size should be 2^N, 5<=N<=32, region base should be multiples of size. */
- assert(!(nonCacheStart % size));
- assert(size == (uint32_t) (1 << i));
- assert(i >= 5);
-
- /* Region 10 setting: Memory with Normal type, not shareable, non-cacheable */
- MPU->RBAR = ARM_MPU_RBAR(10, nonCacheStart);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 0, 0, 0, 0, i - 1);
- }
-
- /* Region 11 setting: Memory with Device type, not shareable, non-cacheable */
- MPU->RBAR = ARM_MPU_RBAR(11, 0x40000000);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_16MB);
-
- /* Region 12 setting: Memory with Device type, not shareable, non-cacheable */
- MPU->RBAR = ARM_MPU_RBAR(12, 0x41000000);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_2MB);
-
- /* Region 13 setting: Memory with Device type, not shareable, non-cacheable */
- MPU->RBAR = ARM_MPU_RBAR(13, 0x41400000);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1MB);
-
- /* Region 14 setting: Memory with Device type, not shareable, non-cacheable */
- MPU->RBAR = ARM_MPU_RBAR(14, 0x41800000);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_2MB);
-
- /* Region 15 setting: Memory with Device type, not shareable, non-cacheable */
- MPU->RBAR = ARM_MPU_RBAR(15, 0x42000000);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1MB);
-
- /* Enable MPU */
- ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
-
- /* Enable I cache and D cache */
- #if defined(__DCACHE_PRESENT) && __DCACHE_PRESENT
- SCB_EnableDCache();
- #endif
- #if defined(__ICACHE_PRESENT) && __ICACHE_PRESENT
- SCB_EnableICache();
- #endif
-}
-
-#elif __CORTEX_M == 4
-
-static void BOARD_ConfigMPU(void) {
- #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
- extern uint32_t Image$$RW_m_ncache$$Base[];
- /* RW_m_ncache_unused is a auxiliary region which is used to get the whole size of noncache section */
- extern uint32_t Image$$RW_m_ncache_unused$$Base[];
- extern uint32_t Image$$RW_m_ncache_unused$$ZI$$Limit[];
- uint32_t nonCacheStart = (uint32_t) Image$$RW_m_ncache$$Base;
- uint32_t nonCacheSize = ((uint32_t) Image$$RW_m_ncache_unused$$Base == nonCacheStart) ? 0 : ((uint32_t) Image$$RW_m_ncache_unused$$ZI$$Limit - nonCacheStart);
- #elif defined(__MCUXPRESSO)
- extern uint32_t __base_NCACHE_REGION;
- extern uint32_t __top_NCACHE_REGION;
- uint32_t nonCacheStart = (uint32_t) (&__base_NCACHE_REGION);
- uint32_t nonCacheSize = (uint32_t) (&__top_NCACHE_REGION) - nonCacheStart;
- #elif defined(__ICCARM__) || defined(__GNUC__)
- extern uint32_t __NCACHE_REGION_START[];
- extern uint32_t __NCACHE_REGION_SIZE[];
- uint32_t nonCacheStart = (uint32_t) __NCACHE_REGION_START;
- uint32_t nonCacheSize = (uint32_t) __NCACHE_REGION_SIZE;
- #endif
- #if defined(__USE_SHMEM)
- #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
- extern uint32_t Image$$RPMSG_SH_MEM$$Base[];
- /* RPMSG_SH_MEM_unused is a auxiliary region which is used to get the whole size of RPMSG_SH_MEM section */
- extern uint32_t Image$$RPMSG_SH_MEM_unused$$Base[];
- extern uint32_t Image$$RPMSG_SH_MEM_unused$$ZI$$Limit[];
- uint32_t rpmsgShmemStart = (uint32_t) Image$$RPMSG_SH_MEM$$Base;
- uint32_t rpmsgShmemSize = (uint32_t) Image$$RPMSG_SH_MEM_unused$$ZI$$Limit - rpmsgShmemStart;
- #elif defined(__MCUXPRESSO)
- extern uint32_t __base_rpmsg_sh_mem;
- extern uint32_t __top_rpmsg_sh_mem;
- uint32_t rpmsgShmemStart = (uint32_t) (&__base_rpmsg_sh_mem);
- uint32_t rpmsgShmemSize = (uint32_t) (&__top_rpmsg_sh_mem) - rpmsgShmemStart;
- #elif defined(__ICCARM__) || defined(__GNUC__)
- extern uint32_t __RPMSG_SH_MEM_START[];
- extern uint32_t __RPMSG_SH_MEM_SIZE[];
- uint32_t rpmsgShmemStart = (uint32_t) __RPMSG_SH_MEM_START;
- uint32_t rpmsgShmemSize = (uint32_t) __RPMSG_SH_MEM_SIZE;
- #endif
- #endif
- uint32_t i = 0;
-
- /* Only config non-cacheable region on system bus */
- assert(nonCacheStart >= 0x20000000);
-
- /* Disable code bus cache */
- if (LMEM_PCCCR_ENCACHE_MASK == (LMEM_PCCCR_ENCACHE_MASK & LMEM->PCCCR)) {
- /* Enable the processor code bus to push all modified lines. */
- LMEM->PCCCR |= LMEM_PCCCR_PUSHW0_MASK | LMEM_PCCCR_PUSHW1_MASK | LMEM_PCCCR_GO_MASK;
- /* Wait until the cache command completes. */
- while ((LMEM->PCCCR & LMEM_PCCCR_GO_MASK) != 0U) {
- }
- /* As a precaution clear the bits to avoid inadvertently re-running this command. */
- LMEM->PCCCR &= ~(LMEM_PCCCR_PUSHW0_MASK | LMEM_PCCCR_PUSHW1_MASK);
- /* Now disable the cache. */
- LMEM->PCCCR &= ~LMEM_PCCCR_ENCACHE_MASK;
- }
-
- /* Disable system bus cache */
- if (LMEM_PSCCR_ENCACHE_MASK == (LMEM_PSCCR_ENCACHE_MASK & LMEM->PSCCR)) {
- /* Enable the processor system bus to push all modified lines. */
- LMEM->PSCCR |= LMEM_PSCCR_PUSHW0_MASK | LMEM_PSCCR_PUSHW1_MASK | LMEM_PSCCR_GO_MASK;
- /* Wait until the cache command completes. */
- while ((LMEM->PSCCR & LMEM_PSCCR_GO_MASK) != 0U) {
- }
- /* As a precaution clear the bits to avoid inadvertently re-running this command. */
- LMEM->PSCCR &= ~(LMEM_PSCCR_PUSHW0_MASK | LMEM_PSCCR_PUSHW1_MASK);
- /* Now disable the cache. */
- LMEM->PSCCR &= ~LMEM_PSCCR_ENCACHE_MASK;
- }
-
- /* Disable MPU */
- ARM_MPU_Disable();
-
- #if defined(CACHE_MODE_WRITE_THROUGH) && CACHE_MODE_WRITE_THROUGH
- /* Region 0 setting: Memory with Normal type, not shareable, write through */
- MPU->RBAR = ARM_MPU_RBAR(0, 0x20200000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_1MB);
-
- /* Region 1 setting: Memory with Normal type, not shareable, write through */
- MPU->RBAR = ARM_MPU_RBAR(1, 0x20300000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_512KB);
-
- /* Region 2 setting: Memory with Normal type, not shareable, write through */
- MPU->RBAR = ARM_MPU_RBAR(2, 0x80000000U);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_64MB);
-
- while ((nonCacheSize >> i) > 0x1U) {
- i++;
- }
-
- if (i != 0) {
- /* The MPU region size should be 2^N, 5<=N<=32, region base should be multiples of size. */
- assert(!(nonCacheStart % nonCacheSize));
- assert(nonCacheSize == (uint32_t) (1 << i));
- assert(i >= 5);
-
- /* Region 3 setting: Memory with device type, not shareable, non-cacheable */
- MPU->RBAR = ARM_MPU_RBAR(3, nonCacheStart);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, i - 1);
- }
-
- #if defined(__USE_SHMEM)
- i = 0;
-
- while ((rpmsgShmemSize >> i) > 0x1U) {
- i++;
- }
-
- if (i != 0) {
- /* The MPU region size should be 2^N, 5<=N<=32, region base should be multiples of size. */
- assert(!(rpmsgShmemStart % rpmsgShmemSize));
- assert(rpmsgShmemSize == (uint32_t) (1 << i));
- assert(i >= 5);
-
- /* Region 4 setting: Memory with device type, not shareable, non-cacheable */
- MPU->RBAR = ARM_MPU_RBAR(4, rpmsgShmemStart);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, i - 1);
- }
- #endif
- #else
- while ((nonCacheSize >> i) > 0x1U) {
- i++;
- }
-
- if (i != 0) {
- /* The MPU region size should be 2^N, 5<=N<=32, region base should be multiples of size. */
- assert(!(nonCacheStart % nonCacheSize));
- assert(nonCacheSize == (uint32_t) (1 << i));
- assert(i >= 5);
-
- /* Region 0 setting: Memory with device type, not shareable, non-cacheable */
- MPU->RBAR = ARM_MPU_RBAR(0, nonCacheStart);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, i - 1);
- }
-
- #if defined(__USE_SHMEM)
- i = 0;
-
- while ((rpmsgShmemSize >> i) > 0x1U) {
- i++;
- }
-
- if (i != 0) {
- /* The MPU region size should be 2^N, 5<=N<=32, region base should be multiples of size. */
- assert(!(rpmsgShmemStart % rpmsgShmemSize));
- assert(rpmsgShmemSize == (uint32_t) (1 << i));
- assert(i >= 5);
-
- /* Region 1 setting: Memory with device type, not shareable, non-cacheable */
- MPU->RBAR = ARM_MPU_RBAR(1, rpmsgShmemStart);
- MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, i - 1);
- }
- #endif
- #endif
-
- /* Enable MPU */
- ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
-
- /* Enables the processor system bus to invalidate all lines in both ways.
- and Initiate the processor system bus cache command. */
- LMEM->PSCCR |= LMEM_PSCCR_INVW0_MASK | LMEM_PSCCR_INVW1_MASK | LMEM_PSCCR_GO_MASK;
- /* Wait until the cache command completes */
- while ((LMEM->PSCCR & LMEM_PSCCR_GO_MASK) != 0U) {
- }
- /* As a precaution clear the bits to avoid inadvertently re-running this command. */
- LMEM->PSCCR &= ~(LMEM_PSCCR_INVW0_MASK | LMEM_PSCCR_INVW1_MASK);
- /* Now enable the system bus cache. */
- LMEM->PSCCR |= LMEM_PSCCR_ENCACHE_MASK;
-
- /* Enables the processor code bus to invalidate all lines in both ways.
- and Initiate the processor code bus code cache command. */
- LMEM->PCCCR |= LMEM_PCCCR_INVW0_MASK | LMEM_PCCCR_INVW1_MASK | LMEM_PCCCR_GO_MASK;
- /* Wait until the cache command completes. */
- while ((LMEM->PCCCR & LMEM_PCCCR_GO_MASK) != 0U) {
- }
- /* As a precaution clear the bits to avoid inadvertently re-running this command. */
- LMEM->PCCCR &= ~(LMEM_PCCCR_INVW0_MASK | LMEM_PCCCR_INVW1_MASK);
- /* Now enable the code bus cache. */
- LMEM->PCCCR |= LMEM_PCCCR_ENCACHE_MASK;
-}
-#endif
-#endif
diff --git a/hw/bsp/imxrt/family.cmake b/hw/bsp/imxrt/family.cmake
index 6224b63a4..feec4973f 100644
--- a/hw/bsp/imxrt/family.cmake
+++ b/hw/bsp/imxrt/family.cmake
@@ -68,8 +68,6 @@ function(add_board_target BOARD_TARGET)
if (NOT M4 STREQUAL "1")
target_compile_definitions(${BOARD_TARGET} PUBLIC
- __ARMVFP__=0
- __ARMFPV5__=0
XIP_EXTERNAL_FLASH=1
XIP_BOOT_HEADER_ENABLE=1
)
diff --git a/hw/bsp/imxrt/family.mk b/hw/bsp/imxrt/family.mk
index 9a2c37121..353f64e57 100644
--- a/hw/bsp/imxrt/family.mk
+++ b/hw/bsp/imxrt/family.mk
@@ -14,8 +14,6 @@ CFLAGS += \
ifneq ($(M4), 1)
CFLAGS += \
- -D__ARMVFP__=0 \
- -D__ARMFPV5__=0 \
-DXIP_EXTERNAL_FLASH=1 \
-DXIP_BOOT_HEADER_ENABLE=1
endif
diff --git a/hw/bsp/rp2040/family.c b/hw/bsp/rp2040/family.c
index a22924131..989140e02 100644
--- a/hw/bsp/rp2040/family.c
+++ b/hw/bsp/rp2040/family.c
@@ -286,6 +286,14 @@ void board_putchar(int c) {
stdio_putchar(c);
}
+void board_init_after_tusb(void) {
+ // nothing to do
+}
+
+void board_reset_to_bootloader(void) {
+ // not implemented
+}
+
//--------------------------------------------------------------------+
// USB Interrupt Handler
// rp2040 implementation will install appropriate handler when initializing
diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake
index 2182e9ad1..3bec5bf70 100644
--- a/hw/bsp/rp2040/family.cmake
+++ b/hw/bsp/rp2040/family.cmake
@@ -95,6 +95,7 @@ target_sources(tinyusb_device_base INTERFACE
${TOP}/src/class/hid/hid_device.c
${TOP}/src/class/midi/midi_device.c
${TOP}/src/class/msc/msc_device.c
+ ${TOP}/src/class/mtp/mtp_device.c
${TOP}/src/class/net/ecm_rndis_device.c
${TOP}/src/class/net/ncm_device.c
${TOP}/src/class/usbtmc/usbtmc_device.c
diff --git a/hw/bsp/samd11/family.cmake b/hw/bsp/samd11/family.cmake
index 965b1cfb5..e3dc23c35 100644
--- a/hw/bsp/samd11/family.cmake
+++ b/hw/bsp/samd11/family.cmake
@@ -54,6 +54,7 @@ function(add_board_target BOARD_TARGET)
OSC32K_OVERWRITE_CALIBRATION=0
CFG_EXAMPLE_MSC_READONLY
CFG_EXAMPLE_VIDEO_READONLY
+ CFG_EXAMPLE_MTP_READONLY
)
update_board(${BOARD_TARGET})
diff --git a/hw/bsp/samd11/family.mk b/hw/bsp/samd11/family.mk
index c41a0dd37..6f89a2d66 100644
--- a/hw/bsp/samd11/family.mk
+++ b/hw/bsp/samd11/family.mk
@@ -8,6 +8,7 @@ CFLAGS += \
-DOSC32K_OVERWRITE_CALIBRATION=0 \
-DCFG_EXAMPLE_MSC_READONLY \
-DCFG_EXAMPLE_VIDEO_READONLY \
+ -DCFG_EXAMPLE_MTP_READONLY \
-DCFG_TUSB_MCU=OPT_MCU_SAMD11
# suppress warning caused by vendor mcu driver
diff --git a/hw/bsp/stm32f7/stm32f7xx_hal_conf.h b/hw/bsp/stm32f7/stm32f7xx_hal_conf.h
index 581f0e46a..9d3397735 100644
--- a/hw/bsp/stm32f7/stm32f7xx_hal_conf.h
+++ b/hw/bsp/stm32f7/stm32f7xx_hal_conf.h
@@ -142,7 +142,7 @@
#define TICK_INT_PRIORITY ((uint32_t)0x0FU) /*!< tick interrupt priority */
#define USE_RTOS 0U
#define PREFETCH_ENABLE 1U
-#define ART_ACCLERATOR_ENABLE 1U /* To enable instruction cache and prefetch */
+#define ART_ACCELERATOR_ENABLE 1U /* To enable instruction cache and prefetch */
#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
#define USE_HAL_CAN_REGISTER_CALLBACKS 0U /* CAN register callback disabled */
diff --git a/hw/bsp/stm32h7/boards/stm32h745disco/board.cmake b/hw/bsp/stm32h7/boards/stm32h745disco/board.cmake
index 39a9d5798..d12a6e587 100644
--- a/hw/bsp/stm32h7/boards/stm32h745disco/board.cmake
+++ b/hw/bsp/stm32h7/boards/stm32h745disco/board.cmake
@@ -1,7 +1,7 @@
set(MCU_VARIANT stm32h745xx)
set(JLINK_DEVICE stm32h745xi_m7)
-set(LD_FILE_GNU ${ST_CMSIS}/Source/Templates/gcc/linker/${MCU_VARIANT}_flash_CM7.ld)
+set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/../../linker/${MCU_VARIANT}_flash_CM7.ld)
set(LD_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/linker/${MCU_VARIANT}_flash_CM7.icf)
function(update_board TARGET)
diff --git a/hw/bsp/stm32h7/boards/stm32h745disco/board.mk b/hw/bsp/stm32h7/boards/stm32h745disco/board.mk
index 588620ce2..64003f5a9 100644
--- a/hw/bsp/stm32h7/boards/stm32h745disco/board.mk
+++ b/hw/bsp/stm32h7/boards/stm32h745disco/board.mk
@@ -6,7 +6,7 @@ CFLAGS += -DSTM32H745xx -DCORE_CM7 -DHSE_VALUE=25000000
# Default is FulSpeed port
PORT ?= 0
-LD_FILE_GCC = $(ST_CMSIS)/Source/Templates/gcc/linker/stm32h745xx_flash_CM7.ld
+LD_FILE_GCC = $(FAMILY_PATH)/linker/${MCU_VARIANT}_flash_CM7.ld
LD_FILE_IAR = $(ST_CMSIS)/Source/Templates/iar/linker/stm32h745xx_flash_CM7.icf
# For flash-jlink target
diff --git a/hw/bsp/stm32h7/linker/stm32h745xx_flash_CM7.ld b/hw/bsp/stm32h7/linker/stm32h745xx_flash_CM7.ld
new file mode 100644
index 000000000..5b7fe4528
--- /dev/null
+++ b/hw/bsp/stm32h7/linker/stm32h745xx_flash_CM7.ld
@@ -0,0 +1,184 @@
+/*
+******************************************************************************
+**
+
+** File : LinkerScript.ld
+**
+**
+** Abstract : Linker script for STM32H7 series
+** 1024Kbytes FLASH and 192Kbytes RAM
+**
+** Set heap size, stack size and stack location according
+** to application requirements.
+**
+** Set memory bank area and size if external memory is used.
+**
+** Target : STMicroelectronics STM32
+**
+** Distribution: The file is distributed as is without any warranty
+** of any kind.
+**
+*****************************************************************************
+** @attention
+**
+** Copyright (c) 2019 STMicroelectronics.
+** All rights reserved.
+**
+** This software is licensed under terms that can be found in the LICENSE file
+** in the root directory of this software component.
+** If no LICENSE file comes with this software, it is provided AS-IS.
+**
+******************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Highest address of the user mode stack */
+_estack = 0x20020000; /* end of RAM */
+/* Generate a link error if heap and stack don't fit into RAM */
+_Min_Heap_Size = 0x200; /* required amount of heap */
+_Min_Stack_Size = 0x400; /* required amount of stack */
+
+/* Specify the memory areas */
+MEMORY
+{
+FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
+ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
+}
+
+/* Define output sections */
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data goes into FLASH */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ } >FLASH
+
+ /* Constant data goes into FLASH */
+ .rodata :
+ {
+ . = ALIGN(4);
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM.extab :
+ {
+ . = ALIGN(4);
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ . = ALIGN(4);
+ } >FLASH
+ .ARM :
+ {
+ . = ALIGN(4);
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ . = ALIGN(4);
+ } >FLASH
+
+ .preinit_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+ .init_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+ .fini_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT(.fini_array.*)))
+ KEEP (*(.fini_array*))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ /* used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* Initialized data sections goes into RAM, load LMA copy after code */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+ } >RAM AT> FLASH
+
+
+ /* Uninitialized data section */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss section */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >RAM
+
+ /* User_heap_stack section, used to check that there is enough RAM left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >RAM
+
+
+
+ /* Remove information from the standard libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
diff --git a/hw/bsp/stm32h7/stm32h7xx_hal_conf.h b/hw/bsp/stm32h7/stm32h7xx_hal_conf.h
index 303dcc137..57b06a8e6 100644
--- a/hw/bsp/stm32h7/stm32h7xx_hal_conf.h
+++ b/hw/bsp/stm32h7/stm32h7xx_hal_conf.h
@@ -1,42 +1,26 @@
/**
******************************************************************************
* @file stm32h7xx_hal_conf_template.h
+ * @author MCD Application Team
* @brief HAL configuration template file.
* This file should be copied to the application folder and renamed
* to stm32h7xx_hal_conf.h.
******************************************************************************
* @attention
*
- * <h2><center>&copy; COPYRIGHT(c) 2019 STMicroelectronics</center></h2>
+ * Copyright (c) 2017 STMicroelectronics.
+ * All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of STMicroelectronics nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
-#ifndef __STM32H7xx_HAL_CONF_H
-#define __STM32H7xx_HAL_CONF_H
+#ifndef STM32H7xx_HAL_CONF_H
+#define STM32H7xx_HAL_CONF_H
#ifdef __cplusplus
extern "C" {
@@ -161,7 +145,7 @@
* frequency, this source is inserted directly through I2S_CKIN pad.
*/
#if !defined (EXTERNAL_CLOCK_VALUE)
- #define EXTERNAL_CLOCK_VALUE 12288000U /*!< Value of the External clock in Hz*/
+ #define EXTERNAL_CLOCK_VALUE 12288000UL /*!< Value of the External clock in Hz*/
#endif /* EXTERNAL_CLOCK_VALUE */
/* Tip: To avoid modifying this file each time you need to use different HSE,
@@ -171,61 +155,75 @@
/**
* @brief This is the HAL system configuration section
*/
-#define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */
-#define TICK_INT_PRIORITY ((uint32_t)0x0F) /*!< tick interrupt priority */
+#define VDD_VALUE (3300UL) /*!< Value of VDD in mv */
+#define TICK_INT_PRIORITY (0x0FUL) /*!< tick interrupt priority */
#define USE_RTOS 0
-#define USE_SD_TRANSCEIVER 1U /*!< use uSD Transceiver */
-#define USE_SPI_CRC 1U /*!< use CRC in SPI */
+#define USE_SD_TRANSCEIVER 0U /*!< use uSD Transceiver */
+#define USE_SPI_CRC 1U /*!< use CRC in SPI */
+#define USE_FLASH_ECC 0U /*!< use ECC error management in FLASH */
+#define USE_SDIO_TRANSCEIVER 0U /*!< use SDIO Transceiver */
+#define SDIO_MAX_IO_NUMBER 7U /*!< SDIO device support maximum IO number */
#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */
#define USE_HAL_COMP_REGISTER_CALLBACKS 0U /* COMP register callback disabled */
+#define USE_HAL_CORDIC_REGISTER_CALLBACKS 0U /* CORDIC register callback disabled */
#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */
#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */
#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U /* DCMI register callback disabled */
#define USE_HAL_DFSDM_REGISTER_CALLBACKS 0U /* DFSDM register callback disabled */
#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U /* DMA2D register callback disabled */
#define USE_HAL_DSI_REGISTER_CALLBACKS 0U /* DSI register callback disabled */
+#define USE_HAL_DTS_REGISTER_CALLBACKS 0U /* DTS register callback disabled */
#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */
#define USE_HAL_FDCAN_REGISTER_CALLBACKS 0U /* FDCAN register callback disabled */
+#define USE_HAL_FMAC_REGISTER_CALLBACKS 0U /* FMAC register callback disabled */
#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */
#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */
#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U /* SDRAM register callback disabled */
#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */
#define USE_HAL_HASH_REGISTER_CALLBACKS 0U /* HASH register callback disabled */
#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */
+#define USE_HAL_GFXMMU_REGISTER_CALLBACKS 0U /* GFXMMU register callback disabled */
#define USE_HAL_HRTIM_REGISTER_CALLBACKS 0U /* HRTIM register callback disabled */
#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */
#define USE_HAL_I2S_REGISTER_CALLBACKS 0U /* I2S register callback disabled */
+#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */
#define USE_HAL_JPEG_REGISTER_CALLBACKS 0U /* JPEG register callback disabled */
#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */
#define USE_HAL_LTDC_REGISTER_CALLBACKS 0U /* LTDC register callback disabled */
#define USE_HAL_MDIOS_REGISTER_CALLBACKS 0U /* MDIO register callback disabled */
+#define USE_HAL_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */
#define USE_HAL_OPAMP_REGISTER_CALLBACKS 0U /* MDIO register callback disabled */
+#define USE_HAL_OSPI_REGISTER_CALLBACKS 0U /* OSPI register callback disabled */
+#define USE_HAL_OTFDEC_REGISTER_CALLBACKS 0U /* OTFDEC register callback disabled */
#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */
#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U /* QSPI register callback disabled */
#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */
#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */
#define USE_HAL_SAI_REGISTER_CALLBACKS 0U /* SAI register callback disabled */
+#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */
+#define USE_HAL_SDIO_REGISTER_CALLBACKS 0U /* SDIO register callback disabled */
+#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */
#define USE_HAL_SPDIFRX_REGISTER_CALLBACKS 0U /* SPDIFRX register callback disabled */
#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U /* SMBUS register callback disabled */
#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */
#define USE_HAL_SWPMI_REGISTER_CALLBACKS 0U /* SWPMI register callback disabled */
#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */
-#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */
-#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */
+#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */
+#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */
#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */
/* ########################### Ethernet Configuration ######################### */
-#define ETH_TX_DESC_CNT 4 /* number of Ethernet Tx DMA descriptors */
-#define ETH_RX_DESC_CNT 4 /* number of Ethernet Rx DMA descriptors */
+#define ETH_TX_DESC_CNT 4U /* number of Ethernet Tx DMA descriptors */
+#define ETH_RX_DESC_CNT 4U /* number of Ethernet Rx DMA descriptors */
-#define ETH_MAC_ADDR0 ((uint8_t)0x02)
-#define ETH_MAC_ADDR1 ((uint8_t)0x00)
-#define ETH_MAC_ADDR2 ((uint8_t)0x00)
-#define ETH_MAC_ADDR3 ((uint8_t)0x00)
-#define ETH_MAC_ADDR4 ((uint8_t)0x00)
-#define ETH_MAC_ADDR5 ((uint8_t)0x00)
+#define ETH_MAC_ADDR0 (0x02UL)
+#define ETH_MAC_ADDR1 (0x00UL)
+#define ETH_MAC_ADDR2 (0x00UL)
+#define ETH_MAC_ADDR3 (0x00UL)
+#define ETH_MAC_ADDR4 (0x00UL)
+#define ETH_MAC_ADDR5 (0x00UL)
/* ########################## Assert Selection ############################## */
/**
@@ -477,7 +475,4 @@
}
#endif
-#endif /* __STM32H7xx_HAL_CONF_H */
-
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+#endif /* STM32H7xx_HAL_CONF_H */
diff --git a/hw/bsp/stm32h7rs/family.mk b/hw/bsp/stm32h7rs/family.mk
index fba38448d..7082cc900 100644
--- a/hw/bsp/stm32h7rs/family.mk
+++ b/hw/bsp/stm32h7rs/family.mk
@@ -43,7 +43,7 @@ CFLAGS += \
-DBOARD_TUD_MAX_SPEED=${RHPORT_DEVICE_SPEED} \
-DBOARD_TUH_RHPORT=${RHPORT_HOST} \
-DBOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED} \
- -DSEGGER_RTT_SECTION="noncacheable_buffer" \
+ -DSEGGER_RTT_SECTION="\"noncacheable_buffer\"" \
-DBUFFER_SIZE_UP=0x300 \
# GCC Flags
diff --git a/hw/bsp/stm32l4/family.c b/hw/bsp/stm32l4/family.c
index 2b555b5c2..5c6ba5c61 100644
--- a/hw/bsp/stm32l4/family.c
+++ b/hw/bsp/stm32l4/family.c
@@ -59,7 +59,9 @@ void board_init(void) {
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
+#if defined(GPIOD)
__HAL_RCC_GPIOD_CLK_ENABLE();
+#endif
#if defined(GPIOE)
__HAL_RCC_GPIOE_CLK_ENABLE();
#endif
diff --git a/hw/bsp/stm32n6/boards/stm32n6570dk/STM32N657XX_AXISRAM2_fsbl.ld b/hw/bsp/stm32n6/boards/stm32n6570dk/STM32N657XX_AXISRAM2_fsbl.ld
new file mode 100644
index 000000000..e4c792cd8
--- /dev/null
+++ b/hw/bsp/stm32n6/boards/stm32n6570dk/STM32N657XX_AXISRAM2_fsbl.ld
@@ -0,0 +1,203 @@
+/*
+******************************************************************************
+**
+** @file : STM32N657XX_AXISRAM2_fsbl.ld
+**
+** @author : GPM Application Team
+**
+** @brief : Linker script for STM32N657XX Device from STM32N6 series
+** 512 KBytes RAM
+**
+** Set heap size, stack size and stack location according
+** to application requirements.
+**
+** Set memory bank area and size if external memory is used
+**
+** Target : STMicroelectronics STM32
+**
+** Distribution: The file is distributed as is, without any warranty
+** of any kind.
+**
+******************************************************************************
+** @attention
+**
+** Copyright (c) 2023 STMicroelectronics.
+** All rights reserved.
+**
+** This software is licensed under terms that can be found in the LICENSE file
+** in the root directory of this software component.
+** If no LICENSE file comes with this software, it is provided AS-IS.
+**
+******************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Highest address of the user mode stack */
+_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
+_sstack = _estack - _Min_Stack_Size;
+
+_Min_Heap_Size = 0x200; /* required amount of heap */
+_Min_Stack_Size = 0x800; /* required amount of stack */
+
+/* Memories definition */
+MEMORY
+{
+ ROM (xrw) : ORIGIN = 0x34180400, LENGTH = 255K
+ RAM (xrw) : ORIGIN = 0x341C0000, LENGTH = 256K
+}
+
+/* Sections */
+SECTIONS
+{
+ /* The startup code into "RAM" Ram type memory */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >ROM
+
+ /* The program code and other data into "RAM" Ram type memory */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+ *(.RamFunc) /* .RamFunc sections */
+ *(.RamFunc*) /* .RamFunc* sections */
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ } >ROM
+
+ /* Constant data into "RAM" Ram type memory */
+ .rodata :
+ {
+ . = ALIGN(4);
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ . = ALIGN(4);
+ } >ROM
+
+ .ARM.extab (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ . = ALIGN(4);
+ } >ROM
+
+ .ARM (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ . = ALIGN(4);
+ } >ROM
+
+ .preinit_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ . = ALIGN(4);
+ } >ROM
+
+ .init_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ . = ALIGN(4);
+ } >ROM
+
+ .fini_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT(.fini_array.*)))
+ KEEP (*(.fini_array*))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ . = ALIGN(4);
+ } >ROM
+
+ /* Used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* Initialized data sections into "RAM" Ram type memory */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+
+ } >RAM AT> ROM
+
+ .noncacheable :
+ {
+ . = ALIGN(8);
+ __snoncacheable = .;/* create symbol for start of section */
+ KEEP(*(.noncacheable))
+ . = ALIGN(8);
+ __enoncacheable = .; /* create symbol for end of section */
+ } > RAM
+
+
+ .gnu.sgstubs :
+ {
+ . = ALIGN(4);
+ *(.gnu.sgstubs*) /* Secure Gateway stubs */
+ . = ALIGN(4);
+ } >ROM
+ /* Uninitialized data section into "RAM" Ram type memory */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss section */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >RAM
+
+ /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >RAM
+
+ /* Remove information from the compiler libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
diff --git a/hw/bsp/stm32n6/boards/stm32n6570dk/board.cmake b/hw/bsp/stm32n6/boards/stm32n6570dk/board.cmake
new file mode 100644
index 000000000..e88efefb9
--- /dev/null
+++ b/hw/bsp/stm32n6/boards/stm32n6570dk/board.cmake
@@ -0,0 +1,17 @@
+set(MCU_VARIANT stm32n657xx)
+set(JLINK_DEVICE stm32n6xx)
+
+set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/STM32N657XX_AXISRAM2_fsbl.ld)
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC
+ STM32N657xx
+ )
+ target_sources(${TARGET} PUBLIC
+ ${ST_TCPP0203}/tcpp0203.c
+ ${ST_TCPP0203}/tcpp0203_reg.c
+ )
+ target_include_directories(${TARGET} PUBLIC
+ ${ST_TCPP0203}
+ )
+endfunction()
diff --git a/hw/bsp/stm32n6/boards/stm32n6570dk/board.h b/hw/bsp/stm32n6/boards/stm32n6570dk/board.h
new file mode 100644
index 000000000..a3d945f76
--- /dev/null
+++ b/hw/bsp/stm32n6/boards/stm32n6570dk/board.h
@@ -0,0 +1,283 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ name: STM32 N6570-DK
+ url: https://www.st.com/en/evaluation-tools/stm32n6570-dk.html
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stm32n657xx.h"
+#include "stm32n6xx_ll_exti.h"
+#include "stm32n6xx_ll_system.h"
+#include "tcpp0203.h"
+
+#define UART_DEV USART1
+#define UART_CLK_EN __HAL_RCC_USART1_CLK_ENABLE
+
+#define BOARD_TUD_RHPORT 1
+
+// VBUS Sense detection
+#define OTG_FS_VBUS_SENSE 1
+#define OTG_HS_VBUS_SENSE 1
+
+#define PINID_LED 0
+#define PINID_BUTTON 1
+#define PINID_UART_TX 2
+#define PINID_UART_RX 3
+#define PINID_TCPP0203_EN 4
+
+static board_pindef_t board_pindef[] = {
+ {// LED
+ .port = GPIOG,
+ .pin_init = {.Pin = GPIO_PIN_10, .Mode = GPIO_MODE_OUTPUT_PP, .Pull = GPIO_PULLDOWN, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0},
+ .active_state = 1},
+ {// Button
+ .port = GPIOC,
+ .pin_init = {.Pin = GPIO_PIN_13, .Mode = GPIO_MODE_INPUT, .Pull = GPIO_PULLDOWN, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0},
+ .active_state = 1},
+ {// UART TX
+ .port = GPIOE,
+ .pin_init = {.Pin = GPIO_PIN_5, .Mode = GPIO_MODE_AF_PP, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_LOW, .Alternate = GPIO_AF7_USART1},
+ .active_state = 0},
+ {// UART RX
+ .port = GPIOE,
+ .pin_init = {.Pin = GPIO_PIN_6, .Mode = GPIO_MODE_AF_PP, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_LOW, .Alternate = GPIO_AF7_USART1},
+ .active_state = 0},
+ {// VBUS input pin used for TCPP0203 EN
+ .port = GPIOA,
+ .pin_init = {.Pin = GPIO_PIN_4, .Mode = GPIO_MODE_OUTPUT_PP, .Pull = GPIO_PULLDOWN, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0},
+ .active_state = 0},
+ {
+ // I2C SCL for TCPP0203
+ .port = GPIOD,
+ .pin_init = {.Pin = GPIO_PIN_14, .Mode = GPIO_MODE_AF_OD, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_LOW, .Alternate = GPIO_AF4_I2C2},
+ },
+ {
+ // I2C SDA for TCPP0203
+ .port = GPIOD,
+ .pin_init = {.Pin = GPIO_PIN_4, .Mode = GPIO_MODE_AF_OD, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_LOW, .Alternate = GPIO_AF4_I2C2},
+ },
+ {
+ // INT for TCPP0203
+ .port = GPIOD,
+ .pin_init = {.Pin = GPIO_PIN_10, .Mode = GPIO_MODE_IT_FALLING, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0},
+ },
+};
+
+//--------------------------------------------------------------------+
+// RCC Clock
+//--------------------------------------------------------------------+
+void SystemClock_Config(void) {
+ RCC_OscInitTypeDef RCC_OscInitStruct = {0};
+ RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
+ /* Configure the power domain */
+ if (HAL_PWREx_ConfigSupply(PWR_EXTERNAL_SOURCE_SUPPLY) != HAL_OK) {
+ Error_Handler();
+ }
+
+ /* Get current CPU/System buses clocks configuration */
+ /* and if necessary switch to intermediate HSI clock */
+ /* to ensure target clock can be set */
+ HAL_RCC_GetClockConfig(&RCC_ClkInitStruct);
+ if ((RCC_ClkInitStruct.CPUCLKSource == RCC_CPUCLKSOURCE_IC1) ||
+ (RCC_ClkInitStruct.SYSCLKSource == RCC_SYSCLKSOURCE_IC2_IC6_IC11)) {
+ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_CPUCLK | RCC_CLOCKTYPE_SYSCLK);
+ RCC_ClkInitStruct.CPUCLKSource = RCC_CPUCLKSOURCE_HSI;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct) != HAL_OK) {
+ Error_Handler();
+ }
+ }
+
+ /* HSE selected as source (stable clock on Level 0 samples */
+ /* PLL1 output = ((HSE/PLLM)*PLLN)/PLLP1/PLLP2 */
+ /* = ((48000000/3)*75)/1/1 */
+ /* = (16000000*75)/1/1 */
+ /* = 1200000000 (1200 MHz) */
+ /* PLL2 off */
+ /* PLL3 off */
+ /* PLL4 off */
+
+ /* Enable HSE && HSI */
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
+ RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
+ RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
+ RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
+ RCC_OscInitStruct.HSEState = RCC_HSE_ON; /* 48 MHz */
+
+ RCC_OscInitStruct.PLL1.PLLState = RCC_PLL_ON;
+ RCC_OscInitStruct.PLL1.PLLSource = RCC_PLLSOURCE_HSE;
+ RCC_OscInitStruct.PLL1.PLLM = 3;
+ RCC_OscInitStruct.PLL1.PLLN = 75; /* PLL1 VCO = 48/3 * 75 = 1200MHz */
+ RCC_OscInitStruct.PLL1.PLLP1 = 1; /* PLL output = PLL VCO frequency / (PLLP1 * PLLP2) */
+ RCC_OscInitStruct.PLL1.PLLP2 = 1; /* PLL output = 1200 MHz */
+ RCC_OscInitStruct.PLL1.PLLFractional = 0;
+
+ if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
+ /* Initialization error */
+ Error_Handler();
+ }
+
+ /* Select PLL1 outputs as CPU and System bus clock source */
+ /* CPUCLK = ic1_ck = PLL1 output/ic1_divider = 600 MHz */
+ /* SYSCLK = ic2_ck = PLL1 output/ic2_divider = 400 MHz */
+ /* Configure the HCLK clock divider */
+ /* HCLK = PLL1 SYSCLK/HCLK divider = 200 MHz */
+ /* PCLKx = HCLK / PCLKx divider = 200 MHz */
+ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_CPUCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK |
+ RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_PCLK4 | RCC_CLOCKTYPE_PCLK5);
+ RCC_ClkInitStruct.CPUCLKSource = RCC_CPUCLKSOURCE_IC1;
+ RCC_ClkInitStruct.IC1Selection.ClockSelection = RCC_ICCLKSOURCE_PLL1;
+ RCC_ClkInitStruct.IC1Selection.ClockDivider = 2;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_IC2_IC6_IC11;
+ RCC_ClkInitStruct.IC2Selection.ClockSelection = RCC_ICCLKSOURCE_PLL1;
+ RCC_ClkInitStruct.IC2Selection.ClockDivider = 3;
+ RCC_ClkInitStruct.IC6Selection.ClockSelection = RCC_ICCLKSOURCE_PLL1;
+ RCC_ClkInitStruct.IC6Selection.ClockDivider = 3;
+ RCC_ClkInitStruct.IC11Selection.ClockSelection = RCC_ICCLKSOURCE_PLL1;
+ RCC_ClkInitStruct.IC11Selection.ClockDivider = 3;
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV1;
+ RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV1;
+ RCC_ClkInitStruct.APB5CLKDivider = RCC_APB5_DIV1;
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct) != HAL_OK) {
+ /* Initialization Error */
+ Error_Handler();
+ }
+
+ /** Initializes the peripherals clock
+ */
+ RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
+ PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USBOTGHS1;
+ PeriphClkInitStruct.UsbOtgHs1ClockSelection = RCC_USBPHY1REFCLKSOURCE_HSE_DIRECT;
+
+ if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
+ /* Initialization Error */
+ Error_Handler();
+ }
+
+ /** Set USB OTG HS PHY1 Reference Clock Source */
+ PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USBPHY1;
+ PeriphClkInitStruct.UsbPhy1ClockSelection = RCC_USBPHY1REFCLKSOURCE_HSE_DIRECT;
+
+ if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
+ /* Initialization Error */
+ Error_Handler();
+ }
+}
+
+//--------------------------------------------------------------------+
+// USB PD
+//--------------------------------------------------------------------+
+static I2C_HandleTypeDef i2c_handle = {
+ .Instance = I2C2,
+ .Init = {
+ .Timing = 0x20C0EDFF,
+ .OwnAddress1 = 0,
+ .AddressingMode = I2C_ADDRESSINGMODE_7BIT,
+ .DualAddressMode = I2C_DUALADDRESS_DISABLE,
+ .OwnAddress2 = 0,
+ .OwnAddress2Masks = I2C_OA2_NOMASK,
+ .GeneralCallMode = I2C_GENERALCALL_DISABLE,
+ .NoStretchMode = I2C_NOSTRETCH_DISABLE,
+ }};
+static TCPP0203_Object_t tcpp0203_obj = {0};
+
+int32_t board_tcpp0203_init(void) {
+ board_pindef_t *pindef = &board_pindef[PINID_TCPP0203_EN];
+ HAL_GPIO_WritePin(pindef->port, pindef->pin_init.Pin, GPIO_PIN_SET);
+
+ __HAL_RCC_I2C2_CLK_ENABLE();
+ __HAL_RCC_I2C2_FORCE_RESET();
+ __HAL_RCC_I2C2_RELEASE_RESET();
+ if (HAL_I2C_Init(&i2c_handle) != HAL_OK) {
+ return HAL_ERROR;
+ }
+
+ NVIC_SetPriority(EXTI10_IRQn, 12);
+ NVIC_EnableIRQ(EXTI10_IRQn);
+
+ return 0;
+}
+
+int32_t board_tcpp0203_deinit(void) {
+ return 0;
+}
+
+int32_t i2c_readreg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
+ TU_ASSERT(HAL_OK == HAL_I2C_Mem_Read(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000));
+ return 0;
+}
+
+int32_t i2c_writereg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
+ TU_ASSERT(HAL_OK == HAL_I2C_Mem_Write(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000));
+ return 0;
+}
+
+static inline void board_init2(void) {
+ TCPP0203_IO_t io_ctx;
+
+ io_ctx.Address = TCPP0203_I2C_ADDRESS_X68;
+ io_ctx.Init = board_tcpp0203_init;
+ io_ctx.DeInit = board_tcpp0203_deinit;
+ io_ctx.ReadReg = i2c_readreg;
+ io_ctx.WriteReg = i2c_writereg;
+
+ TU_ASSERT(TCPP0203_RegisterBusIO(&tcpp0203_obj, &io_ctx) == TCPP0203_OK, );
+
+ TU_ASSERT(TCPP0203_Init(&tcpp0203_obj) == TCPP0203_OK, );
+
+ TU_ASSERT(TCPP0203_SetPowerMode(&tcpp0203_obj, TCPP0203_POWER_MODE_NORMAL) == TCPP0203_OK, );
+}
+
+void board_vbus_set(uint8_t rhport, bool state) {
+ (void) state;
+ if (rhport == 1) {
+ TU_ASSERT(TCPP0203_SetGateDriverProvider(&tcpp0203_obj, TCPP0203_GD_PROVIDER_SWITCH_CLOSED) == TCPP0203_OK, );
+ }
+}
+
+void EXTI10_IRQHandler(void) {
+ __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_10);
+ if (tcpp0203_obj.IsInitialized) {
+ TU_ASSERT(TCPP0203_SetPowerMode(&tcpp0203_obj, TCPP0203_POWER_MODE_NORMAL) == TCPP0203_OK, );
+ TU_ASSERT(TCPP0203_SetGateDriverProvider(&tcpp0203_obj, TCPP0203_GD_PROVIDER_SWITCH_CLOSED) == TCPP0203_OK, );
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/bsp/stm32n6/boards/stm32n6570dk/board.mk b/hw/bsp/stm32n6/boards/stm32n6570dk/board.mk
new file mode 100644
index 000000000..05717699c
--- /dev/null
+++ b/hw/bsp/stm32n6/boards/stm32n6570dk/board.mk
@@ -0,0 +1,17 @@
+MCU_VARIANT = stm32n657xx
+CFLAGS += -DSTM32N657xx
+JLINK_DEVICE = stm32n6xx
+
+LD_FILE_GCC = $(BOARD_PATH)/STM32N657XX_AXISRAM2_fsbl.ld
+
+# flash target using on-board stlink
+flash: flash-stlink
+
+PORT = 1
+
+SRC_C += \
+ $(ST_TCPP0203)/tcpp0203.c \
+ $(ST_TCPP0203)/tcpp0203_reg.c \
+
+INC += \
+ $(TOP)/$(ST_TCPP0203) \
diff --git a/hw/bsp/stm32u0/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/stm32u0/FreeRTOSConfig/FreeRTOSConfig.h
new file mode 100644
index 000000000..b63275276
--- /dev/null
+++ b/hw/bsp/stm32u0/FreeRTOSConfig/FreeRTOSConfig.h
@@ -0,0 +1,149 @@
+/*
+ * FreeRTOS Kernel V10.0.0
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. If you wish to use our Amazon
+ * FreeRTOS name, please do so in a fair use way that does not cause confusion.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://www.FreeRTOS.org
+ * http://aws.amazon.com/freertos
+ *
+ * 1 tab == 4 spaces!
+ */
+
+
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+/*-----------------------------------------------------------
+ * Application specific definitions.
+ *
+ * These definitions should be adjusted for your particular hardware and
+ * application requirements.
+ *
+ * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
+ * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
+ *
+ * See http://www.freertos.org/a00110.html.
+ *----------------------------------------------------------*/
+
+// skip if included from IAR assembler
+#ifndef __IASMARM__
+ #include "stm32u0xx.h"
+#endif
+
+/* Cortex M23/M33 port configuration. */
+#define configENABLE_MPU 0
+#define configENABLE_FPU 0
+#define configENABLE_TRUSTZONE 0
+#define configMINIMAL_SECURE_STACK_SIZE (1024)
+
+#define configUSE_PREEMPTION 1
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
+#define configCPU_CLOCK_HZ SystemCoreClock
+#define configTICK_RATE_HZ ( 1000 )
+#define configMAX_PRIORITIES ( 5 )
+#define configMINIMAL_STACK_SIZE ( 200 )
+#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 )
+#define configMAX_TASK_NAME_LEN 16
+#define configUSE_16_BIT_TICKS 0
+#define configIDLE_SHOULD_YIELD 1
+#define configUSE_MUTEXES 1
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configQUEUE_REGISTRY_SIZE 4
+#define configUSE_QUEUE_SETS 0
+#define configUSE_TIME_SLICING 0
+#define configUSE_NEWLIB_REENTRANT 0
+#define configENABLE_BACKWARD_COMPATIBILITY 1
+#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
+
+#define configSUPPORT_STATIC_ALLOCATION 1
+#define configSUPPORT_DYNAMIC_ALLOCATION 0
+
+/* Hook function related definitions. */
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning
+#define configCHECK_FOR_STACK_OVERFLOW 2
+#define configCHECK_HANDLER_INSTALLATION 0
+
+/* Run time and task stats gathering related definitions. */
+#define configGENERATE_RUN_TIME_STATS 0
+#define configRECORD_STACK_HIGH_ADDRESS 1
+#define configUSE_TRACE_FACILITY 1 // legacy trace
+#define configUSE_STATS_FORMATTING_FUNCTIONS 0
+
+/* Co-routine definitions. */
+#define configUSE_CO_ROUTINES 0
+#define configMAX_CO_ROUTINE_PRIORITIES 2
+
+/* Software timer related definitions. */
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2)
+#define configTIMER_QUEUE_LENGTH 32
+#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
+
+/* Optional functions - most linkers will remove unused functions anyway. */
+#define INCLUDE_vTaskPrioritySet 0
+#define INCLUDE_uxTaskPriorityGet 0
+#define INCLUDE_vTaskDelete 0
+#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY
+#define INCLUDE_xResumeFromISR 0
+#define INCLUDE_vTaskDelayUntil 1
+#define INCLUDE_vTaskDelay 1
+#define INCLUDE_xTaskGetSchedulerState 0
+#define INCLUDE_xTaskGetCurrentTaskHandle 1
+#define INCLUDE_uxTaskGetStackHighWaterMark 0
+#define INCLUDE_xTaskGetIdleTaskHandle 0
+#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
+#define INCLUDE_pcTaskGetTaskName 0
+#define INCLUDE_eTaskGetState 0
+#define INCLUDE_xEventGroupSetBitFromISR 0
+#define INCLUDE_xTimerPendFunctionCall 0
+
+/* FreeRTOS hooks to NVIC vectors */
+#define xPortPendSVHandler PendSV_Handler
+#define xPortSysTickHandler SysTick_Handler
+#define vPortSVCHandler SVC_Handler
+
+//--------------------------------------------------------------------+
+// Interrupt nesting behavior configuration.
+//--------------------------------------------------------------------+
+
+// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header
+#define configPRIO_BITS 2
+
+/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<<configPRIO_BITS) - 1)
+
+/* The highest interrupt priority that can be used by any interrupt service
+routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
+INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
+PRIORITY THAN THIS! (higher priorities are lower numeric values. */
+#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2
+
+/* Interrupt priorities used by the kernel port layer itself. These are generic
+to all Cortex-M ports, and do not rely on any particular library functions. */
+#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+
+/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
+See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+
+#endif
diff --git a/hw/bsp/stm32u0/boards/stm32u083cdk/STM32U083MCTx_FLASH.ld b/hw/bsp/stm32u0/boards/stm32u083cdk/STM32U083MCTx_FLASH.ld
new file mode 100644
index 000000000..c5ea72fb0
--- /dev/null
+++ b/hw/bsp/stm32u0/boards/stm32u083cdk/STM32U083MCTx_FLASH.ld
@@ -0,0 +1,176 @@
+/**
+ ******************************************************************************
+ * @file LinkerScript.ld
+ * @author Auto-generated by STM32CubeIDE
+ * @brief Linker script for STM32U083MCTx Device from STM32U0 series
+ * 256KBytes FLASH
+ * 40KBytes RAM
+ *
+ * Set heap size, stack size and stack location according
+ * to application requirements.
+ *
+ * Set memory bank area and size if external memory is used
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2023 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Memories definition */
+MEMORY
+{
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 40K
+ FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 256K
+}
+
+/* Highest address of the user mode stack */
+_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
+
+_Min_Heap_Size = 0x200; /* required amount of heap */
+_Min_Stack_Size = 0x800; /* required amount of stack */
+
+/* Sections */
+SECTIONS
+{
+ /* The startup code into "FLASH" Rom type memory */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data into "FLASH" Rom type memory */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ } >FLASH
+
+ /* Constant data into "FLASH" Rom type memory */
+ .rodata :
+ {
+ . = ALIGN(4);
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM.extab : {
+ . = ALIGN(4);
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM : {
+ . = ALIGN(4);
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ . = ALIGN(4);
+ } >FLASH
+
+ .preinit_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ .init_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ .fini_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT(.fini_array.*)))
+ KEEP (*(.fini_array*))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ /* Used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* Initialized data sections into "RAM" Ram type memory */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+ *(.RamFunc) /* .RamFunc sections */
+ *(.RamFunc*) /* .RamFunc* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+
+ } >RAM AT> FLASH
+
+ /* Uninitialized data section into "RAM" Ram type memory */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss section */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >RAM
+
+ /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >RAM
+
+ /* Remove information from the compiler libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
diff --git a/hw/bsp/stm32u0/boards/stm32u083cdk/board.cmake b/hw/bsp/stm32u0/boards/stm32u083cdk/board.cmake
new file mode 100644
index 000000000..945146810
--- /dev/null
+++ b/hw/bsp/stm32u0/boards/stm32u083cdk/board.cmake
@@ -0,0 +1,12 @@
+set(MCU_VARIANT stm32u083xx)
+set(JLINK_DEVICE stm32u083mc)
+
+set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/STM32U083MCTx_FLASH.ld)
+set(LD_FILE_IAR ${CMAKE_CURRENT_LIST_DIR}/stm32u083xx_flash.icf)
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC
+ STM32U083xx
+ CFG_EXAMPLE_VIDEO_READONLY
+ )
+endfunction()
diff --git a/hw/bsp/stm32u0/boards/stm32u083cdk/board.h b/hw/bsp/stm32u0/boards/stm32u083cdk/board.h
new file mode 100644
index 000000000..3030b1a1d
--- /dev/null
+++ b/hw/bsp/stm32u0/boards/stm32u083cdk/board.h
@@ -0,0 +1,129 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ name: STM32U083C-DK Discovery Kit
+ url: https://www.st.com/en/evaluation-tools/stm32u083c-dk.html
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// LED - using PA5 (Blue LED from CubeMX)
+#define LED_PORT GPIOA
+#define LED_PIN GPIO_PIN_5
+#define LED_STATE_ON 1
+
+// Button - using PC2 (from CubeMX generated code)
+#define BUTTON_PORT GPIOC
+#define BUTTON_PIN GPIO_PIN_2
+#define BUTTON_STATE_ACTIVE 0 // Active low (pressed = 0)
+
+// UART - using USART2 on PA2/PA3 (VCP TX/RX from CubeMX)
+#define UART_DEV USART2
+#define UART_CLK_EN __HAL_RCC_USART2_CLK_ENABLE
+#define UART_GPIO_PORT GPIOA
+#define UART_GPIO_AF GPIO_AF7_USART2
+#define UART_TX_PIN GPIO_PIN_2
+#define UART_RX_PIN GPIO_PIN_3
+
+//--------------------------------------------------------------------+
+// RCC Clock
+//--------------------------------------------------------------------+
+static inline void board_stm32u0_clock_init(void)
+{
+ RCC_OscInitTypeDef RCC_OscInitStruct = {0};
+ RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
+ RCC_CRSInitTypeDef RCC_CRSInitStruct = {0};
+ RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
+
+ /** Configure the main internal regulator output voltage
+ */
+ HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
+
+ /** Initializes the RCC Oscillators according to the specified parameters
+ * in the RCC_OscInitTypeDef structure.
+ */
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSI48;
+ RCC_OscInitStruct.HSIState = RCC_HSI_ON;
+ RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
+ RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
+ RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
+ RCC_OscInitStruct.PLL.PLLN = 8;
+ RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
+ RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
+ RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV4;
+ HAL_RCC_OscConfig(&RCC_OscInitStruct);
+
+ /** Initializes the CPU, AHB and APB buses clocks
+ */
+ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
+ |RCC_CLOCKTYPE_PCLK1;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
+
+ HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
+
+ /** Enable the CRS clock
+ */
+ __HAL_RCC_CRS_CLK_ENABLE();
+
+ /** Configures CRS
+ */
+ RCC_CRSInitStruct.Prescaler = RCC_CRS_SYNC_DIV1;
+ RCC_CRSInitStruct.Source = RCC_CRS_SYNC_SOURCE_USB;
+ RCC_CRSInitStruct.Polarity = RCC_CRS_SYNC_POLARITY_RISING;
+ RCC_CRSInitStruct.ReloadValue = __HAL_RCC_CRS_RELOADVALUE_CALCULATE(48000000,1000);
+ RCC_CRSInitStruct.ErrorLimitValue = 34;
+ RCC_CRSInitStruct.HSI48CalibrationValue = 32;
+ HAL_RCCEx_CRSConfig(&RCC_CRSInitStruct);
+
+ PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
+ PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
+ HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
+
+ PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
+ PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
+ HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
+}
+
+static inline void board_vbus_sense_init(void)
+{
+ // USB VBUS sensing not required for device-only operation
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* BOARD_H_ */
diff --git a/hw/bsp/stm32u0/boards/stm32u083cdk/board.mk b/hw/bsp/stm32u0/boards/stm32u083cdk/board.mk
new file mode 100644
index 000000000..892854f54
--- /dev/null
+++ b/hw/bsp/stm32u0/boards/stm32u083cdk/board.mk
@@ -0,0 +1,13 @@
+MCU_VARIANT = stm32u083xx
+CFLAGS += \
+ -DSTM32U083xx
+
+# All source paths should be relative to the top level.
+LD_FILE = $(BOARD_PATH)/STM32U083MCTx_FLASH.ld
+LD_FILE_IAR = $(BOARD_PATH)/stm32u083xx_flash.icf
+
+# For flash-jlink target
+JLINK_DEVICE = STM32U083MC
+
+# flash target using on-board stlink
+flash: flash-stlink
diff --git a/hw/bsp/stm32u0/boards/stm32u083cdk/stm32u083xx_flash.icf b/hw/bsp/stm32u0/boards/stm32u083cdk/stm32u083xx_flash.icf
new file mode 100644
index 000000000..cfaa305af
--- /dev/null
+++ b/hw/bsp/stm32u0/boards/stm32u083cdk/stm32u083xx_flash.icf
@@ -0,0 +1,32 @@
+/*###ICF### Section handled by ICF editor, don't touch! ****/
+/*-Editor annotation file-*/
+/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
+/*-Specials-*/
+define symbol __ICFEDIT_intvec_start__ = 0x08000000;
+/*-Memory Regions-*/
+define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
+define symbol __ICFEDIT_region_ROM_end__ = 0x0803FFFF;
+define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
+define symbol __ICFEDIT_region_RAM_end__ = 0x20007FFF;
+
+/*-Sizes-*/
+define symbol __ICFEDIT_size_cstack__ = 0x800;
+define symbol __ICFEDIT_size_heap__ = 0x200;
+/**** End of ICF editor section. ###ICF###*/
+
+
+define memory mem with size = 4G;
+define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
+define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
+
+define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
+define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
+
+initialize by copy { readwrite };
+do not initialize { section .noinit };
+
+place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
+
+place in ROM_region { readonly };
+place in RAM_region { readwrite,
+ block CSTACK, block HEAP };
diff --git a/hw/bsp/stm32u0/family.c b/hw/bsp/stm32u0/family.c
new file mode 100644
index 000000000..bf2503865
--- /dev/null
+++ b/hw/bsp/stm32u0/family.c
@@ -0,0 +1,182 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ manufacturer: STMicroelectronics
+*/
+
+#include "stm32u0xx_hal.h"
+#include "bsp/board_api.h"
+#include "board.h"
+
+//--------------------------------------------------------------------+
+// Forward USB interrupt events to TinyUSB IRQ Handler
+//--------------------------------------------------------------------+
+void USB_DRD_FS_IRQHandler(void) {
+ tud_int_handler(0);
+}
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
+#ifdef UART_DEV
+UART_HandleTypeDef UartHandle;
+#endif
+
+void board_init(void) {
+ board_stm32u0_clock_init();
+
+ // Enable All GPIOs clocks
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+ __HAL_RCC_GPIOC_CLK_ENABLE();
+#ifdef GPIOD
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+#endif
+#ifdef GPIOE
+ __HAL_RCC_GPIOE_CLK_ENABLE();
+#endif
+#ifdef GPIOF
+ __HAL_RCC_GPIOF_CLK_ENABLE();
+#endif
+#ifdef GPIOG
+ __HAL_RCC_GPIOG_CLK_ENABLE();
+#endif
+#ifdef GPIOH
+ __HAL_RCC_GPIOH_CLK_ENABLE();
+#endif
+ __HAL_RCC_PWR_CLK_ENABLE();
+
+ // LED
+ GPIO_InitTypeDef GPIO_InitStruct;
+ GPIO_InitStruct.Pin = LED_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
+
+ // Button
+ GPIO_InitStruct.Pin = BUTTON_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = BUTTON_STATE_ACTIVE ? GPIO_PULLDOWN : GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ HAL_GPIO_Init(BUTTON_PORT, &GPIO_InitStruct);
+
+#ifdef UART_DEV
+ // UART
+ GPIO_InitStruct.Pin = UART_TX_PIN | UART_RX_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ GPIO_InitStruct.Alternate = UART_GPIO_AF;
+ HAL_GPIO_Init(UART_GPIO_PORT, &GPIO_InitStruct);
+
+ UART_CLK_EN();
+ UartHandle.Instance = UART_DEV;
+ UartHandle.Init.BaudRate = CFG_BOARD_UART_BAUDRATE;
+ UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
+ UartHandle.Init.StopBits = UART_STOPBITS_1;
+ UartHandle.Init.Parity = UART_PARITY_NONE;
+ UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
+ UartHandle.Init.Mode = UART_MODE_TX_RX;
+ UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
+ HAL_UART_Init(&UartHandle);
+#endif
+
+#if CFG_TUSB_OS == OPT_OS_FREERTOS
+ // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
+ NVIC_SetPriority(USB_DRD_FS_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
+#endif
+
+ // USB Pins TODO double check USB clock and pin setup
+ // Configure USB DM and DP pins. This is optional, and maintained only for user guidance.
+ GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12);
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF10_USB;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+ // Enable VDDUSB
+ HAL_PWREx_EnableVddUSB();
+ // USB Clock enable
+ __HAL_RCC_USB_CLK_ENABLE();
+
+ board_vbus_sense_init();
+}
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+
+void board_led_write(bool state) {
+ GPIO_PinState pin_state = (GPIO_PinState) (state ? LED_STATE_ON : (1-LED_STATE_ON));
+ HAL_GPIO_WritePin(LED_PORT, LED_PIN, pin_state);
+}
+
+uint32_t board_button_read(void) {
+ return BUTTON_STATE_ACTIVE == HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN);
+}
+
+int board_uart_read(uint8_t* buf, int len) {
+#ifdef UART_DEV
+ (void) buf; (void) len;
+ return 0;
+#else
+ return 0;
+#endif
+}
+
+int board_uart_write(void const * buf, int len) {
+#ifdef UART_DEV
+ HAL_UART_Transmit(&UartHandle, (uint8_t*)(uintptr_t) buf, len, 0xffff);
+ return len;
+#else
+ (void) buf; (void) len;
+ return 0;
+#endif
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+void SysTick_Handler(void) {
+ system_ticks++;
+}
+
+uint32_t board_millis(void) {
+ return system_ticks;
+}
+#endif
+
+void HardFault_Handler(void) {
+ __asm("BKPT #0\n");
+}
+
+// Required by __libc_init_array in startup code if we are compiling using
+// -nostdlib/-nostartfiles.
+void _init(void) {
+
+}
diff --git a/hw/bsp/stm32u0/family.cmake b/hw/bsp/stm32u0/family.cmake
new file mode 100644
index 000000000..fefaea9de
--- /dev/null
+++ b/hw/bsp/stm32u0/family.cmake
@@ -0,0 +1,117 @@
+include_guard()
+
+set(ST_FAMILY u0)
+set(ST_PREFIX stm32${ST_FAMILY}xx)
+
+set(ST_HAL_DRIVER ${TOP}/hw/mcu/st/stm32${ST_FAMILY}xx_hal_driver)
+set(ST_CMSIS ${TOP}/hw/mcu/st/cmsis-device-${ST_FAMILY})
+set(CMSIS_5 ${TOP}/lib/CMSIS_5)
+
+# include board specific
+include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
+
+# toolchain set up
+set(CMAKE_SYSTEM_CPU cortex-m0plus CACHE INTERNAL "System Processor")
+set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
+
+set(FAMILY_MCUS STM32U0 CACHE INTERNAL "")
+
+
+#------------------------------------
+# BOARD_TARGET
+#------------------------------------
+# only need to be built ONCE for all examples
+function(add_board_target BOARD_TARGET)
+ if (TARGET ${BOARD_TARGET})
+ return()
+ endif()
+
+ # Startup & Linker script
+ set(STARTUP_FILE_GNU ${ST_CMSIS}/Source/Templates/gcc/startup_${MCU_VARIANT}.s)
+ set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
+ set(STARTUP_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/startup_${MCU_VARIANT}.s)
+
+ string(REPLACE "stm32u" "STM32U" MCU_VARIANT_UPPER ${MCU_VARIANT})
+ if (NOT DEFINED LD_FILE_GNU)
+ set(LD_FILE_GNU ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/linker/${MCU_VARIANT_UPPER}_FLASH.ld)
+ endif ()
+ set(LD_FILE_Clang ${LD_FILE_GNU})
+ if (NOT DEFINED LD_FILE_IAR)
+ set(LD_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf)
+ endif ()
+
+ add_library(${BOARD_TARGET} STATIC
+ ${ST_CMSIS}/Source/Templates/system_${ST_PREFIX}.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_cortex.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_gpio.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_pwr_ex.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_rcc.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_rcc_ex.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_uart.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_uart_ex.c
+ ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
+ )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMSIS_5}/CMSIS/Core/Include
+ ${ST_CMSIS}/Include
+ ${ST_HAL_DRIVER}/Inc
+ )
+ update_board(${BOARD_TARGET})
+
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--script=${LD_FILE_GNU}"
+ -nostartfiles
+ --specs=nosys.specs --specs=nano.specs
+ )
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--script=${LD_FILE_Clang}"
+ )
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--config=${LD_FILE_IAR}"
+ )
+ endif ()
+endfunction()
+
+
+#------------------------------------
+# Functions
+#------------------------------------
+function(family_configure_example TARGET RTOS)
+ family_configure_common(${TARGET} ${RTOS})
+
+ # Board target
+ add_board_target(board_${BOARD})
+
+ #---------- Port Specific ----------
+ # These files are built for each example since it depends on example's tusb_config.h
+ target_sources(${TARGET} PUBLIC
+ # BSP
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
+ )
+ target_include_directories(${TARGET} PUBLIC
+ # family, hw, board
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
+ )
+
+ # Add TinyUSB target and port source
+ family_add_tinyusb(${TARGET} OPT_MCU_STM32U0)
+ target_sources(${TARGET} PUBLIC
+ ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+ )
+ target_link_libraries(${TARGET} PUBLIC board_${BOARD})
+
+
+
+ # Flashing
+ family_add_bin_hex(${TARGET})
+ family_flash_stlink(${TARGET})
+ family_flash_jlink(${TARGET})
+endfunction()
diff --git a/hw/bsp/stm32u0/family.mk b/hw/bsp/stm32u0/family.mk
new file mode 100644
index 000000000..d5a850050
--- /dev/null
+++ b/hw/bsp/stm32u0/family.mk
@@ -0,0 +1,50 @@
+ST_FAMILY = u0
+ST_CMSIS = hw/mcu/st/cmsis-device-$(ST_FAMILY)
+ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+CPU_CORE ?= cortex-m0plus
+
+CFLAGS += \
+ -DCFG_EXAMPLE_MSC_READONLY \
+ -DCFG_EXAMPLE_VIDEO_READONLY \
+ -DCFG_TUSB_MCU=OPT_MCU_STM32U0
+
+# mcu driver cause following warnings
+CFLAGS_GCC += \
+ -flto \
+ -Wno-error=unused-parameter \
+ -Wno-error=redundant-decls \
+ -Wno-error=cast-align \
+ -Wno-error=maybe-uninitialized \
+
+CFLAGS_CLANG += \
+ -Wno-error=parentheses-equality
+
+LDFLAGS_GCC += \
+ -nostdlib -nostartfiles \
+ --specs=nosys.specs --specs=nano.specs
+
+SRC_C += \
+ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \
+ $(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \
+ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \
+ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_cortex.c \
+ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_rcc.c \
+ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_rcc_ex.c \
+ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_gpio.c \
+ ${ST_HAL_DRIVER}/Src/stm32$(ST_FAMILY)xx_hal_pwr_ex.c \
+ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_uart.c
+
+INC += \
+ $(TOP)/$(BOARD_PATH) \
+ $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
+ $(TOP)/$(ST_CMSIS)/Include \
+ $(TOP)/$(ST_HAL_DRIVER)/Inc
+
+# Startup
+SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}.s
+SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_${MCU_VARIANT}.s
+
+# Linker
+LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash.icf
diff --git a/hw/bsp/stm32u0/stm32u0xx_hal_conf.h b/hw/bsp/stm32u0/stm32u0xx_hal_conf.h
new file mode 100644
index 000000000..ece5baf69
--- /dev/null
+++ b/hw/bsp/stm32u0/stm32u0xx_hal_conf.h
@@ -0,0 +1,337 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * @file stm32u0xx_hal_conf.h
+ * @author MCD Application Team
+ * @brief HAL configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2023 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+/* USER CODE END Header */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32U0xx_HAL_CONF_H
+#define __STM32U0xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* ########################## Module Selection ############################## */
+/**
+ * @brief This is the list of modules to be used in the HAL driver
+ */
+
+#define HAL_MODULE_ENABLED
+/* #define HAL_ADC_MODULE_ENABLED */
+/* #define HAL_COMP_MODULE_ENABLED */
+/* #define HAL_CRC_MODULE_ENABLED */
+/* #define HAL_CRS_MODULE_ENABLED */
+/* #define HAL_CRYP_MODULE_ENABLED */
+/* #define HAL_DAC_MODULE_ENABLED */
+/* #define HAL_I2C_MODULE_ENABLED */
+/* #define HAL_IRDA_MODULE_ENABLED */
+/* #define HAL_IWDG_MODULE_ENABLED */
+/* #define HAL_LCD_MODULE_ENABLED */
+/* #define HAL_LPTIM_MODULE_ENABLED */
+/* #define HAL_OPAMP_MODULE_ENABLED */
+#define HAL_PCD_MODULE_ENABLED
+/* #define HAL_RNG_MODULE_ENABLED */
+/* #define HAL_RTC_MODULE_ENABLED */
+/* #define HAL_SPI_MODULE_ENABLED */
+/* #define HAL_SMARTCARD_MODULE_ENABLED */
+/* #define HAL_TIM_MODULE_ENABLED */
+/* #define HAL_TSC_MODULE_ENABLED */
+#define HAL_UART_MODULE_ENABLED
+/* #define HAL_USART_MODULE_ENABLED */
+/* #define HAL_WWDG_MODULE_ENABLED */
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_EXTI_MODULE_ENABLED
+#define HAL_DMA_MODULE_ENABLED
+#define HAL_RCC_MODULE_ENABLED
+#define HAL_FLASH_MODULE_ENABLED
+#define HAL_PWR_MODULE_ENABLED
+#define HAL_CORTEX_MODULE_ENABLED
+
+/* ########################## Oscillator Values adaptation ####################*/
+/**
+ * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSE is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSE_VALUE)
+ #define HSE_VALUE 4000000U /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSE_STARTUP_TIMEOUT)
+ #define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief Internal Multiple Speed oscillator (MSI) default value.
+ * This value is the default MSI range value after Reset.
+ */
+#if !defined (MSI_VALUE)
+ #define MSI_VALUE 4000000U /*!< Value of the Internal oscillator in Hz*/
+#endif /* MSI_VALUE */
+
+/**
+ * @brief Internal Multiple Speed oscillator (MSI) default value.
+ * This value is the default MSI range value after Reset.
+ */
+#if !defined (MSI32_VALUE)
+#define MSI32_VALUE 32000000U /*!< Value of the Internal oscillator in Hz*/
+#endif /* MSI32_VALUE */
+
+/**
+ * @brief Internal High Speed oscillator (HSI) value.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSI is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSI_VALUE)
+ #define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+/**
+ * @brief Internal High Speed oscillator (HSI48) value for USB FS and RNG.
+ * This internal oscillator is mainly dedicated to provide a high precision clock to
+ * the USB peripheral by means of a special Clock Recovery System (CRS) circuitry.
+ * When the CRS is not used, the HSI48 RC oscillator runs on it default frequency
+ * which is subject to manufacturing process variations.
+ */
+#if !defined (HSI48_VALUE)
+ #define HSI48_VALUE 48000000U /*!< Value of the Internal High Speed oscillator for USB FS/RNG in Hz.
+ The real value my vary depending on manufacturing process variations.*/
+#endif /* HSI48_VALUE */
+
+/**
+ * @brief Internal Low Speed oscillator (LSI) value.
+ */
+#if !defined (LSI_VALUE)
+ #define LSI_VALUE 32000U /*!< LSI Typical Value in Hz*/
+#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
+ The real value may vary depending on the variations
+ in voltage and temperature.*/
+/**
+ * @brief External Low Speed oscillator (LSE) value.
+ * This value is used by the UART, RTC HAL module to compute the system frequency
+ */
+#if !defined (LSE_VALUE)
+ #define LSE_VALUE 32768U /*!< Value of the External oscillator in Hz*/
+#endif /* LSE_VALUE */
+
+#if !defined (LSE_STARTUP_TIMEOUT)
+ #define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */
+#endif /* LSE_STARTUP_TIMEOUT */
+
+/* Tip: To avoid modifying this file each time you need to use different HSE,
+ === you can define the HSE value in your toolchain compiler preprocessor. */
+
+/* ########################### System Configuration ######################### */
+/**
+ * @brief This is the HAL system configuration section
+ */
+
+#define VDD_VALUE 3300U /*!< Value of VDD in mv */
+#define TICK_INT_PRIORITY (3U) /*!< tick interrupt priority (lowest by default) */
+#define USE_RTOS 0U
+#define PREFETCH_ENABLE 0U
+#define INSTRUCTION_CACHE_ENABLE 1U
+
+/* ########################## Assert Selection ############################## */
+/**
+ * @brief Uncomment the line below to expanse the "assert_param" macro in the
+ * HAL drivers code
+ */
+
+/* #define USE_FULL_ASSERT 1U */
+
+/* ################## Register callback feature configuration ############### */
+/**
+ * @brief Set below the peripheral configuration to "1U" to add the support
+ * of HAL callback registration/unregistration feature for the HAL
+ * driver(s). This allows user application to provide specific callback
+ * functions thanks to HAL_PPP_RegisterCallback() rather than overwriting
+ * the default weak callback functions (see each stm32u0xx_hal_ppp.h file
+ * for possible callback identifiers defined in HAL_PPP_CallbackIDTypeDef
+ * for each PPP peripheral).
+ */
+#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
+#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */
+#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */
+#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */
+#define USE_HAL_IWDG_REGISTER_CALLBACKS 0U /* IWDG register callback disabled */
+#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */
+#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */
+#define USE_HAL_LCD_REGISTER_CALLBACKS 0U /* LCD register callback disabled */
+#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */
+#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */
+#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */
+#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */
+#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */
+#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */
+#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */
+#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */
+#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */
+
+/* Includes ------------------------------------------------------------------*/
+/**
+ * @brief Include module's header file
+ */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+#include "stm32u0xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+#include "stm32u0xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+#include "stm32u0xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+#include "stm32u0xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+#include "stm32u0xx_hal_adc.h"
+#include "stm32u0xx_hal_adc_ex.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_COMP_MODULE_ENABLED
+#include "stm32u0xx_hal_comp.h"
+#endif /* HAL_COMP_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+#include "stm32u0xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRS_MODULE_ENABLED
+#include "stm32u0xx_ll_crs.h"
+#endif /* HAL_CRS_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+#include "stm32u0xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DAC_MODULE_ENABLED
+#include "stm32u0xx_hal_dac.h"
+#endif /* HAL_DAC_MODULE_ENABLED */
+
+#ifdef HAL_EXTI_MODULE_ENABLED
+#include "stm32u0xx_hal_exti.h"
+#endif /* HAL_EXTI_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+#include "stm32u0xx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+#include "stm32u0xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+#include "stm32u0xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LPTIM_MODULE_ENABLED
+#include "stm32u0xx_hal_lptim.h"
+#endif /* HAL_LPTIM_MODULE_ENABLED */
+
+#ifdef HAL_LCD_MODULE_ENABLED
+#include "stm32u0xx_hal_lcd.h"
+#endif /* HAL_LCD_MODULE_ENABLED */
+
+#ifdef HAL_OPAMP_MODULE_ENABLED
+#include "stm32u0xx_hal_opamp.h"
+#endif /* HAL_OPAMP_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+#include "stm32u0xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+#include "stm32u0xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+#include "stm32u0xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+#include "stm32u0xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+#include "stm32u0xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_TSC_MODULE_ENABLED
+#include "stm32u0xx_ll_system.h"
+#include "stm32u0xx_hal_tsc.h"
+#endif /* HAL_TSC_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+#include "stm32u0xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+#include "stm32u0xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+#include "stm32u0xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+#include "stm32u0xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+#include "stm32u0xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_LCD_MODULE_ENABLED
+#include "stm32u0xx_hal_lcd.h"
+#endif /* HAL_LCD_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+#include "stm32u0xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+ #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(uint8_t *file, uint32_t line);
+#else
+ #define assert_param(expr) ((void)0U)
+#endif /* USE_FULL_ASSERT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32U0xx_HAL_CONF_H */
diff --git a/hw/bsp/stm32wba/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/stm32wba/FreeRTOSConfig/FreeRTOSConfig.h
new file mode 100644
index 000000000..471d56aec
--- /dev/null
+++ b/hw/bsp/stm32wba/FreeRTOSConfig/FreeRTOSConfig.h
@@ -0,0 +1,153 @@
+/*
+ * FreeRTOS Kernel V10.0.0
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. If you wish to use our Amazon
+ * FreeRTOS name, please do so in a fair use way that does not cause confusion.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://www.FreeRTOS.org
+ * http://aws.amazon.com/freertos
+ *
+ * 1 tab == 4 spaces!
+ */
+
+
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+/*-----------------------------------------------------------
+ * Application specific definitions.
+ *
+ * These definitions should be adjusted for your particular hardware and
+ * application requirements.
+ *
+ * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
+ * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
+ *
+ * See http://www.freertos.org/a00110.html.
+ *----------------------------------------------------------*/
+
+// skip if included from IAR assembler
+#ifndef __IASMARM__
+ #include "stm32wbaxx.h"
+#endif
+
+/* Cortex M23/M33 port configuration. */
+#define configENABLE_MPU 0
+#if defined(__ARM_FP) && __ARM_FP >= 4
+ #define configENABLE_FPU 1
+#else
+ #define configENABLE_FPU 0
+#endif
+#define configENABLE_TRUSTZONE 0
+#define configMINIMAL_SECURE_STACK_SIZE (1024)
+
+#define configUSE_PREEMPTION 1
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
+#define configCPU_CLOCK_HZ SystemCoreClock
+#define configTICK_RATE_HZ ( 1000 )
+#define configMAX_PRIORITIES ( 5 )
+#define configMINIMAL_STACK_SIZE ( 128 )
+#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 )
+#define configMAX_TASK_NAME_LEN 16
+#define configUSE_16_BIT_TICKS 0
+#define configIDLE_SHOULD_YIELD 1
+#define configUSE_MUTEXES 1
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configQUEUE_REGISTRY_SIZE 4
+#define configUSE_QUEUE_SETS 0
+#define configUSE_TIME_SLICING 0
+#define configUSE_NEWLIB_REENTRANT 0
+#define configENABLE_BACKWARD_COMPATIBILITY 1
+#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
+
+#define configSUPPORT_STATIC_ALLOCATION 1
+#define configSUPPORT_DYNAMIC_ALLOCATION 0
+
+/* Hook function related definitions. */
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning
+#define configCHECK_FOR_STACK_OVERFLOW 2
+#define configCHECK_HANDLER_INSTALLATION 0
+
+/* Run time and task stats gathering related definitions. */
+#define configGENERATE_RUN_TIME_STATS 0
+#define configRECORD_STACK_HIGH_ADDRESS 1
+#define configUSE_TRACE_FACILITY 1 // legacy trace
+#define configUSE_STATS_FORMATTING_FUNCTIONS 0
+
+/* Co-routine definitions. */
+#define configUSE_CO_ROUTINES 0
+#define configMAX_CO_ROUTINE_PRIORITIES 2
+
+/* Software timer related definitions. */
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2)
+#define configTIMER_QUEUE_LENGTH 32
+#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
+
+/* Optional functions - most linkers will remove unused functions anyway. */
+#define INCLUDE_vTaskPrioritySet 0
+#define INCLUDE_uxTaskPriorityGet 0
+#define INCLUDE_vTaskDelete 0
+#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY
+#define INCLUDE_xResumeFromISR 0
+#define INCLUDE_vTaskDelayUntil 1
+#define INCLUDE_vTaskDelay 1
+#define INCLUDE_xTaskGetSchedulerState 0
+#define INCLUDE_xTaskGetCurrentTaskHandle 1
+#define INCLUDE_uxTaskGetStackHighWaterMark 0
+#define INCLUDE_xTaskGetIdleTaskHandle 0
+#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
+#define INCLUDE_pcTaskGetTaskName 0
+#define INCLUDE_eTaskGetState 0
+#define INCLUDE_xEventGroupSetBitFromISR 0
+#define INCLUDE_xTimerPendFunctionCall 0
+
+/* FreeRTOS hooks to NVIC vectors */
+#define xPortPendSVHandler PendSV_Handler
+#define xPortSysTickHandler SysTick_Handler
+#define vPortSVCHandler SVC_Handler
+
+//--------------------------------------------------------------------+
+// Interrupt nesting behavior configuration.
+//--------------------------------------------------------------------+
+
+// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header
+#define configPRIO_BITS 4
+
+/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<<configPRIO_BITS) - 1)
+
+/* The highest interrupt priority that can be used by any interrupt service
+routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
+INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
+PRIORITY THAN THIS! (higher priorities are lower numeric values. */
+#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2
+
+/* Interrupt priorities used by the kernel port layer itself. These are generic
+to all Cortex-M ports, and do not rely on any particular library functions. */
+#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+
+/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
+See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+
+#endif
diff --git a/hw/bsp/stm32wba/boards/stm32wba_nucleo/board.cmake b/hw/bsp/stm32wba/boards/stm32wba_nucleo/board.cmake
new file mode 100644
index 000000000..57bd920d3
--- /dev/null
+++ b/hw/bsp/stm32wba/boards/stm32wba_nucleo/board.cmake
@@ -0,0 +1,8 @@
+set(MCU_VARIANT stm32wba65xx)
+set(JLINK_DEVICE STM32WBA65RI)
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC
+ STM32WBA65xx
+ )
+endfunction()
diff --git a/hw/bsp/stm32wba/boards/stm32wba_nucleo/board.h b/hw/bsp/stm32wba/boards/stm32wba_nucleo/board.h
new file mode 100644
index 000000000..eb0622399
--- /dev/null
+++ b/hw/bsp/stm32wba/boards/stm32wba_nucleo/board.h
@@ -0,0 +1,136 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025, Dalton Caron
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+ /* metadata:
+ name: STM32 NUCLEO-WBA65RI
+ url: https://www.st.com/en/evaluation-tools/nucleo-wba65ri.html
+ */
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // LED (user LED 1)
+#define LED_CLK_EN __HAL_RCC_GPIOD_CLK_ENABLE
+#define LED_PORT GPIOD
+#define LED_PIN GPIO_PIN_8
+#define LED_STATE_ON 1
+
+// Button (user button 1)
+#define BUTTON_CLK_EN __HAL_RCC_GPIOC_CLK_ENABLE
+#define BUTTON_PORT GPIOC
+#define BUTTON_PIN GPIO_PIN_13
+#define BUTTON_STATE_ACTIVE 0
+
+// USART (on STM link USB connector)
+#define USART_GPIO_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE
+#define USART_DEV USART3
+#define USART_CLK_EN __HAL_RCC_USART3_CLK_ENABLE
+#define USART_TX_GPIO_PORT GPIOA
+#define USART_RX_GPIO_PORT GPIOA
+#define USART_GPIO_AF GPIO_AF8_USART3
+#define USART_TX_PIN GPIO_PIN_7
+#define USART_RX_PIN GPIO_PIN_5
+
+// USB Pins
+// These pints are only used for USB and must be in analog mode when not used.
+// They are by default configured for USB operation after reset.
+#define USB_DP_PORT GPIOD
+#define USB_DP_PIN GPIO_PIN_6
+
+#define USB_DM_PORT GPIOD
+#define USB_DM_PIN GPIO_PIN_7
+
+//--------------------------------------------------------------------+
+// The system clock is configured as follows:
+// System Clock source = PLL (HSE, crystal)
+// SYSCLK (CPU Clock) = 64 MHz
+// HCLK (AXI and AHB Clocks) = 64 MHz
+// AHB Prescaler = 1
+// APB1 Prescaler = 1 (APB3 Clock = 64MHz)
+// APB2 Prescaler = 1 (APB1 Clock = 64MHz)
+// APB7 Prescaler = 1 (APB2 Clock = 64MHz)
+// HPRE5 Prescaler = 2 (AHB5 Clock = 32MHz)
+// HSE Frequency (Hz) = 32 MHz
+// PLL_M = 2
+// PLL_N = 8
+// PLL_P = 2
+// PLL_Q = 2
+// PLL_R = 2
+// VDD (V) = 3.3 V
+// Flash Latency = 1 Wait States
+//--------------------------------------------------------------------+
+static void board_system_clock_config( void )
+{
+ RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
+ RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };
+
+ __HAL_RCC_SYSCFG_CLK_ENABLE();
+ __HAL_RCC_PWR_CLK_ENABLE();
+
+ ( void ) HAL_PWREx_ConfigSupply( PWR_LDO_SUPPLY );
+
+ // Must be in voltage scaling mode 1 for the OTG USB HS peripheral to function
+ ( void ) HAL_PWREx_ControlVoltageScaling( PWR_REGULATOR_VOLTAGE_SCALE1 );
+
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
+ RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+ RCC_OscInitStruct.HSEDiv = RCC_HSE_DIV1;
+ RCC_OscInitStruct.PLL1.PLLState = RCC_PLL_ON;
+ RCC_OscInitStruct.PLL1.PLLSource = RCC_PLLSOURCE_HSE;
+ RCC_OscInitStruct.PLL1.PLLM = 2;
+ RCC_OscInitStruct.PLL1.PLLN = 8;
+ RCC_OscInitStruct.PLL1.PLLP = 2;
+ RCC_OscInitStruct.PLL1.PLLQ = 2;
+ RCC_OscInitStruct.PLL1.PLLR = 2;
+ RCC_OscInitStruct.PLL1.PLLFractional = 0;
+ ( void ) HAL_RCC_OscConfig( &RCC_OscInitStruct );
+
+ RCC_ClkInitStruct.ClockType = ( RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
+ | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2
+ | RCC_CLOCKTYPE_PCLK7 | RCC_CLOCKTYPE_HCLK5 );
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
+ RCC_ClkInitStruct.APB7CLKDivider = RCC_HCLK_DIV1;
+ RCC_ClkInitStruct.AHB5_PLL1_CLKDivider = RCC_SYSCLK_PLL1_DIV2;
+ RCC_ClkInitStruct.AHB5_HSEHSI_CLKDivider = RCC_SYSCLK_HSEHSI_DIV1;
+
+ ( void ) HAL_RCC_ClockConfig( &RCC_ClkInitStruct, FLASH_LATENCY_1 );
+
+ ( void ) SystemCoreClockUpdate();
+
+ ( void ) HAL_ICACHE_Enable();
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BOARD_H_ */
diff --git a/hw/bsp/stm32wba/boards/stm32wba_nucleo/board.mk b/hw/bsp/stm32wba/boards/stm32wba_nucleo/board.mk
new file mode 100644
index 000000000..dc8463ca0
--- /dev/null
+++ b/hw/bsp/stm32wba/boards/stm32wba_nucleo/board.mk
@@ -0,0 +1,6 @@
+MCU_VARIANT = stm32wba65xx
+
+CFLAGS += -DSTM32WBA65xx
+
+# For flash-jlink target
+JLINK_DEVICE = STM32WBA65RI
diff --git a/hw/bsp/stm32wba/family.c b/hw/bsp/stm32wba/family.c
new file mode 100644
index 000000000..923ea197c
--- /dev/null
+++ b/hw/bsp/stm32wba/family.c
@@ -0,0 +1,216 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Dalton Caron
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ manufacturer: STMicroelectronics
+*/
+
+#include <stdbool.h>
+
+#include "stm32wbaxx_hal.h"
+#include "bsp/board_api.h"
+#include "board.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
+#ifndef USART_TIMEOUT_TICKS
+#define USART_TIMEOUT_TICKS 1000
+#endif
+
+static UART_HandleTypeDef uart_handle;
+
+//--------------------------------------------------------------------+
+// Forward USB interrupt events to TinyUSB IRQ Handler
+//--------------------------------------------------------------------+
+void USB_OTG_HS_IRQHandler(void) {
+ tud_int_handler(0);
+}
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+
+static void board_gpio_configuration(void) {
+ GPIO_InitTypeDef gpio_init = {0};
+
+ USART_GPIO_CLK_EN();
+ USART_CLK_EN();
+
+ // Configure USART TX pin
+ gpio_init.Pin = USART_TX_PIN;
+ gpio_init.Mode = GPIO_MODE_AF_PP;
+ gpio_init.Pull = GPIO_NOPULL;
+ gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
+ gpio_init.Alternate = USART_GPIO_AF;
+ HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init);
+
+ // Configure USART RX pin
+ gpio_init.Pin = USART_RX_PIN;
+ gpio_init.Mode = GPIO_MODE_AF_PP;
+ gpio_init.Pull = GPIO_PULLUP;
+ gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
+ gpio_init.Alternate = USART_GPIO_AF;
+ HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init);
+
+ // Configure the LED
+ LED_CLK_EN();
+ gpio_init.Pin = LED_PIN;
+ gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
+ gpio_init.Pull = GPIO_PULLUP;
+ gpio_init.Speed = GPIO_SPEED_FREQ_LOW;
+ gpio_init.Alternate = 0;
+ HAL_GPIO_Init(LED_PORT, &gpio_init);
+
+ // Default LED state is off
+ board_led_write(false);
+
+ // Configure the button
+ BUTTON_CLK_EN();
+ gpio_init.Pin = BUTTON_PIN;
+ gpio_init.Mode = GPIO_MODE_INPUT;
+ gpio_init.Pull = GPIO_PULLUP;
+ gpio_init.Speed = GPIO_SPEED_FREQ_LOW;
+ gpio_init.Alternate = 0;
+ HAL_GPIO_Init(BUTTON_PORT, &gpio_init);
+
+ // Configure USB DM and DP pins. This is optional, and maintained only for user guidance.
+ gpio_init.Pin = (GPIO_PIN_7 | GPIO_PIN_6);
+ gpio_init.Mode = GPIO_MODE_INPUT;
+ gpio_init.Pull = GPIO_NOPULL;
+ gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
+ HAL_GPIO_Init(GPIOD, &gpio_init);
+}
+
+static void board_uart_configuration(void) {
+ uart_handle = ( UART_HandleTypeDef){
+ .Instance = USART_DEV,
+ .Init.BaudRate = CFG_BOARD_UART_BAUDRATE,
+ .Init.WordLength = UART_WORDLENGTH_8B,
+ .Init.StopBits = UART_STOPBITS_1,
+ .Init.Parity = UART_PARITY_NONE,
+ .Init.HwFlowCtl = UART_HWCONTROL_NONE,
+ .Init.Mode = UART_MODE_TX_RX,
+ .Init.OverSampling = UART_OVERSAMPLING_16
+ };
+ HAL_UART_Init(&uart_handle);
+}
+
+void board_init(void) {
+ board_system_clock_config();
+ board_gpio_configuration();
+ board_uart_configuration();
+
+ #ifdef USB_OTG_HS
+ // STM32WBA65/64/62 only has 1 USB HS port
+
+ #if CFG_TUSB_OS == OPT_OS_NONE
+ // 1ms tick timer
+ SysTick_Config(SystemCoreClock / 1000);
+ #elif CFG_TUSB_OS == OPT_OS_FREERTOS
+ // Explicitly disable systick to prevent its ISR runs before scheduler start
+ SysTick->CTRL &= ~1U;
+
+ // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
+ NVIC_SetPriority(USB_OTG_HS_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
+ #endif
+
+ // USB clock enable
+ __HAL_RCC_USB_OTG_HS_CLK_ENABLE();
+ __HAL_RCC_USB_OTG_HS_PHY_CLK_ENABLE();
+
+ // See the reference manual section 11.4.7 for the USB OTG powering sequence
+
+ // Remove the VDDUSB power isolation
+ PWR->SVMCR |= PWR_SVMCR_USV;
+
+ // Enable VDD11USB supply by clearing VDD11USBDIS to 0
+ PWR->VOSR &= ~PWR_VOSR_VDD11USBDIS;
+
+ // Enable USB OTG internal power by setting USBPWREN to 1
+ PWR->VOSR |= PWR_VOSR_USBPWREN;
+
+ // Wait for VDD11USB supply to be ready in VDD11USBRDY = 1
+ while ((PWR->VOSR & PWR_VOSR_VDD11USBRDY) == 0) {}
+
+ // Enable USB OTG booster by setting USBBOOSTEN to 1
+ PWR->VOSR |= PWR_VOSR_USBBOOSTEN;
+
+ // Wait for USB OTG booster to be ready in USBBOOSTRDY = 1
+ while ((PWR->VOSR & PWR_VOSR_USBBOOSTRDY) == 0) {}
+
+ // Enable USB power on Pwrctrl CR2 register
+ PWR->SVMCR |= PWR_SVMCR_USV;
+
+ // Set the reference clock selection (must match the clock source)
+ SYSCFG->OTGHSPHYCR &= ~SYSCFG_OTGHSPHYCR_CLKSEL;
+ SYSCFG->OTGHSPHYCR |= SYSCFG_OTGHSPHYCR_CLKSEL_0 | SYSCFG_OTGHSPHYCR_CLKSEL_1 |
+ SYSCFG_OTGHSPHYCR_CLKSEL_3;// 32MHz clock
+
+ // Configuring the SYSCFG registers OTG_HS PHY
+ SYSCFG->OTGHSPHYCR |= SYSCFG_OTGHSPHYCR_EN;
+
+ // Disable VBUS sense (B device)
+ USB_OTG_HS->GCCFG &= ~USB_OTG_GCCFG_VBDEN;
+
+ // B-peripheral session valid override enable
+ USB_OTG_HS->GCCFG |= USB_OTG_GCCFG_VBVALEXTOEN;
+ USB_OTG_HS->GCCFG |= USB_OTG_GCCFG_VBVALOVAL;
+ #endif // USB_OTG_FS
+}
+
+void board_led_write(bool state) { HAL_GPIO_WritePin(LED_PORT, LED_PIN, state ? LED_STATE_ON : (1 - LED_STATE_ON)); }
+
+uint32_t board_button_read(void) { return HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN) == BUTTON_STATE_ACTIVE; }
+
+int board_uart_read(uint8_t *buf, int len) {
+ (void) buf;
+ (void) len;
+ return 0;
+}
+
+int board_uart_write(void const *buf, int len) {
+ (void) HAL_UART_Transmit(&uart_handle, (const uint8_t *) buf, len, USART_TIMEOUT_TICKS);
+ return len;
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+
+void SysTick_Handler(void) {
+ HAL_IncTick();
+ system_ticks++;
+}
+
+uint32_t board_millis(void) { return system_ticks; }
+#endif
+
+void HardFault_Handler(void) { asm( "bkpt 1" ); }
+
+// Required by __libc_init_array in startup code if we are compiling using -nostdlib/-nostartfiles.
+void _init(void);
+
+void _init(void) {}
diff --git a/hw/bsp/stm32wba/family.cmake b/hw/bsp/stm32wba/family.cmake
new file mode 100644
index 000000000..3f42879be
--- /dev/null
+++ b/hw/bsp/stm32wba/family.cmake
@@ -0,0 +1,134 @@
+include_guard()
+
+set(ST_FAMILY wba)
+set(ST_PREFIX stm32${ST_FAMILY}xx)
+
+set(ST_HAL_DRIVER ${TOP}/hw/mcu/st/stm32${ST_FAMILY}xx_hal_driver)
+set(ST_CMSIS ${TOP}/hw/mcu/st/cmsis-device-${ST_FAMILY})
+set(CMSIS_5 ${TOP}/lib/CMSIS_5)
+
+# include board specific
+include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
+
+# toolchain set up
+set(CMAKE_SYSTEM_CPU cortex-m33 CACHE INTERNAL "System Processor")
+set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
+
+set(FAMILY_MCUS STM32WBA CACHE INTERNAL "")
+
+# ----------------------
+# Port & Speed Selection
+# ----------------------
+set(RHPORT_DEVICE 0)
+set(RHPORT_HOST 0)
+
+# WBA65/64/62 has built-in HS PHY
+set(RHPORT_DEVICE_SPEED OPT_MODE_HIGH_SPEED)
+set(RHPORT_HOST_SPEED OPT_MODE_HIGH_SPEED)
+
+#------------------------------------
+# BOARD_TARGET
+#------------------------------------
+# only need to be built ONCE for all examples
+function(add_board_target BOARD_TARGET)
+ if (TARGET ${BOARD_TARGET})
+ return()
+ endif()
+
+ # STM32WBA HAL uses uppercase MCU_VARIANT (excluding the x's) for linking and lowercase MCU_VARIANT for startup.
+ string(TOUPPER "${MCU_VARIANT}" UPPERCASE_MCU_VARIANT)
+ string(REGEX REPLACE "X" "x" UPPERCASE_MCU_VARIANT "${UPPERCASE_MCU_VARIANT}")
+
+ # Startup & Linker script
+ set(STARTUP_FILE_GNU ${ST_CMSIS}/Source/Templates/gcc/startup_${MCU_VARIANT}.s)
+ set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
+ set(STARTUP_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/startup_${MCU_VARIANT}.s)
+
+ set(LD_FILE_GNU ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/linker/${UPPERCASE_MCU_VARIANT}_FLASH_ns.ld)
+ set(LD_FILE_Clang ${LD_FILE_GNU})
+ set(LD_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/linker/${MCU_VARIANT}_flash_ns.icf)
+
+ add_library(${BOARD_TARGET} STATIC
+ ${ST_CMSIS}/Source/Templates/system_${ST_PREFIX}.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_cortex.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_icache.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_pwr.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_pwr_ex.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_rcc.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_rcc_ex.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_uart.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_gpio.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_pcd.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_pcd_ex.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_ll_usb.c
+ ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
+ )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMSIS_5}/CMSIS/Core/Include
+ ${ST_CMSIS}/Include
+ ${ST_HAL_DRIVER}/Inc
+ )
+
+ update_board(${BOARD_TARGET})
+
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--script=${LD_FILE_GNU}"
+ -nostartfiles
+ --specs=nosys.specs --specs=nano.specs
+ )
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--script=${LD_FILE_Clang}"
+ )
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--config=${LD_FILE_IAR}"
+ )
+ endif ()
+endfunction()
+
+
+#------------------------------------
+# Functions
+#------------------------------------
+function(family_configure_example TARGET RTOS)
+ family_configure_common(${TARGET} ${RTOS})
+
+ target_compile_definitions(${TARGET} PUBLIC
+ CFG_TUSB_MCU=OPT_MCU_STM32WBA
+ )
+
+ # Board target
+ add_board_target(board_${BOARD})
+
+ #---------- Port Specific ----------
+ # These files are built for each example since it depends on example's tusb_config.h
+ target_sources(${TARGET} PUBLIC
+ # BSP
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
+ )
+ target_include_directories(${TARGET} PUBLIC
+ # family, hw, board
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
+ )
+
+ # Add TinyUSB target and port source
+ family_add_tinyusb(${TARGET} OPT_MCU_STM32WBA)
+ target_sources(${TARGET} PUBLIC
+ ${TOP}/src/portable/synopsys/dwc2/dcd_dwc2.c
+ ${TOP}/src/portable/synopsys/dwc2/hcd_dwc2.c
+ ${TOP}/src/portable/synopsys/dwc2/dwc2_common.c
+ )
+ target_link_libraries(${TARGET} PUBLIC board_${BOARD})
+
+ # Flashing
+ family_add_bin_hex(${TARGET})
+ family_flash_stlink(${TARGET})
+ family_flash_jlink(${TARGET})
+endfunction()
diff --git a/hw/bsp/stm32wba/family.mk b/hw/bsp/stm32wba/family.mk
new file mode 100644
index 000000000..9b319921f
--- /dev/null
+++ b/hw/bsp/stm32wba/family.mk
@@ -0,0 +1,59 @@
+UF2_FAMILY_ID = 0x70d16657
+ST_FAMILY = wba
+
+ST_PREFIX = stm32${ST_FAMILY}xx
+ST_CMSIS = hw/mcu/st/cmsis-device-$(ST_FAMILY)
+ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+CPU_CORE ?= cortex-m33
+
+CFLAGS += \
+ -DCFG_TUSB_MCU=OPT_MCU_STM32WBA
+
+CFLAGS_GCC += \
+ -flto \
+ -Wno-error=cast-align -Wno-unused-parameter
+
+LDFLAGS_GCC += \
+ -nostdlib -nostartfiles \
+ -specs=nosys.specs -specs=nano.specs -Wl,--gc-sections
+
+SRC_C += \
+ src/portable/synopsys/dwc2/dcd_dwc2.c \
+ src/portable/synopsys/dwc2/hcd_dwc2.c \
+ src/portable/synopsys/dwc2/dwc2_common.c \
+ $(ST_CMSIS)/Source/Templates/system_${ST_PREFIX}.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_cortex.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_icache.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pwr.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pwr_ex.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_rcc.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_rcc_ex.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_uart.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_gpio.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pcd.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pcd_ex.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_ll_usb.c
+
+INC += \
+ $(TOP)/$(BOARD_PATH) \
+ $(TOP)/$(BOARD_PATH)/include \
+ $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
+ $(TOP)/$(ST_CMSIS)/Include \
+ $(TOP)/$(ST_HAL_DRIVER)/Inc
+
+# STM32WBA HAL uses uppercase MCU_VARIANT (excluding the x's) for linking and lowercase MCU_VARIANT for startup.
+UPPERCASE_MCU_VARIANT = $(subst XX,xx,$(call to_upper,$(MCU_VARIANT)))
+
+# Startup - Manually specify lowercase version for startup file
+SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_$(MCU_VARIANT).s
+SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT).s
+
+# Linker
+LD_FILE_GCC ?= ${FAMILY_PATH}/linker/${UPPERCASE_MCU_VARIANT}_FLASH_ns.ld
+LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash_ns.icf
+
+# flash target using on-board stlink
+flash: flash-stlink
diff --git a/hw/bsp/stm32wba/linker/STM32WBA65xx_FLASH_ns.ld b/hw/bsp/stm32wba/linker/STM32WBA65xx_FLASH_ns.ld
new file mode 100644
index 000000000..bc1f2997d
--- /dev/null
+++ b/hw/bsp/stm32wba/linker/STM32WBA65xx_FLASH_ns.ld
@@ -0,0 +1,188 @@
+/*
+******************************************************************************
+**
+** File : LinkerScript.ld
+**
+** Author : STM32CubeIDE
+**
+** Abstract : Linker script for STM32WBA65xx Device from STM32WBA series
+** 2048Kbytes FLASH
+** 512Kbytes RAM
+**
+** Set heap size, stack size and stack location according
+** to application requirements.
+**
+** Set memory bank area and size if external memory is used
+**
+** Target : STMicroelectronics STM32
+**
+** Distribution: The file is distributed as is, without any warranty
+** of any kind.
+**
+******************************************************************************
+** @attention
+**
+** Copyright (c) 2024 STMicroelectronics.
+** All rights reserved.
+**
+** This software is licensed under terms that can be found in the LICENSE file
+** in the root directory of this software component.
+** If no LICENSE file comes with this software, it is provided AS-IS.
+**
+******************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+_Min_Heap_Size = 0x200; /* required amount of heap */
+_Min_Stack_Size = 0x400; /* required amount of stack */
+
+/* Memories definition */
+MEMORY
+{
+ RAM (xrw) : ORIGIN = 0x20038000, LENGTH = 224K
+ RAM2 (xrw) : ORIGIN = 0x20078000, LENGTH = 32K
+ FLASH (rx) : ORIGIN = 0x08100000, LENGTH = 1024K
+}
+
+/* Highest address of the user mode stack */
+_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
+
+/* Sections */
+SECTIONS
+{
+ /* The startup code into "FLASH" Rom type memory */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data into "FLASH" Rom type memory */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ } >FLASH
+
+ /* Constant data into "FLASH" Rom type memory */
+ .rodata :
+ {
+ . = ALIGN(4);
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM.extab :
+ {
+ . = ALIGN(4);
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM :
+ {
+ . = ALIGN(4);
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ . = ALIGN(4);
+ } >FLASH
+
+ .preinit_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ .init_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ .fini_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT(.fini_array.*)))
+ KEEP (*(.fini_array*))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ /* Used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* Initialized data sections into "RAM" Ram type memory */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+ *(.RamFunc) /* .RamFunc sections */
+ *(.RamFunc*) /* .RamFunc* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+
+ } >RAM AT> FLASH
+
+ /* Uninitialized data section into "RAM" Ram type memory */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss section */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >RAM
+
+ /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >RAM
+
+ /* Remove information from the compiler libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
diff --git a/hw/bsp/stm32wba/stm32wbaxx_hal_conf.h b/hw/bsp/stm32wba/stm32wbaxx_hal_conf.h
new file mode 100644
index 000000000..f4e49f341
--- /dev/null
+++ b/hw/bsp/stm32wba/stm32wbaxx_hal_conf.h
@@ -0,0 +1,367 @@
+/**
+ ******************************************************************************
+ * @file stm32wbaxx_hal_conf_template.h
+ * @author MCD Application Team
+ * @brief HAL configuration template file.
+ * This file should be copied to the application folder and renamed
+ * to stm32wbaxx_hal_conf.h.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2022 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef STM32WBAxx_HAL_CONF_H
+#define STM32WBAxx_HAL_CONF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* ########################## Module Selection ############################## */
+/**
+ * @brief This is the list of modules to be used in the HAL driver
+ */
+#define HAL_MODULE_ENABLED
+// #define HAL_ADC_MODULE_ENABLED
+// #define HAL_COMP_MODULE_ENABLED
+#define HAL_CORTEX_MODULE_ENABLED
+// #define HAL_CRC_MODULE_ENABLED
+// #define HAL_CRYP_MODULE_ENABLED
+#define HAL_DMA_MODULE_ENABLED
+#define HAL_EXTI_MODULE_ENABLED
+#define HAL_FLASH_MODULE_ENABLED
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_GTZC_MODULE_ENABLED
+#define HAL_HASH_MODULE_ENABLED
+#define HAL_HCD_MODULE_ENABLED
+#define HAL_HSEM_MODULE_ENABLED
+// #define HAL_I2C_MODULE_ENABLED
+#define HAL_ICACHE_MODULE_ENABLED
+// #define HAL_IRDA_MODULE_ENABLED
+// #define HAL_IWDG_MODULE_ENABLED
+// #define HAL_LPTIM_MODULE_ENABLED
+#define HAL_PCD_MODULE_ENABLED
+// #define HAL_PKA_MODULE_ENABLED
+#define HAL_PWR_MODULE_ENABLED
+#define HAL_RAMCFG_MODULE_ENABLED
+#define HAL_RCC_MODULE_ENABLED
+// #define HAL_RNG_MODULE_ENABLED
+// #define HAL_RTC_MODULE_ENABLED
+// #define HAL_SAI_MODULE_ENABLED
+// #define HAL_SMARTCARD_MODULE_ENABLED
+// #define HAL_SMBUS_MODULE_ENABLED
+#define HAL_SPI_MODULE_ENABLED
+#define HAL_TIM_MODULE_ENABLED
+// #define HAL_TSC_MODULE_ENABLED
+#define HAL_UART_MODULE_ENABLED
+#define HAL_USART_MODULE_ENABLED
+// #define HAL_WWDG_MODULE_ENABLED
+// #define HAL_XSPI_MODULE_ENABLED
+
+/* ########################## Oscillator Values adaptation ####################*/
+/**
+ * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSE is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSE_VALUE)
+#define HSE_VALUE 32000000UL /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSE_STARTUP_TIMEOUT)
+#define HSE_STARTUP_TIMEOUT 100UL /*!< Time out for HSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief Internal High Speed oscillator (HSI) value.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSI is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSI_VALUE)
+#define HSI_VALUE 16000000UL /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+/**
+ * @brief Internal Low Speed oscillator (LSI) value.
+ */
+#if !defined (LSI_VALUE)
+#define LSI_VALUE 32000UL /*!< LSI Typical Value in Hz*/
+#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
+ The real value may vary depending on the variations in voltage
+ and temperature.*/
+
+#if defined (RCC_LSI2_SUPPORT)
+#if !defined (LSI2_VALUE)
+#define LSI2_VALUE 32000UL /*!< LSI2 Typical Value in Hz*/
+#endif /* LSI2_VALUE */
+#endif
+
+/**
+ * @brief External Low Speed oscillator (LSE) value.
+ * This value is used by the UART, RTC HAL module to compute the system frequency
+ */
+#if !defined (LSE_VALUE)
+#define LSE_VALUE 32768UL /*!< Value of the External oscillator in Hz*/
+#endif /* LSE_VALUE */
+
+#if !defined (LSE_STARTUP_TIMEOUT)
+#define LSE_STARTUP_TIMEOUT 5000UL /*!< Time out for LSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief External clock source for SAI1 peripheral
+ * This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source
+ * frequency.
+ */
+#if !defined (EXTERNAL_SAI1_CLOCK_VALUE)
+#define EXTERNAL_SAI1_CLOCK_VALUE 48000UL /*!< Value of the SAI1 External clock source in Hz*/
+#endif /* EXTERNAL_SAI1_CLOCK_VALUE */
+
+/* Tip: To avoid modifying this file each time you need to use different HSE,
+ === you can define the HSE value in your toolchain compiler preprocessor. */
+
+/* ########################### System Configuration ######################### */
+/**
+ * @brief This is the HAL system configuration section
+ */
+#define VDD_VALUE 3300UL /*!< Value of VDD in mv */
+#define TICK_INT_PRIORITY ((1UL<<__NVIC_PRIO_BITS) - 1UL) /*!< tick interrupt priority (lowest by default) */
+#define USE_RTOS 0U
+#define PREFETCH_ENABLE 1U /*!< Enable prefetch */
+
+/* ########################## Assert Selection ############################## */
+/**
+ * @brief Uncomment the line below to expanse the "assert_param" macro in the
+ * HAL drivers code
+ */
+/* #define USE_FULL_ASSERT 1U */
+
+/* ################## Register callback feature configuration ############### */
+/**
+ * @brief Set below the peripheral configuration to "1U" to add the support
+ * of HAL callback registration/unregistration feature for the HAL
+ * driver(s). This allows user application to provide specific callback
+ * functions thanks to HAL_PPP_RegisterCallback() rather than overwriting
+ * the default weak callback functions (see each stm32wbaxx_hal_ppp.h file
+ * for possible callback identifiers defined in HAL_PPP_CallbackIDTypeDef
+ * for each PPP peripheral).
+ */
+#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
+#define USE_HAL_COMP_REGISTER_CALLBACKS 0U /* COMP register callback disabled */
+#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */
+#define USE_HAL_HASH_REGISTER_CALLBACKS 0U /* HASH register callback disabled */
+#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */
+#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */
+#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */
+#define USE_HAL_IWDG_REGISTER_CALLBACKS 0U /* IWDG register callback disabled */
+#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */
+#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */
+#define USE_HAL_PKA_REGISTER_CALLBACKS 0U /* PKA register callback disabled */
+#define USE_HAL_RAMCFG_REGISTER_CALLBACKS 0U /* RAMCFG register callback disabled */
+#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */
+#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */
+#define USE_HAL_SAI_REGISTER_CALLBACKS 0U /* SAI register callback disabled */
+#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */
+#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U /* SMBUS register callback disabled */
+#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */
+#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */
+#define USE_HAL_TSC_REGISTER_CALLBACKS 0U /* TSC register callback disabled */
+#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */
+#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */
+#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */
+#define USE_HAL_XSPI_REGISTER_CALLBACKS 0U /* XSPI register callback disabled */
+
+/* ################## SPI peripheral configuration ########################## */
+
+/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
+ * Activated: CRC code is present inside driver
+ * Deactivated: CRC code cleaned from driver
+ */
+#define USE_SPI_CRC 1U
+
+/* ################## CRYP peripheral configuration ########################## */
+
+#define USE_HAL_CRYP_SUSPEND_RESUME 0U
+
+/* ################## HASH peripheral configuration ########################## */
+
+#define USE_HAL_HASH_SUSPEND_RESUME 0U
+
+/* Includes ------------------------------------------------------------------*/
+/**
+ * @brief Include module's header file
+ */
+#ifdef HAL_DMA_MODULE_ENABLED
+#include "stm32wbaxx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+#include "stm32wbaxx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+#include "stm32wbaxx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_COMP_MODULE_ENABLED
+#include "stm32wbaxx_hal_comp.h"
+#endif /* HAL_COMP_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+#include "stm32wbaxx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+#include "stm32wbaxx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+#include "stm32wbaxx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_EXTI_MODULE_ENABLED
+#include "stm32wbaxx_hal_exti.h"
+#endif /* HAL_EXTI_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+#include "stm32wbaxx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+#include "stm32wbaxx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_GTZC_MODULE_ENABLED
+#include "stm32wbaxx_hal_gtzc.h"
+#endif /* HAL_GTZC_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+#include "stm32wbaxx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+#include "stm32wbaxx_hal_hcd.h"
+#endif /* HAL_HCD_MODULE_ENABLED */
+
+#ifdef HAL_HSEM_MODULE_ENABLED
+#include "stm32wbaxx_hal_hsem.h"
+#endif /* HAL_HSEM_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+#include "stm32wbaxx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_ICACHE_MODULE_ENABLED
+#include "stm32wbaxx_hal_icache.h"
+#endif /* HAL_ICACHE_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+#include "stm32wbaxx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+#include "stm32wbaxx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LPTIM_MODULE_ENABLED
+#include "stm32wbaxx_hal_lptim.h"
+#endif /* HAL_LPTIM_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+#include "stm32wbaxx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_PKA_MODULE_ENABLED
+#include "stm32wbaxx_hal_pka.h"
+#endif /* HAL_PKA_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+#include "stm32wbaxx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RAMCFG_MODULE_ENABLED
+#include "stm32wbaxx_hal_ramcfg.h"
+#endif /* HAL_RAMCFG_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+#include "stm32wbaxx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+#include "stm32wbaxx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+#include "stm32wbaxx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+#include "stm32wbaxx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_SMBUS_MODULE_ENABLED
+#include "stm32wbaxx_hal_smbus.h"
+#endif /* HAL_SMBUS_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+#include "stm32wbaxx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+#include "stm32wbaxx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_TSC_MODULE_ENABLED
+#include "stm32wbaxx_hal_tsc.h"
+#endif /* HAL_TSC_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+#include "stm32wbaxx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+#include "stm32wbaxx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+#include "stm32wbaxx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_XSPI_MODULE_ENABLED
+#include "stm32wbaxx_hal_xspi.h"
+#endif /* HAL_XSPI_MODULE_ENABLED */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+void assert_failed(uint8_t *file, uint32_t line);
+#else
+#define assert_param(expr) ((void)0U)
+#endif /* USE_FULL_ASSERT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STM32WBAxx_HAL_CONF_H */
diff --git a/lib/rt-thread/SConscript b/lib/rt-thread/SConscript
index 34399fd45..99517a090 100644
--- a/lib/rt-thread/SConscript
+++ b/lib/rt-thread/SConscript
@@ -34,6 +34,8 @@ if GetDepend(["PKG_TINYUSB_DEVICE_ENABLE"]):
src += ["../../src/class/cdc/cdc_device.c"]
if GetDepend(["PKG_TINYUSB_DEVICE_MSC"]):
src += ["../../src/class/msc/msc_device.c", "port/msc_device_port.c"]
+ if GetDepend(["PKG_TINYUSB_DEVICE_MTP"]):
+ src += ["../../src/class/mtp/mtp_device.c"]
if GetDepend(["PKG_TINYUSB_DEVICE_HID"]):
src += ["../../src/class/hid/hid_device.c"]
diff --git a/library.json b/library.json
index f1bfd6387..718fd84d3 100644
--- a/library.json
+++ b/library.json
@@ -1,6 +1,6 @@
{
"name": "TinyUSB",
- "version": "0.18.0",
+ "version": "0.19.0",
"description": "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.",
"keywords": "usb, host, device",
"repository":
diff --git a/repository.yml b/repository.yml
index 31c9eddc5..5c2aaa6fa 100644
--- a/repository.yml
+++ b/repository.yml
@@ -16,5 +16,6 @@ repo.versions:
"0.16.0": "0.16.0"
"0.17.0": "0.17.0"
"0.18.0": "0.18.0"
- "0-latest": "0.18.0"
+ "0.19.0": "0.19.0"
+ "0-latest": "0.19.0"
"0-dev": "0.0.0"
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 99d3059fc..951683104 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -16,6 +16,7 @@ function(tinyusb_target_add TARGET)
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/hid/hid_device.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/midi/midi_device.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/msc/msc_device.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/mtp/mtp_device.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/net/ecm_rndis_device.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/net/ncm_device.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/usbtmc/usbtmc_device.c
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index bb906c7cf..7df177773 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -79,10 +79,9 @@
// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer
// is available or driver is would need to be changed dramatically
-// Only STM32 and dcd_transdimension use non-linear buffer for now
-// dwc2 except esp32sx (since it may use dcd_esp32sx)
+// Only STM32 and ChipIdea HS use non-linear buffer for now
// Ring buffer is incompatible with dcache, since neither address nor size is aligned to cache line
-#if (defined(TUP_USBIP_DWC2) && !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)) || \
+#if defined(TUP_USBIP_DWC2) || \
defined(TUP_USBIP_FSDEV) || \
CFG_TUSB_MCU == OPT_MCU_RX63X || \
CFG_TUSB_MCU == OPT_MCU_RX65X || \
@@ -192,17 +191,6 @@ tu_static CFG_TUD_MEM_SECTION struct {
#endif
} ctrl_buf;
-// Active alternate setting of interfaces
-tu_static uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
-
-#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
-tu_static uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
-#endif
-
-#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
-tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
-#endif
-
// Aligned buffer for feedback EP
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
tu_static CFG_TUD_MEM_SECTION struct {
@@ -234,13 +222,14 @@ typedef struct
uint8_t ep_in; // TX audio data EP.
uint16_t ep_in_sz; // Current size of TX EP
uint8_t ep_in_as_intf_num;// Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero)
-#endif
+ uint8_t ep_in_alt; // Current alternate setting of TX EP
+ #endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
uint8_t ep_out; // Incoming (into uC) audio data EP.
uint16_t ep_out_sz; // Current size of RX EP
uint8_t ep_out_as_intf_num;// Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero)
-
+ uint8_t ep_out_alt; // Current alternate setting of RX EP
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
uint8_t ep_fb;// Feedback EP.
#endif
@@ -304,9 +293,6 @@ typedef struct
uint8_t *ctrl_buf;
uint8_t ctrl_buf_sz;
- // Current active alternate settings
- uint8_t *alt_setting;// We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP!
-
// EP Transfer buffers and FIFOs
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
tu_fifo_t ep_out_ff;
@@ -475,8 +461,6 @@ static bool audiod_tx_xfer_isr(uint8_t rhport, audiod_function_t* audio, uint16_
static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const *p_request);
static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p_request);
-static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int);
-static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t *audio, uint8_t *idxItf, uint8_t const **pp_desc_int);
static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id);
static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id);
static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id);
@@ -529,11 +513,7 @@ tu_fifo_t *tud_audio_n_get_ep_out_ff(uint8_t func_id) {
}
static bool audiod_rx_xfer_isr(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received) {
- uint8_t idxItf;
- uint8_t const *dummy2;
-
uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio);
- TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2));
#if USE_LINEAR_BUFFER_RX
// Data currently is in linear buffer, copy into EP OUT FIFO
@@ -553,7 +533,7 @@ static bool audiod_rx_xfer_isr(uint8_t rhport, audiod_function_t* audio, uint16_
#endif
// Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO
- TU_VERIFY(tud_audio_rx_done_isr(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
+ TU_VERIFY(tud_audio_rx_done_isr(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->ep_out_alt));
return true;
}
@@ -584,14 +564,10 @@ tu_fifo_t *tud_audio_n_get_ep_in_ff(uint8_t func_id) {
}
static bool audiod_tx_xfer_isr(uint8_t rhport, audiod_function_t * audio, uint16_t n_bytes_sent) {
- uint8_t idxItf;
- uint8_t const *dummy2;
-
uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio);
- TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio, &idxItf, &dummy2));
// Only send something if current alternate interface is not 0 as in this case nothing is to be sent due to UAC2 specifications
- if (audio->alt_setting[idxItf] == 0) { return false; }
+ if (audio->ep_in_alt == 0) { return false; }
// Send everything in ISO EP FIFO
uint16_t n_bytes_tx;
@@ -611,7 +587,7 @@ static bool audiod_tx_xfer_isr(uint8_t rhport, audiod_function_t * audio, uint16
#endif
// Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer
- TU_VERIFY(tud_audio_tx_done_isr(rhport, n_bytes_sent, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
+ TU_VERIFY(tud_audio_tx_done_isr(rhport, n_bytes_sent, idx_audio_fct, audio->ep_in, audio->ep_in_alt));
return true;
}
@@ -704,25 +680,6 @@ void audiod_init(void) {
#endif
}
- // Initialize active alternate interface buffers
- switch (i) {
-#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0
- case 0:
- audio->alt_setting = alt_setting_1;
- break;
-#endif
-#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
- case 1:
- audio->alt_setting = alt_setting_2;
- break;
-#endif
-#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
- case 2:
- audio->alt_setting = alt_setting_3;
- break;
-#endif
- }
-
// Initialize IN EP FIFO if required
#if CFG_TUD_AUDIO_ENABLE_EP_IN
@@ -1029,13 +986,25 @@ static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const *p
uint8_t const itf = tu_u16_low(p_request->wIndex);
// Find index of audio streaming interface
- uint8_t func_id, idxItf;
- uint8_t const *dummy;
+ uint8_t func_id;
+ TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+
+ // Default to 0 if interface not yet activated
+ uint8_t alt = 0;
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
+ if (_audiod_fct[func_id].ep_in_as_intf_num == itf) {
+ alt = _audiod_fct[func_id].ep_in_alt;
+ }
+#endif
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
+ if (_audiod_fct[func_id].ep_out_as_intf_num == itf) {
+ alt = _audiod_fct[func_id].ep_out_alt;
+ }
+#endif
- TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &dummy));
- TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_fct[func_id].alt_setting[idxItf], 1));
+ TU_VERIFY(tud_control_xfer(rhport, p_request, &alt, 1));
- TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_fct[func_id].alt_setting[idxItf]);
+ TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, alt);
return true;
}
@@ -1060,9 +1029,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
TU_LOG2(" Set itf: %u - alt: %u\r\n", itf, alt);
// Find index of audio streaming interface and index of interface
- uint8_t func_id, idxItf;
- uint8_t const *p_desc;
- TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &p_desc));
+ uint8_t func_id;
+ TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
audiod_function_t *audio = &_audiod_fct[func_id];
@@ -1070,6 +1038,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
#if CFG_TUD_AUDIO_ENABLE_EP_IN
if (audio->ep_in_as_intf_num == itf) {
audio->ep_in_as_intf_num = 0;
+ audio->ep_in_alt = 0;
#ifndef TUP_DCD_EDPT_ISO_ALLOC
usbd_edpt_close(rhport, audio->ep_in);
#endif
@@ -1093,6 +1062,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
if (audio->ep_out_as_intf_num == itf) {
audio->ep_out_as_intf_num = 0;
+ audio->ep_out_alt = 0;
#ifndef TUP_DCD_EDPT_ISO_ALLOC
usbd_edpt_close(rhport, audio->ep_out);
#endif
@@ -1116,10 +1086,10 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
}
#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT
- // Save current alternative interface setting
- audio->alt_setting[idxItf] = alt;
-
// Open new EP if necessary - EPs are only to be closed or opened for AS interfaces - Look for AS interface with correct alternate interface
+ uint8_t const *p_desc = tu_desc_next(audio->p_desc);
+ // Skip entire AC descriptor block
+ p_desc += ((audio_desc_cs_ac_interface_t const *) p_desc)->wTotalLength;
// Get pointer at end
uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
@@ -1154,6 +1124,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
// Save address
audio->ep_in = ep_addr;
audio->ep_in_as_intf_num = itf;
+ audio->ep_in_alt = alt;
audio->ep_in_sz = tu_edpt_packet_size(desc_ep);
// If flow control is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters
@@ -1176,6 +1147,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
// Save address
audio->ep_out = ep_addr;
audio->ep_out_as_intf_num = itf;
+ audio->ep_out_alt = alt;
audio->ep_out_sz = tu_edpt_packet_size(desc_ep);
// Prepare for incoming data
@@ -1474,8 +1446,7 @@ bool audiod_xfer_isr(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
#if CFG_TUD_AUDIO_ENABLE_EP_IN
// Data transmission of audio packet finished
- if (audio->ep_in == ep_addr && audio->alt_setting != 0)
- {
+ if (audio->ep_in == ep_addr) {
// USB 2.0, section 5.6.4, third paragraph, states "An isochronous endpoint must specify its required bus access period. However, an isochronous endpoint must be prepared to handle poll rates faster than the one specified."
// That paragraph goes on to say "An isochronous IN endpoint must return a zero-length packet whenever data is requested at a faster interval than the specified interval and data is not available."
// This can only be solved reliably if we load a ZLP after every IN transmission since we can not say if the host requests samples earlier than we declared! Once all samples are collected we overwrite the loaded ZLP.
@@ -1492,8 +1463,7 @@ bool audiod_xfer_isr(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
// New audio packet received
- if (audio->ep_out == ep_addr)
- {
+ if (audio->ep_out == ep_addr) {
audiod_rx_xfer_isr(rhport, audio, (uint16_t) xferred_bytes);
return true;
}
@@ -1694,53 +1664,6 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req
return tud_control_xfer(rhport, p_request, (void *) _audiod_fct[func_id].ctrl_buf, len);
}
-// This helper function finds for a given audio function and AS interface number the index of the attached driver structure, the index of the interface in the audio function
-// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and
-// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero.
-static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t *audio, uint8_t *idxItf, uint8_t const **pp_desc_int) {
- if (audio->p_desc) {
- // Get pointer at end
- uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
-
- // Advance past AC descriptors
- uint8_t const *p_desc = tu_desc_next(audio->p_desc);
- p_desc += ((audio_desc_cs_ac_interface_t const *) p_desc)->wTotalLength;
-
- uint8_t tmp = 0;
- // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
- while (p_desc_end - p_desc > 0) {
- // We assume the number of alternate settings is increasing thus we return the index of alternate setting zero!
- if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *) p_desc)->bAlternateSetting == 0) {
- if (((tusb_desc_interface_t const *) p_desc)->bInterfaceNumber == itf) {
- *idxItf = tmp;
- *pp_desc_int = p_desc;
- return true;
- }
- // Increase index, bytes read, and pointer
- tmp++;
- }
- p_desc = tu_desc_next(p_desc);
- }
- }
- return false;
-}
-
-// This helper function finds for a given AS interface number the index of the attached driver structure, the index of the interface in the audio function
-// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and
-// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero.
-static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int) {
- // Loop over audio driver interfaces
- uint8_t i;
- for (i = 0; i < CFG_TUD_AUDIO; i++) {
- if (audiod_get_AS_interface_index(itf, &_audiod_fct[i], idxItf, pp_desc_int)) {
- *func_id = i;
- return true;
- }
- }
-
- return false;
-}
-
// Verify an entity with the given ID exists and returns also the corresponding driver index
static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id) {
uint8_t i;
@@ -1754,8 +1677,8 @@ static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *
// Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
while (p_desc_end - p_desc > 0) {
- if (p_desc[3] == entityID)// Entity IDs are always at offset 3
- {
+ // Entity IDs are always at offset 3
+ if (p_desc[3] == entityID) {
*func_id = i;
return true;
}
@@ -1775,7 +1698,7 @@ static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) {
uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
// Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
while (p_desc_end - p_desc > 0) {
- if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *) _audiod_fct[i].p_desc)->bInterfaceNumber == itf) {
+ if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)p_desc)->bInterfaceNumber == itf) {
*func_id = i;
return true;
}
diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h
index 6bcedc88c..fd47c649d 100644
--- a/src/class/audio/audio_device.h
+++ b/src/class/audio/audio_device.h
@@ -51,21 +51,6 @@
#endif
#endif
-// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces
-#ifndef CFG_TUD_AUDIO_FUNC_1_N_AS_INT
-#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor!
-#endif
-#if CFG_TUD_AUDIO > 1
-#ifndef CFG_TUD_AUDIO_FUNC_2_N_AS_INT
-#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor!
-#endif
-#endif
-#if CFG_TUD_AUDIO > 2
-#ifndef CFG_TUD_AUDIO_FUNC_3_N_AS_INT
-#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor!
-#endif
-#endif
-
// Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors
#ifndef CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ
#error You must define an audio class control request buffer size!
diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c
index 45cbf2d98..3f1529cb6 100755
--- a/src/class/bth/bth_device.c
+++ b/src/class/bth/bth_device.c
@@ -43,7 +43,7 @@ typedef struct {
uint8_t ep_acl_in;
uint16_t ep_acl_in_pkt_sz;
uint8_t ep_acl_out;
- uint8_t ep_voice[2]; // Not used yet
+ uint8_t ep_voice[2];// Not used yet
uint8_t ep_voice_size[2][CFG_TUD_BTH_ISO_ALT_COUNT];
// Previous amount of bytes sent when issuing ZLP
@@ -61,8 +61,7 @@ typedef struct {
static btd_interface_t _btd_itf;
CFG_TUD_MEM_SECTION static btd_epbuf_t _btd_epbuf;
-static bool bt_tx_data(uint8_t ep, void *data, uint16_t len)
-{
+static bool bt_tx_data(uint8_t ep, void *data, uint16_t len) {
uint8_t const rhport = 0;
// skip if previous transfer not complete
@@ -74,6 +73,27 @@ static bool bt_tx_data(uint8_t ep, void *data, uint16_t len)
}
//--------------------------------------------------------------------+
+// Weak stubs: invoked if no strong implementation is available
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK void tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len) {
+ (void) hci_cmd;
+ (void) cmd_len;
+}
+
+TU_ATTR_WEAK void tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len) {
+ (void) acl_data;
+ (void) data_len;
+}
+
+TU_ATTR_WEAK void tud_bt_event_sent_cb(uint16_t sent_bytes) {
+ (void) sent_bytes;
+}
+
+TU_ATTR_WEAK void tud_bt_acl_data_sent_cb(uint16_t sent_bytes) {
+ (void) sent_bytes;
+}
+
+//--------------------------------------------------------------------+
// READ API
//--------------------------------------------------------------------+
@@ -82,13 +102,11 @@ static bool bt_tx_data(uint8_t ep, void *data, uint16_t len)
// WRITE API
//--------------------------------------------------------------------+
-bool tud_bt_event_send(void *event, uint16_t event_len)
-{
+bool tud_bt_event_send(void *event, uint16_t event_len) {
return bt_tx_data(_btd_itf.ep_ev, event, event_len);
}
-bool tud_bt_acl_data_send(void *event, uint16_t event_len)
-{
+bool tud_bt_acl_data_send(void *event, uint16_t event_len) {
return bt_tx_data(_btd_itf.ep_acl_in, event, event_len);
}
@@ -103,13 +121,11 @@ bool btd_deinit(void) {
return true;
}
-void btd_reset(uint8_t rhport)
-{
- (void)rhport;
+void btd_reset(uint8_t rhport) {
+ (void) rhport;
}
-uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
-{
+uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
tusb_desc_endpoint_t const *desc_ep;
uint16_t drv_len = 0;
// Size of single alternative of ISO interface
@@ -118,8 +134,9 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_
const uint16_t hci_itf_size = sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t);
// Ensure this is BT Primary Controller
TU_VERIFY(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass &&
- TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass &&
- TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0);
+ TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass &&
+ TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol,
+ 0);
TU_ASSERT(itf_desc->bNumEndpoints == 3 && max_len >= hci_itf_size);
@@ -131,10 +148,10 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_
TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
_btd_itf.ep_ev = desc_ep->bEndpointAddress;
- desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep);
+ desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep);
// Open endpoint pair
- TU_ASSERT(usbd_open_edpt_pair(rhport, (uint8_t const *)desc_ep, 2,
+ TU_ASSERT(usbd_open_edpt_pair(rhport, (uint8_t const *) desc_ep, 2,
TUSB_XFER_BULK, &_btd_itf.ep_acl_out,
&_btd_itf.ep_acl_in),
0);
@@ -146,10 +163,10 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_
_btd_itf.ep_acl_in_pkt_sz = tu_edpt_packet_size(desc_ep_acl_in);
break;
}
- desc_ep_acl_in = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep_acl_in);
+ desc_ep_acl_in = (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep_acl_in);
}
- itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(desc_ep));
+ itf_desc = (tusb_desc_interface_t const *) tu_desc_next(tu_desc_next(desc_ep));
// Prepare for incoming data from host
TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_epbuf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE), 0);
@@ -158,13 +175,14 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_
// Ensure this is still BT Primary Controller
TU_ASSERT(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass &&
- TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass &&
- TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0);
+ TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass &&
+ TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol,
+ 0);
TU_ASSERT(itf_desc->bNumEndpoints == 2 && max_len >= iso_alt_itf_size + drv_len);
uint8_t dir;
- desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc);
+ desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0);
TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0);
dir = tu_edpt_dir(desc_ep->bEndpointAddress);
@@ -172,7 +190,7 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_
// Store endpoint size for alternative
_btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
- desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep);
+ desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep);
TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0);
dir = tu_edpt_dir(desc_ep->bEndpointAddress);
_btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress;
@@ -182,29 +200,30 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_
for (int i = 1; i < CFG_TUD_BTH_ISO_ALT_COUNT && drv_len + iso_alt_itf_size <= max_len; ++i) {
// Make sure rest of alternatives matches
- itf_desc = (tusb_desc_interface_t const *)tu_desc_next(desc_ep);
+ itf_desc = (tusb_desc_interface_t const *) tu_desc_next(desc_ep);
if (itf_desc->bDescriptorType != TUSB_DESC_INTERFACE ||
TUSB_CLASS_WIRELESS_CONTROLLER != itf_desc->bInterfaceClass ||
TUD_BT_APP_SUBCLASS != itf_desc->bInterfaceSubClass ||
- TUD_BT_PROTOCOL_PRIMARY_CONTROLLER != itf_desc->bInterfaceProtocol)
- {
+ TUD_BT_PROTOCOL_PRIMARY_CONTROLLER != itf_desc->bInterfaceProtocol) {
// Not an Iso interface instance
break;
}
TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0);
- desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc);
+ desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
dir = tu_edpt_dir(desc_ep->bEndpointAddress);
// Verify that alternative endpoint are same as first ones
TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT &&
- _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0);
+ _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress,
+ 0);
_btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
- desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep);
+ desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep);
dir = tu_edpt_dir(desc_ep->bEndpointAddress);
// Verify that alternative endpoint are same as first ones
TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT &&
- _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0);
+ _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress,
+ 0);
_btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep);
drv_len += iso_alt_itf_size;
}
@@ -215,44 +234,32 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_
// Invoked when a control transfer occurred on an interface of this class
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
// return false to stall control endpoint (e.g unsupported request)
-bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
-{
- (void)rhport;
+bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) {
+ (void) rhport;
- if ( stage == CONTROL_STAGE_SETUP )
- {
+ if (stage == CONTROL_STAGE_SETUP) {
if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS &&
- request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE)
- {
+ request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE) {
// HCI command packet addressing for single function Primary Controllers
// also compatible with historical mode if enabled
TU_VERIFY((request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0) ||
(CFG_TUD_BTH_HISTORICAL_COMPATIBLE && request->bRequest == 0xe0));
- }
- else if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE)
- {
- if (request->bRequest == TUSB_REQ_SET_INTERFACE && _btd_itf.itf_num + 1 == request->wIndex)
- {
+ } else if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) {
+ if (request->bRequest == TUSB_REQ_SET_INTERFACE && _btd_itf.itf_num + 1 == request->wIndex) {
// TODO: Set interface it would involve changing size of endpoint size
- }
- else
- {
+ } else {
// HCI command packet for Primary Controller function in a composite device
TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == _btd_itf.itf_num);
}
- }
- else return false;
+ } else
+ return false;
return tud_control_xfer(rhport, request, &_btd_epbuf.hci_cmd, sizeof(bt_hci_cmd_t));
- }
- else if ( stage == CONTROL_STAGE_DATA )
- {
+ } else if (stage == CONTROL_STAGE_DATA) {
// Handle class request only
TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
- if (tud_bt_hci_cmd_cb) {
- tud_bt_hci_cmd_cb(&_btd_epbuf.hci_cmd, tu_min16(request->wLength, sizeof(bt_hci_cmd_t)));
- }
+ tud_bt_hci_cmd_cb(&_btd_epbuf.hci_cmd, tu_min16(request->wLength, sizeof(bt_hci_cmd_t)));
}
return true;
@@ -261,19 +268,14 @@ bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t c
bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
uint32_t xferred_bytes) {
// received new data from host
- if (ep_addr == _btd_itf.ep_acl_out)
- {
- if (tud_bt_acl_data_received_cb) tud_bt_acl_data_received_cb(_btd_epbuf.epout_buf, xferred_bytes);
+ if (ep_addr == _btd_itf.ep_acl_out) {
+ tud_bt_acl_data_received_cb(_btd_epbuf.epout_buf, xferred_bytes);
// prepare for next data
TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_epbuf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE));
- }
- else if (ep_addr == _btd_itf.ep_ev)
- {
- if (tud_bt_event_sent_cb) tud_bt_event_sent_cb((uint16_t)xferred_bytes);
- }
- else if (ep_addr == _btd_itf.ep_acl_in)
- {
+ } else if (ep_addr == _btd_itf.ep_ev) {
+ tud_bt_event_sent_cb((uint16_t) xferred_bytes);
+ } else if (ep_addr == _btd_itf.ep_acl_in) {
if ((result == XFER_RESULT_SUCCESS) && (xferred_bytes > 0) &&
((xferred_bytes & (_btd_itf.ep_acl_in_pkt_sz - 1)) == 0)) {
// Save number of transferred bytes
@@ -281,12 +283,12 @@ bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
// Send zero-length packet
tud_bt_acl_data_send(NULL, 0);
- } else if (tud_bt_acl_data_sent_cb) {
+ } else {
if (xferred_bytes == 0) {
xferred_bytes = _btd_itf.prev_xferred_bytes;
_btd_itf.prev_xferred_bytes = 0;
}
- tud_bt_acl_data_sent_cb((uint16_t)xferred_bytes);
+ tud_bt_acl_data_sent_cb((uint16_t) xferred_bytes);
}
}
diff --git a/src/class/bth/bth_device.h b/src/class/bth/bth_device.h
index 4f6350839..68f073bff 100755
--- a/src/class/bth/bth_device.h
+++ b/src/class/bth/bth_device.h
@@ -67,23 +67,23 @@ typedef struct TU_ATTR_PACKED
// Part E, 5.4.1.
// Length of the command is from 3 bytes (2 bytes for OpCode,
// 1 byte for parameter total length) to 258.
-TU_ATTR_WEAK void tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len);
+void tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len);
// Invoked when ACL data was received over USB from Bluetooth host.
// Detailed format is described in Bluetooth core specification Vol 2,
// Part E, 5.4.2.
// Length is from 4 bytes, (12 bits for Handle, 4 bits for flags
// and 16 bits for data total length) to endpoint size.
-TU_ATTR_WEAK void tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len);
+void tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len);
// Called when event sent with tud_bt_event_send() was delivered to BT stack.
// Controller can release/reuse buffer with Event packet at this point.
-TU_ATTR_WEAK void tud_bt_event_sent_cb(uint16_t sent_bytes);
+void tud_bt_event_sent_cb(uint16_t sent_bytes);
// Called when ACL data that was sent with tud_bt_acl_data_send()
// was delivered to BT stack.
// Controller can release/reuse buffer with ACL packet at this point.
-TU_ATTR_WEAK void tud_bt_acl_data_sent_cb(uint16_t sent_bytes);
+void tud_bt_acl_data_sent_cb(uint16_t sent_bytes);
// Bluetooth controller calls this function when it wants to send even packet
// as described in Bluetooth core specification Vol 2, Part E, 5.4.4.
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c
index 4e4e01eaf..f1c4a3bbf 100644
--- a/src/class/cdc/cdc_device.c
+++ b/src/class/cdc/cdc_device.c
@@ -120,6 +120,42 @@ static bool _prep_out_transaction(uint8_t itf) {
}
//--------------------------------------------------------------------+
+// Weak stubs: invoked if no strong implementation is available
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf) {
+ (void) itf;
+}
+
+TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
+ (void) itf;
+ (void) wanted_char;
+}
+
+TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf) {
+ (void) itf;
+}
+
+TU_ATTR_WEAK void tud_cdc_notify_complete_cb(uint8_t itf) {
+ (void) itf;
+}
+
+TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
+ (void) itf;
+ (void) dtr;
+ (void) rts;
+}
+
+TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding) {
+ (void) itf;
+ (void) p_line_coding;
+}
+
+TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms) {
+ (void) itf;
+ (void) duration_ms;
+}
+
+//--------------------------------------------------------------------+
// APPLICATION API
//--------------------------------------------------------------------+
bool tud_cdc_configure(const tud_cdc_configure_t* driver_cfg) {
@@ -419,9 +455,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ
TU_LOG_DRV(" Set Line Coding\r\n");
tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
} else if (stage == CONTROL_STAGE_ACK) {
- if (tud_cdc_line_coding_cb) {
- tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
- }
+ tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
}
break;
@@ -456,9 +490,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ
TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts);
// Invoke callback
- if (tud_cdc_line_state_cb) {
- tud_cdc_line_state_cb(itf, dtr, rts);
- }
+ tud_cdc_line_state_cb(itf, dtr, rts);
}
break;
@@ -467,9 +499,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ
tud_control_status(rhport, request);
} else if (stage == CONTROL_STAGE_ACK) {
TU_LOG_DRV(" Send Break\r\n");
- if (tud_cdc_send_break_cb) {
- tud_cdc_send_break_cb(itf, request->wValue);
- }
+ tud_cdc_send_break_cb(itf, request->wValue);
}
break;
@@ -501,7 +531,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
tu_fifo_write_n(&p_cdc->rx_ff, p_epbuf->epout, (uint16_t) xferred_bytes);
// Check for wanted char and invoke callback if needed
- if (tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1)) {
+ if (((signed char) p_cdc->wanted_char) != -1) {
for (uint32_t i = 0; i < xferred_bytes; i++) {
if ((p_cdc->wanted_char == p_epbuf->epout[i]) && !tu_fifo_empty(&p_cdc->rx_ff)) {
tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char);
@@ -510,7 +540,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
}
// invoke receive callback (if there is still data)
- if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff)) {
+ if (!tu_fifo_empty(&p_cdc->rx_ff)) {
tud_cdc_rx_cb(itf);
}
@@ -523,9 +553,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
// Though maybe the baudrate is not really important !!!
if (ep_addr == p_cdc->ep_in) {
// invoke transmit callback to possibly refill tx fifo
- if (tud_cdc_tx_complete_cb) {
- tud_cdc_tx_complete_cb(itf);
- }
+ tud_cdc_tx_complete_cb(itf);
if (0 == tud_cdc_n_write_flush(itf)) {
// If there is no data left, a ZLP should be sent if
@@ -540,9 +568,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
// Sent notification to host
if (ep_addr == p_cdc->ep_notify) {
- if (tud_cdc_notify_complete_cb) {
- tud_cdc_notify_complete_cb(itf);
- }
+ tud_cdc_notify_complete_cb(itf);
}
return true;
diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h
index a34e07e1d..9673b9807 100644
--- a/src/class/cdc/cdc_device.h
+++ b/src/class/cdc/cdc_device.h
@@ -220,28 +220,28 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_write_clear(void) {
//--------------------------------------------------------------------+
// Invoked when received new data
-TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf);
+void tud_cdc_rx_cb(uint8_t itf);
// Invoked when received `wanted_char`
-TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
+void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
// Invoked when a TX is complete and therefore space becomes available in TX buffer
-TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf);
+void tud_cdc_tx_complete_cb(uint8_t itf);
// Invoked when a notification is sent to host
-TU_ATTR_WEAK void tud_cdc_notify_complete_cb(uint8_t itf);
+void tud_cdc_notify_complete_cb(uint8_t itf);
// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
-TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts);
+void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts);
// Invoked when line coding is change via SET_LINE_CODING
-TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding);
+void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding);
// Invoked when received send break
// \param[in] itf interface for which send break was received.
// \param[in] duration_ms the length of time, in milliseconds, of the break signal. If a value of FFFFh, then the
// device will send a break until another SendBreak request is received with value 0000h.
-TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms);
+void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms);
//--------------------------------------------------------------------+
// INTERNAL USBD-CLASS DRIVER API
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index f9a37ed35..beef03eff 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -392,6 +392,25 @@ static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t cons
static bool open_ep_stream_pair(cdch_interface_t * p_cdc , tusb_desc_endpoint_t const *desc_ep);
//--------------------------------------------------------------------+
+// Weak stubs: invoked if no strong implementation is available
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK void tuh_cdc_mount_cb(uint8_t idx) {
+ (void) idx;
+}
+
+TU_ATTR_WEAK void tuh_cdc_umount_cb(uint8_t idx) {
+ (void) idx;
+}
+
+TU_ATTR_WEAK void tuh_cdc_rx_cb(uint8_t idx) {
+ (void) idx;
+}
+
+TU_ATTR_WEAK void tuh_cdc_tx_complete_cb(uint8_t idx) {
+ (void) idx;
+}
+
+//--------------------------------------------------------------------+
// APPLICATION API
//--------------------------------------------------------------------+
@@ -657,9 +676,7 @@ void cdch_close(uint8_t daddr) {
TU_LOG_CDC(p_cdc, "close");
// Invoke application callback
- if (tuh_cdc_umount_cb) {
- tuh_cdc_umount_cb(idx);
- }
+ tuh_cdc_umount_cb(idx);
p_cdc->daddr = 0;
p_cdc->bInterfaceNumber = 0;
@@ -680,9 +697,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t
if (ep_addr == p_cdc->stream.tx.ep_addr) {
// invoke tx complete callback to possibly refill tx fifo
- if (tuh_cdc_tx_complete_cb) {
- tuh_cdc_tx_complete_cb(idx);
- }
+ tuh_cdc_tx_complete_cb(idx);
if (0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx)) {
// If there is no data left, a ZLP should be sent if:
@@ -697,18 +712,14 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t
if (xferred_bytes > 2) {
tu_edpt_stream_read_xfer_complete_with_buf(&p_cdc->stream.rx, p_cdc->stream.rx.ep_buf + 2, xferred_bytes - 2);
- if (tuh_cdc_rx_cb) {
- tuh_cdc_rx_cb(idx); // invoke receive callback
- }
+ tuh_cdc_rx_cb(idx); // invoke receive callback
}
} else
#endif
{
tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes);
- if (tuh_cdc_rx_cb) {
- tuh_cdc_rx_cb(idx); // invoke receive callback
- }
+ tuh_cdc_rx_cb(idx); // invoke receive callback
}
// prepare for next transfer if needed
@@ -794,9 +805,7 @@ static void set_config_complete(cdch_interface_t *p_cdc, bool success) {
if (success) {
const uint8_t idx = get_idx_by_ptr(p_cdc);
p_cdc->mounted = true;
- if (tuh_cdc_mount_cb) {
- tuh_cdc_mount_cb(idx);
- }
+ tuh_cdc_mount_cb(idx);
// Prepare for incoming data
tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx);
} else {
diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h
index 37bfca270..bf6711d7e 100644
--- a/src/class/cdc/cdc_host.h
+++ b/src/class/cdc/cdc_host.h
@@ -230,16 +230,16 @@ TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_disconnect_sync(u
// Invoked when a device with CDC interface is mounted
// idx is index of cdc interface in the internal pool.
-TU_ATTR_WEAK extern void tuh_cdc_mount_cb(uint8_t idx);
+extern void tuh_cdc_mount_cb(uint8_t idx);
// Invoked when a device with CDC interface is unmounted
-TU_ATTR_WEAK extern void tuh_cdc_umount_cb(uint8_t idx);
+extern void tuh_cdc_umount_cb(uint8_t idx);
// Invoked when received new data
-TU_ATTR_WEAK extern void tuh_cdc_rx_cb(uint8_t idx);
+extern void tuh_cdc_rx_cb(uint8_t idx);
// Invoked when a TX is complete and therefore space becomes available in TX buffer
-TU_ATTR_WEAK extern void tuh_cdc_tx_complete_cb(uint8_t idx);
+extern void tuh_cdc_tx_complete_cb(uint8_t idx);
//--------------------------------------------------------------------+
// Internal Class Driver API
diff --git a/src/class/cdc/cdc_rndis_host.c b/src/class/cdc/cdc_rndis_host.c
index 11a5355aa..e975ea440 100644
--- a/src/class/cdc/cdc_rndis_host.c
+++ b/src/class/cdc/cdc_rndis_host.c
@@ -103,7 +103,7 @@ static tusb_error_t rndis_body_subtask(void)
}
- osal_task_delay(100);
+ tusb_time_delay_ms_api(100);
OSAL_SUBTASK_END
}
diff --git a/src/class/dfu/dfu_device.c b/src/class/dfu/dfu_device.c
index d9e2d3f2f..0d2b63b57 100644
--- a/src/class/dfu/dfu_device.c
+++ b/src/class/dfu/dfu_device.c
@@ -77,6 +77,24 @@ static bool process_download_get_status(uint8_t rhport, uint8_t stage, const tus
static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, const tusb_control_request_t* request);
//--------------------------------------------------------------------+
+// Weak stubs: invoked if no strong implementation is available
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK void tud_dfu_detach_cb(void) {
+}
+
+TU_ATTR_WEAK void tud_dfu_abort_cb(uint8_t alt) {
+ (void) alt;
+}
+
+TU_ATTR_WEAK uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length) {
+ (void) alt;
+ (void) block_num;
+ (void) data;
+ (void) length;
+ return 0;
+}
+
+//--------------------------------------------------------------------+
// Debug
//--------------------------------------------------------------------+
#if CFG_TUSB_DEBUG >= 2
@@ -234,9 +252,7 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control
if (stage == CONTROL_STAGE_SETUP) {
tud_control_status(rhport, request);
} else if (stage == CONTROL_STAGE_ACK) {
- if (tud_dfu_detach_cb) {
- tud_dfu_detach_cb();
- }
+ tud_dfu_detach_cb();
}
break;
@@ -258,16 +274,13 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control
reset_state();
tud_control_status(rhport, request);
} else if (stage == CONTROL_STAGE_ACK) {
- if (tud_dfu_abort_cb) {
- tud_dfu_abort_cb(_dfu_ctx.alt);
- }
+ tud_dfu_abort_cb(_dfu_ctx.alt);
}
break;
case DFU_REQUEST_UPLOAD:
if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_UPLOAD);
- TU_VERIFY(tud_dfu_upload_cb);
TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE);
const uint16_t xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, _dfu_epbuf.transfer_buf,
diff --git a/src/class/dfu/dfu_device.h b/src/class/dfu/dfu_device.h
index 00c22ea8b..e59e61ce9 100644
--- a/src/class/dfu/dfu_device.h
+++ b/src/class/dfu/dfu_device.h
@@ -74,13 +74,13 @@ void tud_dfu_manifest_cb(uint8_t alt);
// Invoked when received DFU_UPLOAD request
// Application must populate data with up to length bytes and
// Return the number of written bytes
-TU_ATTR_WEAK uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length);
+uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length);
// Invoked when a DFU_DETACH request is received
-TU_ATTR_WEAK void tud_dfu_detach_cb(void);
+void tud_dfu_detach_cb(void);
// Invoked when the Host has terminated a download or upload transfer
-TU_ATTR_WEAK void tud_dfu_abort_cb(uint8_t alt);
+void tud_dfu_abort_cb(uint8_t alt);
//--------------------------------------------------------------------+
// Internal Class Driver API
diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h
index c2434c20d..b69f623a0 100644
--- a/src/class/hid/hid.h
+++ b/src/class/hid/hid.h
@@ -807,7 +807,9 @@ enum {
HID_USAGE_PAGE_MEDICAL_INSTRUMENT = 0x40,
HID_USAGE_PAGE_LIGHTING_AND_ILLUMINATION = 0x59,
HID_USAGE_PAGE_MONITOR = 0x80, // 0x80 - 0x83
- HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87
+ HID_USAGE_PAGE_POWER = 0x84,
+ HID_USAGE_PAGE_BATTERY = 0x85,
+ // 0x86 - 0x87 is reserved for Power Device
HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c,
HID_USAGE_PAGE_SCALE = 0x8d,
HID_USAGE_PAGE_MSR = 0x8e,
@@ -893,14 +895,51 @@ enum {
/// HID Usage Table: Consumer Page (0x0C)
/// Only contains controls that supported by Windows (whole list is too long)
enum {
+ HID_USAGE_CONSUMER_UNASSIGNED = 0x0000,
+
// Generic Control
HID_USAGE_CONSUMER_CONTROL = 0x0001,
+ HID_USAGE_CONSUMER_NUMERIC_KEY_PAD = 0x0002,
+ HID_USAGE_CONSUMER_PROGRAMMABLE_BUTTONS = 0x0003,
+ HID_USAGE_CONSUMER_MICROPHONE = 0x0004,
+ HID_USAGE_CONSUMER_HEADPHONE = 0x0005,
+ HID_USAGE_CONSUMER_GRAPHIC_EQUALIZER = 0x0006,
+ // 07-1F Reserved
+
+ HID_USAGE_CONSUMER_PLUS_10 = 0x0020,
+ HID_USAGE_CONSUMER_PLUS_100 = 0x0021,
+ HID_USAGE_CONSUMER_AM_PM = 0x0022,
+ // 23-3F Reserved
// Power Control
HID_USAGE_CONSUMER_POWER = 0x0030,
HID_USAGE_CONSUMER_RESET = 0x0031,
HID_USAGE_CONSUMER_SLEEP = 0x0032,
+ HID_USAGE_CONSUMER_SLEEP_AFTER = 0x0033,
+ HID_USAGE_CONSUMER_SLEEP_MODE = 0x0034,
+ HID_USAGE_CONSUMER_ILLUMINATION = 0x0035,
+ HID_USAGE_CONSUMER_FUNCTION_BUTTONS = 0x0036,
+ // 37-3F Reserved
+ HID_USAGE_CONSUMER_MENU = 0x0040,
+ HID_USAGE_CONSUMER_MENU_PICK = 0x0041,
+ HID_USAGE_CONSUMER_MENU_UP = 0x0042,
+ HID_USAGE_CONSUMER_MENU_DOWN = 0x0043,
+ HID_USAGE_CONSUMER_MENU_LEFT = 0x0044,
+ HID_USAGE_CONSUMER_MENU_RIGHT = 0x0045,
+ HID_USAGE_CONSUMER_MENU_ESCAPE = 0x0046,
+ HID_USAGE_CONSUMER_MENU_VALUE_INCREASE = 0x0047,
+ HID_USAGE_CONSUMER_MENU_VALUE_DECREASE = 0x0048,
+ // 49-5F Reserved
+ HID_USAGE_CONSUMER_DATA_ON_SCREEN = 0x0060,
+ HID_USAGE_CONSUMER_CLOSED_CAPTION = 0x0061,
+ HID_USAGE_CONSUMER_CLOSED_CAPTION_SELECT = 0x0062,
+ HID_USAGE_CONSUMER_VCR_TV = 0x0063,
+ HID_USAGE_CONSUMER_BROADCAST_MODE = 0x0064,
+ HID_USAGE_CONSUMER_SNAPSHOT = 0x0065,
+ HID_USAGE_CONSUMER_STILL = 0x0066,
+
+ // 67-7F Reserved
// Screen Brightness
HID_USAGE_CONSUMER_BRIGHTNESS_INCREMENT = 0x006F,
HID_USAGE_CONSUMER_BRIGHTNESS_DECREMENT = 0x0070,
@@ -912,40 +951,382 @@ enum {
HID_USAGE_CONSUMER_WIRELESS_RADIO_LED = 0x00C7,
HID_USAGE_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH = 0x00C8,
+ HID_USAGE_CONSUMER_SELECTION = 0x0080,
+ HID_USAGE_CONSUMER_ASSIGN_SELECTION = 0x0081,
+ HID_USAGE_CONSUMER_MODE_STEP = 0x0082,
+ HID_USAGE_CONSUMER_RECALL_LAST = 0x0083,
+ HID_USAGE_CONSUMER_ENTER_CHANNEL = 0x0084,
+ HID_USAGE_CONSUMER_ORDER_MOVIE = 0x0085,
+ HID_USAGE_CONSUMER_CHANNEL = 0x0086,
+ HID_USAGE_CONSUMER_MEDIA_SELECTION = 0x0087,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_COMPUTER = 0x0088,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_TV = 0x0089,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_WWW = 0x008A,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_DVD = 0x008B,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_TELEPHONE = 0x008C,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_PROGRAM_GUIDE = 0x008D,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_VIDEO_PHONE = 0x008E,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_GAMES = 0x008F,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_MESSAGES = 0x0090,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_CD = 0x0091,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_VCR = 0x0092,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_TUNER = 0x0093,
+ HID_USAGE_CONSUMER_QUIT = 0x0094,
+ HID_USAGE_CONSUMER_HELP = 0x0095,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_TAPE = 0x0096,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_CABLE = 0x0097,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_SATELLITE = 0x0098,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_SECURITY = 0x0099,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_HOME = 0x009A,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_CALL = 0x009B,
+ HID_USAGE_CONSUMER_CHANNEL_INCREMENT = 0x009C,
+ HID_USAGE_CONSUMER_CHANNEL_DECREMENT = 0x009D,
+ HID_USAGE_CONSUMER_MEDIA_SELECT_SAP = 0x009E,
+ // 9F Reserved
+ HID_USAGE_CONSUMER_VCR_PLUS = 0x00A0,
+ HID_USAGE_CONSUMER_ONCE = 0x00A1,
+ HID_USAGE_CONSUMER_DAILY = 0x00A2,
+ HID_USAGE_CONSUMER_WEEKLY = 0x00A3,
+ HID_USAGE_CONSUMER_MONTHLY = 0x00A4,
+ // A5-AF Reserved
+
+ HID_USAGE_CONSUMER_PLAY = 0x00B0,
+ HID_USAGE_CONSUMER_PAUSE = 0x00B1,
+ HID_USAGE_CONSUMER_RECORD = 0x00B2,
+ HID_USAGE_CONSUMER_FAST_FORWARD = 0x00B3,
+ HID_USAGE_CONSUMER_REWIND = 0x00B4,
+ HID_USAGE_CONSUMER_SCAN_NEXT_TRACK = 0x00B5,
+ HID_USAGE_CONSUMER_SCAN_PREVIOUS_TRACK = 0x00B6,
+ HID_USAGE_CONSUMER_STOP = 0x00B7,
+ HID_USAGE_CONSUMER_EJECT = 0x00B8,
+ HID_USAGE_CONSUMER_RANDOM_PLAY = 0x00B9,
+ HID_USAGE_CONSUMER_SELECT_DISC = 0x00BA,
+ HID_USAGE_CONSUMER_ENTER_DISC = 0x00BB,
+ HID_USAGE_CONSUMER_REPEAT = 0x00BC,
+ HID_USAGE_CONSUMER_TRACKING = 0x00BD,
+ HID_USAGE_CONSUMER_TRACK_NORMAL = 0x00BE,
+ HID_USAGE_CONSUMER_SLOW_TRACKING = 0x00BF,
+ HID_USAGE_CONSUMER_FRAME_FORWARD = 0x00C0,
+ HID_USAGE_CONSUMER_FRAME_BACK = 0x00C1,
+ HID_USAGE_CONSUMER_MARK = 0x00C2,
+ HID_USAGE_CONSUMER_CLEAR_MARK = 0x00C3,
+ HID_USAGE_CONSUMER_REPEAT_FROM_MARK = 0x00C4,
+ HID_USAGE_CONSUMER_RETURN_TO_MARK = 0x00C5,
+ HID_USAGE_CONSUMER_SEARCH_MARK_FORWARD = 0x00C6,
+ HID_USAGE_CONSUMER_SEARCH_MARK_BACKWARDS = 0x00C7,
+ HID_USAGE_CONSUMER_COUNTER_RESET = 0x00C8,
+ HID_USAGE_CONSUMER_SHOW_COUNTER = 0x00C9,
+ HID_USAGE_CONSUMER_TRACKING_INCREMENT = 0x00CA,
+ HID_USAGE_CONSUMER_TRACKING_DECREMENT = 0x00CB,
+ HID_USAGE_CONSUMER_STOP_EJECT = 0x00CC,
+
+
// Media Control
HID_USAGE_CONSUMER_PLAY_PAUSE = 0x00CD,
- HID_USAGE_CONSUMER_SCAN_NEXT = 0x00B5,
- HID_USAGE_CONSUMER_SCAN_PREVIOUS = 0x00B6,
- HID_USAGE_CONSUMER_STOP = 0x00B7,
+
+ HID_USAGE_CONSUMER_PLAY_SKIP = 0x00CE,
+
+ // CF-DF Reserved
HID_USAGE_CONSUMER_VOLUME = 0x00E0,
+ HID_USAGE_CONSUMER_BALANCE = 0x00E1,
HID_USAGE_CONSUMER_MUTE = 0x00E2,
HID_USAGE_CONSUMER_BASS = 0x00E3,
HID_USAGE_CONSUMER_TREBLE = 0x00E4,
HID_USAGE_CONSUMER_BASS_BOOST = 0x00E5,
+ HID_USAGE_CONSUMER_SURROUND_MODE = 0x00E6,
+ HID_USAGE_CONSUMER_LOUDNESS = 0x00E7,
+ HID_USAGE_CONSUMER_MPX = 0x00E8,
HID_USAGE_CONSUMER_VOLUME_INCREMENT = 0x00E9,
HID_USAGE_CONSUMER_VOLUME_DECREMENT = 0x00EA,
+ // EB-EF Reserved
+ HID_USAGE_CONSUMER_SPEED_SELECT = 0x00F0,
+ HID_USAGE_CONSUMER_PLAYBACK_SPEED = 0x00F1,
+ HID_USAGE_CONSUMER_STANDARD_PLAY = 0x00F2,
+ HID_USAGE_CONSUMER_LONG_PLAY = 0x00F3,
+ HID_USAGE_CONSUMER_EXTENDED_PLAY = 0x00F4,
+ HID_USAGE_CONSUMER_SLOW = 0x00F5,
+ // F6-FF Reserved
+ HID_USAGE_CONSUMER_FAN_ENABLE = 0x0100,
+ HID_USAGE_CONSUMER_FAN_SPEED = 0x0101,
+ HID_USAGE_CONSUMER_LIGHT_ENABLE = 0x0102,
+ HID_USAGE_CONSUMER_LIGHT_ILLUMINATION_LEVEL = 0x0103,
+ HID_USAGE_CONSUMER_CLIMATE_CONTROL_ENABLE = 0x0104,
+ HID_USAGE_CONSUMER_ROOM_TEMPERATURE = 0x0105,
+ HID_USAGE_CONSUMER_SECURITY_ENABLE = 0x0106,
+ HID_USAGE_CONSUMER_FIRE_ALARM = 0x0107,
+ HID_USAGE_CONSUMER_POLICE_ALARM = 0x0108,
+ HID_USAGE_CONSUMER_PROXIMITY = 0x0109,
+ HID_USAGE_CONSUMER_MOTION = 0x010A,
+ HID_USAGE_CONSUMER_DURESS_ALARM = 0x010B,
+ HID_USAGE_CONSUMER_HOLDUP_ALARM = 0x010C,
+ HID_USAGE_CONSUMER_MEDICAL_ALARM = 0x010D,
+ // 10E-14F Reserved
+ HID_USAGE_CONSUMER_BALANCE_RIGHT = 0x0150,
+ HID_USAGE_CONSUMER_BALANCE_LEFT = 0x0151,
HID_USAGE_CONSUMER_BASS_INCREMENT = 0x0152,
HID_USAGE_CONSUMER_BASS_DECREMENT = 0x0153,
HID_USAGE_CONSUMER_TREBLE_INCREMENT = 0x0154,
HID_USAGE_CONSUMER_TREBLE_DECREMENT = 0x0155,
- // Application Launcher
+ // 156-15F Reserved
+ HID_USAGE_CONSUMER_SPEAKER_SYSTEM = 0x0160,
+ HID_USAGE_CONSUMER_CHANNEL_LEFT = 0x0161,
+ HID_USAGE_CONSUMER_CHANNEL_RIGHT = 0x0162,
+ HID_USAGE_CONSUMER_CHANNEL_CENTER = 0x0163,
+ HID_USAGE_CONSUMER_CHANNEL_FRONT = 0x0164,
+ HID_USAGE_CONSUMER_CHANNEL_CENTER_FRONT = 0x0165,
+ HID_USAGE_CONSUMER_CHANNEL_SIDE = 0x0166,
+ HID_USAGE_CONSUMER_CHANNEL_SURROUND = 0x0167,
+ HID_USAGE_CONSUMER_CHANNEL_LOW_FREQUENCY = 0x0168,
+ // Enhancement
+ // CL 15.12.1
+ HID_USAGE_CONSUMER_CHANNEL_TOP = 0x0169,
+ HID_USAGE_CONSUMER_CHANNEL_UNKNOWN = 0x016A,
+ // 16B-16F Reserved
+ HID_USAGE_CONSUMER_SUB_CHANNEL = 0x0170,
+ HID_USAGE_CONSUMER_SUB_CHANNEL_INCREMENT = 0x0171,
+ HID_USAGE_CONSUMER_SUB_CHANNEL_DECREMENT = 0x0172,
+ HID_USAGE_CONSUMER_ALTERNATE_AUDIO_INCREMENT = 0x0173,
+ HID_USAGE_CONSUMER_ALTERNATE_AUDIO_DECREMENT = 0x0174,
+ // 175-17F Reserved
+ HID_USAGE_CONSUMER_APPLICATION_LAUNCH_BUTTONS = 0x0180,
+ HID_USAGE_CONSUMER_AL_LAUNCH_BUTTON_CONFIGURATION = 0x0181,
+ // Tool
+ // Sel 15.15
+ HID_USAGE_CONSUMER_AL_PROGRAMMABLE_BUTTON = 0x0182,
+ // Configuration
+ // Sel 15.15
HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183,
+ // Configuration
+ // Sel 15.15
+ HID_USAGE_CONSUMER_AL_WORD_PROCESSOR = 0x0184,
+ HID_USAGE_CONSUMER_AL_TEXT_EDITOR = 0x0185,
+ HID_USAGE_CONSUMER_AL_SPREADSHEET = 0x0186,
+ HID_USAGE_CONSUMER_AL_GRAPHICS_EDITOR = 0x0187,
+ HID_USAGE_CONSUMER_AL_PRESENTATION_APP = 0x0188,
+ HID_USAGE_CONSUMER_AL_DATABASE_APP = 0x0189,
HID_USAGE_CONSUMER_AL_EMAIL_READER = 0x018A,
+ HID_USAGE_CONSUMER_AL_NEWSREADER = 0x018B,
+ HID_USAGE_CONSUMER_AL_VOICEMAIL = 0x018C,
+ HID_USAGE_CONSUMER_AL_CONTACTS_ADDRESS_BOOK = 0x018D,
+ HID_USAGE_CONSUMER_AL_CALENDAR_SCHEDULE = 0x018E,
+ HID_USAGE_CONSUMER_AL_TASK_PROJECT_MANAGER = 0x018F,
+ HID_USAGE_CONSUMER_AL_LOG_JOURNAL_TIMECARD = 0x0190,
+ HID_USAGE_CONSUMER_AL_CHECKBOOK_FINANCE = 0x0191,
HID_USAGE_CONSUMER_AL_CALCULATOR = 0x0192,
- HID_USAGE_CONSUMER_AL_LOCAL_BROWSER = 0x0194,
-
+ HID_USAGE_CONSUMER_AL_A_V_CAPTURE_PLAYBACK = 0x0193,
+ HID_USAGE_CONSUMER_AL_LOCAL_MACHINE_BROWSER = 0x0194,
+ HID_USAGE_CONSUMER_AL_LAN_WAN_BROWSER = 0x0195,
+ HID_USAGE_CONSUMER_AL_INTERNET_BROWSER = 0x0196,
+ HID_USAGE_CONSUMER_AL_REMOTE_NETWORKING_ISP = 0x0197,
+ // Connect
+ // Sel 15.15
+ HID_USAGE_CONSUMER_AL_NETWORK_CONFERENCE = 0x0198,
+ HID_USAGE_CONSUMER_AL_NETWORK_CHAT = 0x0199,
+ HID_USAGE_CONSUMER_AL_TELEPHONY_DIALER = 0x019A,
+ HID_USAGE_CONSUMER_AL_LOGON = 0x019B,
+ HID_USAGE_CONSUMER_AL_LOGOFF = 0x019C,
+ HID_USAGE_CONSUMER_AL_LOGON_LOGOFF = 0x019D,
+ HID_USAGE_CONSUMER_AL_TERMINAL_LOCK_SCREENSAVER = 0x019E,
+ HID_USAGE_CONSUMER_AL_CONTROL_PANEL = 0x019F,
+ HID_USAGE_CONSUMER_AL_COMMAND_LINE_PROCESSOR_RUN = 0x01A0,
+ HID_USAGE_CONSUMER_AL_PROCESS_TASK_MANAGER = 0x01A1,
+ HID_USAGE_CONSUMER_AL_SELECT_TASK_APPLICATION = 0x01A2,
+ HID_USAGE_CONSUMER_AL_NEXT_TASK_APPLICATION = 0x01A3,
+ HID_USAGE_CONSUMER_AL_PREVIOUS_TASK_APPLICATION = 0x01A4,
+ HID_USAGE_CONSUMER_AL_PREEMPTIVE_HALT = 0x01A5,
+ // Task_Application
+ // Sel 15.15
+ HID_USAGE_CONSUMER_AL_INTEGRATED_HELP_CENTER = 0x01A6,
+ HID_USAGE_CONSUMER_AL_DOCUMENTS = 0x01A7,
+ HID_USAGE_CONSUMER_AL_THESAURUS = 0x01A8,
+ HID_USAGE_CONSUMER_AL_DICTIONARY = 0x01A9,
+ HID_USAGE_CONSUMER_AL_DESKTOP = 0x01AA,
+ HID_USAGE_CONSUMER_AL_SPELL_CHECK = 0x01AB,
+ HID_USAGE_CONSUMER_AL_GRAMMAR_CHECK = 0x01AC,
+ HID_USAGE_CONSUMER_AL_WIRELESS_STATUS = 0x01AD,
+ HID_USAGE_CONSUMER_AL_KEYBOARD_LAYOUT = 0x01AE,
+ HID_USAGE_CONSUMER_AL_VIRUS_PROTECTION = 0x01AF,
+ HID_USAGE_CONSUMER_AL_ENCRYPTION = 0x01B0,
+ HID_USAGE_CONSUMER_AL_SCREEN_SAVER = 0x01B1,
+ HID_USAGE_CONSUMER_AL_ALARMS = 0x01B2,
+ HID_USAGE_CONSUMER_AL_CLOCK = 0x01B3,
+ HID_USAGE_CONSUMER_AL_FILE_BROWSER = 0x01B4,
+ HID_USAGE_CONSUMER_AL_POWER_STATUS = 0x01B5,
+ HID_USAGE_CONSUMER_AL_IMAGE_BROWSER = 0x01B6,
+ HID_USAGE_CONSUMER_AL_AUDIO_BROWSER = 0x01B7,
+ HID_USAGE_CONSUMER_AL_MOVIE_BROWSER = 0x01B8,
+ HID_USAGE_CONSUMER_AL_DIGITAL_RIGHTS_MANAGER = 0x01B9,
+ HID_USAGE_CONSUMER_AL_DIGITAL_WALLET = 0x01BA,
+ // 1BB Reserved
+ HID_USAGE_CONSUMER_AL_INSTANT_MESSAGING = 0x01BC,
+ HID_USAGE_CONSUMER_AL_OEM_FEATURES_TIPS_TUTORIAL = 0x01BD,
+ // Browser
+ // Sel 15.15
+ HID_USAGE_CONSUMER_AL_OEM_HELP = 0x01BE,
+ HID_USAGE_CONSUMER_AL_ONLINE_COMMUNITY = 0x01BF,
+ HID_USAGE_CONSUMER_AL_ENTERTAINMENT_CONTENT = 0x01C0,
+ // Browser
+ // Sel 15.15
+ HID_USAGE_CONSUMER_AL_ONLINE_SHOPPING_BROWSER = 0x01C1,
+ HID_USAGE_CONSUMER_AL_SMARTCARD_INFORMATION_HELP = 0x01C2,
+ HID_USAGE_CONSUMER_AL_MARKET_MONITOR_FINANCE = 0x01C3,
+ // Browser
+ // Sel 15.15
+ HID_USAGE_CONSUMER_AL_CUSTOMIZED_CORPORATE_NEWS = 0x01C4,
+ // Browser
+ // Sel 15.15
+ HID_USAGE_CONSUMER_AL_ONLINE_ACTIVITY_BROWSER = 0x01C5,
+ HID_USAGE_CONSUMER_AL_RESEARCH_SEARCH_BROWSER = 0x01C6,
+ HID_USAGE_CONSUMER_AL_AUDIO_PLAYER = 0x01C7,
+ // 1C8-1FF Reserved
+ HID_USAGE_CONSUMER_GENERIC_GUI_APPLICATION = 0x0200,
+ // ' Controls
+ // '
+ HID_USAGE_CONSUMER_AC_NEW = 0x0201,
+ HID_USAGE_CONSUMER_AC_OPEN = 0x0202,
+ HID_USAGE_CONSUMER_AC_CLOSE = 0x0203,
+ HID_USAGE_CONSUMER_AC_EXIT = 0x0204,
+ HID_USAGE_CONSUMER_AC_MAXIMIZE = 0x0205,
+ HID_USAGE_CONSUMER_AC_MINIMIZE = 0x0206,
+ HID_USAGE_CONSUMER_AC_SAVE = 0x0207,
+ HID_USAGE_CONSUMER_AC_PRINT = 0x0208,
+ HID_USAGE_CONSUMER_AC_PROPERTIES = 0x0209,
+ HID_USAGE_CONSUMER_AC_UNDO = 0x021A,
+ HID_USAGE_CONSUMER_AC_COPY = 0x021B,
+ HID_USAGE_CONSUMER_AC_CUT = 0x021C,
+ HID_USAGE_CONSUMER_AC_PASTE = 0x021D,
+ HID_USAGE_CONSUMER_AC_SELECT_ALL = 0x021E,
+ HID_USAGE_CONSUMER_AC_FIND = 0x021F,
+ HID_USAGE_CONSUMER_AC_FIND_AND_REPLACE = 0x0220,
// Browser/Explorer Specific
HID_USAGE_CONSUMER_AC_SEARCH = 0x0221,
+ HID_USAGE_CONSUMER_AC_GO_TO = 0x0222,
HID_USAGE_CONSUMER_AC_HOME = 0x0223,
HID_USAGE_CONSUMER_AC_BACK = 0x0224,
HID_USAGE_CONSUMER_AC_FORWARD = 0x0225,
HID_USAGE_CONSUMER_AC_STOP = 0x0226,
HID_USAGE_CONSUMER_AC_REFRESH = 0x0227,
+ HID_USAGE_CONSUMER_AC_PREVIOUS_LINK = 0x0228,
+ HID_USAGE_CONSUMER_AC_NEXT_LINK = 0x0229,
HID_USAGE_CONSUMER_AC_BOOKMARKS = 0x022A,
-
+ HID_USAGE_CONSUMER_AC_HISTORY = 0x022B,
+ HID_USAGE_CONSUMER_AC_SUBSCRIPTIONS = 0x022C,
+ HID_USAGE_CONSUMER_AC_ZOOM_IN = 0x022D,
+ HID_USAGE_CONSUMER_AC_ZOOM_OUT = 0x022E,
+ HID_USAGE_CONSUMER_AC_ZOOM = 0x022F,
+ HID_USAGE_CONSUMER_AC_FULL_SCREEN_VIEW = 0x0230,
+ HID_USAGE_CONSUMER_AC_NORMAL_VIEW = 0x0231,
+ HID_USAGE_CONSUMER_AC_VIEW_TOGGLE = 0x0232,
+ HID_USAGE_CONSUMER_AC_SCROLL_UP = 0x0233,
+ HID_USAGE_CONSUMER_AC_SCROLL_DOWN = 0x0234,
+ HID_USAGE_CONSUMER_AC_SCROLL = 0x0235,
+ HID_USAGE_CONSUMER_AC_PAN_LEFT = 0x0236,
+ HID_USAGE_CONSUMER_AC_PAN_RIGHT = 0x0237,
// Mouse Horizontal scroll
HID_USAGE_CONSUMER_AC_PAN = 0x0238,
+ HID_USAGE_CONSUMER_AC_NEW_WINDOW = 0x0239,
+ HID_USAGE_CONSUMER_AC_TILE_HORIZONTALLY = 0x023A,
+ HID_USAGE_CONSUMER_AC_TILE_VERTICALLY = 0x023B,
+ HID_USAGE_CONSUMER_AC_FORMAT = 0x023C,
+ HID_USAGE_CONSUMER_AC_EDIT = 0x023D,
+ HID_USAGE_CONSUMER_AC_BOLD = 0x023E,
+ HID_USAGE_CONSUMER_AC_ITALICS = 0x023F,
+ HID_USAGE_CONSUMER_AC_UNDERLINE = 0x0240,
+ HID_USAGE_CONSUMER_AC_STRIKETHROUGH = 0x0241,
+ HID_USAGE_CONSUMER_AC_SUBSCRIPT = 0x0242,
+ HID_USAGE_CONSUMER_AC_SUPERSCRIPT = 0x0243,
+ HID_USAGE_CONSUMER_AC_ALL_CAPS = 0x0244,
+ HID_USAGE_CONSUMER_AC_ROTATE = 0x0245,
+ HID_USAGE_CONSUMER_AC_RESIZE = 0x0246,
+ HID_USAGE_CONSUMER_AC_FLIP_HORIZONTAL = 0x0247,
+ HID_USAGE_CONSUMER_AC_FLIP_VERTICAL = 0x0248,
+ HID_USAGE_CONSUMER_AC_MIRROR_HORIZONTAL = 0x0249,
+ HID_USAGE_CONSUMER_AC_MIRROR_VERTICAL = 0x024A,
+ HID_USAGE_CONSUMER_AC_FONT_SELECT = 0x024B,
+ HID_USAGE_CONSUMER_AC_FONT_COLOR = 0x024C,
+ HID_USAGE_CONSUMER_AC_FONT_SIZE = 0x024D,
+ HID_USAGE_CONSUMER_AC_JUSTIFY_LEFT = 0x024E,
+ HID_USAGE_CONSUMER_AC_JUSTIFY_CENTER_H = 0x024F,
+ HID_USAGE_CONSUMER_AC_JUSTIFY_RIGHT = 0x0250,
+ HID_USAGE_CONSUMER_AC_JUSTIFY_BLOCK_H = 0x0251,
+ HID_USAGE_CONSUMER_AC_JUSTIFY_TOP = 0x0252,
+ HID_USAGE_CONSUMER_AC_JUSTIFY_CENTER_V = 0x0253,
+ HID_USAGE_CONSUMER_AC_JUSTIFY_BOTTOM = 0x0254,
+ HID_USAGE_CONSUMER_AC_JUSTIFY_BLOCK_V = 0x0255,
+ HID_USAGE_CONSUMER_AC_INDENT_DECREASE = 0x0256,
+ HID_USAGE_CONSUMER_AC_INDENT_INCREASE = 0x0257,
+ HID_USAGE_CONSUMER_AC_NUMBERED_LIST = 0x0258,
+ HID_USAGE_CONSUMER_AC_RESTART_NUMBERING = 0x0259,
+ HID_USAGE_CONSUMER_AC_BULLETED_LIST = 0x025A,
+ HID_USAGE_CONSUMER_AC_PROMOTE = 0x025B,
+ HID_USAGE_CONSUMER_AC_DEMOTE = 0x025C,
+ HID_USAGE_CONSUMER_AC_YES = 0x025D,
+ HID_USAGE_CONSUMER_AC_NO = 0x025E,
+ HID_USAGE_CONSUMER_AC_CANCEL = 0x025F,
+ HID_USAGE_CONSUMER_AC_CATALOG = 0x0260,
+ HID_USAGE_CONSUMER_AC_BUY_CHECKOUT = 0x0261,
+ HID_USAGE_CONSUMER_AC_ADD_TO_CART = 0x0262,
+ HID_USAGE_CONSUMER_AC_EXPAND = 0x0263,
+ HID_USAGE_CONSUMER_AC_EXPAND_ALL = 0x0264,
+ HID_USAGE_CONSUMER_AC_COLLAPSE = 0x0265,
+ HID_USAGE_CONSUMER_AC_COLLAPSE_ALL = 0x0266,
+ HID_USAGE_CONSUMER_AC_PRINT_PREVIEW = 0x0267,
+ HID_USAGE_CONSUMER_AC_PASTE_SPECIAL = 0x0268,
+ HID_USAGE_CONSUMER_AC_INSERT_MODE = 0x0269,
+ HID_USAGE_CONSUMER_AC_DELETE = 0x026A,
+ HID_USAGE_CONSUMER_AC_LOCK = 0x026B,
+ HID_USAGE_CONSUMER_AC_UNLOCK = 0x026C,
+ HID_USAGE_CONSUMER_AC_PROTECT = 0x026D,
+ HID_USAGE_CONSUMER_AC_UNPROTECT = 0x026E,
+ HID_USAGE_CONSUMER_AC_ATTACH_COMMENT = 0x026F,
+ HID_USAGE_CONSUMER_AC_DELETE_COMMENT = 0x0270,
+ HID_USAGE_CONSUMER_AC_VIEW_COMMENT = 0x0271,
+ HID_USAGE_CONSUMER_AC_SELECT_WORD = 0x0272,
+ HID_USAGE_CONSUMER_AC_SELECT_SENTENCE = 0x0273,
+ HID_USAGE_CONSUMER_AC_SELECT_PARAGRAPH = 0x0274,
+ HID_USAGE_CONSUMER_AC_SELECT_COLUMN = 0x0275,
+ HID_USAGE_CONSUMER_AC_SELECT_ROW = 0x0276,
+ HID_USAGE_CONSUMER_AC_SELECT_TABLE = 0x0277,
+ HID_USAGE_CONSUMER_AC_SELECT_OBJECT = 0x0278,
+ HID_USAGE_CONSUMER_AC_REDO_REPEAT = 0x0279,
+ HID_USAGE_CONSUMER_AC_SORT = 0x027A,
+ HID_USAGE_CONSUMER_AC_SORT_ASCENDING = 0x027B,
+ HID_USAGE_CONSUMER_AC_SORT_DESCENDING = 0x027C,
+ HID_USAGE_CONSUMER_AC_FILTER = 0x027D,
+ HID_USAGE_CONSUMER_AC_SET_CLOCK = 0x027E,
+ HID_USAGE_CONSUMER_AC_VIEW_CLOCK = 0x027F,
+ HID_USAGE_CONSUMER_AC_SELECT_TIME_ZONE = 0x0280,
+ HID_USAGE_CONSUMER_AC_EDIT_TIME_ZONES = 0x0281,
+ HID_USAGE_CONSUMER_AC_SET_ALARM = 0x0282,
+ HID_USAGE_CONSUMER_AC_CLEAR_ALARM = 0x0283,
+ HID_USAGE_CONSUMER_AC_SNOOZE_ALARM = 0x0284,
+ HID_USAGE_CONSUMER_AC_RESET_ALARM = 0x0285,
+ HID_USAGE_CONSUMER_AC_SYNCHRONIZE = 0x0286,
+ HID_USAGE_CONSUMER_AC_SEND_RECEIVE = 0x0287,
+ HID_USAGE_CONSUMER_AC_SEND_TO = 0x0288,
+ HID_USAGE_CONSUMER_AC_REPLY = 0x0289,
+ HID_USAGE_CONSUMER_AC_REPLY_ALL = 0x028A,
+ HID_USAGE_CONSUMER_AC_FORWARD_MSG = 0x028B,
+ HID_USAGE_CONSUMER_AC_SEND = 0x028C,
+ HID_USAGE_CONSUMER_AC_ATTACH_FILE = 0x028D,
+ HID_USAGE_CONSUMER_AC_UPLOAD = 0x028E,
+ HID_USAGE_CONSUMER_AC_DOWNLOAD_SAVE_TARGET_AS = 0x028F,
+ HID_USAGE_CONSUMER_AC_SET_BORDERS = 0x0290,
+ HID_USAGE_CONSUMER_AC_INSERT_ROW = 0x0291,
+ HID_USAGE_CONSUMER_AC_INSERT_COLUMN = 0x0292,
+ HID_USAGE_CONSUMER_AC_INSERT_FILE = 0x0293,
+ HID_USAGE_CONSUMER_AC_INSERT_PICTURE = 0x0294,
+ HID_USAGE_CONSUMER_AC_INSERT_OBJECT = 0x0295,
+ HID_USAGE_CONSUMER_AC_INSERT_SYMBOL = 0x0296,
+ HID_USAGE_CONSUMER_AC_SAVE_AND_CLOSE = 0x0297,
+ HID_USAGE_CONSUMER_AC_RENAME = 0x0298,
+ HID_USAGE_CONSUMER_AC_MERGE = 0x0299,
+ HID_USAGE_CONSUMER_AC_SPLIT = 0x029A,
+ HID_USAGE_CONSUMER_AC_DISRIBUTE_HORIZONTALLY = 0x029B,
+ HID_USAGE_CONSUMER_AC_DISTRIBUTE_VERTICALLY = 0x029C,
+ // 29D-FFFF Reserved
+
};
/// HID Usage Table: Digitizer Page (0x0D)
@@ -1216,6 +1597,200 @@ enum {
HID_USAGE_LIGHTING_AUTONOMOUS_MODE = 0x71,
};
+/// HID Usage Table: Power Device Page (0x84)
+enum {
+ HID_USAGE_POWER_UNDEFINED = 0x00,
+ HID_USAGE_POWER_I_NAME = 0x01,
+ HID_USAGE_POWER_PRESENT_STATUS = 0x02,
+ HID_USAGE_POWER_CHANGED_STATUS = 0x03,
+ HID_USAGE_POWER_UPS = 0x04,
+ HID_USAGE_POWER_POWER_SUPPLY = 0x05,
+ // 06-0F Reserved
+ HID_USAGE_POWER_BATTERY_SYSTEM = 0x10,
+ HID_USAGE_POWER_BATTERY_SYSTEM_ID = 0x11,
+ HID_USAGE_POWER_BATTERY = 0x12,
+ HID_USAGE_POWER_BATTERY_ID = 0x13,
+ HID_USAGE_POWER_CHARGER = 0x14,
+ HID_USAGE_POWER_CHARGER_ID = 0x15,
+ HID_USAGE_POWER_POWER_CONVERTER = 0x16,
+ HID_USAGE_POWER_POWER_CONVERTER_ID = 0x17,
+ HID_USAGE_POWER_OUTLET_SYSTEM = 0x18,
+ HID_USAGE_POWER_OUTLET_SYSTEM_ID = 0x19,
+ HID_USAGE_POWER_INPUT = 0x1A,
+ HID_USAGE_POWER_INPUT_ID = 0x1B,
+ HID_USAGE_POWER_OUTPUT = 0x1C,
+ HID_USAGE_POWER_OUTPUT_ID = 0x1D,
+ HID_USAGE_POWER_FLOW = 0x1E,
+ HID_USAGE_POWER_FLOW_ID = 0x1F,
+ HID_USAGE_POWER_OUTLET = 0x20,
+ HID_USAGE_POWER_OUTLET_ID = 0x21,
+ HID_USAGE_POWER_GANG = 0x22,
+ HID_USAGE_POWER_GANG_ID = 0x23,
+ HID_USAGE_POWER_POWER_SUMMARY = 0x24,
+ HID_USAGE_POWER_POWER_SUMMARY_ID = 0x25,
+ // 26-2F Reserved
+ HID_USAGE_POWER_VOLTAGE = 0x30,
+ HID_USAGE_POWER_CURRENT = 0x31,
+ HID_USAGE_POWER_FREQUENCY = 0x32,
+ HID_USAGE_POWER_APPARENT_POWER = 0x33,
+ HID_USAGE_POWER_ACTIVE_POWER = 0x34,
+ HID_USAGE_POWER_PERCENT_LOAD = 0x35,
+ HID_USAGE_POWER_TEMPERATURE = 0x36,
+ HID_USAGE_POWER_HUMIDITY = 0x37,
+ HID_USAGE_POWER_BAD_COUNT = 0x38,
+ // 39-3F Reserved
+ HID_USAGE_POWER_CONFIG_VOLTAGE = 0x40,
+ HID_USAGE_POWER_CONFIG_CURRENT = 0x41,
+ HID_USAGE_POWER_CONFIG_FREQUENCY = 0x42,
+ HID_USAGE_POWER_CONFIG_APPARENT_POWER = 0x43,
+ HID_USAGE_POWER_CONFIG_ACTIVE_POWER = 0x44,
+ HID_USAGE_POWER_CONFIG_PERCENT_LOAD = 0x45,
+ HID_USAGE_POWER_CONFIG_TEMPERATURE = 0x46,
+ HID_USAGE_POWER_CONFIG_HUMIDITY = 0x47,
+ // 48-4F Reserved
+ HID_USAGE_POWER_SWITCH_ON_CONTROL = 0x50,
+ HID_USAGE_POWER_SWITCH_OFF_CONTROL = 0x51,
+ HID_USAGE_POWER_TOGGLE_CONTROL = 0x52,
+ HID_USAGE_POWER_LOW_VOLTAGE_TRANSFER = 0x53,
+ HID_USAGE_POWER_HIGH_VOLTAGE_TRANSFER = 0x54,
+ HID_USAGE_POWER_DELAY_BEFORE_REBOOT = 0x55,
+ HID_USAGE_POWER_DELAY_BEFORE_STARTUP = 0x56,
+ HID_USAGE_POWER_DELAY_BEFORE_SHUTDOWN = 0x57,
+ HID_USAGE_POWER_TEST = 0x58,
+ HID_USAGE_POWER_MODULE_RESET = 0x59,
+ HID_USAGE_POWER_AUDIBLE_ALARM_CONTROL = 0x5A,
+ // 5B-5F Reserved
+ HID_USAGE_POWER_PRESENT = 0x60,
+ HID_USAGE_POWER_GOOD = 0x61,
+ HID_USAGE_POWER_INTERNAL_FAILURE = 0x62,
+ HID_USAGE_POWER_VOLTAGE_OUT_OF_RANGE = 0x63,
+ HID_USAGE_POWER_FREQUENCY_OUT_OF_RANGE = 0x64,
+ HID_USAGE_POWER_OVERLOAD = 0x65,
+ HID_USAGE_POWER_OVER_CHARGED = 0x66,
+ HID_USAGE_POWER_OVER_TEMPERATURE = 0x67,
+ HID_USAGE_POWER_SHUTDOWN_REQUESTED = 0x68,
+ HID_USAGE_POWER_SHUTDOWN_IMMINENT = 0x69,
+ // 6A Reserved
+ HID_USAGE_POWER_SWITCH_ON_OFF = 0x6B,
+ HID_USAGE_POWER_SWITCHABLE = 0x6C,
+ HID_USAGE_POWER_USED = 0x6D,
+ HID_USAGE_POWER_BOOST = 0x6E,
+ HID_USAGE_POWER_BUCK = 0x6F,
+ HID_USAGE_POWER_INITIALIZED = 0x70,
+ HID_USAGE_POWER_TESTED = 0x71,
+ HID_USAGE_POWER_AWAITING_POWER = 0x72,
+ HID_USAGE_POWER_COMMUNICATION_LOST = 0x73,
+ // 74-FC Reserved
+ HID_USAGE_POWER_I_MANUFACTURER = 0xFD,
+ HID_USAGE_POWER_I_PRODUCT = 0xFE,
+ HID_USAGE_POWER_I_SERIAL_NUMBER = 0xFF
+};
+
+/// HID Usage Table: Battery System Page (0x85)
+enum {
+ HID_USAGE_BATTERY_UNDEFINED = 0x00,
+ HID_USAGE_BATTERY_SMB_BATTERY_MODE = 0x01,
+ HID_USAGE_BATTERY_SMB_BATTERY_STATUS = 0x02,
+ HID_USAGE_BATTERY_SMB_ALARM_WARNING = 0x03,
+ HID_USAGE_BATTERY_SMB_CHARGER_MODE = 0x04,
+ HID_USAGE_BATTERY_SMB_CHARGER_STATUS = 0x05,
+ HID_USAGE_BATTERY_SMB_CHARGER_SPEC_INFO = 0x06,
+ HID_USAGE_BATTERY_SMB_SELECTOR_STATE = 0x07,
+ HID_USAGE_BATTERY_SMB_SELECTOR_PRESETS = 0x08,
+ HID_USAGE_BATTERY_SMB_SELECTOR_INFO = 0x09,
+ // 0A-0F Reserved
+ HID_USAGE_BATTERY_OPTIONAL_MFG_FUNCTION_1 = 0x10,
+ HID_USAGE_BATTERY_OPTIONAL_MFG_FUNCTION_2 = 0x11,
+ HID_USAGE_BATTERY_OPTIONAL_MFG_FUNCTION_3 = 0x12,
+ HID_USAGE_BATTERY_OPTIONAL_MFG_FUNCTION_4 = 0x13,
+ HID_USAGE_BATTERY_OPTIONAL_MFG_FUNCTION_5 = 0x14,
+ HID_USAGE_BATTERY_CONNECTION_TO_SMBUS = 0x15,
+ HID_USAGE_BATTERY_OUTPUT_CONNECTION = 0x16,
+ HID_USAGE_BATTERY_CHARGER_CONNECTION = 0x17,
+ HID_USAGE_BATTERY_BATTERY_INSERTION = 0x18,
+ HID_USAGE_BATTERY_USE_NEXT = 0x19,
+ HID_USAGE_BATTERY_OK_TO_USE = 0x1A,
+ HID_USAGE_BATTERY_BATTERY_SUPPORTED = 0x1B,
+ HID_USAGE_BATTERY_SELECTOR_REVISION = 0x1C,
+ HID_USAGE_BATTERY_CHARGING_INDICATOR = 0x1D,
+ // 1E-27 Reserved
+ HID_USAGE_BATTERY_MANUFACTURER_ACCESS = 0x28,
+ HID_USAGE_BATTERY_REMAINING_CAPACITY_LIMIT = 0x29,
+ HID_USAGE_BATTERY_REMAINING_TIME_LIMIT = 0x2A,
+ HID_USAGE_BATTERY_AT_RATE = 0x2B,
+ HID_USAGE_BATTERY_CAPACITY_MODE = 0x2C,
+ HID_USAGE_BATTERY_BROADCAST_TO_CHARGER = 0x2D,
+ HID_USAGE_BATTERY_PRIMARY_BATTERY = 0x2E,
+ HID_USAGE_BATTERY_CHARGE_CONTROLLER = 0x2F,
+ // 30-3F Reserved
+ HID_USAGE_BATTERY_TERMINATE_CHARGE = 0x40,
+ HID_USAGE_BATTERY_TERMINATE_DISCHARGE = 0x41,
+ HID_USAGE_BATTERY_BELOW_REMAINING_CAPACITY_LIMIT = 0x42,
+ HID_USAGE_BATTERY_REMAINING_TIME_LIMIT_EXPIRED = 0x43,
+ HID_USAGE_BATTERY_CHARGING = 0x44,
+ HID_USAGE_BATTERY_DISCHARGING = 0x45,
+ HID_USAGE_BATTERY_FULLY_CHARGED = 0x46,
+ HID_USAGE_BATTERY_FULLY_DISCHARGED = 0x47,
+ HID_USAGE_BATTERY_CONDITIONING_FLAG = 0x48,
+ HID_USAGE_BATTERY_AT_RATE_OK = 0x49,
+ HID_USAGE_BATTERY_SMB_ERROR_CODE = 0x4A,
+ HID_USAGE_BATTERY_NEED_REPLACEMENT = 0x4B,
+ // 4C-5F Reserved
+ HID_USAGE_BATTERY_AT_RATE_TIME_TO_FULL = 0x60,
+ HID_USAGE_BATTERY_AT_RATE_TIME_TO_EMPTY = 0x61,
+ HID_USAGE_BATTERY_AVERAGE_CURRENT = 0x62,
+ HID_USAGE_BATTERY_MAX_ERROR = 0x63,
+ HID_USAGE_BATTERY_RELATIVE_STATE_OF_CHARGE = 0x64,
+ HID_USAGE_BATTERY_ABSOLUTE_STATE_OF_CHARGE = 0x65,
+ HID_USAGE_BATTERY_REMAINING_CAPACITY = 0x66,
+ HID_USAGE_BATTERY_FULL_CHARGE_CAPACITY = 0x67,
+ HID_USAGE_BATTERY_RUN_TIME_TO_EMPTY = 0x68,
+ HID_USAGE_BATTERY_AVERAGE_TIME_TO_EMPTY = 0x69,
+ HID_USAGE_BATTERY_AVERAGE_TIME_TO_FULL = 0x6A,
+ HID_USAGE_BATTERY_CYCLE_COUNT = 0x6B,
+ // 6C-7F Reserved
+ HID_USAGE_BATTERY_BATT_PACK_MODEL_LEVEL = 0x80,
+ HID_USAGE_BATTERY_INTERNAL_CHARGE_CONTROLLER = 0x81,
+ HID_USAGE_BATTERY_PRIMARY_BATTERY_SUPPORT = 0x82,
+ HID_USAGE_BATTERY_DESIGN_CAPACITY = 0x83,
+ HID_USAGE_BATTERY_SPECIFICATION_INFO = 0x84,
+ HID_USAGE_BATTERY_MANUFACTURER_DATE = 0x85,
+ HID_USAGE_BATTERY_SERIAL_NUMBER = 0x86,
+ HID_USAGE_BATTERY_I_MANUFACTURER_NAME = 0x87,
+ HID_USAGE_BATTERY_I_DEVICE_NAME = 0x88,
+ HID_USAGE_BATTERY_I_DEVICE_CHEMISTRY = 0x89,
+ HID_USAGE_BATTERY_MANUFACTURER_DATA = 0x8A,
+ HID_USAGE_BATTERY_RECHARGEABLE = 0x8B,
+ HID_USAGE_BATTERY_WARNING_CAPACITY_LIMIT = 0x8C,
+ HID_USAGE_BATTERY_CAPACITY_GRANULARITY_1 = 0x8D,
+ HID_USAGE_BATTERY_CAPACITY_GRANULARITY_2 = 0x8E,
+ HID_USAGE_BATTERY_I_OEMINFORMATION = 0x8F,
+ // 90-BF Reserved
+ HID_USAGE_BATTERY_INHIBIT_CHARGE = 0xC0,
+ HID_USAGE_BATTERY_ENABLE_POLLING = 0xC1,
+ HID_USAGE_BATTERY_RESET_TO_ZERO = 0xC2,
+ // C3-CF Reserved
+ HID_USAGE_BATTERY_AC_PRESENT = 0xD0,
+ HID_USAGE_BATTERY_BATTERY_PRESENT = 0xD1,
+ HID_USAGE_BATTERY_POWER_FAIL = 0xD2,
+ HID_USAGE_BATTERY_ALARM_INHIBITED = 0xD3,
+ HID_USAGE_BATTERY_THERMISTOR_UNDER_RANGE = 0xD4,
+ HID_USAGE_BATTERY_THERMISTOR_HOT = 0xD5,
+ HID_USAGE_BATTERY_THERMISTOR_COLD = 0xD6,
+ HID_USAGE_BATTERY_THERMISTOR_OVER_RANGE = 0xD7,
+ HID_USAGE_BATTERY_VOLTAGE_OUT_OF_RANGE = 0xD8,
+ HID_USAGE_BATTERY_CURRENT_OUT_OF_RANGE = 0xD9,
+ HID_USAGE_BATTERY_CURRENT_NOT_REGULATED = 0xDA,
+ HID_USAGE_BATTERY_VOLTAGE_NOT_REGULATED = 0xDB,
+ HID_USAGE_BATTERY_MASTER_MODE = 0xDC,
+ // DD-EF Reserved
+ HID_USAGE_BATTERY_CHARGER_SELECTOR_SUPPORT = 0xF0,
+ HID_USAGE_BATTERY_CHARGER_SPEC = 0xF1,
+ HID_USAGE_BATTERY_LEVEL_2 = 0xF2,
+ HID_USAGE_BATTERY_LEVEL_3 = 0xF3
+ // F4-FF Reserved
+};
+
/// HID Usage Table: FIDO Alliance Page (0xF1D0)
enum {
HID_USAGE_FIDO_U2FHID = 0x01, // U2FHID usage for top-level collection
diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h
index fc1dbcbd8..32b572973 100644
--- a/src/class/hid/hid_device.h
+++ b/src/class/hid/hid_device.h
@@ -267,14 +267,14 @@ void tud_hid_report_failed_cb(uint8_t instance, hid_report_type_t report_type, u
// Stylus Pen Report Descriptor Template
#define TUD_HID_REPORT_DESC_STYLUS_PEN(...) \
HID_USAGE_PAGE ( HID_USAGE_PAGE_DIGITIZER ) , \
- HID_USAGE ( HID_USAGE_DIGITIZER_TOUCH_SCREEN ) , \
+ HID_USAGE ( HID_USAGE_DIGITIZER_PEN ) , \
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) , \
/* Report ID if any */\
__VA_ARGS__ \
- HID_USAGE ( HID_USAGE_DIGITIZER_STYLUS ) , \
- HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) , \
- HID_USAGE_PAGE ( HID_USAGE_DIGITIZER_TIP_SWITCH ) , \
- HID_USAGE_PAGE ( HID_USAGE_DIGITIZER_IN_RANGE ) , \
+ HID_USAGE ( HID_USAGE_DIGITIZER_STYLUS ), \
+ HID_COLLECTION ( HID_COLLECTION_PHYSICAL ), \
+ HID_USAGE ( HID_USAGE_DIGITIZER_TIP_SWITCH ), \
+ HID_USAGE ( HID_USAGE_DIGITIZER_IN_RANGE ), \
HID_LOGICAL_MIN ( 0 ), \
HID_LOGICAL_MAX ( 1 ), \
HID_REPORT_SIZE ( 1 ), \
diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c
index 56fccdd22..da776d04c 100644
--- a/src/class/hid/hid_host.c
+++ b/src/class/hid/hid_host.c
@@ -71,6 +71,50 @@ CFG_TUH_MEM_SECTION static hidh_epbuf_t _hidh_epbuf[CFG_TUH_HID];
static uint8_t _hidh_default_protocol = HID_PROTOCOL_BOOT;
//--------------------------------------------------------------------+
+// Weak stubs: invoked if no strong implementation is available
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report_desc, uint16_t desc_len) {
+ (void) dev_addr;
+ (void) idx;
+ (void) report_desc;
+ (void) desc_len;
+}
+
+TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t idx) {
+ (void) dev_addr;
+ (void) idx;
+}
+
+TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len) {
+ (void) dev_addr;
+ (void) idx;
+ (void) report;
+ (void) len;
+}
+
+TU_ATTR_WEAK void tuh_hid_get_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len) {
+ (void) dev_addr;
+ (void) idx;
+ (void) report_id;
+ (void) report_type;
+ (void) len;
+}
+
+TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len) {
+ (void) dev_addr;
+ (void) idx;
+ (void) report_id;
+ (void) report_type;
+ (void) len;
+}
+
+TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol) {
+ (void) dev_addr;
+ (void) idx;
+ (void) protocol;
+}
+
+//--------------------------------------------------------------------+
// Helper
//--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_hid_itf(uint8_t daddr, uint8_t idx) {
@@ -183,9 +227,7 @@ static void set_protocol_complete(tuh_xfer_t* xfer) {
p_hid->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue);
}
- if (tuh_hid_set_protocol_complete_cb) {
- tuh_hid_set_protocol_complete_cb(daddr, idx, p_hid->protocol_mode);
- }
+ tuh_hid_set_protocol_complete_cb(daddr, idx, p_hid->protocol_mode);
}
void tuh_hid_set_default_protocol(uint8_t protocol) {
@@ -230,16 +272,14 @@ bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol) {
static void get_report_complete(tuh_xfer_t* xfer) {
TU_LOG_DRV("HID Get Report complete\r\n");
- if (tuh_hid_get_report_complete_cb) {
- uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
- uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num);
+ uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num);
- uint8_t const report_type = tu_u16_high(xfer->setup->wValue);
+ uint8_t const report_type = tu_u16_high(xfer->setup->wValue);
uint8_t const report_id = tu_u16_low(xfer->setup->wValue);
- tuh_hid_get_report_complete_cb(xfer->daddr, idx, report_id, report_type,
- (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0);
- }
+ tuh_hid_get_report_complete_cb(xfer->daddr, idx, report_id, report_type,
+ (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0);
}
bool tuh_hid_get_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) {
@@ -274,16 +314,14 @@ bool tuh_hid_get_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t r
static void set_report_complete(tuh_xfer_t* xfer) {
TU_LOG_DRV("HID Set Report complete\r\n");
- if (tuh_hid_set_report_complete_cb) {
- uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
- uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num);
+ uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num);
- uint8_t const report_type = tu_u16_high(xfer->setup->wValue);
- uint8_t const report_id = tu_u16_low(xfer->setup->wValue);
+ uint8_t const report_type = tu_u16_high(xfer->setup->wValue);
+ uint8_t const report_id = tu_u16_low(xfer->setup->wValue);
- tuh_hid_set_report_complete_cb(xfer->daddr, idx, report_id, report_type,
- (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0);
- }
+ tuh_hid_set_report_complete_cb(xfer->daddr, idx, report_id, report_type,
+ (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0);
}
bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) {
@@ -448,9 +486,7 @@ bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t
TU_LOG3_MEM(epbuf->epin, xferred_bytes, 2);
tuh_hid_report_received_cb(daddr, idx, epbuf->epin, (uint16_t) xferred_bytes);
} else {
- if (tuh_hid_report_sent_cb) {
- tuh_hid_report_sent_cb(daddr, idx, epbuf->epout, (uint16_t) xferred_bytes);
- }
+ tuh_hid_report_sent_cb(daddr, idx, epbuf->epout, (uint16_t) xferred_bytes);
}
return true;
@@ -461,9 +497,7 @@ void hidh_close(uint8_t daddr) {
hidh_interface_t* p_hid = &_hidh_itf[i];
if (p_hid->daddr == daddr) {
TU_LOG_DRV(" HIDh close addr = %u index = %u\r\n", daddr, i);
- if (tuh_hid_umount_cb) {
- tuh_hid_umount_cb(daddr, i);
- }
+ tuh_hid_umount_cb(daddr, i);
tu_memclr(p_hid, sizeof(hidh_interface_t));
}
}
@@ -519,7 +553,8 @@ bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const* desc_
// Assume bNumDescriptors = 1
p_hid->report_desc_type = desc_hid->bReportType;
- p_hid->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength);
+ // Use offsetof to avoid pointer to the odd/misaligned address
+ p_hid->report_desc_len = tu_unaligned_read16((uint8_t const*)desc_hid + offsetof(tusb_hid_descriptor_hid_t, wReportLength));
// Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config
p_hid->protocol_mode = _hidh_default_protocol;
@@ -624,7 +659,7 @@ static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t con
p_hid->mounted = true;
// enumeration is complete
- if (tuh_hid_mount_cb) tuh_hid_mount_cb(daddr, idx, desc_report, desc_len);
+ tuh_hid_mount_cb(daddr, idx, desc_report, desc_len);
// notify usbh that driver enumeration is complete
usbh_driver_set_config_complete(daddr, p_hid->itf_num);
diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h
index 9681c704b..032827af1 100644
--- a/src/class/hid/hid_host.h
+++ b/src/class/hid/hid_host.h
@@ -145,28 +145,28 @@ bool tuh_hid_send_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, const
// can be used to parse common/simple enough descriptor.
// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped
// therefore report_desc = NULL, desc_len = 0
-TU_ATTR_WEAK void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report_desc, uint16_t desc_len);
+void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report_desc, uint16_t desc_len);
// Invoked when device with hid interface is un-mounted
-TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t idx);
+void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t idx);
// Invoked when received report from device via interrupt endpoint
// Note: if there is report ID (composite), it is 1st byte of report
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len);
// Invoked when sent report to device successfully via interrupt endpoint
-TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len);
+void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len);
// Invoked when Get Report to device via either control endpoint
// len = 0 indicate there is error in the transfer e.g stalled response
-TU_ATTR_WEAK void tuh_hid_get_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len);
+void tuh_hid_get_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len);
// Invoked when Sent Report to device via either control endpoint
// len = 0 indicate there is error in the transfer e.g stalled response
-TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len);
+void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len);
// Invoked when Set Protocol request is complete
-TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol);
+void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol);
//--------------------------------------------------------------------+
// Internal Class Driver API
diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c
index 0bbb3caf4..7dac7c4a5 100644
--- a/src/class/midi/midi_device.c
+++ b/src/class/midi/midi_device.c
@@ -107,6 +107,14 @@ static void _prep_out_transaction(uint8_t idx) {
}
}
+
+//--------------------------------------------------------------------+
+// Weak stubs: invoked if no strong implementation is available
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf) {
+ (void) itf;
+}
+
//--------------------------------------------------------------------+
// READ API
//--------------------------------------------------------------------+
@@ -528,9 +536,7 @@ bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32
tu_fifo_write_n(&p_midi->rx_ff, _midid_epbuf[idx].epout, (uint16_t)xferred_bytes);
// invoke receive callback if available
- if (tud_midi_rx_cb) {
- tud_midi_rx_cb(idx);
- }
+ tud_midi_rx_cb(idx);
// prepare for next
// TODO for now ep_out is not used by public API therefore there is no race condition,
diff --git a/src/class/midi/midi_device.h b/src/class/midi/midi_device.h
index 3e89cc0a3..c2c6e9859 100644
--- a/src/class/midi/midi_device.h
+++ b/src/class/midi/midi_device.h
@@ -116,9 +116,9 @@ static inline bool tud_midi_receive(uint8_t packet[4])
}
//--------------------------------------------------------------------+
-// Application Callback API (weak is optional)
+// Application Callback API (optional)
//--------------------------------------------------------------------+
-TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf);
+void tud_midi_rx_cb(uint8_t itf);
//--------------------------------------------------------------------+
// Inline Functions
diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c
index 50bda1e36..e6ace316c 100644
--- a/src/class/midi/midi_host.c
+++ b/src/class/midi/midi_host.c
@@ -575,6 +575,11 @@ uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buff
}
}
}
+ else {
+ // bad packet discard
+ nread = tu_edpt_stream_read(p_midi->daddr, &p_midi->ep_stream.rx, p_midi->stream_read.buffer, 4);
+ continue;
+ }
} else if (status < MIDI_STATUS_SYSEX_START) {
// then it is a channel message either three bytes or two
uint8_t fake_cin = (status & 0xf0) >> 4;
@@ -617,6 +622,11 @@ uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buff
bytes_to_add_to_stream = 1;
}
}
+ else {
+ // bad packet discard
+ nread = tu_edpt_stream_read(p_midi->daddr, &p_midi->ep_stream.rx, p_midi->stream_read.buffer, 4);
+ continue;
+ }
for (uint8_t i = 1; i <= bytes_to_add_to_stream; i++) {
*p_buffer++ = p_midi->stream_read.buffer[i];
diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c
index a32014c2d..b0eafd5da 100644
--- a/src/class/msc/msc_device.c
+++ b/src/class/msc/msc_device.c
@@ -224,6 +224,53 @@ static bool proc_stage_status(mscd_interface_t *p_msc) {
}
//--------------------------------------------------------------------+
+// Weak stubs: invoked if no strong implementation is available
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun) {
+ (void) lun;
+}
+
+TU_ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun) {
+ (void) lun;
+}
+
+TU_ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]) {
+ (void) lun;
+ (void) scsi_cmd;
+}
+
+TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void) {
+ return 1;
+}
+
+TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
+ (void) lun;
+ (void) power_condition;
+ (void) start;
+ (void) load_eject;
+ return true;
+}
+
+TU_ATTR_WEAK bool tud_msc_prevent_allow_medium_removal_cb(uint8_t lun, uint8_t prohibit_removal, uint8_t control) {
+ (void) lun;
+ (void) prohibit_removal;
+ (void) control;
+ return true;
+}
+
+TU_ATTR_WEAK int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize) {
+ (void) lun;
+ (void) buffer;
+ (void) bufsize;
+ return sizeof(scsi_sense_fixed_resp_t);
+}
+
+TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun) {
+ (void) lun;
+ return true;
+}
+
+//--------------------------------------------------------------------+
// Debug
//--------------------------------------------------------------------+
#if CFG_TUSB_DEBUG >= CFG_TUD_MSC_LOG_LEVEL
@@ -403,10 +450,7 @@ bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
TU_LOG_DRV(" MSC Get Max Lun\r\n");
TU_VERIFY(request->wValue == 0 && request->wLength == 1);
- uint8_t maxlun = 1;
- if (tud_msc_get_maxlun_cb) {
- maxlun = tud_msc_get_maxlun_cb();
- }
+ uint8_t maxlun = tud_msc_get_maxlun_cb();
TU_VERIFY(maxlun);
maxlun--; // MAX LUN is minus 1 by specs
tud_control_xfer(rhport, request, &maxlun, 1);
@@ -584,21 +628,15 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
// if complete_cb() is invoked after queuing the status.
switch (p_cbw->command[0]) {
case SCSI_CMD_READ_10:
- if (tud_msc_read10_complete_cb) {
- tud_msc_read10_complete_cb(p_cbw->lun);
- }
+ tud_msc_read10_complete_cb(p_cbw->lun);
break;
case SCSI_CMD_WRITE_10:
- if (tud_msc_write10_complete_cb) {
- tud_msc_write10_complete_cb(p_cbw->lun);
- }
+ tud_msc_write10_complete_cb(p_cbw->lun);
break;
default:
- if (tud_msc_scsi_complete_cb) {
- tud_msc_scsi_complete_cb(p_cbw->lun, p_cbw->command);
- }
+ tud_msc_scsi_complete_cb(p_cbw->lun, p_cbw->command);
break;
}
@@ -648,16 +686,14 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
case SCSI_CMD_START_STOP_UNIT:
resplen = 0;
- if (tud_msc_start_stop_cb) {
- scsi_start_stop_unit_t const* start_stop = (scsi_start_stop_unit_t const*)scsi_cmd;
- if (!tud_msc_start_stop_cb(lun, start_stop->power_condition, start_stop->start, start_stop->load_eject)) {
- // Failed status response
- resplen = -1;
+ scsi_start_stop_unit_t const* start_stop = (scsi_start_stop_unit_t const*)scsi_cmd;
+ if (!tud_msc_start_stop_cb(lun, start_stop->power_condition, start_stop->start, start_stop->load_eject)) {
+ // Failed status response
+ resplen = -1;
- // set default sense if not set by callback
- if (p_msc->sense_key == 0) {
- set_sense_medium_not_present(lun);
- }
+ // set default sense if not set by callback
+ if (p_msc->sense_key == 0) {
+ set_sense_medium_not_present(lun);
}
}
break;
@@ -665,16 +701,14 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
resplen = 0;
- if (tud_msc_prevent_allow_medium_removal_cb) {
- scsi_prevent_allow_medium_removal_t const* prevent_allow = (scsi_prevent_allow_medium_removal_t const*)scsi_cmd;
- if (!tud_msc_prevent_allow_medium_removal_cb(lun, prevent_allow->prohibit_removal, prevent_allow->control)) {
- // Failed status response
- resplen = -1;
+ scsi_prevent_allow_medium_removal_t const* prevent_allow = (scsi_prevent_allow_medium_removal_t const*)scsi_cmd;
+ if (!tud_msc_prevent_allow_medium_removal_cb(lun, prevent_allow->prohibit_removal, prevent_allow->control)) {
+ // Failed status response
+ resplen = -1;
- // set default sense if not set by callback
- if (p_msc->sense_key == 0) {
- set_sense_medium_not_present(lun);
- }
+ // set default sense if not set by callback
+ if (p_msc->sense_key == 0) {
+ set_sense_medium_not_present(lun);
}
}
break;
@@ -767,10 +801,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
.block_descriptor_len = 0 // no block descriptor are included
};
- bool writable = true;
- if (tud_msc_is_writable_cb) {
- writable = tud_msc_is_writable_cb(lun);
- }
+ bool writable = tud_msc_is_writable_cb(lun);
mode_resp.write_protected = !writable;
@@ -794,9 +825,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &sense_rsp, (size_t) resplen));
// request sense callback could overwrite the sense data
- if (tud_msc_request_sense_cb) {
- resplen = tud_msc_request_sense_cb(lun, buffer, (uint16_t)bufsize);
- }
+ resplen = tud_msc_request_sense_cb(lun, buffer, (uint16_t)bufsize);
// Clear sense data after copy
tud_msc_set_sense(lun, 0, 0, 0);
@@ -854,11 +883,7 @@ static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) {
static void proc_write10_cmd(mscd_interface_t* p_msc) {
msc_cbw_t const* p_cbw = &p_msc->cbw;
- bool writable = true;
-
- if (tud_msc_is_writable_cb) {
- writable = tud_msc_is_writable_cb(p_cbw->lun);
- }
+ bool writable = tud_msc_is_writable_cb(p_cbw->lun);
if (!writable) {
// Not writable, complete this SCSI op with error
diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h
index 144b74f71..7d898e988 100644
--- a/src/class/msc/msc_device.h
+++ b/src/class/msc/msc_device.h
@@ -128,30 +128,30 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
/*------------- Optional callbacks -------------*/
// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation
-TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void);
+uint8_t tud_msc_get_maxlun_cb(void);
// Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
-TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject);
+bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject);
//Invoked when we receive the Prevent / Allow Medium Removal command
-TU_ATTR_WEAK bool tud_msc_prevent_allow_medium_removal_cb(uint8_t lun, uint8_t prohibit_removal, uint8_t control);
+bool tud_msc_prevent_allow_medium_removal_cb(uint8_t lun, uint8_t prohibit_removal, uint8_t control);
// Invoked when received REQUEST_SENSE
-TU_ATTR_WEAK int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize);
+int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize);
// Invoked when Read10 command is complete
-TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun);
+void tud_msc_read10_complete_cb(uint8_t lun);
// Invoke when Write10 command is complete, can be used to flush flash caching
-TU_ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun);
+void tud_msc_write10_complete_cb(uint8_t lun);
// Invoked when command in tud_msc_scsi_cb is complete
-TU_ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]);
+void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]);
// Invoked to check if device is writable as part of SCSI WRITE10
-TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun);
+bool tud_msc_is_writable_cb(uint8_t lun);
//--------------------------------------------------------------------+
// Internal Class Driver API
diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c
index ef0635bbe..eb69ae400 100644
--- a/src/class/msc/msc_host.c
+++ b/src/class/msc/msc_host.c
@@ -88,6 +88,17 @@ TU_ATTR_ALWAYS_INLINE static inline msch_epbuf_t* get_epbuf(uint8_t daddr) {
}
//--------------------------------------------------------------------+
+// Weak stubs: invoked if no strong implementation is available
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK void tuh_msc_mount_cb(uint8_t dev_addr) {
+ (void) dev_addr;
+}
+
+TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr) {
+ (void) dev_addr;
+}
+
+//--------------------------------------------------------------------+
// PUBLIC API
//--------------------------------------------------------------------+
uint8_t tuh_msc_get_maxlun(uint8_t dev_addr) {
@@ -304,9 +315,7 @@ void msch_close(uint8_t dev_addr) {
// invoke Application Callback
if (p_msc->mounted) {
- if (tuh_msc_umount_cb) {
- tuh_msc_umount_cb(dev_addr);
- }
+ tuh_msc_umount_cb(dev_addr);
}
tu_memclr(p_msc, sizeof(msch_interface_t));
@@ -497,9 +506,7 @@ static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_dat
// Mark enumeration is complete
p_msc->mounted = true;
- if (tuh_msc_mount_cb) {
- tuh_msc_mount_cb(dev_addr);
- }
+ tuh_msc_mount_cb(dev_addr);
// notify usbh that driver enumeration is complete
usbh_driver_set_config_complete(dev_addr, p_msc->itf_num);
diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h
index 09d777066..b5fd55547 100644
--- a/src/class/msc/msc_host.h
+++ b/src/class/msc/msc_host.h
@@ -109,10 +109,10 @@ bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_r
//------------- Application Callback -------------//
// Invoked when a device with MassStorage interface is mounted
-TU_ATTR_WEAK void tuh_msc_mount_cb(uint8_t dev_addr);
+void tuh_msc_mount_cb(uint8_t dev_addr);
// Invoked when a device with MassStorage interface is unmounted
-TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr);
+void tuh_msc_umount_cb(uint8_t dev_addr);
//--------------------------------------------------------------------+
// Internal Class Driver API
diff --git a/src/class/mtp/mtp.h b/src/class/mtp/mtp.h
new file mode 100644
index 000000000..40b6dd8b0
--- /dev/null
+++ b/src/class/mtp/mtp.h
@@ -0,0 +1,888 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef TUSB_MTP_H_
+#define TUSB_MTP_H_
+
+#include "common/tusb_common.h"
+
+#if (CFG_TUD_ENABLED && CFG_TUD_MTP)
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Media Transfer Protocol Class Constant
+//--------------------------------------------------------------------+
+
+// Media Transfer Protocol Subclass
+typedef enum {
+ MTP_SUBCLASS_STILL_IMAGE = 1
+} mtp_subclass_type_t;
+
+// MTP Protocol.
+typedef enum {
+ MTP_PROTOCOL_PIMA_15470 = 1, ///< Picture Transfer Protocol (PIMA 15470)
+} mtp_protocol_type_t;
+
+// PTP/MTP protocol phases
+typedef enum {
+ MTP_PHASE_COMMAND = 0,
+ MTP_PHASE_DATA,
+ MTP_PHASE_RESPONSE,
+ MTP_PHASE_ERROR
+} mtp_phase_type_t;
+
+// PTP/MTP Class requests, PIMA 15740-2000: D.5.2
+typedef enum {
+ MTP_REQ_CANCEL = 0x64,
+ MTP_REQ_GET_EXT_EVENT_DATA = 0x65,
+ MTP_REQ_RESET = 0x66,
+ MTP_REQ_GET_DEVICE_STATUS = 0x67,
+} mtp_class_request_t;
+
+// PTP/MTP Container type
+typedef enum {
+ MTP_CONTAINER_TYPE_UNDEFINED = 0,
+ MTP_CONTAINER_TYPE_COMMAND_BLOCK = 1,
+ MTP_CONTAINER_TYPE_DATA_BLOCK = 2,
+ MTP_CONTAINER_TYPE_RESPONSE_BLOCK = 3,
+ MTP_CONTAINER_TYPE_EVENT_BLOCK = 4,
+} mtp_container_type_t;
+
+// MTP 1.1 Appendix A: Object formats
+typedef enum {
+ // ---- Base formats ----
+ MTP_OBJ_FORMAT_UNDEFINED = 0x3000u, // Undefined object
+ MTP_OBJ_FORMAT_ASSOCIATION = 0x3001u, // Association (for example, a folder)
+ MTP_OBJ_FORMAT_SCRIPT = 0x3002u, // Device model-specific script
+ MTP_OBJ_FORMAT_EXECUTABLE = 0x3003u, // Device model-specific binary executable
+ MTP_OBJ_FORMAT_TEXT = 0x3004u, // Text file
+ MTP_OBJ_FORMAT_HTML = 0x3005u, // Hypertext Markup Language file (text)
+ MTP_OBJ_FORMAT_DPOF = 0x3006u, // Digital Print Order Format file (text)
+ MTP_OBJ_FORMAT_AIFF = 0x3007u, // Audio clip (AIFF)
+ MTP_OBJ_FORMAT_WAV = 0x3008u, // Audio clip (WAV)
+ MTP_OBJ_FORMAT_MP3 = 0x3009u, // MPEG-1 Layer III audio (ISO/IEC 13818-3)
+ MTP_OBJ_FORMAT_AVI = 0x300Au, // Video clip (AVI)
+ MTP_OBJ_FORMAT_MPEG = 0x300Bu, // Video clip (MPEG)
+ MTP_OBJ_FORMAT_ASF = 0x300Cu, // Microsoft Advanced Streaming Format (video)
+
+ // ---- Image formats ----
+ MTP_OBJ_FORMAT_UNDEFINED_IMAGE = 0x3800u, // Undefined image object
+ MTP_OBJ_FORMAT_EXIF_JPEG = 0x3801u, // Exchangeable Image Format, JEIDA standard
+ MTP_OBJ_FORMAT_TIFF_EP = 0x3802u, // Tag Image File Format for Electronic Photography
+ MTP_OBJ_FORMAT_FLASHPIX = 0x3803u, // Structured Storage Image Format (FlashPix)
+ MTP_OBJ_FORMAT_BMP = 0x3804u, // Microsoft Windows Bitmap file
+ MTP_OBJ_FORMAT_CIFF = 0x3805u, // Canon Camera Image File Format
+ MTP_OBJ_FORMAT_UNDEFINED_3806 = 0x3806u, // Reserved / Undefined
+ MTP_OBJ_FORMAT_GIF = 0x3807u, // Graphics Interchange Format
+ MTP_OBJ_FORMAT_JFIF = 0x3808u, // JPEG File Interchange Format
+ MTP_OBJ_FORMAT_CD = 0x3809u, // PhotoCD Image Pac
+ MTP_OBJ_FORMAT_PICT = 0x380Au, // Quickdraw Image Format
+ MTP_OBJ_FORMAT_PNG = 0x380Bu, // Portable Network Graphics
+ MTP_OBJ_FORMAT_UNDEFINED_380C = 0x380Cu, // Reserved / Undefined
+ MTP_OBJ_FORMAT_TIFF = 0x380Du, // Tag Image File Format (baseline)
+ MTP_OBJ_FORMAT_TIFF_IT = 0x380Eu, // Tag Image File Format for IT (graphic arts)
+ MTP_OBJ_FORMAT_JP2 = 0x380Fu, // JPEG2000 Baseline File Format
+ MTP_OBJ_FORMAT_JPX = 0x3810u, // JPEG2000 Extended File Format
+
+ // ---- Firmware & misc ----
+ MTP_OBJ_FORMAT_UNDEFINED_FIRMWARE = 0xB802u, // Undefined Firmware
+ MTP_OBJ_FORMAT_WBMP = 0xB803u, // Wireless Application Protocol Bitmap Format (.wbmp)
+ MTP_OBJ_FORMAT_WINDOWS_IMAGE = 0xB881u, // Windows Image Format
+ MTP_OBJ_FORMAT_JPEGXR = 0xB804u, // JPEG XR (.hdp, .jxr, .wdp)
+
+ // ---- Audio formats ----
+ MTP_OBJ_FORMAT_UNDEFINED_AUDIO = 0xB900u, // Undefined audio object
+ MTP_OBJ_FORMAT_WMA = 0xB901u, // Windows Media Audio
+ MTP_OBJ_FORMAT_OGG = 0xB902u, // OGG container
+ MTP_OBJ_FORMAT_AAC = 0xB903u, // Advanced Audio Coding (.aac)
+ MTP_OBJ_FORMAT_AUDIBLE = 0xB904u, // Audible format
+ MTP_OBJ_FORMAT_FLAC = 0xB906u, // Free Lossless Audio Codec
+ MTP_OBJ_FORMAT_QCELP = 0xB907u, // Qualcomm Code Excited Linear Prediction (.qcp)
+ MTP_OBJ_FORMAT_AMR = 0xB908u, // Adaptive Multi-Rate audio (.amr)
+
+ // ---- Video formats ----
+ MTP_OBJ_FORMAT_UNDEFINED_VIDEO = 0xB980u, // Undefined video object
+ MTP_OBJ_FORMAT_WMV = 0xB981u, // Windows Media Video
+ MTP_OBJ_FORMAT_MP4 = 0xB982u, // MP4 Container (ISO 14496-1)
+ MTP_OBJ_FORMAT_MP2 = 0xB983u, // MPEG-1 Layer II audio
+ MTP_OBJ_FORMAT_3GP = 0xB984u, // 3GP Container
+ MTP_OBJ_FORMAT_3G2 = 0xB985u, // 3GPP2 Container
+ MTP_OBJ_FORMAT_AVCHD = 0xB986u, // AVCHD (MPEG-4 AVC + Dolby Digital)
+ MTP_OBJ_FORMAT_ATSC_TS = 0xB987u, // ATSC-compliant MPEG-2 Transport Stream
+ MTP_OBJ_FORMAT_DVB_TS = 0xB988u, // DVB-compliant MPEG-2 Transport Stream
+
+ // ---- Collections ----
+ MTP_OBJ_FORMAT_UNDEFINED_COLLECTION = 0xBA00u, // Undefined collection
+ MTP_OBJ_FORMAT_ABSTRACT_MULTIMEDIA_ALBUM = 0xBA01u, // Abstract Multimedia Album
+ MTP_OBJ_FORMAT_ABSTRACT_IMAGE_ALBUM = 0xBA02u, // Abstract Image Album
+ MTP_OBJ_FORMAT_ABSTRACT_AUDIO_ALBUM = 0xBA03u, // Abstract Audio Album
+ MTP_OBJ_FORMAT_ABSTRACT_VIDEO_ALBUM = 0xBA04u, // Abstract Video Album
+ MTP_OBJ_FORMAT_ABSTRACT_AV_PLAYLIST = 0xBA05u, // Abstract Audio & Video Playlist
+ MTP_OBJ_FORMAT_ABSTRACT_CONTACT_GROUP = 0xBA06u, // Abstract Contact Group
+ MTP_OBJ_FORMAT_ABSTRACT_MESSAGE_FOLDER = 0xBA07u, // Abstract Message Folder
+ MTP_OBJ_FORMAT_ABSTRACT_CHAPTERED_PRODUCTION = 0xBA08u, // Abstract Chaptered Production
+ MTP_OBJ_FORMAT_ABSTRACT_AUDIO_PLAYLIST = 0xBA09u, // Abstract Audio Playlist
+ MTP_OBJ_FORMAT_ABSTRACT_VIDEO_PLAYLIST = 0xBA0Au, // Abstract Video Playlist
+ MTP_OBJ_FORMAT_ABSTRACT_MEDIACAST = 0xBA0Bu, // Abstract Mediacast (RSS enclosure)
+
+ // ---- Playlist formats ----
+ MTP_OBJ_FORMAT_WPL_PLAYLIST = 0xBA10u, // Windows Media Player Playlist (.wpl)
+ MTP_OBJ_FORMAT_M3U_PLAYLIST = 0xBA11u, // M3U Playlist
+ MTP_OBJ_FORMAT_MPL_PLAYLIST = 0xBA12u, // MPL Playlist
+ MTP_OBJ_FORMAT_ASX_PLAYLIST = 0xBA13u, // ASX Playlist
+ MTP_OBJ_FORMAT_PLS_PLAYLIST = 0xBA14u, // PLS Playlist
+
+ // ---- Document formats ----
+ MTP_OBJ_FORMAT_UNDEFINED_DOC = 0xBA80u, // Undefined Document
+ MTP_OBJ_FORMAT_ABSTRACT_DOC = 0xBA81u, // Abstract Document
+ MTP_OBJ_FORMAT_XML_DOC = 0xBA82u, // XML Document
+ MTP_OBJ_FORMAT_DOC = 0xBA83u, // Microsoft Word Document
+ MTP_OBJ_FORMAT_MHT_DOC = 0xBA84u, // MHT Compiled HTML Document
+ MTP_OBJ_FORMAT_XLS = 0xBA85u, // Microsoft Excel Spreadsheet
+ MTP_OBJ_FORMAT_PPT = 0xBA86u, // Microsoft PowerPoint Presentation
+
+ // ---- Messaging ----
+ MTP_OBJ_FORMAT_UNDEFINED_MSG = 0xBB00u, // Undefined Message
+ MTP_OBJ_FORMAT_ABSTRACT_MSG = 0xBB01u, // Abstract Message
+
+ // ---- Bookmarks ----
+ MTP_OBJ_FORMAT_UNDEFINED_BOOKMARK = 0xBB10u, // Undefined Bookmark
+ MTP_OBJ_FORMAT_ABSTRACT_BOOKMARK = 0xBB11u, // Abstract Bookmark
+
+ // ---- Appointments ----
+ MTP_OBJ_FORMAT_UNDEFINED_APPT = 0xBB20u, // Undefined Appointment
+ MTP_OBJ_FORMAT_ABSTRACT_APPT = 0xBB21u, // Abstract Appointment
+ MTP_OBJ_FORMAT_VCALENDAR1 = 0xBB22u, // vCalendar 1.0
+
+ // ---- Tasks ----
+ MTP_OBJ_FORMAT_UNDEFINED_TASK = 0xBB40u, // Undefined Task
+ MTP_OBJ_FORMAT_ABSTRACT_TASK = 0xBB41u, // Abstract Task
+ MTP_OBJ_FORMAT_ICALENDAR = 0xBB42u, // iCalendar
+
+ // ---- Notes ----
+ MTP_OBJ_FORMAT_UNDEFINED_NOTE = 0xBB60u, // Undefined Note
+ MTP_OBJ_FORMAT_ABSTRACT_NOTE = 0xBB61u, // Abstract Note
+
+ // ---- Contacts ----
+ MTP_OBJ_FORMAT_UNDEFINED_CONTACT= 0xBB80u, // Undefined Contact
+ MTP_OBJ_FORMAT_ABSTRACT_CONTACT = 0xBB81u, // Abstract Contact
+ MTP_OBJ_FORMAT_VCARD2 = 0xBB82u, // vCard 2.1
+ MTP_OBJ_FORMAT_VCARD3 = 0xBB83u, // vCard 3.0
+} mtp_object_formats_t;
+
+// MTP 1.1 Appendix B: Object Properties
+typedef enum {
+ MTP_OBJ_PROP_STORAGE_ID = 0xDC01u, // StorageID
+ MTP_OBJ_PROP_OBJECT_FORMAT = 0xDC02u, // Object Format
+ MTP_OBJ_PROP_PROTECTION_STATUS = 0xDC03u, // Protection Status
+ MTP_OBJ_PROP_OBJECT_SIZE = 0xDC04u, // Object Size
+ MTP_OBJ_PROP_ASSOCIATION_TYPE = 0xDC05u, // Association Type
+ MTP_OBJ_PROP_ASSOCIATION_DESC = 0xDC06u, // Association Description
+ MTP_OBJ_PROP_OBJECT_FILE_NAME = 0xDC07u, // Object File Name
+ MTP_OBJ_PROP_DATE_CREATED = 0xDC08u, // Date Created
+ MTP_OBJ_PROP_DATE_MODIFIED = 0xDC09u, // Date Modified
+ MTP_OBJ_PROP_KEYWORDS = 0xDC0Au, // Keywords
+ MTP_OBJ_PROP_PARENT_OBJECT = 0xDC0Bu, // Parent Object
+ MTP_OBJ_PROP_ALLOWED_FOLDER_CONTENTS = 0xDC0Cu, // Allowed Folder Contents
+ MTP_OBJ_PROP_HIDDEN = 0xDC0Du, // Hidden
+ MTP_OBJ_PROP_SYSTEM_OBJECT = 0xDC0Eu, // System Object
+ // 0xDC0F-0xDC40 is reserved
+
+ MTP_OBJ_PROP_PERSISTENT_UID = 0xDC41u, // Persistent Unique Object Identifier
+ MTP_OBJ_PROP_SYNC_ID = 0xDC42u, // SyncID
+ MTP_OBJ_PROP_PROPERTY_BAG = 0xDC43u, // Property Bag
+ MTP_OBJ_PROP_NAME = 0xDC44u, // Name
+ MTP_OBJ_PROP_CREATED_BY = 0xDC45u, // Created By
+ MTP_OBJ_PROP_ARTIST = 0xDC46u, // Artist
+ MTP_OBJ_PROP_DATE_AUTHORED = 0xDC47u, // Date Authored
+ MTP_OBJ_PROP_DESCRIPTION = 0xDC48u, // Description
+ MTP_OBJ_PROP_URL_REFERENCE = 0xDC49u, // URL Reference
+ MTP_OBJ_PROP_LANGUAGE_LOCALE = 0xDC4Au, // Language-Locale
+ MTP_OBJ_PROP_COPYRIGHT_INFO = 0xDC4Bu, // Copyright Information
+ MTP_OBJ_PROP_SOURCE = 0xDC4Cu, // Source
+ MTP_OBJ_PROP_ORIGIN_LOCATION = 0xDC4Du, // Origin Location
+ MTP_OBJ_PROP_DATE_ADDED = 0xDC4Eu, // Date Added
+ MTP_OBJ_PROP_NON_CONSUMABLE = 0xDC4Fu, // Non-Consumable
+ MTP_OBJ_PROP_CORRUPT_UNPLAYABLE = 0xDC50u, // Corrupt/Unplayable
+ MTP_OBJ_PROP_PRODUCER_SERIAL_NUMBER = 0xDC51u, // ProducerSerialNumber
+ // 0xDC52-0xDC80 is reserved
+
+ MTP_OBJ_PROP_REP_SAMPLE_FORMAT = 0xDC81u, // Representative Sample Format
+ MTP_OBJ_PROP_REP_SAMPLE_SIZE = 0xDC82u, // Representative Sample Size
+ MTP_OBJ_PROP_REP_SAMPLE_HEIGHT = 0xDC83u, // Representative Sample Height
+ MTP_OBJ_PROP_REP_SAMPLE_WIDTH = 0xDC84u, // Representative Sample Width
+ MTP_OBJ_PROP_REP_SAMPLE_DURATION = 0xDC85u, // Representative Sample Duration
+ MTP_OBJ_PROP_REP_SAMPLE_DATA = 0xDC86u, // Representative Sample Data
+ MTP_OBJ_PROP_WIDTH = 0xDC87u, // Width
+ MTP_OBJ_PROP_HEIGHT = 0xDC88u, // Height
+ MTP_OBJ_PROP_DURATION = 0xDC89u, // Duration
+ MTP_OBJ_PROP_RATING = 0xDC8Au, // Rating
+ MTP_OBJ_PROP_TRACK = 0xDC8Bu, // Track
+ MTP_OBJ_PROP_GENRE = 0xDC8Cu, // Genre
+ MTP_OBJ_PROP_CREDITS = 0xDC8Du, // Credits
+ MTP_OBJ_PROP_LYRICS = 0xDC8Eu, // Lyrics
+ MTP_OBJ_PROP_SUBSCRIPTION_CONTENT_ID = 0xDC8Fu, // Subscription Content ID
+ MTP_OBJ_PROP_PRODUCED_BY = 0xDC90u, // Produced By
+ MTP_OBJ_PROP_USE_COUNT = 0xDC91u, // Use Count
+ MTP_OBJ_PROP_SKIP_COUNT = 0xDC92u, // Skip Count
+ MTP_OBJ_PROP_LAST_ACCESSED = 0xDC93u, // Last Accessed
+ MTP_OBJ_PROP_PARENTAL_RATING = 0xDC94u, // Parental Rating
+ MTP_OBJ_PROP_META_GENRE = 0xDC95u, // Meta Genre
+ MTP_OBJ_PROP_COMPOSER = 0xDC96u, // Composer
+ MTP_OBJ_PROP_EFFECTIVE_RATING = 0xDC97u, // Effective Rating
+ MTP_OBJ_PROP_SUBTITLE = 0xDC98u, // Subtitle
+ MTP_OBJ_PROP_ORIGINAL_RELEASE_DATE = 0xDC99u, // Original Release Date
+ MTP_OBJ_PROP_ALBUM_NAME = 0xDC9Au, // Album Name
+ MTP_OBJ_PROP_ALBUM_ARTIST = 0xDC9Bu, // Album Artist
+ MTP_OBJ_PROP_MOOD = 0xDC9Cu, // Mood
+ MTP_OBJ_PROP_DRM_STATUS = 0xDC9Du, // DRM Status
+ MTP_OBJ_PROP_SUB_DESCRIPTION = 0xDC9Eu, // Sub Description
+ // 0xDC9F-0xDCD0 is reserved
+
+ MTP_OBJ_PROP_IS_CROPPED = 0xDCD1u, // Is Cropped
+ MTP_OBJ_PROP_IS_COLOUR_CORRECTED = 0xDCD2u, // Is Colour Corrected
+ MTP_OBJ_PROP_IMAGE_BIT_DEPTH = 0xDCD3u, // Image Bit Depth
+ MTP_OBJ_PROP_FNUMBER = 0xDCD4u, // Fnumber (aperture ×100)
+ MTP_OBJ_PROP_EXPOSURE_TIME = 0xDCD5u, // Exposure Time (sec ×10,000)
+ MTP_OBJ_PROP_EXPOSURE_INDEX = 0xDCD6u, // Exposure Index (ISO)
+ // 0xDCD7-0xDCDF is reserved
+
+ MTP_OBJ_PROP_DISPLAY_NAME = 0xDCE0u, // Display Name
+ MTP_OBJ_PROP_BODY_TEXT = 0xDCE1u, // Body Text
+ MTP_OBJ_PROP_SUBJECT = 0xDCE2u, // Subject
+ MTP_OBJ_PROP_PRIORITY = 0xDCE3u, // Priority
+ // 0xDCE4-0xDCFF is reserved
+
+ MTP_OBJ_PROP_GIVEN_NAME = 0xDD00u, // Given Name
+ MTP_OBJ_PROP_MIDDLE_NAMES = 0xDD01u, // Middle Names
+ MTP_OBJ_PROP_FAMILY_NAME = 0xDD02u, // Family Name
+ MTP_OBJ_PROP_PREFIX = 0xDD03u, // Prefix
+ MTP_OBJ_PROP_SUFFIX = 0xDD04u, // Suffix
+ MTP_OBJ_PROP_PHONETIC_GIVEN_NAME = 0xDD05u, // Phonetic Given Name
+ MTP_OBJ_PROP_PHONETIC_FAMILY_NAME = 0xDD06u, // Phonetic Family Name
+ MTP_OBJ_PROP_EMAIL_PRIMARY = 0xDD07u, // Email Primary
+ MTP_OBJ_PROP_EMAIL_PERSONAL_1 = 0xDD08u, // Email Personal 1
+ MTP_OBJ_PROP_EMAIL_PERSONAL_2 = 0xDD09u, // Email Personal 2
+ MTP_OBJ_PROP_EMAIL_BUSINESS_1 = 0xDD0Au, // Email Business 1
+ MTP_OBJ_PROP_EMAIL_BUSINESS_2 = 0xDD0Bu, // Email Business 2
+ MTP_OBJ_PROP_EMAIL_OTHERS = 0xDD0Cu, // Email Others
+ MTP_OBJ_PROP_PHONE_PRIMARY = 0xDD0Du, // Phone Number Primary
+ MTP_OBJ_PROP_PHONE_PERSONAL_1 = 0xDD0Eu, // Phone Number Personal
+ MTP_OBJ_PROP_PHONE_PERSONAL_2 = 0xDD0Fu, // Phone Number Personal 2
+ MTP_OBJ_PROP_PHONE_BUSINESS_1 = 0xDD10u, // Phone Number Business
+ MTP_OBJ_PROP_PHONE_BUSINESS_2 = 0xDD11u, // Phone Number Business 2
+ MTP_OBJ_PROP_PHONE_MOBILE_1 = 0xDD12u, // Phone Number Mobile
+ MTP_OBJ_PROP_PHONE_MOBILE_2 = 0xDD13u, // Phone Number Mobile 2
+ MTP_OBJ_PROP_FAX_PRIMARY = 0xDD14u, // Fax Number Primary
+ MTP_OBJ_PROP_FAX_PERSONAL = 0xDD15u, // Fax Number Personal
+ MTP_OBJ_PROP_FAX_BUSINESS = 0xDD16u, // Fax Number Business
+ MTP_OBJ_PROP_PAGER_NUMBER = 0xDD17u, // Pager Number
+ MTP_OBJ_PROP_PHONE_OTHERS = 0xDD18u, // Phone Number Others
+ MTP_OBJ_PROP_WEB_PRIMARY = 0xDD19u, // Primary Web Address
+ MTP_OBJ_PROP_WEB_PERSONAL = 0xDD1Au, // Personal Web Address
+ MTP_OBJ_PROP_WEB_BUSINESS = 0xDD1Bu, // Business Web Address
+ MTP_OBJ_PROP_IM_ADDRESS_1 = 0xDD1Cu, // Instant Messenger Address
+ MTP_OBJ_PROP_IM_ADDRESS_2 = 0xDD1Du, // Instant Messenger Address 2
+ MTP_OBJ_PROP_IM_ADDRESS_3 = 0xDD1Eu, // Instant Messenger Address 3
+ MTP_OBJ_PROP_ADDR_PERSONAL_FULL = 0xDD1Fu, // Postal Address Personal Full
+ MTP_OBJ_PROP_ADDR_PERSONAL_LINE1 = 0xDD20u, // Postal Address Personal Line 1
+ MTP_OBJ_PROP_ADDR_PERSONAL_LINE2 = 0xDD21u, // Postal Address Personal Line 2
+ MTP_OBJ_PROP_ADDR_PERSONAL_CITY = 0xDD22u, // Postal Address Personal City
+ MTP_OBJ_PROP_ADDR_PERSONAL_REGION = 0xDD23u, // Postal Address Personal Region
+ MTP_OBJ_PROP_ADDR_PERSONAL_POSTAL_CODE = 0xDD24u, // Postal Address Personal Postal Code
+ MTP_OBJ_PROP_ADDR_PERSONAL_COUNTRY = 0xDD25u, // Postal Address Personal Country
+ MTP_OBJ_PROP_ADDR_BUSINESS_FULL = 0xDD26u, // Postal Address Business Full
+ MTP_OBJ_PROP_ADDR_BUSINESS_LINE1 = 0xDD27u, // Postal Address Business Line 1
+ MTP_OBJ_PROP_ADDR_BUSINESS_LINE2 = 0xDD28u, // Postal Address Business Line 2
+ MTP_OBJ_PROP_ADDR_BUSINESS_CITY = 0xDD29u, // Postal Address Business City
+ MTP_OBJ_PROP_ADDR_BUSINESS_REGION = 0xDD2Au, // Postal Address Business Region
+ MTP_OBJ_PROP_ADDR_BUSINESS_POSTAL_CODE = 0xDD2Bu, // Postal Address Business Postal Code
+ MTP_OBJ_PROP_ADDR_BUSINESS_COUNTRY = 0xDD2Cu, // Postal Address Business Country
+ MTP_OBJ_PROP_ADDR_OTHER_FULL = 0xDD2Du, // Postal Address Other Full
+ MTP_OBJ_PROP_ADDR_OTHER_LINE1 = 0xDD2Eu, // Postal Address Other Line 1
+ MTP_OBJ_PROP_ADDR_OTHER_LINE2 = 0xDD2Fu, // Postal Address Other Line 2
+ MTP_OBJ_PROP_ADDR_OTHER_CITY = 0xDD30u, // Postal Address Other City
+ MTP_OBJ_PROP_ADDR_OTHER_REGION = 0xDD31u, // Postal Address Other Region
+ MTP_OBJ_PROP_ADDR_OTHER_POSTAL_CODE = 0xDD32u, // Postal Address Other Postal Code
+ MTP_OBJ_PROP_ADDR_OTHER_COUNTRY = 0xDD33u, // Postal Address Other Country
+ MTP_OBJ_PROP_ORGANIZATION_NAME = 0xDD34u, // Organization Name
+ MTP_OBJ_PROP_PHONETIC_ORG_NAME = 0xDD35u, // Phonetic Organization Name
+ MTP_OBJ_PROP_ROLE = 0xDD36u, // Role
+ MTP_OBJ_PROP_BIRTHDATE = 0xDD37u, // Birthdate
+ // 0xDD38-0xDD3F is reserved
+
+ MTP_OBJ_PROP_MESSAGE_TO = 0xDD40u, // Message To
+ MTP_OBJ_PROP_MESSAGE_CC = 0xDD41u, // Message CC
+ MTP_OBJ_PROP_MESSAGE_BCC = 0xDD42u, // Message BCC
+ MTP_OBJ_PROP_MESSAGE_READ = 0xDD43u, // Message Read
+ MTP_OBJ_PROP_MESSAGE_RECEIVED_TIME = 0xDD44u, // Message Received Time
+ MTP_OBJ_PROP_MESSAGE_SENDER = 0xDD45u, // Message Sender
+ // 0xDD46-0xDD4F is reserved
+
+ MTP_OBJ_PROP_ACTIVITY_BEGIN_TIME = 0xDD50u, // Activity Begin Time
+ MTP_OBJ_PROP_ACTIVITY_END_TIME = 0xDD51u, // Activity End Time
+ MTP_OBJ_PROP_ACTIVITY_LOCATION = 0xDD52u, // Activity Location
+ // 0xDD53 is reserved
+ MTP_OBJ_PROP_ACTIVITY_REQUIRED_ATTENDEES= 0xDD54u, // Activity Required Attendees
+ MTP_OBJ_PROP_ACTIVITY_OPTIONAL_ATTENDEES= 0xDD55u, // Activity Optional Attendees
+ MTP_OBJ_PROP_ACTIVITY_RESOURCES = 0xDD56u, // Activity Resources
+ MTP_OBJ_PROP_ACTIVITY_ACCEPTED = 0xDD57u, // Activity Accepted
+ MTP_OBJ_PROP_ACTIVITY_TENTATIVE = 0xDD58u, // Activity Tentative
+ MTP_OBJ_PROP_ACTIVITY_DECLINED = 0xDD59u, // Activity Declined
+ MTP_OBJ_PROP_ACTIVITY_REMINDER_TIME = 0xDD5Au, // Activity Reminder Time
+ MTP_OBJ_PROP_ACTIVITY_OWNER = 0xDD5Bu, // Activity Owner
+ MTP_OBJ_PROP_ACTIVITY_STATUS = 0xDD5Cu, // Activity Status
+ MTP_OBJ_PROP_OWNER = 0xDD5Du, // Owner
+ MTP_OBJ_PROP_EDITOR = 0xDD5Eu, // Editor
+ MTP_OBJ_PROP_WEBMASTER = 0xDD5Fu, // Webmaster
+
+ MTP_OBJ_PROP_URL_SOURCE = 0xDD60u, // URL Source
+ MTP_OBJ_PROP_URL_DESTINATION = 0xDD61u, // URL Destination
+ MTP_OBJ_PROP_TIME_BOOKMARK = 0xDD62u, // Time Bookmark
+ MTP_OBJ_PROP_OBJECT_BOOKMARK = 0xDD63u, // Object Bookmark
+ MTP_OBJ_PROP_BYTE_BOOKMARK = 0xDD64u, // Byte Bookmark
+ // 0xDD65-0xDD6F is reserved
+
+ MTP_OBJ_PROP_LAST_BUILD_DATE = 0xDD70u, // Last Build Date
+ MTP_OBJ_PROP_TIME_TO_LIVE = 0xDD71u, // Time to Live (minutes)
+ MTP_OBJ_PROP_MEDIA_GUID = 0xDD72u, // Media GUID
+ // 0xDD73-0xDDFF is reserved
+
+ // media encoding
+ MTP_OBJ_PROP_TOTAL_BITRATE = 0xDE91u, // Total BitRate
+ MTP_OBJ_PROP_BITRATE_TYPE = 0xDE92u, // Bitrate Type
+ MTP_OBJ_PROP_SAMPLE_RATE = 0xDE93u, // Sample Rate
+ MTP_OBJ_PROP_NUM_CHANNELS = 0xDE94u, // Number Of Channels
+ MTP_OBJ_PROP_AUDIO_BITDEPTH = 0xDE95u, // Audio BitDepth
+ // 0xDE96 is reserved
+ MTP_OBJ_PROP_SCAN_TYPE = 0xDE97u, // Scan Type
+ // 0xDE98 is reserved
+ MTP_OBJ_PROP_AUDIO_WAVE_CODEC = 0xDE99u, // Audio WAVE Codec
+ MTP_OBJ_PROP_AUDIO_BITRATE = 0xDE9Au, // Audio BitRate
+ MTP_OBJ_PROP_VIDEO_FOURCC_CODEC = 0xDE9Bu, // Video FourCC Codec
+ MTP_OBJ_PROP_VIDEO_BITRATE = 0xDE9Cu, // Video BitRate
+ MTP_OBJ_PROP_FRAMES_PER_KSEC = 0xDE9Du, // Frames Per Thousand Seconds
+ MTP_OBJ_PROP_KEYFRAME_DISTANCE = 0xDE9Eu, // KeyFrame Distance (ms)
+ MTP_OBJ_PROP_BUFFER_SIZE = 0xDE9Fu, // Buffer Size
+ MTP_OBJ_PROP_ENCODING_QUALITY = 0xDEA0u, // Encoding Quality
+ MTP_OBJ_PROP_ENCODING_PROFILE = 0xDEA1u // Encoding Profile
+} mtp_object_properties_t;
+
+
+// MTP 1.1 Appendeix C: Device Properties
+typedef enum {
+ MTP_DEV_PROP_UNDEFINED = 0x5000u,
+ MTP_DEV_PROP_BATTERY_LEVEL = 0x5001u,
+ MTP_DEV_PROP_FUNCTIONAL_MODE = 0x5002u,
+ MTP_DEV_PROP_IMAGE_SIZE = 0x5003u,
+ MTP_DEV_PROP_COMPRESSION_SETTING = 0x5004u,
+ MTP_DEV_PROP_WHITE_BALANCE = 0x5005u,
+ MTP_DEV_PROP_RGB_GAIN = 0x5006u,
+ MTP_DEV_PROP_F_NUMBER = 0x5007u,
+ MTP_DEV_PROP_FOCAL_LENGTH = 0x5008u,
+ MTP_DEV_PROP_FOCUS_DISTANCE = 0x5009u,
+ MTP_DEV_PROP_FOCUS_MODE = 0x500Au,
+ MTP_DEV_PROP_EXPOSURE_METERING_MODE = 0x500Bu,
+ MTP_DEV_PROP_FLASH_MODE = 0x500Cu,
+ MTP_DEV_PROP_EXPOSURE_TIME = 0x500Du,
+ MTP_DEV_PROP_EXPOSURE_PROGRAM_MODE = 0x500Eu,
+ MTP_DEV_PROP_EXPOSURE_INDEX = 0x500Fu,
+ MTP_DEV_PROP_EXPOSURE_BIAS_COMPENSATION = 0x5010u,
+ MTP_DEV_PROP_DATE_TIME = 0x5011u,
+ MTP_DEV_PROP_CAPTURE_DELAY = 0x5012u,
+ MTP_DEV_PROP_STILL_CAPTURE_MODE = 0x5013u,
+ MTP_DEV_PROP_CONTRAST = 0x5014u,
+ MTP_DEV_PROP_SHARPNESS = 0x5015u,
+ MTP_DEV_PROP_DIGITAL_ZOOM = 0x5016u,
+ MTP_DEV_PROP_EFFECT_MODE = 0x5017u,
+ MTP_DEV_PROP_BURST_NUMBER = 0x5018u,
+ MTP_DEV_PROP_BURST_INTERVAL = 0x5019u,
+ MTP_DEV_PROP_TIMELAPSE_NUMBER = 0x501Au,
+ MTP_DEV_PROP_TIMELAPSE_INTERVAL = 0x501Bu,
+ MTP_DEV_PROP_FOCUS_METERING_MODE = 0x501Cu,
+ MTP_DEV_PROP_UPLOAD_URL = 0x501Du,
+ MTP_DEV_PROP_ARTIST = 0x501Eu,
+ MTP_DEV_PROP_COPYRIGHT_INFO = 0x501Fu,
+ MTP_DEV_PROP_SYNCHRONIZTION_PARTNER = 0xD401,
+ MTP_DEV_PROP_DEVICE_FRIENDLY_NAME = 0xD402u,
+ MTP_DEV_PROP_VOLUME = 0xD403u,
+ MTP_DEV_PROP_SUPPORTED_FORMATS_ORDERED = 0xD404u,
+ MTP_DEV_PROP_DEVICE_ICON = 0xD405u,
+ MTP_DEV_PROP_SECTION_INITIATOR_VERSION_INFO = 0xD406u,
+ MTP_DEV_PROP_PERCEIVED_DEVICE_TYPE = 0xD407u,
+ MTP_DEV_PROP_PLAYBACK_RATE = 0xD410u,
+ MTP_DEV_PROP_PLAYBACK_OBJECT = 0xD411u,
+ MTP_DEV_PROP_PLAYBACK_CONTAINER_INDEX = 0xD412u,
+} mtp_event_properties_t;
+
+// MTP 1.1 Appendix D: Operations
+typedef enum {
+ MTP_OP_UNDEFINED = 0x1000u,
+ MTP_OP_GET_DEVICE_INFO = 0x1001u,
+ MTP_OP_OPEN_SESSION = 0x1002u,
+ MTP_OP_CLOSE_SESSION = 0x1003u,
+ MTP_OP_GET_STORAGE_IDS = 0x1004u,
+ MTP_OP_GET_STORAGE_INFO = 0x1005u,
+ MTP_OP_GET_NUM_OBJECTS = 0x1006u,
+ MTP_OP_GET_OBJECT_HANDLES = 0x1007u,
+ MTP_OP_GET_OBJECT_INFO = 0x1008u,
+ MTP_OP_GET_OBJECT = 0x1009u,
+ MTP_OP_GET_THUMB = 0x100Au,
+ MTP_OP_DELETE_OBJECT = 0x100Bu,
+ MTP_OP_SEND_OBJECT_INFO = 0x100Cu,
+ MTP_OP_SEND_OBJECT = 0x100Du,
+ MTP_OP_INITIATE_CAPTURE = 0x100Eu,
+ MTP_OP_FORMAT_STORE = 0x100Fu,
+ MTP_OP_RESET_DEVICE = 0x1010u,
+ MTP_OP_SELF_TEST = 0x1011u,
+ MTP_OP_SET_OBJECT_PROTECTION = 0x1012u,
+ MTP_OP_POWER_DOWN = 0x1013u,
+ MTP_OP_GET_DEVICE_PROP_DESC = 0x1014u,
+ MTP_OP_GET_DEVICE_PROP_VALUE = 0x1015u,
+ MTP_OP_SET_DEVICE_PROP_VALUE = 0x1016u,
+ MTP_OP_RESET_DEVICE_PROP_VALUE = 0x1017u,
+ MTP_OP_TERMINATE_OPEN_CAPTURE = 0x1018u,
+ MTP_OP_MOVE_OBJECT = 0x1019u,
+ MTP_OP_COPY_OBJECT = 0x101Au,
+ MTP_OP_GET_PARTIAL_OBJECT = 0x101Bu,
+ MTP_OP_INITIATE_OPEN_CAPTURE = 0x101Bu,
+ MTP_OP_GET_OBJECT_PROPS_SUPPORTED = 0x9801u,
+ MTP_OP_GET_OBJECT_PROP_DESC = 0x9802u,
+ MTP_OP_GET_OBJECT_PROP_VALUE = 0x9803u,
+ MTP_OP_SET_OBJECT_PROP_VALUE = 0x9804u,
+ MTP_OP_GET_OBJECT_PROPLIST = 0x9805u,
+ MTP_OP_GET_OBJECT_PROP_REFERENCES = 0x9810u,
+
+ MTP_OP_GET_SERVICE_IDS = 0x9301u,
+ MTP_OP_GET_SERVICE_INFO = 0x9302u,
+ MTP_OP_GET_SERVICE_CAPABILITIES = 0x9303u,
+ MTP_OP_GET_SERVICE_PROP_DESC = 0x9304u,
+
+ // Appendix E: Enhanced Operations
+ MTP_OP_GET_OBJECT_PROP_LIST = 0x9805u,
+ MTP_OP_SET_OBJECT_PROP_LIST = 0x9806u,
+ MTP_OP_GET_INTERDEPENDENT_PROP_DESC = 0x9807u,
+ MTP_OP_SEND_OBJECT_PROP_LIST = 0x9808u,
+} mtp_operation_code_t;
+
+// Appendix F: Responses
+typedef enum {
+ MTP_RESP_UNDEFINED = 0x2000u,
+ MTP_RESP_OK = 0x2001u,
+ MTP_RESP_GENERAL_ERROR = 0x2002u,
+ MTP_RESP_SESSION_NOT_OPEN = 0x2003u,
+ MTP_RESP_INVALID_TRANSACTION_ID = 0x2004u,
+ MTP_RESP_OPERATION_NOT_SUPPORTED = 0x2005u,
+ MTP_RESP_PARAMETER_NOT_SUPPORTED = 0x2006u,
+ MTP_RESP_INCOMPLETE_TRANSFER = 0x2007u,
+ MTP_RESP_INVALID_STORAGE_ID = 0x2008u,
+ MTP_RESP_INVALID_OBJECT_HANDLE = 0x2009u,
+ MTP_RESP_DEVICE_PROP_NOT_SUPPORTED = 0x200Au,
+ MTP_RESP_INVALID_OBJECT_FORMAT_CODE = 0x200Bu,
+ MTP_RESP_STORE_FULL = 0x200Cu,
+ MTP_RESP_OBJECT_WRITE_PROTECTED = 0x200Du,
+ MPT_RESC_STORE_READ_ONLY = 0x200Eu,
+ MTP_RESP_ACCESS_DENIED = 0x200Fu,
+ MTP_RESP_NO_THUMBNAIL_PRESENT = 0x2010u,
+ MTP_RESP_SELF_TEST_FAILED = 0x2011u,
+ MTP_RESP_PARTIAL_DELETION = 0x2012u,
+ MTP_RESP_STORE_NOT_AVAILABLE = 0x2013u,
+ MTP_RESP_SPECIFICATION_BY_FORMAT_UNSUPPORTED = 0x2014u,
+ MTP_RESP_NO_VALID_OBJECTINFO = 0x2015u,
+ MTP_RESP_INVALID_CODE_FORMAT = 0x2016u,
+ MTP_RESP_UNKNOWN_VENDOR_CODE = 0x2017u,
+ MTP_RESP_CAPTURE_ALREADY_TERMINATED = 0x2018u,
+ MTP_RESP_DEVICE_BUSY = 0x2019u,
+ MTP_RESP_INVALID_PARENT_OBJECT = 0x201Au,
+ MTP_RESP_INVALID_DEVICE_PROP_FORMAT = 0x201Bu,
+ MTP_RESP_INVALID_DEVICE_PROP_VALUE = 0x201Cu,
+ MTP_RESP_INVALID_PARAMETER = 0x201Du,
+ MTP_RESP_SESSION_ALREADY_OPEN = 0x201Eu,
+ MTP_RESP_TRANSACTION_CANCELLED = 0x201Fu,
+ MTP_RESP_SPEC_OF_DESTINATION_UNSUPPORTED = 0x2020u,
+
+ MTP_RESP_INVALID_OBJECT_PROP_CODE = 0xA801u,
+ MTP_RESP_INVALID_OBJECT_PROP_FORMAT = 0xA802u,
+ MTP_RESP_INVALID_OBJECT_PROP_VALUE = 0xA803u,
+ MTP_RESP_INVALID_OBJECT_REFERENCE = 0xA804u,
+ MTP_RESP_GROUP_NOT_SUPPORTED = 0xA805u,
+ MTP_RESP_INVALID_DATASET = 0xA806u,
+ MTP_RESP_SPEC_BY_GROUP_UNSUPPORTED = 0xA807u,
+ MTP_RESP_SPEC_BY_DEPTH_UNSUPPORTED = 0xA808u,
+ MTP_RESP_OBJECT_TOO_LARGE = 0xA809u,
+ MTP_RESP_OBJECT_PROP_NOT_SUPPORTED = 0xA80Au,
+} mtp_response_t;
+
+// Appendix G: Events
+typedef enum {
+ MTP_EVENT_UNDEFINED = 0x4000,
+ MTP_EVENT_CANCEL_TRANSACTION = 0x4001,
+ MTP_EVENT_OBJECT_ADDED = 0x4002,
+ MTP_EVENT_OBJECT_REMOVED = 0x4003,
+ MTP_EVENT_STORE_ADDED = 0x4004,
+ MTP_EVENT_STORE_REMOVED = 0x4005,
+ MTP_EVENT_DEVICE_PROP_CHANGED = 0x4006,
+ MTP_EVENT_OBJECT_INFO_CHANGED = 0x4007,
+ MTP_EVENT_DEVICE_INFO_CHANGED = 0x4008,
+ MTP_EVENT_REQUEST_OBJECT_TRANSFER = 0x4009,
+ MTP_EVENT_STORE_FULL = 0x400Au,
+ MTP_EVENT_DEVICE_RESET = 0x400Bu,
+ MTP_EVENT_STORAGE_INFO_CHANGED = 0x400Cu,
+ MTP_EVENT_CAPTURE_COMPLETE = 0x400Du,
+ MTP_EVENT_UNREPORTED_STATUS = 0x400Eu,
+ MTP_EVENT_OBJECT_PROP_CHANGED = 0xC801u,
+ MTP_EVENT_OBJECT_PROP_DESC_CHANGED = 0xC802u,
+ MTP_EVENT_OBJECT_REFERENCES_CHANGED = 0xC803u,
+} mtp_event_code_t;
+
+// Datatypes
+typedef enum {
+ MTP_DATA_TYPE_UNDEFINED = 0x0000u,
+ // scalars
+ MTP_DATA_TYPE_INT8 = 0x0001u,
+ MTP_DATA_TYPE_UINT8 = 0x0002u,
+ MTP_DATA_TYPE_INT16 = 0x0003u,
+ MTP_DATA_TYPE_UINT16 = 0x0004u,
+ MTP_DATA_TYPE_INT32 = 0x0005u,
+ MTP_DATA_TYPE_UINT32 = 0x0006u,
+ MTP_DATA_TYPE_INT64 = 0x0007u,
+ MTP_DATA_TYPE_UINT64 = 0x0008u,
+ MTP_DATA_TYPE_INT128 = 0x0009u,
+ MTP_DATA_TYPE_UINT128 = 0x000Au,
+ // array
+ MTP_DATA_TYPE_AINT8 = 0x4001u,
+ MTP_DATA_TYPE_AUINT8 = 0x4002u,
+ MTP_DATA_TYPE_AINT16 = 0x4003u,
+ MTP_DATA_TYPE_AUINT16 = 0x4004u,
+ MTP_DATA_TYPE_AINT32 = 0x4005u,
+ MTP_DATA_TYPE_AUINT32 = 0x4006u,
+ MTP_DATA_TYPE_AINT64 = 0x4007u,
+ MTP_DATA_TYPE_AUINT64 = 0x4008u,
+ MTP_DATA_TYPE_AINT128 = 0x4009u,
+ MTP_DATA_TYPE_AUINT128 = 0x400Au,
+ MTP_DATA_TYPE_STR = 0xFFFFu,
+} mtp_data_type_t;
+
+// Get/Set
+typedef enum {
+ MTP_MODE_GET = 0x00u,
+ MTP_MODE_GET_SET = 0x01u,
+} mtp_mode_get_set_t;
+
+typedef enum {
+ MTP_STORAGE_TYPE_UNDEFINED = 0x0000u,
+ MTP_STORAGE_TYPE_FIXED_ROM = 0x0001u,
+ MTP_STORAGE_TYPE_REMOVABLE_ROM = 0x0002u,
+ MTP_STORAGE_TYPE_FIXED_RAM = 0x0003u,
+ MTP_STORAGE_TYPE_REMOVABLE_RAM = 0x0004u,
+} mtp_storage_type_t;
+
+typedef enum {
+ MTP_FILESYSTEM_TYPE_UNDEFINED = 0x0000u,
+ MTP_FILESYSTEM_TYPE_GENERIC_FLAT = 0x0001u,
+ MTP_FILESYSTEM_TYPE_GENERIC_HIERARCHICAL = 0x0002u,
+ MTP_FILESYSTEM_TYPE_DCF = 0x0003u,
+} mtp_filesystem_type_t;
+
+typedef enum {
+ MTP_ACCESS_CAPABILITY_READ_WRITE = 0x0000u,
+ MTP_ACCESS_CAPABILITY_READ_ONLY_WITHOUT_OBJECT_DELETION = 0x0001u,
+ MTP_ACCESS_CAPABILITY_READ_ONLY_WITH_OBJECT_DELETION = 0x0002u,
+} mtp_access_capability_t;
+
+typedef enum {
+ MTP_PROTECTION_STATUS_NO_PROTECTION = 0x0000u,
+ MTP_PROTECTION_STATUS_READ_ONLY = 0x0001u,
+ MTP_PROTECTION_STATUS_READ_ONLY_DATA = 0x8002u,
+ MTP_PROTECTION_NON_TRANSFERABLE_DATA = 0x8003u,
+} mtp_protection_status_t;
+
+typedef enum {
+ MTP_ASSOCIATION_UNDEFINED = 0x0000u,
+ MTP_ASSOCIATION_GENERIC_FOLDER = 0x0001u,
+ MTP_ASSOCIATION_ALBUM = 0x0002u,
+ MTP_ASSOCIATION_TIME_SEQUENCE = 0x0003u,
+ MTP_ASSOCIATION_HORIZONTAL_PANORAMIC = 0x0004u,
+ MTP_ASSOCIATION_VERTICAL_PANORAMIC = 0x0005u,
+ MTP_ASSOCIATION_2D_PANORAMIC = 0x0006u,
+ MTP_ASSOCIATION_ANCILLARY_DATA = 0x0007u,
+} mtp_association_t;
+
+//--------------------------------------------------------------------+
+// Data structures
+//--------------------------------------------------------------------+
+typedef struct TU_ATTR_PACKED {
+ uint32_t len;
+ uint16_t type;
+ uint16_t code;
+ uint32_t transaction_id;
+} mtp_container_header_t;
+TU_VERIFY_STATIC(sizeof(mtp_container_header_t) == 12, "size is not correct");
+
+typedef struct TU_ATTR_PACKED {
+ mtp_container_header_t header;
+ uint32_t params[5];
+} mtp_container_command_t;
+TU_VERIFY_STATIC(sizeof(mtp_container_command_t) == 32, "size is not correct");
+
+// PTP/MTP Generic container
+typedef struct TU_ATTR_PACKED {
+ mtp_container_header_t header;
+ uint8_t payload[(CFG_TUD_MTP_EP_BUFSIZE - sizeof(mtp_container_header_t))];
+} mtp_generic_container_t;
+
+typedef struct {
+ mtp_container_header_t* header;
+ union {
+ uint8_t* payload;
+ uint16_t* payload16;
+ uint32_t* payload32;
+ };
+ uint32_t payload_bytes; // available bytes for read/write
+} mtp_container_info_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint16_t code;
+ uint32_t session_id;
+ uint32_t transaction_id;
+ uint32_t params[3];
+} mtp_event_t;
+TU_VERIFY_STATIC(sizeof(mtp_event_t) == 22, "size is not correct");
+
+#define mtp_string_t(_nchars) \
+ struct TU_ATTR_PACKED { \
+ uint8_t count; /* in characters including null */ \
+ uint16_t utf16[_nchars]; \
+ }
+
+#define mtp_array_t(_type, _count) \
+ struct TU_ATTR_PACKED { \
+ uint32_t count; \
+ _type arr[_count];\
+ }
+
+#define mtp_aint8_t(_count) mtp_array_t(int8_t, _count)
+#define mtp_auint16_t(_count) mtp_array_t(uint16_t, _count)
+#define mtp_auint32_t(_count) mtp_array_t(uint32_t, _count)
+#define mtp_auint64_t(_count) mtp_array_t(uint64_t, _count)
+
+#define MTP_STORAGE_INFO_STRUCT(_storage_desc_chars, _volume_id_chars) \
+ struct TU_ATTR_PACKED { \
+ uint16_t storage_type; \
+ uint16_t filesystem_type; \
+ uint16_t access_capability; \
+ uint64_t max_capacity_in_bytes; \
+ uint64_t free_space_in_bytes; \
+ uint32_t free_space_in_objects; \
+ mtp_string_t(_storage_desc_chars) storage_description; \
+ mtp_string_t(_volume_id_chars) volume_identifier; \
+ }
+
+// Object Info Dataset without dynamic string: filename, date_created, date_modified, keywords
+typedef struct TU_ATTR_PACKED {
+ uint32_t storage_id;
+ uint16_t object_format;
+ uint16_t protection_status;
+ uint32_t object_compressed_size;
+ uint16_t thumb_format;
+ uint32_t thumb_compressed_size;
+ uint32_t thumb_pix_width;
+ uint32_t thumb_pix_height;
+ uint32_t image_pix_width;
+ uint32_t image_pix_height;
+ uint32_t image_bit_depth;
+ uint32_t parent_object; // 0: root
+ uint16_t association_type;
+ uint32_t association_desc;
+ uint32_t sequence_number;
+ // mtp_string_t() filename
+ // mtp_string_t() date_created
+ // mtp_string_t() date_modified
+ // mtp_string_t() keywords
+} mtp_object_info_header_t;
+
+// Device property desc up to get/set
+typedef struct TU_ATTR_PACKED {
+ uint16_t device_property_code;
+ uint16_t datatype;
+ uint8_t get_set;
+} mtp_device_prop_desc_header_t;
+
+// The following fields will be dynamically added to the struct at runtime:
+// - wstring factory_def_value;
+// - wstring current_value_len;
+// - uint8_t form_flag;
+
+// no form
+#define MTP_DEVICE_PROPERTIES_STRUCT(_type) \
+ struct TU_ATTR_PACKED { \
+ uint16_t device_property_code; \
+ uint16_t datatype; \
+ uint8_t get_set; \
+ _type factory_default; \
+ _type current_value; \
+ uint8_t form_flag; /* 0: none, 1: range, 2: enum */ \
+ };
+
+typedef struct TU_ATTR_PACKED {
+ uint16_t code;
+ uint32_t transaction_id;
+} mtp_request_reset_cancel_data_t;
+TU_VERIFY_STATIC(sizeof(mtp_request_reset_cancel_data_t) == 6, "size is not correct");
+
+//--------------------------------------------------------------------+
+// Container helper function
+// return number of bytes added
+//--------------------------------------------------------------------+
+
+// return payload buffer for next write
+TU_ATTR_ALWAYS_INLINE static inline uint8_t* mtp_container_payload_ptr(mtp_container_info_t* p_container) {
+ // only 1st packet include header
+ uint32_t pos = p_container->header->len - sizeof(mtp_container_header_t);
+ while (pos > CFG_TUD_MTP_EP_BUFSIZE) {
+ pos -= CFG_TUD_MTP_EP_BUFSIZE;
+ }
+ return p_container->payload + pos;
+}
+
+// only add_raw does partial copy
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_raw(mtp_container_info_t* p_container, const void* data, uint32_t len) {
+ uint8_t* buf = mtp_container_payload_ptr(p_container);
+ const uint32_t added_len = tu_min32(len, CFG_TUD_MTP_EP_BUFSIZE - p_container->header->len);
+ if (added_len > 0) {
+ memcpy(buf, data, added_len);
+ }
+ p_container->header->len += len; // always increase len, even partial copy
+ return added_len;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_array(mtp_container_info_t* p_container, uint8_t scalar_size, uint32_t count, const void* data) {
+ const uint32_t added_len = 4 + count * scalar_size;
+ TU_ASSERT(p_container->header->len + added_len < CFG_TUD_MTP_EP_BUFSIZE, 0);
+ uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t);
+
+ tu_unaligned_write32(buf, count);
+ p_container->header->len += 4;
+ buf += 4;
+
+ memcpy(buf, data, count * scalar_size);
+ p_container->header->len += count * scalar_size;
+
+ return added_len;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_string(mtp_container_info_t* p_container, uint16_t* utf16) {
+ uint8_t count = 0;
+ while (utf16[count]) {
+ count++;
+ }
+ const uint32_t added_len = 1u + 2u * count;
+ TU_ASSERT(p_container->header->len + added_len < CFG_TUD_MTP_EP_BUFSIZE, 0);
+ uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t);
+
+ *buf++ = count;
+ p_container->header->len++;
+
+ memcpy(buf, utf16, 2 * count);
+ p_container->header->len += 2 * count;
+
+ return added_len;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_cstring(mtp_container_info_t* p_container, const char* str) {
+ const uint8_t len = (uint8_t) (strlen(str) + 1); // include null
+ TU_ASSERT(p_container->header->len + 1 + 2 * len < CFG_TUD_MTP_EP_BUFSIZE, 0);
+ uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t);
+
+ if (len == 1) {
+ // empty string (null only): single zero byte
+ *buf = 0;
+ p_container->header->len++;
+ return 1;
+ } else {
+ *buf++ = len;
+ p_container->header->len++;
+
+ for (uint8_t i = 0; i < len; i++) {
+ buf[0] = str[i];
+ buf[1] = 0;
+ buf += 2;
+ p_container->header->len += 2;
+ }
+ return 1u + 2u * len;
+ }
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint8(mtp_container_info_t* p_container, uint8_t data) {
+ return mtp_container_add_raw(p_container, &data, 1);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint16(mtp_container_info_t* p_container, uint16_t data) {
+ return mtp_container_add_raw(p_container, &data, 2);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint32(mtp_container_info_t* p_container, uint32_t data) {
+ return mtp_container_add_raw(p_container, &data, 4);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint64(mtp_container_info_t* p_container, uint64_t data) {
+ return mtp_container_add_raw(p_container, &data, 8);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint128(mtp_container_info_t* p_container, const void* data) {
+ return mtp_container_add_raw(p_container, data, 16);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint8(mtp_container_info_t* p_container, uint32_t count, const uint8_t* data) {
+ return mtp_container_add_array(p_container, sizeof(uint8_t), count, data);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint16(mtp_container_info_t* p_container, uint32_t count, const uint16_t* data) {
+ return mtp_container_add_array(p_container, sizeof(uint16_t), count, data);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint32(mtp_container_info_t* p_container, uint32_t count, const uint32_t* data) {
+ return mtp_container_add_array(p_container, sizeof(uint32_t), count, data);
+}
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_get_string(uint8_t* buf, uint16_t utf16[]) {
+ uint8_t nchars = *buf++;
+ memcpy(utf16, buf, 2 * nchars);
+ return 1u + 2u * nchars;
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
+#endif
diff --git a/src/class/mtp/mtp_device.c b/src/class/mtp/mtp_device.c
new file mode 100644
index 000000000..04bde9415
--- /dev/null
+++ b/src/class/mtp/mtp_device.c
@@ -0,0 +1,540 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if (CFG_TUD_ENABLED && CFG_TUD_MTP)
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "device/dcd.h"
+#include "device/usbd.h"
+#include "device/usbd_pvt.h"
+
+#include "mtp_device.h"
+
+// Level where CFG_TUSB_DEBUG must be at least for this driver is logged
+#ifndef CFG_TUD_MTP_LOG_LEVEL
+ #define CFG_TUD_MTP_LOG_LEVEL CFG_TUD_LOG_LEVEL
+#endif
+
+#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_MTP_LOG_LEVEL, __VA_ARGS__)
+
+//--------------------------------------------------------------------+
+// Weak stubs: invoked if no strong implementation is available
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK bool tud_mtp_request_cancel_cb(tud_mtp_request_cb_data_t* cb_data) {
+ (void) cb_data;
+ return false;
+}
+TU_ATTR_WEAK bool tud_mtp_request_device_reset_cb(tud_mtp_request_cb_data_t* cb_data) {
+ (void) cb_data;
+ return false;
+}
+TU_ATTR_WEAK int32_t tud_mtp_request_get_extended_event_cb(tud_mtp_request_cb_data_t* cb_data) {
+ (void) cb_data;
+ return -1;
+}
+TU_ATTR_WEAK int32_t tud_mtp_request_get_device_status_cb(tud_mtp_request_cb_data_t* cb_data) {
+ (void) cb_data;
+ return -1;
+}
+TU_ATTR_WEAK bool tud_mtp_request_vendor_cb(tud_mtp_request_cb_data_t* cb_data) {
+ (void) cb_data;
+ return false;
+}
+TU_ATTR_WEAK int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t * cb_data) {
+ (void) cb_data;
+ return -1;
+}
+TU_ATTR_WEAK int32_t tud_mtp_data_xfer_cb(tud_mtp_cb_data_t* cb_data) {
+ (void) cb_data;
+ return -1;
+}
+TU_ATTR_WEAK int32_t tud_mtp_data_complete_cb(tud_mtp_cb_data_t* cb_data) {
+ (void) cb_data;
+ return -1;
+}
+TU_ATTR_WEAK int32_t tud_mtp_response_complete_cb(tud_mtp_cb_data_t* cb_data) {
+ (void) cb_data;
+ return -1;
+}
+
+//--------------------------------------------------------------------+
+// STRUCT
+//--------------------------------------------------------------------+
+typedef struct {
+ uint8_t rhport;
+ uint8_t itf_num;
+ uint8_t ep_in;
+ uint8_t ep_out;
+ uint8_t ep_event;
+
+ // Bulk Only Transfer (BOT) Protocol
+ uint8_t phase;
+
+ uint32_t total_len;
+ uint32_t xferred_len;
+
+ uint32_t session_id;
+ mtp_container_command_t command;
+ mtp_container_header_t io_header;
+
+ TU_ATTR_ALIGNED(4) uint8_t control_buf[CFG_TUD_MTP_EP_CONTROL_BUFSIZE];
+} mtpd_interface_t;
+
+typedef struct {
+ TUD_EPBUF_DEF(buf, CFG_TUD_MTP_EP_BUFSIZE);
+ TUD_EPBUF_TYPE_DEF(mtp_event_t, buf_event);
+} mtpd_epbuf_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+static mtpd_interface_t _mtpd_itf;
+CFG_TUD_MEM_SECTION static mtpd_epbuf_t _mtpd_epbuf;
+
+static void preprocess_cmd(mtpd_interface_t* p_mtp, tud_mtp_cb_data_t* cb_data);
+
+//--------------------------------------------------------------------+
+// Debug
+//--------------------------------------------------------------------+
+#if CFG_TUSB_DEBUG >= CFG_TUD_MTP_LOG_LEVEL
+
+TU_ATTR_UNUSED static tu_lookup_entry_t const _mpt_op_lookup[] = {
+{.key = MTP_OP_UNDEFINED , .data = "Undefined" } ,
+{.key = MTP_OP_GET_DEVICE_INFO , .data = "GetDeviceInfo" } ,
+{.key = MTP_OP_OPEN_SESSION , .data = "OpenSession" } ,
+{.key = MTP_OP_CLOSE_SESSION , .data = "CloseSession" } ,
+{.key = MTP_OP_GET_STORAGE_IDS , .data = "GetStorageIDs" } ,
+{.key = MTP_OP_GET_STORAGE_INFO , .data = "GetStorageInfo" } ,
+{.key = MTP_OP_GET_NUM_OBJECTS , .data = "GetNumObjects" } ,
+{.key = MTP_OP_GET_OBJECT_HANDLES , .data = "GetObjectHandles" } ,
+{.key = MTP_OP_GET_OBJECT_INFO , .data = "GetObjectInfo" } ,
+{.key = MTP_OP_GET_OBJECT , .data = "GetObject" } ,
+{.key = MTP_OP_GET_THUMB , .data = "GetThumb" } ,
+{.key = MTP_OP_DELETE_OBJECT , .data = "DeleteObject" } ,
+{.key = MTP_OP_SEND_OBJECT_INFO , .data = "SendObjectInfo" } ,
+{.key = MTP_OP_SEND_OBJECT , .data = "SendObject" } ,
+{.key = MTP_OP_INITIATE_CAPTURE , .data = "InitiateCapture" } ,
+{.key = MTP_OP_FORMAT_STORE , .data = "FormatStore" } ,
+{.key = MTP_OP_RESET_DEVICE , .data = "ResetDevice" } ,
+{.key = MTP_OP_SELF_TEST , .data = "SelfTest" } ,
+{.key = MTP_OP_SET_OBJECT_PROTECTION , .data = "SetObjectProtection" } ,
+{.key = MTP_OP_POWER_DOWN , .data = "PowerDown" } ,
+{.key = MTP_OP_GET_DEVICE_PROP_DESC , .data = "GetDevicePropDesc" } ,
+{.key = MTP_OP_GET_DEVICE_PROP_VALUE , .data = "GetDevicePropValue" } ,
+{.key = MTP_OP_SET_DEVICE_PROP_VALUE , .data = "SetDevicePropValue" } ,
+{.key = MTP_OP_RESET_DEVICE_PROP_VALUE , .data = "ResetDevicePropValue" } ,
+{.key = MTP_OP_TERMINATE_OPEN_CAPTURE , .data = "TerminateOpenCapture" } ,
+{.key = MTP_OP_MOVE_OBJECT , .data = "MoveObject" } ,
+{.key = MTP_OP_COPY_OBJECT , .data = "CopyObject" } ,
+{.key = MTP_OP_GET_PARTIAL_OBJECT , .data = "GetPartialObject" } ,
+{.key = MTP_OP_INITIATE_OPEN_CAPTURE , .data = "InitiateOpenCapture" } ,
+{.key = MTP_OP_GET_OBJECT_PROPS_SUPPORTED , .data = "GetObjectPropsSupported" } ,
+{.key = MTP_OP_GET_OBJECT_PROP_DESC , .data = "GetObjectPropDesc" } ,
+{.key = MTP_OP_GET_OBJECT_PROP_VALUE , .data = "GetObjectPropValue" } ,
+{.key = MTP_OP_SET_OBJECT_PROP_VALUE , .data = "SetObjectPropValue" } ,
+{.key = MTP_OP_GET_OBJECT_PROPLIST , .data = "GetObjectPropList" } ,
+{.key = MTP_OP_GET_OBJECT_PROP_REFERENCES , .data = "GetObjectPropReferences" } ,
+{.key = MTP_OP_GET_SERVICE_IDS , .data = "GetServiceIDs" } ,
+{.key = MTP_OP_GET_SERVICE_INFO , .data = "GetServiceInfo" } ,
+{.key = MTP_OP_GET_SERVICE_CAPABILITIES , .data = "GetServiceCapabilities" } ,
+{.key = MTP_OP_GET_SERVICE_PROP_DESC , .data = "GetServicePropDesc" } ,
+{.key = MTP_OP_GET_OBJECT_PROP_LIST , .data = "GetObjectPropList" } ,
+{.key = MTP_OP_SET_OBJECT_PROP_LIST , .data = "SetObjectPropList" } ,
+{.key = MTP_OP_GET_INTERDEPENDENT_PROP_DESC , .data = "GetInterdependentPropDesc" } ,
+{.key = MTP_OP_SEND_OBJECT_PROP_LIST , .data = "SendObjectPropList" }
+};
+
+TU_ATTR_UNUSED static tu_lookup_table_t const _mtp_op_table = {
+ .count = TU_ARRAY_SIZE(_mpt_op_lookup),
+ .items = _mpt_op_lookup
+};
+
+TU_ATTR_UNUSED static const char* _mtp_phase_str[] = {
+ "Command",
+ "Data",
+ "Response",
+ "Error"
+};
+
+#endif
+
+
+//--------------------------------------------------------------------+
+// Helper
+//--------------------------------------------------------------------+
+static bool prepare_new_command(mtpd_interface_t* p_mtp) {
+ p_mtp->phase = MTP_PHASE_COMMAND;
+ return usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_out, _mtpd_epbuf.buf, CFG_TUD_MTP_EP_BUFSIZE);
+}
+
+static bool mtpd_data_xfer(mtp_container_info_t* p_container, uint8_t ep_addr) {
+ mtpd_interface_t* p_mtp = &_mtpd_itf;
+ if (p_mtp->phase == MTP_PHASE_COMMAND) {
+ // 1st data block: header + payload
+ p_mtp->phase = MTP_PHASE_DATA;
+ p_mtp->xferred_len = 0;
+
+ if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
+ p_mtp->total_len = p_container->header->len;
+ p_container->header->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
+ p_container->header->transaction_id = p_mtp->command.header.transaction_id;
+ p_mtp->io_header = *p_container->header; // save header for subsequent data
+ } else {
+ // OUT transfer: total length is at least max packet size
+ p_mtp->total_len = tu_max32(p_container->header->len, CFG_TUD_MTP_EP_BUFSIZE);
+ }
+ } else {
+ // subsequent data block: payload only
+ TU_ASSERT(p_mtp->phase == MTP_PHASE_DATA);
+ }
+
+ const uint16_t xact_len = (uint16_t) tu_min32(p_mtp->total_len - p_mtp->xferred_len, CFG_TUD_MTP_EP_BUFSIZE);
+ if (xact_len) {
+ // already transferred all bytes in header's length. Application make an unnecessary extra call
+ TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, ep_addr));
+ TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, ep_addr, _mtpd_epbuf.buf, xact_len));
+ }
+ return true;
+}
+
+bool tud_mtp_data_send(mtp_container_info_t* p_container) {
+ return mtpd_data_xfer(p_container, _mtpd_itf.ep_in);
+}
+
+bool tud_mtp_data_receive(mtp_container_info_t* p_container) {
+ return mtpd_data_xfer(p_container, _mtpd_itf.ep_out);
+}
+
+bool tud_mtp_response_send(mtp_container_info_t* p_container) {
+ mtpd_interface_t* p_mtp = &_mtpd_itf;
+ p_mtp->phase = MTP_PHASE_RESPONSE;
+ p_container->header->type = MTP_CONTAINER_TYPE_RESPONSE_BLOCK;
+ p_container->header->transaction_id = p_mtp->command.header.transaction_id;
+ TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, p_mtp->ep_in));
+ return usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, _mtpd_epbuf.buf, (uint16_t)p_container->header->len);
+}
+
+bool tud_mtp_mounted(void) {
+ mtpd_interface_t* p_mtp = &_mtpd_itf;
+ return p_mtp->ep_out != 0 && p_mtp->ep_in != 0;
+}
+
+bool tud_mtp_event_send(mtp_event_t* event) {
+ mtpd_interface_t* p_mtp = &_mtpd_itf;
+ TU_VERIFY(p_mtp->ep_event != 0);
+ _mtpd_epbuf.buf_event = *event;
+ TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, p_mtp->ep_event)); // Claim the endpoint
+ return usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_event, (uint8_t*) &_mtpd_epbuf.buf_event, sizeof(mtp_event_t));
+}
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+void mtpd_init(void) {
+ tu_memclr(&_mtpd_itf, sizeof(mtpd_interface_t));
+}
+
+bool mtpd_deinit(void) {
+ return true; // nothing to do
+}
+
+void mtpd_reset(uint8_t rhport) {
+ (void) rhport;
+ tu_memclr(&_mtpd_itf, sizeof(mtpd_interface_t));
+}
+
+uint16_t mtpd_open(uint8_t rhport, tusb_desc_interface_t const* itf_desc, uint16_t max_len) {
+ // only support PIMA 15470 protocol
+ TU_VERIFY(TUSB_CLASS_IMAGE == itf_desc->bInterfaceClass &&
+ MTP_SUBCLASS_STILL_IMAGE == itf_desc->bInterfaceSubClass &&
+ MTP_PROTOCOL_PIMA_15470 == itf_desc->bInterfaceProtocol, 0);
+
+ // mtp driver length is fixed
+ const uint16_t mtpd_itf_size = sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t);
+
+ // Max length must be at least 1 interface + 3 endpoints
+ TU_ASSERT(itf_desc->bNumEndpoints == 3 && max_len >= mtpd_itf_size);
+ mtpd_interface_t* p_mtp = &_mtpd_itf;
+ tu_memclr(p_mtp, sizeof(mtpd_interface_t));
+ p_mtp->rhport = rhport;
+ p_mtp->itf_num = itf_desc->bInterfaceNumber;
+
+ // Open interrupt IN endpoint
+ const tusb_desc_endpoint_t* ep_desc = (const tusb_desc_endpoint_t*) tu_desc_next(itf_desc);
+ TU_ASSERT(ep_desc->bDescriptorType == TUSB_DESC_ENDPOINT && ep_desc->bmAttributes.xfer == TUSB_XFER_INTERRUPT, 0);
+ TU_ASSERT(usbd_edpt_open(rhport, ep_desc), 0);
+ p_mtp->ep_event = ep_desc->bEndpointAddress;
+
+ // Open endpoint pair
+ TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(ep_desc), 2, TUSB_XFER_BULK, &p_mtp->ep_out, &p_mtp->ep_in), 0);
+ TU_ASSERT(prepare_new_command(p_mtp), 0);
+
+ return mtpd_itf_size;
+}
+
+// Invoked when a control transfer occurred on an interface of this class
+// Driver response accordingly to the request and the transfer stage (setup/data/ack)
+// return false to stall control endpoint (e.g unsupported request)
+bool mtpd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) {
+ mtpd_interface_t* p_mtp = &_mtpd_itf;
+ tud_mtp_request_cb_data_t cb_data = {
+ .idx = 0,
+ .stage = stage,
+ .session_id = p_mtp->session_id,
+ .request = request,
+ .buf = p_mtp->control_buf,
+ .bufsize = tu_le16toh(request->wLength),
+ };
+
+ switch (request->bRequest) {
+ case MTP_REQ_CANCEL:
+ TU_LOG_DRV(" MTP request: Cancel\n");
+ if (stage == CONTROL_STAGE_SETUP) {
+ return tud_control_xfer(rhport, request, p_mtp->control_buf, CFG_TUD_MTP_EP_CONTROL_BUFSIZE);
+ } else if (stage == CONTROL_STAGE_ACK) {
+ return tud_mtp_request_cancel_cb(&cb_data);
+ }
+ break;
+
+ case MTP_REQ_GET_EXT_EVENT_DATA:
+ TU_LOG_DRV(" MTP request: Get Extended Event Data\n");
+ if (stage == CONTROL_STAGE_SETUP) {
+ const int32_t len = tud_mtp_request_get_extended_event_cb(&cb_data);
+ TU_VERIFY(len > 0);
+ return tud_control_xfer(rhport,request, p_mtp->control_buf, (uint16_t) len);
+ }
+ break;
+
+ case MTP_REQ_RESET:
+ TU_LOG_DRV(" MTP request: Device Reset\n");
+ // used by the host to return the Still Image Capture Device to the Idle state after the Bulk-pipe has stalled
+ if (stage == CONTROL_STAGE_SETUP) {
+ // clear stalled
+ if (usbd_edpt_stalled(rhport, p_mtp->ep_out)) {
+ usbd_edpt_clear_stall(rhport, p_mtp->ep_out);
+ }
+ if (usbd_edpt_stalled(rhport, p_mtp->ep_in)) {
+ usbd_edpt_clear_stall(rhport, p_mtp->ep_in);
+ }
+ } else if (stage == CONTROL_STAGE_ACK) {
+ prepare_new_command(p_mtp);
+ return tud_mtp_request_device_reset_cb(&cb_data);
+ }
+ break;
+
+ case MTP_REQ_GET_DEVICE_STATUS: {
+ TU_LOG_DRV(" MTP request: Get Device Status\n");
+ if (stage == CONTROL_STAGE_SETUP) {
+ const int32_t len = tud_mtp_request_get_device_status_cb(&cb_data);
+ TU_VERIFY(len > 0);
+ return tud_control_xfer(rhport, request, p_mtp->control_buf, (uint16_t) len);
+ }
+ break;
+ }
+
+ default:
+ return tud_mtp_request_vendor_cb(&cb_data);
+ }
+
+ return true;
+}
+
+// Transfer on bulk endpoints
+bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) {
+ if (ep_addr == _mtpd_itf.ep_event) {
+ // nothing to do
+ return true;
+ }
+
+ mtpd_interface_t* p_mtp = &_mtpd_itf;
+ mtp_generic_container_t* p_container = (mtp_generic_container_t*) _mtpd_epbuf.buf;
+
+#if CFG_TUSB_DEBUG >= CFG_TUD_MTP_LOG_LEVEL
+ tu_lookup_find(&_mtp_op_table, p_mtp->command.header.code);
+ TU_LOG_DRV(" MTP %s: %s phase\r\n", (const char *) tu_lookup_find(&_mtp_op_table, p_mtp->command.header.code),
+ _mtp_phase_str[p_mtp->phase]);
+#endif
+
+ const mtp_container_info_t headered_packet = {
+ .header = &p_container->header,
+ .payload = p_container->payload,
+ .payload_bytes = CFG_TUD_MTP_EP_BUFSIZE - sizeof(mtp_container_header_t)
+ };
+
+ const mtp_container_info_t headerless_packet = {
+ .header = &p_mtp->io_header,
+ .payload = _mtpd_epbuf.buf,
+ .payload_bytes = CFG_TUD_MTP_EP_BUFSIZE
+ };
+
+ tud_mtp_cb_data_t cb_data;
+ cb_data.idx = 0;
+ cb_data.phase = p_mtp->phase;
+ cb_data.session_id = p_mtp->session_id;
+ cb_data.command_container = &p_mtp->command;
+ cb_data.io_container = headered_packet;
+ cb_data.total_xferred_bytes = 0;
+ cb_data.xfer_result = event;
+
+ switch (p_mtp->phase) {
+ case MTP_PHASE_COMMAND: {
+ // received new command
+ TU_VERIFY(ep_addr == p_mtp->ep_out && p_container->header.type == MTP_CONTAINER_TYPE_COMMAND_BLOCK);
+ memcpy(&p_mtp->command, p_container, sizeof(mtp_container_command_t)); // save new command
+ p_container->header.len = sizeof(mtp_container_header_t); // default container to header only
+ preprocess_cmd(p_mtp, &cb_data);
+ if (tud_mtp_command_received_cb(&cb_data) < 0) {
+ p_mtp->phase = MTP_PHASE_ERROR;
+ }
+ break;
+ }
+
+ case MTP_PHASE_DATA: {
+ const uint16_t bulk_mps = (tud_speed_get() == TUSB_SPEED_HIGH) ? 512 : 64;
+ p_mtp->xferred_len += xferred_bytes;
+ cb_data.total_xferred_bytes = p_mtp->xferred_len;
+
+ bool is_complete = false;
+ // complete if ZLP or short packet or overflow
+ if (xferred_bytes == 0 || // ZLP
+ (xferred_bytes & (bulk_mps - 1)) || // short packet
+ p_mtp->xferred_len > p_mtp->total_len) {
+ is_complete = true;
+ }
+
+ if (ep_addr == p_mtp->ep_in) {
+ // Data In
+ if (is_complete) {
+ cb_data.io_container.header->len = sizeof(mtp_container_header_t);
+ tud_mtp_data_complete_cb(&cb_data);
+ } else {
+ // 2nd+ packet: payload only
+ cb_data.io_container = headerless_packet;
+ tud_mtp_data_xfer_cb(&cb_data);
+ }
+ } else {
+ // Data Out
+ if (p_mtp->xferred_len == xferred_bytes) {
+ // 1st OUT packet: header + payload
+ p_mtp->io_header = p_container->header; // save header for subsequent transaction
+ cb_data.io_container.payload_bytes = xferred_bytes - sizeof(mtp_container_header_t);
+ } else {
+ // 2nd+ packet: payload only
+ cb_data.io_container = headerless_packet;
+ cb_data.io_container.payload_bytes = xferred_bytes;
+ }
+ tud_mtp_data_xfer_cb(&cb_data);
+
+ if (is_complete) {
+ // back to header + payload for response
+ cb_data.io_container = headered_packet;
+ cb_data.io_container.header->len = sizeof(mtp_container_header_t);
+ tud_mtp_data_complete_cb(&cb_data);
+ }
+ }
+ break;
+ }
+
+ case MTP_PHASE_RESPONSE:
+ // response phase is complete -> prepare for new command
+ TU_ASSERT(ep_addr == p_mtp->ep_in);
+ tud_mtp_response_complete_cb(&cb_data);
+ prepare_new_command(p_mtp);
+ break;
+
+ case MTP_PHASE_ERROR:
+ // handled after switch, supposedly to be empty
+ break;
+ default: return false;
+ }
+
+ if (p_mtp->phase == MTP_PHASE_ERROR) {
+ // stall both IN & OUT endpoints
+ usbd_edpt_stall(rhport, p_mtp->ep_out);
+ usbd_edpt_stall(rhport, p_mtp->ep_in);
+ }
+
+ return true;
+}
+
+
+//--------------------------------------------------------------------+
+// MTPD Internal functionality
+//--------------------------------------------------------------------+
+
+// pre-processed commands
+void preprocess_cmd(mtpd_interface_t* p_mtp, tud_mtp_cb_data_t* cb_data) {
+ switch (p_mtp->command.header.code) {
+ case MTP_OP_GET_DEVICE_INFO: {
+ tud_mtp_device_info_t dev_info = {
+ .standard_version = 100,
+ .mtp_vendor_extension_id = 6, // MTP specs say 0xFFFFFFFF but libMTP check for value 6
+ .mtp_version = 100,
+ .mtp_extensions = {
+ .count = sizeof(CFG_TUD_MTP_DEVICEINFO_EXTENSIONS),
+ .utf16 = { 0 }
+ },
+ .functional_mode = 0x0000,
+ .supported_operations = {
+ .count = TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS),
+ .arr = { CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS }
+ },
+ .supported_events = {
+ .count = TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS),
+ .arr = { CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS }
+ },
+ .supported_device_properties = {
+ .count = TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES),
+ .arr = { CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES }
+ },
+ .capture_formats = {
+ .count = TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS),
+ .arr = { CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS }
+ },
+ .playback_formats = {
+ .count = TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS),
+ .arr = { CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS }
+ }
+ };
+
+ for (uint8_t i=0; i < dev_info.mtp_extensions.count; i++) {
+ dev_info.mtp_extensions.utf16[i] = (uint16_t)CFG_TUD_MTP_DEVICEINFO_EXTENSIONS[i];
+ }
+
+ mtp_container_add_raw(&cb_data->io_container, &dev_info, sizeof(tud_mtp_device_info_t));
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+#endif
diff --git a/src/class/mtp/mtp_device.h b/src/class/mtp/mtp_device.h
new file mode 100644
index 000000000..397fbbbce
--- /dev/null
+++ b/src/class/mtp/mtp_device.h
@@ -0,0 +1,167 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN0
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef TUSB_MTP_DEVICE_H_
+#define TUSB_MTP_DEVICE_H_
+
+#include "common/tusb_common.h"
+#include "mtp.h"
+
+#if (CFG_TUD_ENABLED && CFG_TUD_MTP)
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// callback data for Bulk Only Transfer (BOT) protocol
+typedef struct {
+ uint8_t idx; // mtp instance
+ uint8_t phase; // current phase
+ uint32_t session_id;
+
+ const mtp_container_command_t* command_container;
+ mtp_container_info_t io_container;
+
+ tusb_xfer_result_t xfer_result;
+ uint32_t total_xferred_bytes; // number of bytes transferred so far in this phase
+} tud_mtp_cb_data_t;
+
+// callback data for Control requests
+typedef struct {
+ uint8_t idx;
+ uint8_t stage; // control stage
+ uint32_t session_id;
+
+ const tusb_control_request_t* request;
+ // buffer for data stage
+ uint8_t* buf;
+ uint16_t bufsize;
+} tud_mtp_request_cb_data_t;
+
+// Number of supported operations, events, device properties, capture formats, playback formats
+// and max number of characters for strings manufacturer, model, device_version, serial_number
+#define MTP_DEVICE_INFO_STRUCT(_extension_nchars, _op_count, _event_count, _devprop_count, _capture_count, _playback_count) \
+ struct TU_ATTR_PACKED { \
+ uint16_t standard_version; \
+ uint32_t mtp_vendor_extension_id; \
+ uint16_t mtp_version; \
+ mtp_string_t(_extension_nchars) mtp_extensions; \
+ uint16_t functional_mode; \
+ mtp_auint16_t(_op_count) supported_operations; \
+ mtp_auint16_t(_event_count) supported_events; \
+ mtp_auint16_t(_devprop_count) supported_device_properties; \
+ mtp_auint16_t(_capture_count) capture_formats; \
+ mtp_auint16_t(_playback_count) playback_formats; \
+ /* string fields will be added using append function */ \
+ }
+
+typedef MTP_DEVICE_INFO_STRUCT(
+ sizeof(CFG_TUD_MTP_DEVICEINFO_EXTENSIONS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS),
+ TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES),
+ TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS)
+) tud_mtp_device_info_t;
+
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
+
+// check if mtp interface is mounted
+bool tud_mtp_mounted(void);
+
+// send data phase
+bool tud_mtp_data_send(mtp_container_info_t* p_container);
+
+// receive data phase
+bool tud_mtp_data_receive(mtp_container_info_t* p_container);
+
+// send response
+bool tud_mtp_response_send(mtp_container_info_t* p_container);
+
+// send event notification on event endpoint
+bool tud_mtp_event_send(mtp_event_t* event);
+
+//--------------------------------------------------------------------+
+// Control request Callbacks
+//--------------------------------------------------------------------+
+
+// Invoked when received Cancel request. Data is available in callback data's buffer
+// return false to stall the request
+bool tud_mtp_request_cancel_cb(tud_mtp_request_cb_data_t* cb_data);
+
+// Invoked when received Device Reset request
+// return false to stall the request
+bool tud_mtp_request_device_reset_cb(tud_mtp_request_cb_data_t* cb_data);
+
+// Invoked when received Get Extended Event request. Application fill callback data's buffer for response
+// return negative to stall the request
+int32_t tud_mtp_request_get_extended_event_cb(tud_mtp_request_cb_data_t* cb_data);
+
+// Invoked when received Get DeviceStatus request. Application fill callback data's buffer for response
+// return negative to stall the request
+int32_t tud_mtp_request_get_device_status_cb(tud_mtp_request_cb_data_t* cb_data);
+
+// Invoked when received vendor-specific request not in the above standard MTP requests
+// return false to stall the request
+bool tud_mtp_request_vendor_cb(tud_mtp_request_cb_data_t* cb_data);
+
+//--------------------------------------------------------------------+
+// Bulk only protocol Callbacks
+//--------------------------------------------------------------------+
+
+// Invoked when new command is received. Application fill the cb_data->io_container and call tud_mtp_data_send() or
+// tud_mtp_response_send() for Data or Response phase.
+// Return negative to stall the endpoints
+int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t * cb_data);
+
+// Invoked when a data packet is transferred. If data spans over multiple packets, application can use
+// total_xferred_bytes and io_container's payload_bytes to determine the offset and remaining bytes to be transferred.
+// Return negative to stall the endpoints
+int32_t tud_mtp_data_xfer_cb(tud_mtp_cb_data_t* cb_data);
+
+// Invoked when all bytes in DATA phase is complete. A response packet is expected
+// Return negative to stall the endpoints
+int32_t tud_mtp_data_complete_cb(tud_mtp_cb_data_t* cb_data);
+
+// Invoked when response phase is complete
+// Return negative to stall the endpoints
+int32_t tud_mtp_response_complete_cb(tud_mtp_cb_data_t* cb_data);
+
+//--------------------------------------------------------------------+
+// Internal Class Driver API
+//--------------------------------------------------------------------+
+void mtpd_init (void);
+bool mtpd_deinit (void);
+void mtpd_reset (uint8_t rhport);
+uint16_t mtpd_open (uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
+bool mtpd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const *p_request);
+bool mtpd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
+#endif
diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c
index 7ec939b64..3f6bedd4c 100644
--- a/src/class/usbtmc/usbtmc_device.c
+++ b/src/class/usbtmc/usbtmc_device.c
@@ -159,6 +159,25 @@ TU_VERIFY_STATIC(USBTMCD_BUFFER_SIZE >= 32u, "USBTMC dev buffer size too small")
static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len);
static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen);
+
+// USBTMC Device Callbacks weak implementations
+TU_ATTR_WEAK bool tud_usbtmc_notification_complete_cb(void) {
+ return true;
+}
+
+TU_ATTR_WEAK bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult) {
+ (void) msg;
+ (void) tmcResult;
+ return true;
+}
+
+#if (CFG_TUD_USBTMC_ENABLE_488)
+TU_ATTR_WEAK bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg) {
+ (void) msg;
+ return true;
+}
+#endif
+
#ifndef NDEBUG
tu_static uint8_t termChar;
#endif
@@ -262,16 +281,10 @@ void usbtmcd_init_cb(void) {
usbtmc_state.capabilities = tud_usbtmc_get_capabilities_cb();
#ifndef NDEBUG
#if CFG_TUD_USBTMC_ENABLE_488
- if (usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger) {
- TU_ASSERT(&tud_usbtmc_msg_trigger_cb != NULL, );
- }
// Per USB488 spec: table 8
TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.listenOnly, );
TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.talkOnly, );
#endif
- if (usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse) {
- TU_ASSERT(&tud_usbtmc_indicator_pulse_cb != NULL, );
- }
#endif
usbtmcLock = osal_mutex_create(&usbtmcLockBuffer);
@@ -587,9 +600,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
TU_ASSERT(false);
}
} else if (ep_addr == usbtmc_state.ep_int_in) {
- if (tud_usbtmc_notification_complete_cb) {
- TU_VERIFY(tud_usbtmc_notification_complete_cb());
- }
+ TU_VERIFY(tud_usbtmc_notification_complete_cb());
return true;
}
return false;
diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h
index b85ef12b5..235f1276e 100644
--- a/src/class/usbtmc/usbtmc_device.h
+++ b/src/class/usbtmc/usbtmc_device.h
@@ -75,15 +75,14 @@ bool tud_usbtmc_check_clear_cb(usbtmc_get_clear_status_rsp_t *rsp);
// The interrupt-IN endpoint buffer was transmitted to the host. Use
// tud_usbtmc_transmit_notification_data to send another notification.
-TU_ATTR_WEAK bool tud_usbtmc_notification_complete_cb(void);
+bool tud_usbtmc_notification_complete_cb(void);
// Indicator pulse should be 0.5 to 1.0 seconds long
-TU_ATTR_WEAK bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult);
+bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult);
#if (CFG_TUD_USBTMC_ENABLE_488)
uint8_t tud_usbtmc_get_stb_cb(uint8_t *tmcResult);
-TU_ATTR_WEAK bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg);
-//TU_ATTR_WEAK bool tud_usbtmc_app_go_to_local_cb();
+bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg);
#endif
// Called from app
diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c
index b0332b0fe..27724b194 100644
--- a/src/class/vendor/vendor_device.c
+++ b/src/class/vendor/vendor_device.c
@@ -67,6 +67,20 @@ typedef struct {
CFG_TUD_MEM_SECTION static vendord_epbuf_t _vendord_epbuf[CFG_TUD_VENDOR];
+//--------------------------------------------------------------------+
+// Weak stubs: invoked if no strong implementation is available
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize) {
+ (void) itf;
+ (void) buffer;
+ (void) bufsize;
+}
+
+TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) {
+ (void) itf;
+ (void) sent_bytes;
+}
+
//--------------------------------------------------------------------
// Application API
//--------------------------------------------------------------------
@@ -259,16 +273,12 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
tu_edpt_stream_read_xfer_complete(&p_vendor->rx.stream, xferred_bytes);
// Invoked callback if any
- if (tud_vendor_rx_cb) {
- tud_vendor_rx_cb(itf, p_epbuf->epout, (uint16_t) xferred_bytes);
- }
+ tud_vendor_rx_cb(itf, p_epbuf->epout, (uint16_t) xferred_bytes);
tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream);
} else if ( ep_addr == p_vendor->tx.stream.ep_addr ) {
// Send complete
- if (tud_vendor_tx_cb) {
- tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes);
- }
+ tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes);
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
// try to send more if possible
diff --git a/src/class/vendor/vendor_device.h b/src/class/vendor/vendor_device.h
index 149ae2d56..5fe4fc9ff 100644
--- a/src/class/vendor/vendor_device.h
+++ b/src/class/vendor/vendor_device.h
@@ -119,9 +119,9 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_available(void) {
//--------------------------------------------------------------------+
// Invoked when received new data
-TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize);
+void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize);
// Invoked when last rx transfer finished
-TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes);
+void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes);
//--------------------------------------------------------------------+
// Inline Functions
diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c
index 3124d5596..5c00cc358 100644
--- a/src/class/video/video_device.c
+++ b/src/class/video/video_device.c
@@ -193,6 +193,28 @@ static char const* const tu_str_video_vs_control_selector[] = {
#endif
//--------------------------------------------------------------------+
+// Weak stubs: invoked if no strong implementation is available
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) {
+ (void) ctl_idx;
+ (void) stm_idx;
+}
+
+TU_ATTR_WEAK int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod) {
+ (void) ctl_idx;
+ (void) power_mod;
+ return VIDEO_ERROR_NONE;
+}
+
+TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx,
+ video_probe_and_commit_control_t const *parameters) {
+ (void) ctl_idx;
+ (void) stm_idx;
+ (void) parameters;
+ return VIDEO_ERROR_NONE;
+}
+
+//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
@@ -902,7 +924,7 @@ static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage,
TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN);
} else if (stage == CONTROL_STAGE_DATA) {
- if (tud_video_power_mode_cb) return tud_video_power_mode_cb(ctl_idx, self->power_mode);
+ return tud_video_power_mode_cb(ctl_idx, self->power_mode);
}
return VIDEO_ERROR_NONE;
@@ -1104,10 +1126,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
TU_VERIFY(_update_streaming_parameters(stm, param), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
/* Set the negotiated value */
stm->max_payload_transfer_size = param->dwMaxPayloadTransferSize;
- int ret = VIDEO_ERROR_NONE;
- if (tud_video_commit_cb) {
- ret = tud_video_commit_cb(stm->index_vc, stm->index_vs, param);
- }
+ int ret = tud_video_commit_cb(stm->index_vc, stm->index_vs, param);
if (VIDEO_ERROR_NONE == ret) {
stm->state = VS_STATE_COMMITTED;
stm->buffer = NULL;
@@ -1419,9 +1438,7 @@ bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
stm->buffer = NULL;
stm->bufsize = 0;
stm->offset = 0;
- if (tud_video_frame_xfer_complete_cb) {
- tud_video_frame_xfer_complete_cb(stm->index_vc, stm->index_vs);
- }
+ tud_video_frame_xfer_complete_cb(stm->index_vc, stm->index_vs);
}
return true;
}
diff --git a/src/class/video/video_device.h b/src/class/video/video_device.h
index 648a221d5..2b41c3bfe 100644
--- a/src/class/video/video_device.h
+++ b/src/class/video/video_device.h
@@ -61,7 +61,7 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu
*
* @param[in] ctl_idx Destination control interface index
* @param[in] stm_idx Destination streaming interface index */
-TU_ATTR_WEAK void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx);
+void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx);
//--------------------------------------------------------------------+
// Application Callback API (weak is optional)
@@ -72,7 +72,7 @@ TU_ATTR_WEAK void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fa
* @param[in] ctl_idx Destination control interface index
* @param[in] stm_idx Destination streaming interface index
* @return video_error_code_t */
-TU_ATTR_WEAK int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod);
+int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod);
/** Invoked when VS_COMMIT_CONTROL(SET_CUR) request received
*
@@ -80,7 +80,7 @@ TU_ATTR_WEAK int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod
* @param[in] stm_idx Destination streaming interface index
* @param[in] parameters Video streaming parameters
* @return video_error_code_t */
-TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx,
+int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx,
video_probe_and_commit_control_t const *parameters);
//--------------------------------------------------------------------+
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h
index 489e09a15..2b095e238 100644
--- a/src/common/tusb_common.h
+++ b/src/common/tusb_common.h
@@ -35,6 +35,7 @@
// Macros Helper
//--------------------------------------------------------------------+
#define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
+#define TU_FIELD_SIZE(_type, _field) (sizeof(((_type *)0)->_field))
#define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) )
#define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) )
#define TU_DIV_CEIL(n, d) (((n) + (d) - 1) / (d))
@@ -78,19 +79,25 @@
#include "tusb_debug.h"
//--------------------------------------------------------------------+
-// Optional API implemented by application if needed
+// API implemented by application if needed
// TODO move to a more obvious place/file
//--------------------------------------------------------------------+
+// Get current milliseconds, required by some port/configuration without RTOS
+extern uint32_t tusb_time_millis_api(void);
+
+// Delay in milliseconds, use tusb_time_millis_api() by default. required by some port/configuration with no RTOS
+extern void tusb_time_delay_ms_api(uint32_t ms);
+
// flush data cache
-TU_ATTR_WEAK extern void tusb_app_dcache_flush(uintptr_t addr, uint32_t data_size);
+extern void tusb_app_dcache_flush(uintptr_t addr, uint32_t data_size);
// invalidate data cache
-TU_ATTR_WEAK extern void tusb_app_dcache_invalidate(uintptr_t addr, uint32_t data_size);
+extern void tusb_app_dcache_invalidate(uintptr_t addr, uint32_t data_size);
// Optional physical <-> virtual address translation
-TU_ATTR_WEAK extern void* tusb_app_virt_to_phys(void *virt_addr);
-TU_ATTR_WEAK extern void* tusb_app_phys_to_virt(void *phys_addr);
+extern void* tusb_app_virt_to_phys(void *virt_addr);
+extern void* tusb_app_phys_to_virt(void *phys_addr);
//--------------------------------------------------------------------+
// Internal Inline Functions
@@ -162,8 +169,8 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u16_high(uint16_t ui16) { return
TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u16_low (uint16_t ui16) { return TU_U16_LOW(ui16); }
//------------- Bits -------------//
-TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_bit_set (uint32_t value, uint8_t pos) { return value | TU_BIT(pos); }
-TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_bit_clear(uint32_t value, uint8_t pos) { return value & (~TU_BIT(pos)); }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_bit_set (uint32_t value, uint8_t pos) { return value | TU_BIT(pos); }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_bit_clear(uint32_t value, uint8_t pos) { return value & (~TU_BIT(pos)); }
TU_ATTR_ALWAYS_INLINE static inline bool tu_bit_test (uint32_t value, uint8_t pos) { return (value & TU_BIT(pos)) ? true : false; }
//------------- Min -------------//
diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c
index ecf002b09..f7679556f 100644
--- a/src/common/tusb_fifo.c
+++ b/src/common/tusb_fifo.c
@@ -428,7 +428,6 @@ static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16
if ( cnt > f->depth )
{
rd_idx = _ff_correct_read_index(f, wr_idx);
- cnt = f->depth;
}
uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index 6632341d7..1c11df114 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -295,6 +295,12 @@
#define TUP_USBIP_FSDEV_STM32
#define TUP_DCD_ENDPOINT_MAX 8
+#elif TU_CHECK_MCU(OPT_MCU_STM32WBA)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
+ #define TUP_DCD_ENDPOINT_MAX 9
+ #define TUP_RHPORT_HIGHSPEED 1
+
#elif TU_CHECK_MCU(OPT_MCU_STM32U5)
#if defined (STM32U535xx) || defined (STM32U545xx)
#define TUP_USBIP_FSDEV
@@ -381,7 +387,7 @@
//--------------------------------------------------------------------+
// Espressif
//--------------------------------------------------------------------+
-#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_ESP32H4)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_ESP32
#define TUP_DCD_ENDPOINT_MAX 7 // only 5 TX FIFO for endpoint IN
@@ -414,7 +420,7 @@
#define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
#define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 64
-#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C6, OPT_MCU_ESP32H2)
+#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C5, OPT_MCU_ESP32C6, OPT_MCU_ESP32C61, OPT_MCU_ESP32H2)
#if (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421))
#error "MCUs are only supported with CFG_TUH_MAX3421 enabled"
#endif
@@ -436,7 +442,7 @@
#define TUP_DCD_ENDPOINT_MAX 16
#define TUP_MCU_MULTIPLE_CORE 1
- #define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb")))
+ #define TU_ATTR_FAST_FUNC __not_in_flash("tinyusb")
//--------------------------------------------------------------------+
// Silabs
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
index 6d02d3572..db91a73d9 100644
--- a/src/common/tusb_verify.h
+++ b/src/common/tusb_verify.h
@@ -53,11 +53,11 @@
* The difference in behavior is that ASSERT triggers a breakpoint while
* verify does not.
*
- * #define TU_VERIFY(cond) if(cond) return false;
- * #define TU_VERIFY(cond,ret) if(cond) return ret;
+ * #define TU_VERIFY(cond) if (!cond) return false;
+ * #define TU_VERIFY(cond,ret) if (!cond) return ret;
*
- * #define TU_ASSERT(cond) if(cond) {TU_MESS_FAILED(); TU_BREAKPOINT(), return false;}
- * #define TU_ASSERT(cond,ret) if(cond) {TU_MESS_FAILED(); TU_BREAKPOINT(), return ret;}
+ * #define TU_ASSERT(cond) if (!cond) {TU_MESS_FAILED(); TU_BREAKPOINT(), return false;}
+ * #define TU_ASSERT(cond,ret) if (!cond) {TU_MESS_FAILED(); TU_BREAKPOINT(), return ret;}
*------------------------------------------------------------------*/
#ifdef __cplusplus
diff --git a/src/device/dcd.h b/src/device/dcd.h
index 789552d47..400f62bff 100644
--- a/src/device/dcd.h
+++ b/src/device/dcd.h
@@ -162,7 +162,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer
// Submit an transfer using fifo, When complete dcd_event_xfer_complete() is invoked to notify the stack
// This API is optional, may be useful for register-based for transferring data.
-bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) TU_ATTR_WEAK;
+bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes);
// Stall endpoint, any queuing transfer should be removed from endpoint
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr);
diff --git a/src/device/usbd.c b/src/device/usbd.c
index b09d02fbd..339ccf4b4 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -321,6 +321,20 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
.sof = NULL
},
#endif
+
+ #if CFG_TUD_MTP
+ {
+ .name = DRIVER_NAME("MTP"),
+ .init = mtpd_init,
+ .deinit = mtpd_deinit,
+ .reset = mtpd_reset,
+ .open = mtpd_open,
+ .control_xfer_cb = mtpd_control_xfer_cb,
+ .xfer_cb = mtpd_xfer_cb,
+ .xfer_isr = NULL,
+ .sof = NULL
+ },
+ #endif
};
enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) };
@@ -393,6 +407,18 @@ void usbd_control_set_request(tusb_control_request_t const *request);
void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp );
bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+//--------------------------------------------------------------------+
+// Weak stubs: invoked if no strong implementation is available
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) {
+ *driver_count = 0;
+ return NULL;
+}
+
+TU_ATTR_WEAK bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) {
+ (void) rhport; (void) ep_addr; (void) ff; (void) total_bytes;
+ return false;
+}
//--------------------------------------------------------------------+
// Debug
@@ -516,10 +542,8 @@ bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
TU_ASSERT(_usbd_q);
// Get application driver if available
- if (usbd_app_driver_get_cb) {
- _app_driver = usbd_app_driver_get_cb(&_app_driver_count);
- TU_ASSERT(_app_driver_count + BUILTIN_DRIVER_COUNT <= UINT8_MAX);
- }
+ _app_driver = usbd_app_driver_get_cb(&_app_driver_count);
+ TU_ASSERT(_app_driver_count + BUILTIN_DRIVER_COUNT <= UINT8_MAX);
// Init class drivers
for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
diff --git a/src/device/usbd.h b/src/device/usbd.h
index e5a848809..a4104e47d 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -270,6 +270,25 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ
//--------------------------------------------------------------------+
+// MTP Descriptor Templates
+//--------------------------------------------------------------------+
+
+// Length of template descriptor: 30 bytes
+#define TUD_MTP_DESC_LEN (9 + 7 + 7 + 7)
+
+// Interface number, string index, EP event, EP event size, EP event polling, EP Out & EP In address, EP size
+#define TUD_MTP_DESCRIPTOR(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_polling_interval, _epout, _epin, _epsize) \
+ /* Interface */\
+ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 3, TUSB_CLASS_IMAGE, MTP_SUBCLASS_STILL_IMAGE, MTP_PROTOCOL_PIMA_15470, _stridx,\
+ /* Endpoint Interrupt */\
+ 7, TUSB_DESC_ENDPOINT, _ep_evt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_evt_size), _ep_evt_polling_interval,\
+ /* Endpoint Out */\
+ 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+ /* Endpoint In */\
+ 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
+
+
+//--------------------------------------------------------------------+
// HID Descriptor Templates
//--------------------------------------------------------------------+
diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h
index f1797bf0d..a688cf497 100644
--- a/src/device/usbd_pvt.h
+++ b/src/device/usbd_pvt.h
@@ -64,7 +64,7 @@ typedef struct {
// Invoked when initializing device stack to get additional class drivers.
// Can be implemented by application to extend/overwrite class driver support.
// Note: The drivers array must be accessible at all time when stack is active
-usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) TU_ATTR_WEAK;
+usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count);
typedef bool (*usbd_control_xfer_cb_t)(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
diff --git a/src/host/usbh.c b/src/host/usbh.c
index ce83977c5..6bafde368 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -88,6 +88,19 @@ TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_si
return false;
}
+TU_ATTR_WEAK usbh_class_driver_t const* usbh_app_driver_get_cb(uint8_t* driver_count) {
+ *driver_count = 0;
+ return NULL;
+}
+
+TU_ATTR_WEAK void tuh_mount_cb(uint8_t daddr) {
+ (void) daddr;
+}
+
+TU_ATTR_WEAK void tuh_umount_cb(uint8_t daddr) {
+ (void) daddr;
+}
+
//--------------------------------------------------------------------+
// Data Structure
//--------------------------------------------------------------------+
@@ -400,7 +413,7 @@ bool tuh_descriptor_get_device_local(uint8_t daddr, tusb_desc_device_t* desc_dev
tusb_speed_t tuh_speed_get(uint8_t daddr) {
tuh_bus_info_t bus_info;
tuh_bus_info_get(daddr, &bus_info);
- return bus_info.speed;
+ return (tusb_speed_t)bus_info.speed;
}
bool tuh_rhport_is_active(uint8_t rhport) {
@@ -481,9 +494,7 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
#endif
// Get application driver if available
- if (usbh_app_driver_get_cb) {
- _app_driver = usbh_app_driver_get_cb(&_app_driver_count);
- }
+ _app_driver = usbh_app_driver_get_cb(&_app_driver_count);
// Device
tu_memclr(_usbh_devices, sizeof(_usbh_devices));
@@ -651,7 +662,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
tuh_xfer_t xfer = {
.daddr = event.dev_addr,
.ep_addr = ep_addr,
- .result = event.xfer_complete.result,
+ .result = (xfer_result_t)event.xfer_complete.result,
.actual_len = event.xfer_complete.len,
.buflen = 0, // not available
.buffer = NULL, // not available
@@ -832,18 +843,19 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t
}
TU_ATTR_FALLTHROUGH;
- case CONTROL_STAGE_DATA:
- if (request->wLength) {
- TU_LOG_USBH("[%u:%u] Control data:\r\n", rhport, daddr);
- TU_LOG_MEM_USBH(ctrl_info->buffer, xferred_bytes, 2);
- }
- ctrl_info->actual_len = (uint16_t) xferred_bytes;
+ case CONTROL_STAGE_DATA: {
+ if (request->wLength) {
+ TU_LOG_USBH("[%u:%u] Control data:\r\n", rhport, daddr);
+ TU_LOG_MEM_USBH(ctrl_info->buffer, xferred_bytes, 2);
+ }
+ ctrl_info->actual_len = (uint16_t) xferred_bytes;
- // ACK stage: toggle is always 1
- _control_set_xfer_stage(CONTROL_STAGE_ACK);
- const uint8_t ep_status = tu_edpt_addr(0, 1 - request->bmRequestType_bit.direction);
- TU_ASSERT(hcd_edpt_xfer(rhport, daddr, ep_status, NULL, 0));
- break;
+ // ACK stage: toggle is always 1
+ _control_set_xfer_stage(CONTROL_STAGE_ACK);
+ const uint8_t ep_status = tu_edpt_addr(0, 1 - request->bmRequestType_bit.direction);
+ TU_ASSERT(hcd_edpt_xfer(rhport, daddr, ep_status, NULL, 0));
+ break;
+ }
case CONTROL_STAGE_ACK: {
// Abort all pending transfers if SET_CONFIGURATION request
@@ -1318,9 +1330,7 @@ static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub
#endif
{
// Invoke callback before closing driver (maybe call it later ?)
- if (tuh_umount_cb) {
- tuh_umount_cb(daddr);
- }
+ tuh_umount_cb(daddr);
}
// Close class driver
@@ -1909,9 +1919,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) {
TU_LOG_USBH("HUB address = %u is mounted\r\n", dev_addr);
}else {
// Invoke callback if available
- if (tuh_mount_cb) {
- tuh_mount_cb(dev_addr);
- }
+ tuh_mount_cb(dev_addr);
}
}
}
diff --git a/src/host/usbh.h b/src/host/usbh.h
index 1e9bb26bc..8d48bf90d 100644
--- a/src/host/usbh.h
+++ b/src/host/usbh.h
@@ -123,13 +123,13 @@ void tuh_enum_descriptor_device_cb(uint8_t daddr, const tusb_desc_device_t *desc
bool tuh_enum_descriptor_configuration_cb(uint8_t daddr, uint8_t cfg_index, const tusb_desc_configuration_t *desc_config);
// Invoked when a device is mounted (configured)
-TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr);
+void tuh_mount_cb (uint8_t daddr);
// Invoked when a device failed to mount during enumeration process
-// TU_ATTR_WEAK void tuh_mount_failed_cb (uint8_t daddr);
+// void tuh_mount_failed_cb (uint8_t daddr);
// Invoked when a device is unmounted (detached)
-TU_ATTR_WEAK void tuh_umount_cb(uint8_t daddr);
+void tuh_umount_cb(uint8_t daddr);
// Invoked when there is a new usb event, which need to be processed by tuh_task()/tuh_task_ext()
void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr);
diff --git a/src/host/usbh_pvt.h b/src/host/usbh_pvt.h
index cb092e5f3..9d91e52e8 100644
--- a/src/host/usbh_pvt.h
+++ b/src/host/usbh_pvt.h
@@ -58,7 +58,7 @@ typedef struct {
// Invoked when initializing host stack to get additional class drivers.
// Can be implemented by application to extend/overwrite class driver support.
// Note: The drivers array must be accessible at all time when stack is active
-usbh_class_driver_t const* usbh_app_driver_get_cb(uint8_t* driver_count) TU_ATTR_WEAK;
+usbh_class_driver_t const* usbh_app_driver_get_cb(uint8_t* driver_count);
// Call by class driver to tell USBH that it has complete the enumeration
void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num);
diff --git a/src/osal/osal_mynewt.h b/src/osal/osal_mynewt.h
index ee95e684f..6d51f8ec3 100644
--- a/src/osal/osal_mynewt.h
+++ b/src/osal/osal_mynewt.h
@@ -63,7 +63,7 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx,
if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
return; // single core MCU does not need to lock in ISR
}
- OS_ENTER_CRITICAL(*ctx);
+ OS_EXIT_CRITICAL(*ctx);
}
//--------------------------------------------------------------------+
diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h
index a8eb1042b..3e397ef35 100644
--- a/src/osal/osal_none.h
+++ b/src/osal/osal_none.h
@@ -32,15 +32,6 @@ extern "C" {
#endif
//--------------------------------------------------------------------+
-// TASK API
-//--------------------------------------------------------------------+
-
-#if CFG_TUH_ENABLED
-// currently only needed/available in host mode
-TU_ATTR_WEAK void osal_task_delay(uint32_t msec);
-#endif
-
-//--------------------------------------------------------------------+
// Spinlock API
//--------------------------------------------------------------------+
typedef struct {
diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c
index da9f49d29..953483583 100644
--- a/src/portable/ehci/ehci.c
+++ b/src/portable/ehci/ehci.c
@@ -35,9 +35,15 @@
#include "host/hcd.h"
#include "host/usbh.h"
+#include "host/usbh_pvt.h"
#include "ehci_api.h"
#include "ehci.h"
+// NXP specific fixes
+#if TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX, OPT_MCU_LPC55, OPT_MCU_MCXN9)
+#include "fsl_device_registers.h"
+#endif
+
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
@@ -179,12 +185,43 @@ static void ehci_enable_schedule(ehci_registers_t* regs, bool is_period) {
}
}
+#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
+static void nxp_usbphy_disconn_detector_set(uint8_t port, bool enable) {
+ // unify naming convention
+#if !defined(USBPHY1) && defined(USBPHY)
+ #define USBPHY1 USBPHY
+#endif
+
+ if (port == 0) {
+ if (enable) {
+ USBPHY1->CTRL_SET = USBPHY_CTRL_ENHOSTDISCONDETECT_MASK;
+ } else {
+ USBPHY1->CTRL_CLR = USBPHY_CTRL_ENHOSTDISCONDETECT_MASK;
+ }
+ }
+#if FSL_FEATURE_SOC_USBPHY_COUNT > 1U
+ else if (port == 1) {
+ if (enable) {
+ USBPHY2->CTRL_SET = USBPHY_CTRL_ENHOSTDISCONDETECT_MASK;
+ } else {
+ USBPHY2->CTRL_CLR = USBPHY_CTRL_ENHOSTDISCONDETECT_MASK;
+ }
+ }
+#endif
+
+#if !defined(USBPHY1) && defined(USBPHY)
+ #undef USBPHY1
+#endif
+}
+#endif
+
//--------------------------------------------------------------------+
// HCD API
//--------------------------------------------------------------------+
uint32_t hcd_frame_number(uint8_t rhport) {
(void) rhport;
- return (ehci_data.uframe_number + ehci_data.regs->frame_index) >> 3;
+ uint32_t uframe = ehci_data.regs->frame_index;
+ return (ehci_data.uframe_number + uframe) >> 3;
}
void hcd_port_reset(uint8_t rhport) {
@@ -212,16 +249,21 @@ void hcd_port_reset_end(uint8_t rhport) {
(void) rhport;
ehci_registers_t* regs = ehci_data.regs;
- // skip if reset is already complete
- if (!regs->portsc_bm.port_reset) {
- return;
- }
+ // stop reset only if is not complete yet
+ if (regs->portsc_bm.port_reset) {
+ // mask out all change bits since they are Write 1 to clear
+ uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_W1C;
+ portsc &= ~EHCI_PORTSC_MASK_PORT_RESET;
- // mask out all change bits since they are Write 1 to clear
- uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_W1C;
- portsc &= ~EHCI_PORTSC_MASK_PORT_RESET;
+ regs->portsc = portsc;
+ }
- regs->portsc = portsc;
+#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
+ // Enable disconnect detector for highspeed device only
+ if (hcd_port_speed_get(rhport) == TUSB_SPEED_HIGH) {
+ nxp_usbphy_disconn_detector_set(rhport, true);
+ }
+#endif
}
bool hcd_port_connect_status(uint8_t rhport) {
@@ -578,6 +620,10 @@ void port_connect_status_change_isr(uint8_t rhport) {
hcd_event_device_attach(rhport, true);
} else // device unplugged
{
+#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
+ // Disable disconnect detector
+ nxp_usbphy_disconn_detector_set(rhport, false);
+#endif
hcd_event_device_remove(rhport, true);
}
}
@@ -821,14 +867,21 @@ static ehci_qhd_t *qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr) {
}
ehci_qhd_t *qhd_pool = ehci_data.qhd_pool;
+
+ // protect qhd_pool since 'used' and 'removing' can be changed in isr
+ ehci_qhd_t *result = NULL;
+ usbh_spin_lock(false);
for (uint32_t i = 0; i < QHD_MAX; i++) {
if ((qhd_pool[i].dev_addr == dev_addr) &&
- ep_addr == qhd_ep_addr(&qhd_pool[i])) {
- return &qhd_pool[i];
+ ep_addr == qhd_ep_addr(&qhd_pool[i]) &&
+ qhd_pool[i].used && !qhd_pool[i].removing) {
+ result = &qhd_pool[i];
+ break;
}
}
+ usbh_spin_unlock(false);
- return NULL;
+ return result;
}
// Init queue head with endpoint descriptor
@@ -896,7 +949,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
p_qhd->used = 1;
p_qhd->removing = 0;
p_qhd->attached_qtd = NULL;
- p_qhd->pid = tu_edpt_dir(ep_desc->bEndpointAddress) ? EHCI_PID_IN : EHCI_PID_OUT; // PID for TD under this endpoint
+ p_qhd->pid = tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN ? EHCI_PID_IN : EHCI_PID_OUT; // PID for TD under this endpoint
//------------- active, but no TD list -------------//
p_qhd->qtd_overlay.halted = 0;
diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c
deleted file mode 100644
index 1b6aae026..000000000
--- a/src/portable/espressif/esp32sx/dcd_esp32sx.c
+++ /dev/null
@@ -1,889 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2018 Scott Shawcroft, 2019 William D. Jones for Adafruit Industries
- * Copyright (c) 2019 Ha Thach (tinyusb.org)
- * Additions Copyright (c) 2020, Espressif Systems (Shanghai) Co. Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-#include "tusb_option.h"
-
-#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && CFG_TUD_ENABLED)
-
-// Espressif
-#include "xtensa/xtensa_api.h"
-
-#include "esp_intr_alloc.h"
-#include "esp_log.h"
-#include "soc/dport_reg.h"
-#include "soc/gpio_sig_map.h"
-#include "soc/usb_periph.h"
-#include "soc/usb_reg.h"
-#include "soc/usb_struct.h"
-#include "soc/periph_defs.h" // for interrupt source
-
-#include "device/dcd.h"
-
-#ifndef USB_OUT_EP_NUM
-#define USB_OUT_EP_NUM ((int) (sizeof(USB0.out_ep_reg) / sizeof(USB0.out_ep_reg[0])))
-#endif
-
-#ifndef USB_IN_EP_NUM
-#define USB_IN_EP_NUM ((int) (sizeof(USB0.in_ep_reg) / sizeof(USB0.in_ep_reg[0])))
-#endif
-
-// Max number of bi-directional endpoints including EP0
-// Note: ESP32S2 specs say there are only up to 5 IN active endpoints include EP0
-// We should probably prohibit enabling Endpoint IN > 4 (not done yet)
-#define EP_MAX USB_OUT_EP_NUM
-
-// FIFO size in bytes
-#define EP_FIFO_SIZE 1024
-
-// Max number of IN EP FIFOs
-#define EP_FIFO_NUM 5
-
-typedef struct {
- uint8_t *buffer;
- // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API
- uint16_t total_len;
- uint16_t queued_len;
- uint16_t max_size;
- bool short_packet;
- uint8_t interval;
-} xfer_ctl_t;
-
-static const char *TAG = "TUSB:DCD";
-static intr_handle_t usb_ih;
-
-
-static uint32_t _setup_packet[2];
-
-#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
-static xfer_ctl_t xfer_status[EP_MAX][2];
-
-// Keep count of how many FIFOs are in use
-static uint8_t _allocated_fifos = 1; //FIFO0 is always in use
-
-// Will either return an unused FIFO number, or 0 if all are used.
-static uint8_t get_free_fifo(void)
-{
- if (_allocated_fifos < EP_FIFO_NUM) return _allocated_fifos++;
- return 0;
-}
-
-// Setup the control endpoint 0.
-static void bus_reset(void)
-{
- for (int ep_num = 0; ep_num < USB_OUT_EP_NUM; ep_num++) {
- USB0.out_ep_reg[ep_num].doepctl |= USB_DO_SNAK0_M; // DOEPCTL0_SNAK
- }
-
- // clear device address
- USB0.dcfg &= ~USB_DEVADDR_M;
-
- USB0.daintmsk = USB_OUTEPMSK0_M | USB_INEPMSK0_M;
- USB0.doepmsk = USB_SETUPMSK_M | USB_XFERCOMPLMSK;
- USB0.diepmsk = USB_TIMEOUTMSK_M | USB_DI_XFERCOMPLMSK_M /*| USB_INTKNTXFEMPMSK_M*/;
-
- // "USB Data FIFOs" section in reference manual
- // Peripheral FIFO architecture
- //
- // --------------- 320 or 1024 ( 1280 or 4096 bytes )
- // | IN FIFO MAX |
- // ---------------
- // | ... |
- // --------------- y + x + 16 + GRXFSIZ
- // | IN FIFO 2 |
- // --------------- x + 16 + GRXFSIZ
- // | IN FIFO 1 |
- // --------------- 16 + GRXFSIZ
- // | IN FIFO 0 |
- // --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
- // --------------- 0
- //
- // According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits):
- // - Each EP IN needs at least max packet size, 16 words is sufficient for EP0 IN
- //
- // - All EP OUT shared a unique OUT FIFO which uses
- // * 10 locations in hardware for setup packets + setup control words (up to 3 setup packets).
- // * 2 locations for OUT endpoint control words.
- // * 16 for largest packet size of 64 bytes. ( TODO Highspeed is 512 bytes)
- // * 1 location for global NAK (not required/used here).
- // * It is recommended to allocate 2 times the largest packet size, therefore
- // Recommended value = 10 + 1 + 2 x (16+2) = 47 --> Let's make it 52
- USB0.grstctl |= 0x10 << USB_TXFNUM_S; // fifo 0x10,
- USB0.grstctl |= USB_TXFFLSH_M; // Flush fifo
- USB0.grxfsiz = 52;
-
- // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word )
- USB0.gnptxfsiz = (16 << USB_NPTXFDEP_S) | (USB0.grxfsiz & 0x0000ffffUL);
-
- // Ready to receive SETUP packet
- USB0.out_ep_reg[0].doeptsiz |= USB_SUPCNT0_M;
-
- USB0.gintmsk |= USB_IEPINTMSK_M | USB_OEPINTMSK_M;
-}
-
-static void enum_done_processing(void)
-{
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - Speed enumeration done! Sending DCD_EVENT_BUS_RESET then");
- // On current silicon on the Full Speed core, speed is fixed to Full Speed.
- // However, keep for debugging and in case Low Speed is ever supported.
- uint32_t enum_spd = (USB0.dsts >> USB_ENUMSPD_S) & (USB_ENUMSPD_V);
-
- // Maximum packet size for EP 0 is set for both directions by writing DIEPCTL
- if (enum_spd == 0x03) { // Full-Speed (PHY on 48 MHz)
- USB0.in_ep_reg[0].diepctl &= ~USB_D_MPS0_V; // 64 bytes
- USB0.in_ep_reg[0].diepctl &= ~USB_D_STALL0_M; // clear Stall
- xfer_status[0][TUSB_DIR_OUT].max_size = 64;
- xfer_status[0][TUSB_DIR_IN].max_size = 64;
- } else {
- USB0.in_ep_reg[0].diepctl |= USB_D_MPS0_V; // 8 bytes
- USB0.in_ep_reg[0].diepctl &= ~USB_D_STALL0_M; // clear Stall
- xfer_status[0][TUSB_DIR_OUT].max_size = 8;
- xfer_status[0][TUSB_DIR_IN].max_size = 8;
- }
-}
-
-
-/*------------------------------------------------------------------*/
-/* Controller API
- *------------------------------------------------------------------*/
-bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
- (void) rh_init;
- ESP_LOGV(TAG, "DCD init - Start");
-
- // A. Disconnect
- ESP_LOGV(TAG, "DCD init - Soft DISCONNECT and Setting up");
- USB0.dctl |= USB_SFTDISCON_M; // Soft disconnect
-
- // B. Programming DCFG
- /* If USB host misbehaves during status portion of control xfer
- (non zero-length packet), send STALL back and discard. Full speed. */
- USB0.dcfg |= USB_NZSTSOUTHSHK_M | // NonZero .... STALL
- (3 << 0); // dev speed: fullspeed 1.1 on 48 mhz // TODO no value in usb_reg.h (IDF-1476)
-
- USB0.gahbcfg |= USB_NPTXFEMPLVL_M | USB_GLBLLNTRMSK_M; // Global interruptions ON
- USB0.gusbcfg |= USB_FORCEDEVMODE_M; // force devmode
- USB0.gotgctl &= ~(USB_BVALIDOVVAL_M | USB_BVALIDOVEN_M | USB_VBVALIDOVVAL_M); //no overrides
-
- // C. Setting SNAKs, then connect
- for (int n = 0; n < USB_OUT_EP_NUM; n++) {
- USB0.out_ep_reg[n].doepctl |= USB_DO_SNAK0_M; // DOEPCTL0_SNAK
- }
-
- // D. Interruption masking
- USB0.gintmsk = 0; //mask all
- USB0.gotgint = ~0U; //clear OTG ints
- USB0.gintsts = ~0U; //clear pending ints
- USB0.gintmsk = USB_OTGINTMSK_M |
- USB_MODEMISMSK_M |
- USB_RXFLVIMSK_M |
- USB_ERLYSUSPMSK_M |
- USB_USBSUSPMSK_M |
- USB_USBRSTMSK_M |
- USB_ENUMDONEMSK_M |
- USB_RESETDETMSK_M |
- USB_WKUPINT_M |
- USB_DISCONNINTMSK_M; // host most only
-
- dcd_connect(rhport);
- return true;
-}
-
-void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
-{
- (void)rhport;
- ESP_LOGV(TAG, "DCD init - Set address : %u", dev_addr);
- USB0.dcfg |= ((dev_addr & USB_DEVADDR_V) << USB_DEVADDR_S);
- // Response with status after changing device address
- dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
-}
-
-void dcd_remote_wakeup(uint8_t rhport)
-{
- (void)rhport;
-
- // set remote wakeup
- USB0.dctl |= USB_RMTWKUPSIG_M;
-
- // enable SOF to detect bus resume
- USB0.gintsts = USB_SOF_M;
- USB0.gintmsk |= USB_SOFMSK_M;
-
- // Per specs: remote wakeup signal bit must be clear within 1-15ms
- vTaskDelay(pdMS_TO_TICKS(1));
-
- USB0.dctl &= ~USB_RMTWKUPSIG_M;
-}
-
-// connect by enabling internal pull-up resistor on D+/D-
-void dcd_connect(uint8_t rhport)
-{
- (void) rhport;
- USB0.dctl &= ~USB_SFTDISCON_M;
-}
-
-// disconnect by disabling internal pull-up resistor on D+/D-
-void dcd_disconnect(uint8_t rhport)
-{
- (void) rhport;
- USB0.dctl |= USB_SFTDISCON_M;
-}
-
-void dcd_sof_enable(uint8_t rhport, bool en)
-{
- (void) rhport;
- (void) en;
-
- // TODO implement later
-}
-
-/*------------------------------------------------------------------*/
-/* DCD Endpoint port
- *------------------------------------------------------------------*/
-
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
-{
- ESP_LOGV(TAG, "DCD endpoint opened");
- (void)rhport;
-
- usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
- usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
-
- uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
- uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
-
- TU_ASSERT(epnum < EP_MAX);
-
- xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
- xfer->max_size = tu_edpt_packet_size(desc_edpt);
- xfer->interval = desc_edpt->bInterval;
-
- if (dir == TUSB_DIR_OUT) {
- out_ep[epnum].doepctl |= USB_USBACTEP1_M |
- desc_edpt->bmAttributes.xfer << USB_EPTYPE1_S |
- (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_DO_SETD0PID1_M : 0) |
- xfer->max_size << USB_MPS1_S;
- USB0.daintmsk |= (1 << (16 + epnum));
- } else {
- // "USB Data FIFOs" section in reference manual
- // Peripheral FIFO architecture
- //
- // --------------- 320 or 1024 ( 1280 or 4096 bytes )
- // | IN FIFO MAX |
- // ---------------
- // | ... |
- // --------------- y + x + 16 + GRXFSIZ
- // | IN FIFO 2 |
- // --------------- x + 16 + GRXFSIZ
- // | IN FIFO 1 |
- // --------------- 16 + GRXFSIZ
- // | IN FIFO 0 |
- // --------------- GRXFSIZ
- // | OUT FIFO |
- // | ( Shared ) |
- // --------------- 0
- //
- // Since OUT FIFO = GRXFSIZ, FIFO 0 = 16, for simplicity, we equally allocated for the rest of endpoints
- // - Size : (FIFO_SIZE/4 - GRXFSIZ - 16) / (EP_MAX-1)
- // - Offset: GRXFSIZ + 16 + Size*(epnum-1)
- // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
-
- uint8_t fifo_num = get_free_fifo();
- TU_ASSERT(fifo_num != 0);
-
- in_ep[epnum].diepctl &= ~(USB_D_TXFNUM1_M | USB_D_EPTYPE1_M | USB_DI_SETD0PID1 | USB_D_MPS1_M);
- in_ep[epnum].diepctl |= USB_D_USBACTEP1_M |
- fifo_num << USB_D_TXFNUM1_S |
- desc_edpt->bmAttributes.xfer << USB_D_EPTYPE1_S |
- (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? (1 << USB_DI_SETD0PID1_S) : 0) |
- xfer->max_size << 0;
-
- USB0.daintmsk |= (1 << (0 + epnum));
-
- // Both TXFD and TXSA are in unit of 32-bit words.
- // IN FIFO 0 was configured during enumeration, hence the "+ 16".
- uint16_t const allocated_size = (USB0.grxfsiz & 0x0000ffff) + 16;
- uint16_t const fifo_size = (EP_FIFO_SIZE/4 - allocated_size) / (EP_FIFO_NUM-1);
- uint32_t const fifo_offset = allocated_size + fifo_size*(fifo_num-1);
-
- // DIEPTXF starts at FIFO #1.
- USB0.dieptxf[epnum - 1] = (fifo_size << USB_NPTXFDEP_S) | fifo_offset;
- }
- return true;
-}
-
-void dcd_edpt_close_all(uint8_t rhport)
-{
- (void) rhport;
-
- usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
- usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
-
- // Disable non-control interrupt
- USB0.daintmsk = USB_OUTEPMSK0_M | USB_INEPMSK0_M;
-
- for(uint8_t n = 1; n < EP_MAX; n++)
- {
- // disable OUT endpoint
- out_ep[n].doepctl = 0;
- xfer_status[n][TUSB_DIR_OUT].max_size = 0;
-
- // disable IN endpoint
- in_ep[n].diepctl = 0;
- xfer_status[n][TUSB_DIR_IN].max_size = 0;
- }
-
- _allocated_fifos = 1;
-}
-
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
-{
- (void)rhport;
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = buffer;
- // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API
- xfer->total_len = total_bytes;
- xfer->queued_len = 0;
- xfer->short_packet = false;
-
- uint16_t num_packets = (total_bytes / xfer->max_size);
- uint8_t short_packet_size = total_bytes % xfer->max_size;
-
- // Zero-size packet is special case.
- if (short_packet_size > 0 || (total_bytes == 0)) {
- num_packets++;
- }
-
- ESP_LOGV(TAG, "Transfer <-> EP%i, %s, pkgs: %i, bytes: %i",
- epnum, ((dir == TUSB_DIR_IN) ? "USB0.HOST (in)" : "HOST->DEV (out)"),
- num_packets, total_bytes);
-
- // IN and OUT endpoint xfers are interrupt-driven, we just schedule them
- // here.
- if (dir == TUSB_DIR_IN) {
- // A full IN transfer (multiple packets, possibly) triggers XFRC.
- USB0.in_ep_reg[epnum].dieptsiz = (num_packets << USB_D_PKTCNT0_S) | total_bytes;
- USB0.in_ep_reg[epnum].diepctl |= USB_D_EPENA1_M | USB_D_CNAK1_M; // Enable | CNAK
-
- // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame
- if ((USB0.in_ep_reg[epnum].diepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) {
- // Take odd/even bit from frame counter.
- uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S));
- USB0.in_ep_reg[epnum].diepctl |= (odd_frame_now ? USB_DI_SETD0PID1 : USB_DI_SETD1PID1);
- }
-
- // Enable fifo empty interrupt only if there are something to put in the fifo.
- if(total_bytes != 0) {
- USB0.dtknqr4_fifoemptymsk |= (1 << epnum);
- }
- } else {
- // Each complete packet for OUT xfers triggers XFRC.
- USB0.out_ep_reg[epnum].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
- USB0.out_ep_reg[epnum].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
-
- // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame
- if ((USB0.out_ep_reg[epnum].doepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) {
- // Take odd/even bit from frame counter.
- uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S));
- USB0.out_ep_reg[epnum].doepctl |= (odd_frame_now ? USB_DO_SETD0PID1 : USB_DO_SETD1PID1);
- }
- }
- return true;
-}
-
-#if 0 // TODO support dcd_edpt_xfer_fifo API
-bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
-{
- (void)rhport;
-}
-#endif
-
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
-{
- (void)rhport;
-
- usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
- usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if (dir == TUSB_DIR_IN) {
- // Only disable currently enabled non-control endpoint
- if ((epnum == 0) || !(in_ep[epnum].diepctl & USB_D_EPENA1_M)) {
- in_ep[epnum].diepctl |= (USB_DI_SNAK1_M | USB_D_STALL1_M);
- } else {
- // Stop transmitting packets and NAK IN xfers.
- in_ep[epnum].diepctl |= USB_DI_SNAK1_M;
- while ((in_ep[epnum].diepint & USB_DI_SNAK1_M) == 0) ;
-
- // Disable the endpoint. Note that both SNAK and STALL are set here.
- in_ep[epnum].diepctl |= (USB_DI_SNAK1_M | USB_D_STALL1_M | USB_D_EPDIS1_M);
- while ((in_ep[epnum].diepint & USB_D_EPDISBLD0_M) == 0) ;
- in_ep[epnum].diepint = USB_D_EPDISBLD0_M;
- }
-
- // Flush the FIFO, and wait until we have confirmed it cleared.
- uint8_t const fifo_num = ((in_ep[epnum].diepctl >> USB_D_TXFNUM1_S) & USB_D_TXFNUM1_V);
- USB0.grstctl |= (fifo_num << USB_TXFNUM_S);
- USB0.grstctl |= USB_TXFFLSH_M;
- while ((USB0.grstctl & USB_TXFFLSH_M) != 0) ;
- } else {
- // Only disable currently enabled non-control endpoint
- if ((epnum == 0) || !(out_ep[epnum].doepctl & USB_EPENA0_M)) {
- out_ep[epnum].doepctl |= USB_STALL0_M;
- } else {
- // Asserting GONAK is required to STALL an OUT endpoint.
- // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt
- // anyway, and it can't be cleared by user code. If this while loop never
- // finishes, we have bigger problems than just the stack.
- USB0.dctl |= USB_SGOUTNAK_M;
- while ((USB0.gintsts & USB_GOUTNAKEFF_M) == 0) ;
-
- // Ditto here- disable the endpoint. Note that only STALL and not SNAK
- // is set here.
- out_ep[epnum].doepctl |= (USB_STALL0_M | USB_EPDIS0_M);
- while ((out_ep[epnum].doepint & USB_EPDISBLD0_M) == 0) ;
- out_ep[epnum].doepint = USB_EPDISBLD0_M;
-
- // Allow other OUT endpoints to keep receiving.
- USB0.dctl |= USB_CGOUTNAK_M;
- }
- }
-}
-
-void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
-{
- (void)rhport;
-
- usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
- usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
-
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- if (dir == TUSB_DIR_IN) {
- in_ep[epnum].diepctl &= ~USB_D_STALL1_M;
-
- uint8_t eptype = (in_ep[epnum].diepctl & USB_D_EPTYPE1_M) >> USB_D_EPTYPE1_S;
- // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt
- // and bulk endpoints.
- if (eptype == 2 || eptype == 3) {
- in_ep[epnum].diepctl |= USB_DI_SETD0PID1_M;
- }
- } else {
- out_ep[epnum].doepctl &= ~USB_STALL1_M;
-
- uint8_t eptype = (out_ep[epnum].doepctl & USB_EPTYPE1_M) >> USB_EPTYPE1_S;
- // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt
- // and bulk endpoints.
- if (eptype == 2 || eptype == 3) {
- out_ep[epnum].doepctl |= USB_DO_SETD0PID1_M;
- }
- }
-}
-
-/*------------------------------------------------------------------*/
-
-static void receive_packet(xfer_ctl_t *xfer, /* usb_out_endpoint_t * out_ep, */ uint16_t xfer_size)
-{
- ESP_EARLY_LOGV(TAG, "USB - receive_packet");
- volatile uint32_t *rx_fifo = USB0.fifo[0];
-
- // See above TODO
- // uint16_t remaining = (out_ep->DOEPTSIZ & UsbDOEPTSIZ_XFRSIZ_Msk) >> UsbDOEPTSIZ_XFRSIZ_Pos;
- // xfer->queued_len = xfer->total_len - remaining;
-
- uint16_t remaining = xfer->total_len - xfer->queued_len;
- uint16_t to_recv_size;
-
- if (remaining <= xfer->max_size) {
- // Avoid buffer overflow.
- to_recv_size = (xfer_size > remaining) ? remaining : xfer_size;
- } else {
- // Room for full packet, choose recv_size based on what the microcontroller
- // claims.
- to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size;
- }
-
- // Common buffer read
-#if 0 // TODO support dcd_edpt_xfer_fifo API
- if (xfer->ff)
- {
- // Ring buffer
- tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) rx_fifo, to_recv_size);
- }
- else
-#endif
- {
- uint8_t to_recv_rem = to_recv_size % 4;
- uint16_t to_recv_size_aligned = to_recv_size - to_recv_rem;
-
- // Do not assume xfer buffer is aligned.
- uint8_t *base = (xfer->buffer + xfer->queued_len);
-
- // This for loop always runs at least once- skip if less than 4 bytes
- // to collect.
- if (to_recv_size >= 4) {
- for (uint16_t i = 0; i < to_recv_size_aligned; i += 4) {
- uint32_t tmp = (*rx_fifo);
- base[i] = tmp & 0x000000FF;
- base[i + 1] = (tmp & 0x0000FF00) >> 8;
- base[i + 2] = (tmp & 0x00FF0000) >> 16;
- base[i + 3] = (tmp & 0xFF000000) >> 24;
- }
- }
-
- // Do not read invalid bytes from RX FIFO.
- if (to_recv_rem != 0) {
- uint32_t tmp = (*rx_fifo);
- uint8_t *last_32b_bound = base + to_recv_size_aligned;
-
- last_32b_bound[0] = tmp & 0x000000FF;
- if (to_recv_rem > 1) {
- last_32b_bound[1] = (tmp & 0x0000FF00) >> 8;
- }
- if (to_recv_rem > 2) {
- last_32b_bound[2] = (tmp & 0x00FF0000) >> 16;
- }
- }
- }
-
- xfer->queued_len += xfer_size;
-
- // Per USB spec, a short OUT packet (including length 0) is always
- // indicative of the end of a transfer (at least for ctl, bulk, int).
- xfer->short_packet = (xfer_size < xfer->max_size);
-}
-
-static void transmit_packet(xfer_ctl_t *xfer, volatile usb_in_endpoint_t *in_ep, uint8_t fifo_num)
-{
- ESP_EARLY_LOGV(TAG, "USB - transmit_packet");
- volatile uint32_t *tx_fifo = USB0.fifo[fifo_num];
-
- uint16_t remaining = (in_ep->dieptsiz & 0x7FFFFU) >> USB_D_XFERSIZE0_S;
- xfer->queued_len = xfer->total_len - remaining;
-
- uint16_t to_xfer_size = (remaining > xfer->max_size) ? xfer->max_size : remaining;
-
-#if 0 // TODO support dcd_edpt_xfer_fifo API
- if (xfer->ff)
- {
- tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) tx_fifo, to_xfer_size);
- }
- else
-#endif
- {
- uint8_t to_xfer_rem = to_xfer_size % 4;
- uint16_t to_xfer_size_aligned = to_xfer_size - to_xfer_rem;
-
- // Buffer might not be aligned to 32b, so we need to force alignment
- // by copying to a temp var.
- uint8_t *base = (xfer->buffer + xfer->queued_len);
-
- // This for loop always runs at least once- skip if less than 4 bytes
- // to send off.
- if (to_xfer_size >= 4) {
- for (uint16_t i = 0; i < to_xfer_size_aligned; i += 4) {
- uint32_t tmp = base[i] | (base[i + 1] << 8) |
- (base[i + 2] << 16) | (base[i + 3] << 24);
- (*tx_fifo) = tmp;
- }
- }
-
- // Do not read beyond end of buffer if not divisible by 4.
- if (to_xfer_rem != 0) {
- uint32_t tmp = 0;
- uint8_t *last_32b_bound = base + to_xfer_size_aligned;
-
- tmp |= last_32b_bound[0];
- if (to_xfer_rem > 1) {
- tmp |= (last_32b_bound[1] << 8);
- }
- if (to_xfer_rem > 2) {
- tmp |= (last_32b_bound[2] << 16);
- }
-
- (*tx_fifo) = tmp;
- }
- }
-}
-
-static void read_rx_fifo(void)
-{
- // Pop control word off FIFO (completed xfers will have 2 control words,
- // we only pop one ctl word each interrupt).
- uint32_t const ctl_word = USB0.grxstsp;
- uint8_t const pktsts = (ctl_word & USB_PKTSTS_M) >> USB_PKTSTS_S;
- uint8_t const epnum = (ctl_word & USB_CHNUM_M ) >> USB_CHNUM_S;
- uint16_t const bcnt = (ctl_word & USB_BCNT_M ) >> USB_BCNT_S;
-
- switch (pktsts) {
- case 0x01: // Global OUT NAK (Interrupt)
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX type : Global OUT NAK");
- break;
-
- case 0x02: { // Out packet recvd
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX type : Out packet");
- xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
- receive_packet(xfer, bcnt);
- }
- break;
-
- case 0x03: // Out packet done (Interrupt)
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX type : Out packet done");
- break;
-
- case 0x04: // Step 2: Setup transaction completed (Interrupt)
- // After this event, OEPINT interrupt will occur with SETUP bit set
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX : Setup packet done");
- USB0.out_ep_reg[epnum].doeptsiz |= USB_SUPCNT0_M;
- break;
-
- case 0x06: { // Step1: Setup data packet received
- volatile uint32_t *rx_fifo = USB0.fifo[0];
-
- // We can receive up to three setup packets in succession, but
- // only the last one is valid. Therefore we just overwrite it
- _setup_packet[0] = (*rx_fifo);
- _setup_packet[1] = (*rx_fifo);
-
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX : Setup packet : 0x%08x 0x%08x", _setup_packet[0], _setup_packet[1]);
- }
- break;
-
- default: // Invalid, do something here, like breakpoint?
- TU_BREAKPOINT();
- break;
- }
-}
-
-static void handle_epout_ints(void)
-{
- // GINTSTS will be cleared with DAINT == 0
- // DAINT for a given EP clears when DOEPINTx is cleared.
- // DOEPINT will be cleared when DAINT's out bits are cleared.
- for (int n = 0; n < USB_OUT_EP_NUM; n++) {
- xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
-
- if (USB0.daint & (1 << (16 + n))) {
- // SETUP packet Setup Phase done.
- if ((USB0.out_ep_reg[n].doepint & USB_SETUP0_M)) {
- USB0.out_ep_reg[n].doepint = USB_STUPPKTRCVD0_M | USB_SETUP0_M; // clear
- dcd_event_setup_received(0, (uint8_t *)&_setup_packet[0], true);
- }
-
- // OUT XFER complete (single packet).q
- if (USB0.out_ep_reg[n].doepint & USB_XFERCOMPL0_M) {
-
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - EP OUT - XFER complete (single packet)");
- USB0.out_ep_reg[n].doepint = USB_XFERCOMPL0_M;
-
- // Transfer complete if short packet or total len is transferred
- if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
- xfer->short_packet = false;
- dcd_event_xfer_complete(0, n, xfer->queued_len, XFER_RESULT_SUCCESS, true);
- } else {
- // Schedule another packet to be received.
- USB0.out_ep_reg[n].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
- USB0.out_ep_reg[n].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
- }
- }
- }
- }
-}
-
-static void handle_epin_ints(void)
-{
- // GINTSTS will be cleared with DAINT == 0
- // DAINT for a given EP clears when DIEPINTx is cleared.
- // IEPINT will be cleared when DAINT's out bits are cleared.
- for (uint32_t n = 0; n < USB_IN_EP_NUM; n++) {
- xfer_ctl_t *xfer = &xfer_status[n][TUSB_DIR_IN];
-
- if (USB0.daint & (1 << (0 + n))) {
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - EP IN %u", n);
- // IN XFER complete (entire xfer).
- if (USB0.in_ep_reg[n].diepint & USB_D_XFERCOMPL0_M) {
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - IN XFER complete!");
- USB0.in_ep_reg[n].diepint = USB_D_XFERCOMPL0_M;
- dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true);
- }
-
- // XFER FIFO empty
- if (USB0.in_ep_reg[n].diepint & USB_D_TXFEMP0_M) {
- ESP_EARLY_LOGV(TAG, "TUSB IRQ - IN XFER FIFO empty!");
- USB0.in_ep_reg[n].diepint = USB_D_TXFEMP0_M;
- transmit_packet(xfer, &USB0.in_ep_reg[n], n);
-
- // Turn off TXFE if all bytes are written.
- if (xfer->queued_len == xfer->total_len)
- {
- USB0.dtknqr4_fifoemptymsk &= ~(1 << n);
- }
- }
-
- // XFER Timeout
- if (USB0.in_ep_reg[n].diepint & USB_D_TIMEOUT0_M) {
- // Clear interrupt or endpoint will hang.
- USB0.in_ep_reg[n].diepint = USB_D_TIMEOUT0_M;
- // Maybe retry?
- }
- }
- }
-}
-
-
-static void _dcd_int_handler(void* arg)
-{
- (void) arg;
- uint8_t const rhport = 0;
-
- const uint32_t int_msk = USB0.gintmsk;
- const uint32_t int_status = USB0.gintsts & int_msk;
-
- if (int_status & USB_USBRST_M) {
- // start of reset
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - reset");
- USB0.gintsts = USB_USBRST_M;
- // FIFOs will be reassigned when the endpoints are reopen
- _allocated_fifos = 1;
- bus_reset();
- }
-
- if (int_status & USB_RESETDET_M) {
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - reset while suspend");
- USB0.gintsts = USB_RESETDET_M;
- bus_reset();
- }
-
- if (int_status & USB_ENUMDONE_M) {
- // ENUMDNE detects speed of the link. For full-speed, we
- // always expect the same value. This interrupt is considered
- // the end of reset.
- USB0.gintsts = USB_ENUMDONE_M;
- enum_done_processing();
- dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
- }
-
- if(int_status & USB_USBSUSP_M)
- {
- USB0.gintsts = USB_USBSUSP_M;
- dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
- }
-
- if(int_status & USB_WKUPINT_M)
- {
- USB0.gintsts = USB_WKUPINT_M;
- dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
- }
-
- if (int_status & USB_OTGINT_M)
- {
- // OTG INT bit is read-only
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - disconnected");
-
- uint32_t const otg_int = USB0.gotgint;
-
- if (otg_int & USB_SESENDDET_M)
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
- }
-
- USB0.gotgint = otg_int;
- }
-
- if (int_status & USB_SOF_M) {
- USB0.gintsts = USB_SOF_M;
-
- // Disable SOF interrupt since currently only used for remote wakeup detection
- USB0.gintmsk &= ~USB_SOFMSK_M;
-
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
- }
-
-
- if (int_status & USB_RXFLVI_M) {
- // RXFLVL bit is read-only
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - rx!");
-
- // Mask out RXFLVL while reading data from FIFO
- USB0.gintmsk &= ~USB_RXFLVIMSK_M;
- read_rx_fifo();
- USB0.gintmsk |= USB_RXFLVIMSK_M;
- }
-
- // OUT endpoint interrupt handling.
- if (int_status & USB_OEPINT_M) {
- // OEPINT is read-only
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - OUT endpoint!");
- handle_epout_ints();
- }
-
- // IN endpoint interrupt handling.
- if (int_status & USB_IEPINT_M) {
- // IEPINT bit read-only
- ESP_EARLY_LOGV(TAG, "dcd_int_handler - IN endpoint!");
- handle_epin_ints();
- }
-
- // Without handling
- USB0.gintsts |= USB_CURMOD_INT_M |
- USB_MODEMIS_M |
- USB_OTGINT_M |
- USB_NPTXFEMP_M |
- USB_GINNAKEFF_M |
- USB_GOUTNAKEFF |
- USB_ERLYSUSP_M |
- USB_USBSUSP_M |
- USB_ISOOUTDROP_M |
- USB_EOPF_M |
- USB_EPMIS_M |
- USB_INCOMPISOIN_M |
- USB_INCOMPIP_M |
- USB_FETSUSP_M |
- USB_PTXFEMP_M;
-}
-
-void dcd_int_enable (uint8_t rhport)
-{
- (void) rhport;
- esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, (intr_handler_t) _dcd_int_handler, NULL, &usb_ih);
-}
-
-void dcd_int_disable (uint8_t rhport)
-{
- (void) rhport;
- esp_intr_free(usb_ih);
-}
-
-#endif // #if OPT_MCU_ESP32S2 || OPT_MCU_ESP32S3
diff --git a/src/portable/microchip/pic32mz/dcd_pic32mz.c b/src/portable/microchip/pic32mz/dcd_pic32mz.c
index 8709baf67..cbd157d6b 100644
--- a/src/portable/microchip/pic32mz/dcd_pic32mz.c
+++ b/src/portable/microchip/pic32mz/dcd_pic32mz.c
@@ -162,13 +162,7 @@ void dcd_remote_wakeup(uint8_t rhport)
(void) rhport;
USB_REGS->POWERbits.RESUME = 1;
-#if CFG_TUSB_OS != OPT_OS_NONE
- osal_task_delay(10);
-#else
- // TODO: Wait in non blocking mode
- unsigned cnt = 2000;
- while (cnt--) __asm__("nop");
-#endif
+ tusb_time_delay_ms_api(10);
USB_REGS->POWERbits.RESUME = 0;
}
diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c
index a9246e1cd..340d8c56a 100644
--- a/src/portable/ohci/ohci.c
+++ b/src/portable/ohci/ohci.c
@@ -177,14 +177,12 @@ static gtd_extra_data_t *gtd_get_extra_data(ohci_gtd_t const * const gtd);
// tusb_app_virt_to_phys and tusb_app_virt_to_phys in your application.
TU_ATTR_ALWAYS_INLINE static inline void *_phys_addr(void *virtual_address)
{
- if (tusb_app_virt_to_phys) return tusb_app_virt_to_phys(virtual_address);
- return virtual_address;
+ return tusb_app_virt_to_phys(virtual_address);
}
TU_ATTR_ALWAYS_INLINE static inline void *_virt_addr(void *physical_address)
{
- if (tusb_app_phys_to_virt) return tusb_app_phys_to_virt(physical_address);
- return physical_address;
+ return tusb_app_phys_to_virt(physical_address);
}
// Initialization according to 5.1.1.4
@@ -217,12 +215,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
//Wait 20 ms. (Ref Usb spec 7.1.7.7)
OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_RESUME;
-#if CFG_TUSB_OS != OPT_OS_NONE
- // os_none implement task delay using usb frame counter which is not started yet
- // therefore cause infinite delay.
- // TODO find a way to delay in case of os none e.g __nop
- osal_task_delay(20);
-#endif
+ tusb_time_delay_ms_api(20);
}
hcd_dcache_clean(&ohci_data, sizeof(ohci_data));
@@ -252,10 +245,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
OHCI_REG->control_bit.hc_functional_state = OHCI_CONTROL_FUNCSTATE_OPERATIONAL; // make HC's state to operational state TODO use this to suspend (save power)
OHCI_REG->rh_status_bit.local_power_status_change = 1; // set global power for ports
-#if CFG_TUSB_OS != OPT_OS_NONE
- // TODO as above delay
- osal_task_delay(OHCI_REG->rh_descriptorA_bit.power_on_to_good_time * 2); // Wait POTG after power up
-#endif
+ tusb_time_delay_ms_api(OHCI_REG->rh_descriptorA_bit.power_on_to_good_time * 2); // Wait POTG after power up
return true;
}
diff --git a/src/portable/renesas/rusb2/rusb2_common.c b/src/portable/renesas/rusb2/rusb2_common.c
index 72e65736b..856f9714f 100644
--- a/src/portable/renesas/rusb2/rusb2_common.c
+++ b/src/portable/renesas/rusb2/rusb2_common.c
@@ -50,10 +50,6 @@ void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum) {
rusb2_controller[rhport].irqnum = irqnum;
}
-// void osal_task_delay(uint32_t msec) {
-// R_BSP_SoftwareDelay(msec, BSP_DELAY_UNITS_MILLISECONDS);
-// }
-
#else
#error "Unsupported MCU"
#endif
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index 5d6033a66..ed823a832 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -333,8 +333,13 @@ static void handle_ctr_rx(uint32_t ep_id) {
xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_OUT);
uint8_t buf_id;
- if (is_iso) {
- buf_id = (ep_reg & USB_EP_DTOG_RX) ? 0 : 1; // ISO are double buffered
+#if FSDEV_USE_SBUF_ISO == 0
+ bool const dbl_buf = is_iso;
+#else
+ bool const dbl_buf = false;
+#endif
+ if (dbl_buf) {
+ buf_id = (ep_reg & USB_EP_DTOG_RX) ? 0 : 1;
} else {
buf_id = BTABLE_BUF_RX;
}
@@ -529,10 +534,16 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
return i;
}
+#if FSDEV_USE_SBUF_ISO == 0
+ bool const dbl_buf = ep_type == TUSB_XFER_ISOCHRONOUS;
+#else
+ bool const dbl_buf = false;
+#endif
+
// If EP of current direction is not allocated
- // Except for ISO endpoint, both direction should be free
+ // For double-buffered mode both directions needs to be free
if (!ep_alloc_status[i].allocated[dir] &&
- (ep_type != TUSB_XFER_ISOCHRONOUS || !ep_alloc_status[i].allocated[dir ^ 1])) {
+ (!dbl_buf || !ep_alloc_status[i].allocated[dir ^ 1])) {
// Check if EP number is the same
if (ep_alloc_status[i].ep_num == 0xFF || ep_alloc_status[i].ep_num == epnum) {
// One EP pair has to be the same type
@@ -654,9 +665,7 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet
uint8_t const dir = tu_edpt_dir(ep_addr);
uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS);
- /* Create a packet memory buffer area. Enable double buffering for devices with 2048 bytes PMA,
- for smaller devices double buffering occupy too much space. */
-#if FSDEV_PMA_SIZE > 1024u
+#if CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP != 0
uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, true);
uint16_t pma_addr2 = pma_addr >> 16;
#else
@@ -664,8 +673,13 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet
uint16_t pma_addr2 = pma_addr;
#endif
+#if FSDEV_USE_SBUF_ISO == 0
btable_set_addr(ep_idx, 0, pma_addr);
btable_set_addr(ep_idx, 1, pma_addr2);
+#else
+ btable_set_addr(ep_idx, dir == TUSB_DIR_IN ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr);
+ (void) pma_addr2;
+#endif
xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir);
xfer->ep_idx = ep_idx;
@@ -686,10 +700,23 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK;
ep_reg |= tu_edpt_number(ep_addr) | USB_EP_ISOCHRONOUS | USB_EP_CTR_TX | USB_EP_CTR_RX;
+#if FSDEV_USE_SBUF_ISO != 0
+ ep_reg |= USB_EP_KIND;
+
+ ep_change_status(&ep_reg, dir, EP_STAT_DISABLED);
+ ep_change_dtog(&ep_reg, dir, 0);
+
+ if (dir == TUSB_DIR_IN) {
+ ep_reg &= ~(USB_EPRX_STAT | USB_EP_DTOG_RX);
+ } else {
+ ep_reg &= ~(USB_EPTX_STAT | USB_EP_DTOG_TX);
+ }
+#else
ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_DISABLED);
ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_DISABLED);
ep_change_dtog(&ep_reg, dir, 0);
ep_change_dtog(&ep_reg, (tusb_dir_t)(1 - dir), 1);
+#endif
ep_write(ep_idx, ep_reg, true);
@@ -704,7 +731,12 @@ static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) {
bool const is_iso = ep_is_iso(ep_reg);
uint8_t buf_id;
- if (is_iso) {
+#if FSDEV_USE_SBUF_ISO == 0
+ bool const dbl_buf = is_iso;
+#else
+ bool const dbl_buf = false;
+#endif
+ if (dbl_buf) {
buf_id = (ep_reg & USB_EP_DTOG_TX) ? 1 : 0;
} else {
buf_id = BTABLE_BUF_TX;
diff --git a/src/portable/st/stm32_fsdev/fsdev_at32.h b/src/portable/st/stm32_fsdev/fsdev_at32.h
index 3a785bbbd..f7ee89995 100644
--- a/src/portable/st/stm32_fsdev/fsdev_at32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_at32.h
@@ -36,9 +36,14 @@
#endif
#define FSDEV_PMA_SIZE (512u)
+#define FSDEV_USE_SBUF_ISO 0
#define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL)
#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL)
+#ifndef CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP
+ #define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 0
+#endif
+
/**************************** ISTR interrupt events *************************/
#define USB_ISTR_CTR ((uint16_t)0x8000U) /*!< Correct TRansfer (clear-only bit) */
#define USB_ISTR_PMAOVR ((uint16_t)0x4000U) /*!< DMA OVeR/underrun (clear-only bit) */
diff --git a/src/portable/st/stm32_fsdev/fsdev_ch32.h b/src/portable/st/stm32_fsdev/fsdev_ch32.h
index 518197c47..ceebb6dab 100644
--- a/src/portable/st/stm32_fsdev/fsdev_ch32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_ch32.h
@@ -54,9 +54,14 @@
#endif
#define FSDEV_PMA_SIZE (512u)
+#define FSDEV_USE_SBUF_ISO 0
#define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL)
#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL)
+#ifndef CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP
+ #define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 0
+#endif
+
/**************************** ISTR interrupt events *************************/
#define USB_ISTR_CTR ((uint16_t)0x8000U) /*!< Correct TRansfer (clear-only bit) */
#define USB_ISTR_PMAOVR ((uint16_t)0x4000U) /*!< DMA OVeR/underrun (clear-only bit) */
diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h
index ccf31e035..63b50f13d 100644
--- a/src/portable/st/stm32_fsdev/fsdev_stm32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h
@@ -36,6 +36,7 @@
#include "stm32f0xx.h"
#define FSDEV_PMA_SIZE (1024u)
#define FSDEV_REG_BASE USB_BASE
+ #define FSDEV_HAS_SBUF_ISO 0
// F0x2 models are crystal-less
// All have internal D+ pull-up
// 070RB: 2 x 16 bits/word memory LPM Support, BCD Support
@@ -44,6 +45,7 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
#include "stm32f1xx.h"
#define FSDEV_PMA_SIZE (512u)
+ #define FSDEV_HAS_SBUF_ISO 0
// NO internal Pull-ups
// *B, and *C: 2 x 16 bits/word
@@ -55,6 +57,7 @@
defined(STM32F373xC)
#include "stm32f3xx.h"
#define FSDEV_PMA_SIZE (512u)
+ #define FSDEV_HAS_SBUF_ISO 0
// NO internal Pull-ups
// *B, and *C: 1 x 16 bits/word
// PMA dedicated to USB (no sharing with CAN)
@@ -64,6 +67,7 @@
defined(STM32F303xD) || defined(STM32F303xE)
#include "stm32f3xx.h"
#define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_HAS_SBUF_ISO 0
// NO internal Pull-ups
// *6, *8, *D, and *E: 2 x 16 bits/word LPM Support
// When CAN clock is enabled, USB can use first 768 bytes ONLY.
@@ -71,18 +75,22 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32L0
#include "stm32l0xx.h"
#define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_HAS_SBUF_ISO 0
#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
#include "stm32l1xx.h"
#define FSDEV_PMA_SIZE (512u)
+ #define FSDEV_HAS_SBUF_ISO 0
#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
#include "stm32g4xx.h"
#define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_HAS_SBUF_ISO 0
#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
#include "stm32g0xx.h"
#define FSDEV_PMA_SIZE (2048u)
+ #define FSDEV_HAS_SBUF_ISO 1
#define USB USB_DRD_FS
#define USB_EP_CTR_RX USB_EP_VTRX
@@ -107,6 +115,7 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32C0
#include "stm32c0xx.h"
#define FSDEV_PMA_SIZE (2048u)
+ #define FSDEV_HAS_SBUF_ISO 1
#define USB USB_DRD_FS
#define USB_EP_CTR_RX USB_CHEP_VTRX
#define USB_EP_CTR_TX USB_CHEP_VTTX
@@ -121,6 +130,7 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
#include "stm32h5xx.h"
#define FSDEV_PMA_SIZE (2048u)
+ #define FSDEV_HAS_SBUF_ISO 1
#define USB USB_DRD_FS
#define USB_EP_CTR_RX USB_EP_VTRX
@@ -145,16 +155,19 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
#include "stm32wbxx.h"
#define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_HAS_SBUF_ISO 0
/* ST provided header has incorrect value of USB_PMAADDR */
#define FSDEV_PMA_BASE USB1_PMAADDR
#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
#include "stm32l4xx.h"
#define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_HAS_SBUF_ISO 0
#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
#include "stm32l5xx.h"
#define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_HAS_SBUF_ISO 0
#ifndef USB_PMAADDR
#define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS))
@@ -163,6 +176,7 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
#include "stm32u5xx.h"
#define FSDEV_PMA_SIZE (2048u)
+ #define FSDEV_HAS_SBUF_ISO 1
#define USB USB_DRD_FS
#define USB_EP_CTR_RX USB_EP_VTRX
@@ -186,7 +200,10 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32U0
#include "stm32u0xx.h"
- #define FSDEV_PMA_SIZE (2048u)
+ #define FSDEV_PMA_SIZE (1024u)
+ #define FSDEV_BUS_32BIT
+ // Disable SBUF_ISO on U0 for now due to bad performance (audio glitching)
+ #define FSDEV_HAS_SBUF_ISO 0
#define USB USB_DRD_FS
#define USB_EP_CTR_RX USB_EP_VTRX
@@ -248,6 +265,36 @@
#define USB_ISTR_ALL_EVENTS (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP | \
USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED )
+#ifndef FSDEV_HAS_SBUF_ISO
+ #error "FSDEV_HAS_SBUF_ISO not defined"
+#endif
+
+#ifndef CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP
+ // Default configuration for double-buffered isochronous endpoints:
+ // - Enable double buffering on devices with >1KB Packet Memory Area (PMA)
+ // to improve isochronous transfer reliability and performance
+ // - Disable on devices with limited PMA to conserve memory space
+ #if FSDEV_PMA_SIZE > 1024u
+ #define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 1
+ #else
+ #define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 0
+ #endif
+#endif
+
+#if FSDEV_HAS_SBUF_ISO != 0 && CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP == 0
+ // SBUF_ISO configuration:
+ // - Some STM32 devices have special hardware support for single-buffered isochronous endpoints
+ // - When SBUF_ISO bit is available and double buffering is disabled:
+ // Enable SBUF_ISO to optimize endpoint register usage (one half of endpoint pair register)
+ #define FSDEV_USE_SBUF_ISO 1
+#else
+ // When either:
+ // - Hardware doesn't support SBUF_ISO feature, or
+ // - Double buffering is enabled for isochronous endpoints
+ // We must use the entire endpoint pair register
+ #define FSDEV_USE_SBUF_ISO 0
+#endif
+
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c
index 21f13b279..9801a485f 100644
--- a/src/portable/sunxi/dcd_sunxi_musb.c
+++ b/src/portable/sunxi/dcd_sunxi_musb.c
@@ -99,22 +99,12 @@ static void usb_phy_write(int addr, int data, int len)
}
}
-static void delay_ms(uint32_t ms)
-{
-#if CFG_TUSB_OS == OPT_OS_NONE
- int now = board_millis();
- while (board_millis() - now <= ms) asm("nop");
-#else
- osal_task_delay(ms);
-#endif
-}
-
static void USBC_HardwareReset(void)
{
// Reset phy and controller
USBC_REG_set_bit_l(USBPHY_CLK_RST_BIT, USBPHY_CLK_REG);
USBC_REG_set_bit_l(BUS_RST_USB_BIT, BUS_CLK_RST_REG);
- delay_ms(2);
+ tusb_time_delay_ms_api(2);
USBC_REG_set_bit_l(USBPHY_CLK_GAT_BIT, USBPHY_CLK_REG);
USBC_REG_set_bit_l(USBPHY_CLK_RST_BIT, USBPHY_CLK_REG);
diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c
index b001f343d..5ff18ab94 100644
--- a/src/portable/synopsys/dwc2/dwc2_common.c
+++ b/src/portable/synopsys/dwc2/dwc2_common.c
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
- * Copyright (c) 2024 Ha Thach (tinyusb.org)
+ * Copyright (c) 2024-2025 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -45,17 +45,26 @@
//
//--------------------------------------------------------------------
static void reset_core(dwc2_regs_t* dwc2) {
+ // The software must check that bit 31 in this register is set to 1 (AHB Master is Idle) before starting any operation
+ while (!(dwc2->grstctl & GRSTCTL_AHBIDL)) {
+ }
+
+ // load gsnpsid (it is not readable after reset is asserted)
+ const uint32_t gsnpsid = dwc2->gsnpsid;
+
// reset core
dwc2->grstctl |= GRSTCTL_CSRST;
- if ((dwc2->gsnpsid & DWC2_CORE_REV_MASK) < (DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) {
- // prior v42.0 CSRST is self-clearing
+ if ((gsnpsid & DWC2_CORE_REV_MASK) < (DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) {
+ // prior v4.20a: CSRST is self-clearing and the core clears this bit after all the necessary logic is reset in
+ // the core, which can take several clocks, depending on the current state of the core. Once this bit has been
+ // cleared, the software must wait at least 3 PHY clocks before accessing the PHY domain (synchronization delay).
while (dwc2->grstctl & GRSTCTL_CSRST) {}
} else {
- // From v4.20a CSRST bit is write only, CSRT_DONE (w1c) is introduced for checking.
- // CSRST must also be explicitly cleared
+ // From v4.20a: CSRST bit is write only. The application must clear this bit after checking the bit 29 of this
+ // register i.e Core Soft Reset Done CSRT_DONE (w1c)
while (!(dwc2->grstctl & GRSTCTL_CSRST_DONE)) {}
- dwc2->grstctl = (dwc2->grstctl & ~GRSTCTL_CSRST) | GRSTCTL_CSRST_DONE;
+ dwc2->grstctl = (dwc2->grstctl & ~GRSTCTL_CSRST) | GRSTCTL_CSRST_DONE;
}
while (!(dwc2->grstctl & GRSTCTL_AHBIDL)) {} // wait for AHB master IDLE
@@ -92,6 +101,14 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
const dwc2_ghwcfg4_t ghwcfg4 = {.value = dwc2->ghwcfg4};
+ uint8_t phy_width;
+ if (CFG_TUSB_MCU != OPT_MCU_AT32F402_405 && // at32f402_405 does not support 16-bit
+ ghwcfg4.phy_data_width) {
+ phy_width = 16; // 16-bit PHY interface if supported
+ } else {
+ phy_width = 8; // 8-bit PHY interface
+ }
+
// De-select FS PHY
gusbcfg &= ~GUSBCFG_PHYSEL;
@@ -119,12 +136,10 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
gusbcfg &= ~GUSBCFG_ULPI_UTMI_SEL;
// Set 16-bit interface if supported
- if (ghwcfg4.phy_data_width) {
- #if CFG_TUSB_MCU != OPT_MCU_AT32F402_405 // at32f402_405 does not actually support 16-bit
- gusbcfg |= GUSBCFG_PHYIF16; // 16 bit
- #endif
+ if (phy_width == 16) {
+ gusbcfg |= GUSBCFG_PHYIF16;
} else {
- gusbcfg &= ~GUSBCFG_PHYIF16; // 8 bit
+ gusbcfg &= ~GUSBCFG_PHYIF16;
}
}
@@ -141,13 +156,7 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
// - 9 if using 8-bit PHY interface
// - 5 if using 16-bit PHY interface
gusbcfg &= ~GUSBCFG_TRDT_Msk;
-
-#if CFG_TUSB_MCU == OPT_MCU_AT32F402_405 // at32f402_405 does not actually support 16-bit
- gusbcfg |= 9u << GUSBCFG_TRDT_Pos;
-#else
- gusbcfg |= (dwc2->ghwcfg4_bm.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos;
-#endif
-
+ gusbcfg |= (phy_width == 16 ? 5u : 9u) << GUSBCFG_TRDT_Pos;
dwc2->gusbcfg = gusbcfg;
// MCU specific PHY update post reset
diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h
index 49b8c54cb..a4e0d1770 100644
--- a/src/portable/synopsys/dwc2/dwc2_esp32.h
+++ b/src/portable/synopsys/dwc2/dwc2_esp32.h
@@ -47,6 +47,23 @@ static const dwc2_controller_t _dwc2_controller[] = {
{ .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 }
};
+#elif TU_CHECK_MCU(OPT_MCU_ESP32H4)
+// H4's USB_WRAP register block uses "wrap_*" field names. Map them to the
+// names used by TinyUSB's DWC2 port to keep the source unchanged.
+#define otg_conf wrap_otg_conf
+#define pad_pull_override wrap_pad_pull_override
+#define dp_pullup wrap_dp_pullup
+#define dp_pulldown wrap_dp_pulldown
+#define dm_pullup wrap_dm_pullup
+#define dm_pulldown wrap_dm_pulldown
+
+#define DWC2_FS_REG_BASE 0x60040000UL
+#define DWC2_EP_MAX 7
+
+static const dwc2_controller_t _dwc2_controller[] = {
+ { .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_OTG11_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 }
+};
+
#elif TU_CHECK_MCU(OPT_MCU_ESP32P4)
#define DWC2_FS_REG_BASE 0x50040000UL
#define DWC2_HS_REG_BASE 0x50000000UL
diff --git a/src/portable/synopsys/dwc2/dwc2_info.md b/src/portable/synopsys/dwc2/dwc2_info.md
index 595c89b75..f655e4dba 100644
--- a/src/portable/synopsys/dwc2/dwc2_info.md
+++ b/src/portable/synopsys/dwc2/dwc2_info.md
@@ -1,58 +1,58 @@
-| | BCM2711 (Pi4) | EFM32GG | ESP32-S2/S3 | ESP32-P4 | ST F207/F407/411/429 FS | ST F407/429 HS | ST F412/76x FS | ST F723/L4P5 FS | ST F723 HS | ST F76x HS | ST H743/H750 | ST L476 FS | ST U5A5/H7RS/N6 HS | XMC4500 | GD32VF103 |
-|:---------------------------|:----------------|:-------------|:--------------|:-------------|:--------------------------|:-----------------|:-----------------|:------------------|:-------------|:-------------|:---------------|:-------------|:---------------------|:-------------|:------------|
-| GUID | 0x2708A000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00001200 | 0x00001100 | 0x00002000 | 0x00003000 | 0x00003100 | 0x00002100 | 0x00002300 | 0x00002000 | 0x00005000 | 0x00AEC000 | 0x00001000 |
-| GSNPSID | 0x4F54280A | 0x4F54330A | 0x4F54400A | 0x4F54400A | 0x4F54281A | 0x4F54281A | 0x4F54320A | 0x4F54330A | 0x4F54330A | 0x4F54320A | 0x4F54330A | 0x4F54310A | 0x4F54411A | 0x4F54292A | 0x00000000 |
-| - specs version | 2.80a | 3.30a | 4.00a | 4.00a | 2.81a | 2.81a | 3.20a | 3.30a | 3.30a | 3.20a | 3.30a | 3.10a | 4.11a | 2.92a | 0.00W |
-| GHWCFG1 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 |
-| GHWCFG2 | 0x228DDD50 | 0x228F5910 | 0x224DD930 | 0x215FFFD0 | 0x229DCD20 | 0x229ED590 | 0x229ED520 | 0x229ED520 | 0x229FE1D0 | 0x229FE190 | 0x229FE190 | 0x229ED520 | 0x228FE052 | 0x228F5930 | 0x00000000 |
-| - op_mode | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | noHNP noSRP | HNP SRP | HNP SRP |
-| - arch | DMA internal | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | Slave only | Slave only | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | DMA internal | Slave only |
-| - single_point | hub | hub | n/a | hub | n/a | hub | n/a | n/a | hub | hub | hub | n/a | hub | n/a | hub |
-| - hs_phy_type | UTMI+ | n/a | n/a | UTMI+/ULPI | n/a | ULPI | n/a | n/a | UTMI+/ULPI | ULPI | ULPI | n/a | UTMI+ | n/a | n/a |
-| - fs_phy_type | Dedicated | Dedicated | Dedicated | Shared ULPI | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | n/a | Dedicated | n/a |
-| - num_dev_ep | 7 | 6 | 6 | 15 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
-| - num_host_ch | 7 | 13 | 7 | 15 | 7 | 11 | 11 | 11 | 15 | 15 | 15 | 11 | 15 | 13 | 0 |
-| - period_channel_support | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - enable_dynamic_fifo | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - mul_proc_intrpt | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
-| - reserved21 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - nptx_q_depth | 8 | 8 | 4 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
-| - ptx_q_depth | 8 | 8 | 8 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
-| - token_q_depth | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 |
-| - otg_enable_ic_usb | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| GHWCFG3 | 0x0FF000E8 | 0x01F204E8 | 0x00C804B5 | 0x03805EB5 | 0x020001E8 | 0x03F403E8 | 0x0200D1E8 | 0x0200D1E8 | 0x03EED2E8 | 0x03EED2E8 | 0x03B8D2E8 | 0x0200D1E8 | 0x03B882E8 | 0x027A01E5 | 0x00000000 |
-| - xfer_size_width | 8 | 8 | 5 | 5 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 5 | 0 |
-| - packet_size_width | 6 | 6 | 3 | 3 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 0 |
-| - otg_enable | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - i2c_enable | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
-| - vendor_ctrl_itf | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 |
-| - optional_feature_removed | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - synch_reset | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - otg_adp_support | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
-| - otg_enable_hsic | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - battery_charger_support | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
-| - lpm_mode | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
-| - dfifo_depth | 4080 | 498 | 200 | 896 | 512 | 1012 | 512 | 512 | 1006 | 1006 | 952 | 512 | 952 | 634 | 0 |
-| GHWCFG4 | 0x1FF00020 | 0x1BF08030 | 0xD3F0A030 | 0xDFF1A030 | 0x0FF08030 | 0x17F00030 | 0x17F08030 | 0x17F08030 | 0x23F00030 | 0x23F00030 | 0xE3F00030 | 0x17F08030 | 0xE2103E30 | 0xDBF08030 | 0x00000000 |
-| - num_dev_period_in_ep | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - partial_powerdown | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - ahb_freq_min | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - extended_hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - reserved8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - enhanced_lpm_support1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - service_interval_flow | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - ipg_isoc_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - acg_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - enhanced_lpm_support | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - phy_data_width | 8 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8 bit | 8/16 bit | 8/16 bit | 8 bit | 8 bit | 8 bit | 8/16 bit | 8 bit | 8/16 bit | 8 bit |
-| - ctrl_ep_num | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - iddg_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - vbus_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
-| - a_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
-| - b_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
-| - session_end_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
-| - dedicated_fifos | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - num_dev_in_eps | 7 | 6 | 4 | 7 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
-| - dma_desc_enable | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
-| - dma_desc_dynamic | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
+| | AT32 F405 FS | AT32 F405 HS | AT32 F415 | BCM2711 (Pi4) | EFM32GG | ESP32-S2/S3 | ESP32-P4 | nRF54 | ST F207/F407/411/429 FS | ST F407/429 HS | ST F412/76x FS | ST F723/L4P5 FS | ST F723 HS | ST F76x HS | ST H743/H750 | ST L476 FS | ST U5A5/H7RS/N6 HS | XMC4500 | GD32VF103 |
+|:---------------------------|:---------------|:---------------|:------------|:----------------|:-------------|:--------------|:-------------|:-------------|:--------------------------|:-----------------|:-----------------|:------------------|:-------------|:-------------|:---------------|:-------------|:---------------------|:-------------|:------------|
+| GUID | 0x00002000 | 0x00000000 | 0x00001000 | 0x2708A000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00001200 | 0x00001100 | 0x00002000 | 0x00003000 | 0x00003100 | 0x00002100 | 0x00002300 | 0x00002000 | 0x00005000 | 0x00AEC000 | 0x00001000 |
+| GSNPSID | 0x4F54400A | 0x4F54400A | 0x4F54400A | 0x4F54280A | 0x4F54330A | 0x4F54400A | 0x4F54400A | 0x4F54430A | 0x4F54281A | 0x4F54281A | 0x4F54320A | 0x4F54330A | 0x4F54330A | 0x4F54320A | 0x4F54330A | 0x4F54310A | 0x4F54411A | 0x4F54292A | 0x00000000 |
+| - specs version | 4.00a | 4.00a | 4.00a | 2.80a | 3.30a | 4.00a | 4.00a | 4.30a | 2.81a | 2.81a | 3.20a | 3.30a | 3.30a | 3.20a | 3.30a | 3.10a | 4.11a | 2.92a | 0.00W |
+| GHWCFG1 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0xAA555000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 |
+| GHWCFG2 | 0x228FDD00 | 0x229FDDD0 | 0x228DCD00 | 0x228DDD50 | 0x228F5910 | 0x224DD930 | 0x215FFFD0 | 0x228BFC72 | 0x229DCD20 | 0x229ED590 | 0x229ED520 | 0x229ED520 | 0x229FE1D0 | 0x229FE190 | 0x229FE190 | 0x229ED520 | 0x228FE052 | 0x228F5930 | 0x00000000 |
+| - op_mode | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | noHNP noSRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | noHNP noSRP | HNP SRP | HNP SRP |
+| - arch | Slave only | DMA internal | Slave only | DMA internal | DMA internal | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | Slave only | Slave only | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | DMA internal | Slave only |
+| - single_point | hub | hub | hub | hub | hub | n/a | hub | n/a | n/a | hub | n/a | n/a | hub | hub | hub | n/a | hub | n/a | hub |
+| - hs_phy_type | n/a | UTMI+/ULPI | n/a | UTMI+ | n/a | n/a | UTMI+/ULPI | UTMI+ | n/a | ULPI | n/a | n/a | UTMI+/ULPI | ULPI | ULPI | n/a | UTMI+ | n/a | n/a |
+| - fs_phy_type | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Shared ULPI | n/a | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | n/a | Dedicated | n/a |
+| - num_dev_ep | 7 | 7 | 3 | 7 | 6 | 6 | 15 | 15 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
+| - num_host_ch | 15 | 15 | 7 | 7 | 13 | 7 | 15 | 15 | 7 | 11 | 11 | 11 | 15 | 15 | 15 | 11 | 15 | 13 | 0 |
+| - period_channel_support | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - enable_dynamic_fifo | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - mul_proc_intrpt | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
+| - reserved21 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - nptx_q_depth | 8 | 8 | 8 | 8 | 8 | 4 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
+| - ptx_q_depth | 8 | 8 | 8 | 8 | 8 | 8 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
+| - token_q_depth | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 |
+| - otg_enable_ic_usb | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| GHWCFG3 | 0x020004E8 | 0x03F006E8 | 0x020004E8 | 0x0FF000E8 | 0x01F204E8 | 0x00C804B5 | 0x03805EB5 | 0x0BEAC0E8 | 0x020001E8 | 0x03F403E8 | 0x0200D1E8 | 0x0200D1E8 | 0x03EED2E8 | 0x03EED2E8 | 0x03B8D2E8 | 0x0200D1E8 | 0x03B882E8 | 0x027A01E5 | 0x00000000 |
+| - xfer_size_width | 8 | 8 | 8 | 8 | 8 | 5 | 5 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 5 | 0 |
+| - packet_size_width | 6 | 6 | 6 | 6 | 6 | 3 | 3 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 0 |
+| - otg_enable | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - i2c_enable | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
+| - vendor_ctrl_itf | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 |
+| - optional_feature_removed | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - synch_reset | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - otg_adp_support | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
+| - otg_enable_hsic | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - battery_charger_support | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
+| - lpm_mode | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
+| - dfifo_depth | 512 | 1008 | 512 | 4080 | 498 | 200 | 896 | 3050 | 512 | 1012 | 512 | 512 | 1006 | 1006 | 952 | 512 | 952 | 634 | 0 |
+| GHWCFG4 | 0x1FF0A020 | 0x1FF0A020 | 0x0000000F | 0x1FF00020 | 0x1BF08030 | 0xD3F0A030 | 0xDFF1A030 | 0x1E10AA60 | 0x0FF08030 | 0x17F00030 | 0x17F08030 | 0x17F08030 | 0x23F00030 | 0x23F00030 | 0xE3F00030 | 0x17F08030 | 0xE2103E30 | 0xDBF08030 | 0x00000000 |
+| - num_dev_period_in_ep | 0 | 0 | 15 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - partial_powerdown | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - ahb_freq_min | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - extended_hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - reserved8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - enhanced_lpm_support1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - service_interval_flow | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - ipg_isoc_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - acg_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - enhanced_lpm_support | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - phy_data_width | 8/16 bit | 8/16 bit | 8 bit | 8 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8 bit | 8/16 bit | 8/16 bit | 8 bit | 8 bit | 8 bit | 8/16 bit | 8 bit | 8/16 bit | 8 bit |
+| - ctrl_ep_num | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - iddg_filter | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - vbus_valid_filter | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - a_valid_filter | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - b_valid_filter | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - session_end_filter | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - dedicated_fifos | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - num_dev_in_eps | 7 | 7 | 0 | 7 | 6 | 4 | 7 | 7 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
+| - dma_desc_enable | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
+| - dma_desc_dynamic | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
diff --git a/src/portable/synopsys/dwc2/dwc2_info.py b/src/portable/synopsys/dwc2/dwc2_info.py
index 3b1993cc5..f6bd2785a 100755
--- a/src/portable/synopsys/dwc2/dwc2_info.py
+++ b/src/portable/synopsys/dwc2/dwc2_info.py
@@ -9,10 +9,14 @@ import pandas as pd
# Note: FS is FullSpeed, HS is HighSpeed
dwc2_reg_list = ['GUID', 'GSNPSID', 'GHWCFG1', 'GHWCFG2', 'GHWCFG3', 'GHWCFG4']
dwc2_reg_value = {
+ 'AT32 F405 FS': [0x00002000, 0x4F54400A, 0x00000000, 0x228FDD00, 0x020004E8, 0x1FF0A020],
+ 'AT32 F405 HS': [0x00000000, 0x4F54400A, 0x00000000, 0x229FDDD0, 0x03F006E8, 0x1FF0A020],
+ 'AT32 F415': [0x00001000, 0x4F54400A, 0x00000000, 0x228DCD00, 0x020004E8, 0x0F],
'BCM2711 (Pi4)': [0x2708A000, 0x4F54280A, 0, 0x228DDD50, 0xFF000E8, 0x1FF00020],
'EFM32GG': [0, 0x4F54330A, 0, 0x228F5910, 0x01F204E8, 0x1BF08030],
'ESP32-S2/S3': [0, 0x4F54400A, 0, 0x224DD930, 0x0C804B5, 0xD3F0A030],
'ESP32-P4': [0, 0x4F54400A, 0, 0x215FFFD0, 0x03805EB5, 0xDFF1A030],
+ 'nRF54': [0, 0x4F54430A, 0xAA555000, 0x228BFC72, 0x0BEAC0E8, 0x1E10AA60],
'ST F207/F407/411/429 FS': [0x1200, 0x4F54281A, 0, 0x229DCD20, 0x020001E8, 0x0FF08030],
'ST F407/429 HS': [0x1100, 0x4F54281A, 0, 0x229ED590, 0x03F403E8, 0x17F00030],
'ST F412/76x FS': [0x2000, 0x4F54320A, 0, 0x229ED520, 0x0200D1E8, 0x17F08030],
diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h
index 5f2b8419c..08950ccc0 100644
--- a/src/portable/synopsys/dwc2/dwc2_stm32.h
+++ b/src/portable/synopsys/dwc2/dwc2_stm32.h
@@ -113,6 +113,22 @@ extern "C" {
#define EP_MAX_HS 9
#define EP_FIFO_SIZE_HS 4096
#endif
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WBA
+ #if defined(STM32WBA62xx)
+ #include "stm32wba62xx.h"
+ #elif defined(STM32WBA64xx)
+ #include "stm32wba64xx.h"
+ #elif defined(STM32WBA65xx)
+ #include "stm32wba65xx.h"
+ #else
+ #error "The selected STM32WBA series chip does not support OTG USB HS"
+ #endif
+
+ #define USB_OTG_HS_PERIPH_BASE USB_OTG_HS_BASE_NS
+ #define OTG_HS_IRQn USB_OTG_HS_IRQn
+ #define EP_MAX_HS 9
+ #define EP_FIFO_SIZE_HS 4096
#else
#error "Unsupported MCUs"
#endif
@@ -166,6 +182,7 @@ TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) {
// MCU specific PHY init, called BEFORE core reset
// - dwc2 3.30a (H5) use USB_HS_PHYC
// - dwc2 4.11a (U5) use femtoPHY
+// - dwc2 x.xxx (WBA) use USB_OTG_HS
static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
if (hs_phy_type == GHWCFG2_HSPHY_NOT_SUPPORTED) {
// Enable on-chip FS PHY
@@ -194,11 +211,10 @@ static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
#endif
} else {
-#if CFG_TUSB_MCU != OPT_MCU_STM32U5
+#if CFG_TUSB_MCU != OPT_MCU_STM32U5 && CFG_TUSB_MCU != OPT_MCU_STM32WBA
// Disable FS PHY, TODO on U5A5 (dwc2 4.11a) 16th bit is 'Host CDP behavior enable'
dwc2->stm32_gccfg &= ~STM32_GCCFG_PWRDWN;
#endif
-
// Enable on-chip HS PHY
if (hs_phy_type == GHWCFG2_HSPHY_UTMI || hs_phy_type == GHWCFG2_HSPHY_UTMI_ULPI) {
#ifdef USB_HS_PHYC
@@ -233,6 +249,9 @@ static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
// Enable PLL internal PHY
USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN;
+
+ // Wait ~2ms until the PLL is ready (there's no RDY bit to query)
+ tusb_time_delay_ms_api(2);
#else
#endif
diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
index 3752ae251..64cbc5087 100644
--- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
+++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
@@ -662,24 +662,10 @@ static void handle_setup_packet(void)
dcd_event_setup_received(0, (uint8_t*) &_setup_packet[0], true);
}
-#if CFG_TUSB_OS == OPT_OS_NONE
-TU_ATTR_ALWAYS_INLINE static inline void tu_delay(uint32_t ms) {
- // msp430 can run up to 25Mhz -> 40ns per cycle. 1 ms = 25000 cycles
- // each loop need 4 cycle: 1 sub, 1 cmp, 1 jump, 1 nop
- volatile uint32_t cycles = (25000 * ms) >> 2;
- while (cycles > 0) {
- cycles--;
- asm("nop");
- }
-}
-#else
-#define tu_delay(ms) osal_task_delay(ms)
-#endif
-
static void handle_bus_power_event(void *param) {
(void) param;
- tu_delay(5); // Bus power settling delay.
+ tusb_time_delay_ms_api(5); // Bus power settling delay.
USBKEYPID = USBKEY;
@@ -694,7 +680,7 @@ static void handle_bus_power_event(void *param) {
uint16_t attempts = 0;
do { // Poll the PLL, checking for a successful lock.
USBPLLIR = 0;
- tu_delay(1);
+ tusb_time_delay_ms_api(1);
attempts++;
} while ((attempts < 10) && (USBPLLIR != 0));
diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c
index d176f40c5..200136906 100644
--- a/src/portable/wch/hcd_ch32_usbfs.c
+++ b/src/portable/wch/hcd_ch32_usbfs.c
@@ -28,6 +28,8 @@
#if CFG_TUH_ENABLED && defined(TUP_USBIP_WCH_USBFS) && defined(CFG_TUH_WCH_USBIP_USBFS) && CFG_TUH_WCH_USBIP_USBFS
+#include <stdlib.h>
+
#include "host/hcd.h"
#include "host/usbh.h"
#include "host/usbh_pvt.h"
@@ -55,19 +57,17 @@ TU_ATTR_ALIGNED(4) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN];
#define LOG_CH32_USBFSH(...) TU_LOG3(__VA_ARGS__)
// Busywait for delay microseconds/nanoseconds
-// static void loopdelay(uint32_t count)
-// {
-// volatile uint32_t c = count / 3;
-// if (c == 0) { return; }
-// // while (c-- != 0);
-// asm volatile(
-// "1: \n" // loop label
-// " addi %0, %0, -1 \n" // c--
-// " bne %0, zero, 1b \n" // if (c != 0) goto loop
-// : "+r"(c) // c is input/output operand
-// );
-// }
-
+TU_ATTR_ALWAYS_INLINE static inline void loopdelay(uint32_t count) {
+ volatile uint32_t c = count / 3;
+ if (c == 0) { return; }
+ // while (c-- != 0);
+ asm volatile(
+ "1: \n" // loop label
+ " addi %0, %0, -1 \n" // c--
+ " bne %0, zero, 1b \n" // if (c != 0) goto loop
+ : "+r"(c) // c is input/output operand
+ );
+}
// Endpoint status
typedef struct usb_edpt {
@@ -82,6 +82,10 @@ typedef struct usb_edpt {
// Data toggle (0 or not 0) for DATA0/1
uint8_t data_toggle;
+
+ bool is_nak_pending;
+ uint16_t buflen;
+ uint8_t* buf;
} usb_edpt_t;
static usb_edpt_t usb_edpt_list[CFG_TUH_DEVICE_MAX * 6] = {};
@@ -95,6 +99,7 @@ typedef struct usb_current_xfer_st {
uint8_t *buffer;
uint16_t bufferlen;
uint16_t xferred_len;
+ bool nak_pending;
} usb_current_xfer_t;
static volatile usb_current_xfer_t usb_current_xfer_info = {};
@@ -120,9 +125,6 @@ static usb_edpt_t *get_empty_record_slot(void) {
static usb_edpt_t *add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) {
usb_edpt_t *slot = get_empty_record_slot();
- if (slot == NULL) {
- PANIC("add_edpt_record(0x%02x, 0x%02x, ...) no slot for new record\r\n", dev_addr, ep_addr);
- }
TU_ASSERT(slot != NULL, NULL);
slot->dev_addr = dev_addr;
@@ -130,6 +132,9 @@ static usb_edpt_t *add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t m
slot->max_packet_size = max_packet_size;
slot->xfer_type = xfer_type;
slot->data_toggle = 0;
+ slot->is_nak_pending = false;
+ slot->buflen = 0;
+ slot->buf = NULL;
slot->configured = true;
@@ -197,10 +202,13 @@ static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggl
: "(other)",
pid, ep_addr, data_toggle);
- // if (pid == USB_PID_IN)
- // { // FIXME: long delay needed (at release build) about 30msec
- // loopdelay(SystemCoreClock / 1000 * 30);
- // }
+ //WORKAROUND: For LowSpeed device, insert small delay
+ bool is_lowspeed_device = tuh_speed_get(usb_current_xfer_info.dev_addr) == TUSB_SPEED_LOW;
+ if (is_lowspeed_device) {
+ //NOTE: worked -> SystemCoreClock / 1000000 * 50, 25
+ // NOT worked -> 20 and less (at 144MHz internal clock)
+ loopdelay(SystemCoreClock / 1000000 * 40);
+ }
uint8_t pid_edpt = (pid << 4) | (tu_edpt_number(ep_addr) & 0x0f);
USBOTG_H_FS->HOST_TX_CTRL = (data_toggle != 0) ? USBFS_UH_T_TOG : 0;
@@ -336,7 +344,7 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
uint32_t hcd_frame_number(uint8_t rhport) {
(void) rhport;
- return board_millis();
+ return tusb_time_millis_api();
}
void hcd_int_enable(uint8_t rhport) {
@@ -351,6 +359,28 @@ void hcd_int_disable(uint8_t rhport) {
interrupt_enabled = false;
}
+
+static void xfer_retry(void* _params) {
+ LOG_CH32_USBFSH("xfer_retry()\r\n");
+ usb_edpt_t* edpt_info = (usb_edpt_t*)_params;
+ if (usb_current_xfer_info.nak_pending) {
+ usb_current_xfer_info.nak_pending = false;
+ edpt_info->is_nak_pending = false;
+
+ uint8_t dev_addr = edpt_info->dev_addr;
+ uint8_t ep_addr = edpt_info->ep_addr;
+ uint16_t buflen = edpt_info->buflen;
+ uint8_t* buf = edpt_info->buf;
+
+ // Check connectivity
+ usb_edpt_t* edpt_info_current = get_edpt_record(dev_addr, ep_addr);
+ if (edpt_info_current) {
+ hcd_edpt_xfer(0, dev_addr, ep_addr, buf, buflen);
+ }
+ }
+}
+
+
void hcd_int_handler(uint8_t rhport, bool in_isr) {
(void) rhport;
(void) in_isr;
@@ -407,15 +437,12 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
if (usb_current_xfer_info.bufferlen == 0) {
LOG_CH32_USBFSH("USB_PID_%s completed %d bytes\r\n", request_pid == USB_PID_OUT ? "OUT" : "SETUP", usb_current_xfer_info.xferred_len);
usb_current_xfer_info.is_busy = false;
- hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.xferred_len, XFER_RESULT_SUCCESS, true);
+ hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.xferred_len, XFER_RESULT_SUCCESS, in_isr);
return;
} else {
LOG_CH32_USBFSH("USB_PID_OUT continue...\r\n");
usb_current_xfer_info.buffer += tx_len;
- uint16_t copylen = USBFS_TX_BUF_LEN;
- if (copylen > usb_current_xfer_info.bufferlen) {
- copylen = usb_current_xfer_info.bufferlen;
- }
+ uint16_t copylen = TU_MIN(edpt_info->max_packet_size, usb_current_xfer_info.bufferlen);
memcpy(USBFS_TX_Buf, usb_current_xfer_info.buffer, copylen);
hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle);
return;
@@ -435,7 +462,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
// USB device sent all data.
LOG_CH32_USBFSH("USB_PID_IN completed\r\n");
usb_current_xfer_info.is_busy = false;
- hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true);
+ hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, in_isr);
return;
} else {
// USB device may send more data.
@@ -445,7 +472,10 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
}
}
default: {
- PANIC("Unknown PID: 0x%02x\n", request_pid);
+ LOG_CH32_USBFSH("hcd_int_handler() L%d: unexpected response PID: 0x%02x\r\n", __LINE__, response_pid);
+ usb_current_xfer_info.is_busy = false;
+ hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr);
+ return;
}
}
} else {
@@ -457,26 +487,42 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
return;
} else if (response_pid == USB_PID_NAK) {
LOG_CH32_USBFSH("NAK reposense\r\n");
- uint32_t elapsed_time = board_millis() - usb_current_xfer_info.start_ms;
+ uint32_t elapsed_time = tusb_time_millis_api() - usb_current_xfer_info.start_ms;
+ (void)elapsed_time;
if (edpt_info->xfer_type == TUSB_XFER_INTERRUPT) {
usb_current_xfer_info.is_busy = false;
- hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true);
- } else if (elapsed_time > USB_XFER_TIMEOUT_MILLIS) {
- usb_current_xfer_info.is_busy = false;
- hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true);
+ hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, in_isr);
+
} else {
- hardware_start_xfer(request_pid, ep_addr, edpt_info->data_toggle);
+ usb_current_xfer_info.is_busy = false;
+ usb_current_xfer_info.nak_pending = true;
+
+
+ edpt_info->is_nak_pending = true;
+ edpt_info->buflen = usb_current_xfer_info.bufferlen;
+ edpt_info->buf = usb_current_xfer_info.buffer;
+
+ hcd_event_t event = {
+ .rhport = rhport,
+ .dev_addr = dev_addr,
+ .event_id = USBH_EVENT_FUNC_CALL,
+ .func_call = {
+ .func = xfer_retry,
+ .param = edpt_info
+ }
+ };
+ hcd_event_handler(&event, in_isr);
}
return;
} else if (response_pid == USB_PID_DATA0 || response_pid == USB_PID_DATA1) {
LOG_CH32_USBFSH("Data toggle mismatched and DATA0/1 (not STALL). RX_LEN=%d\r\n", USBOTG_H_FS->RX_LEN);
usb_current_xfer_info.is_busy = false;
- hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true);
+ hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr);
return;
} else {
- LOG_CH32_USBFSH("In USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid);
+ LOG_CH32_USBFSH("hcd_int_handler() L%d: unexpected response PID: 0x%02x\r\n", __LINE__, response_pid);
usb_current_xfer_info.is_busy = false;
- hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true);
+ hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, in_isr);
return;
}
}
@@ -495,6 +541,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
uint8_t xfer_type = ep_desc->bmAttributes.xfer;
LOG_CH32_USBFSH("hcd_edpt_open(rhport=%d, dev_addr=0x%02x, %p) EndpointAdderss=0x%02x,maxPacketSize=%d,xfer_type=%d\r\n", rhport, dev_addr, ep_desc, ep_addr, max_packet_size, xfer_type);
+ while (usb_current_xfer_info.is_busy) { }
+
if (ep_num == 0x00) {
TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x00, max_packet_size, xfer_type) != NULL, false);
TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x80, max_packet_size, xfer_type) != NULL, false);
@@ -519,9 +567,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
usb_current_xfer_info.is_busy = true;
usb_edpt_t *edpt_info = get_edpt_record(dev_addr, ep_addr);
- if (edpt_info == NULL) {
- PANIC("get_edpt_record() returned NULL in hcd_edpt_xfer()\r\n");
- }
+ TU_ASSERT(edpt_info != NULL);
hardware_set_port_address_speed(dev_addr);
@@ -529,18 +575,16 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
usb_current_xfer_info.ep_addr = ep_addr;
usb_current_xfer_info.buffer = buffer;
usb_current_xfer_info.bufferlen = buflen;
- usb_current_xfer_info.start_ms = board_millis();
+ usb_current_xfer_info.start_ms = tusb_time_millis_api();
usb_current_xfer_info.xferred_len = 0;
+ usb_current_xfer_info.nak_pending = false;
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
LOG_CH32_USBFSH("hcd_edpt_xfer(): READ, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen);
return hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle);
} else {
LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen);
- uint16_t copylen = USBFS_TX_BUF_LEN;
- if (copylen > buflen) {
- copylen = buflen;
- }
+ uint16_t copylen = TU_MIN(edpt_info->max_packet_size, buflen);
USBOTG_H_FS->HOST_TX_LEN = copylen;
memcpy(USBFS_TX_Buf, buffer, copylen);
return hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle);
@@ -582,10 +626,11 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
uint8_t ep_addr = (setup_packet[0] & 0x80) ? 0x80 : 0x00;
usb_current_xfer_info.dev_addr = dev_addr;
usb_current_xfer_info.ep_addr = ep_addr;
- usb_current_xfer_info.start_ms = board_millis();
+ usb_current_xfer_info.start_ms = tusb_time_millis_api();
usb_current_xfer_info.buffer = USBFS_TX_Buf;
usb_current_xfer_info.bufferlen = setup_packet_datalen;
usb_current_xfer_info.xferred_len = 0;
+ usb_current_xfer_info.nak_pending = false;
hardware_start_xfer(USB_PID_SETUP, 0, 0);
@@ -596,7 +641,6 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
(void) rhport;
(void) dev_addr;
LOG_CH32_USBFSH("hcd_edpt_clear_stall(rhport=%d, dev_addr=0x%02x, ep_addr=0x%02x)\r\n", rhport, dev_addr, ep_addr);
- // PANIC("\r\install\r\n");
uint8_t edpt_num = tu_edpt_number(ep_addr);
uint8_t setup_request_clear_stall[8] = {
0x02, 0x01, 0x00, 0x00, edpt_num, 0x00, 0x00, 0x00
diff --git a/src/tinyusb.mk b/src/tinyusb.mk
index a9f623c24..8f9d52de9 100644
--- a/src/tinyusb.mk
+++ b/src/tinyusb.mk
@@ -12,6 +12,7 @@ TINYUSB_SRC_C += \
src/class/hid/hid_device.c \
src/class/midi/midi_device.c \
src/class/msc/msc_device.c \
+ src/class/mtp/mtp_device.c \
src/class/net/ecm_rndis_device.c \
src/class/net/ncm_device.c \
src/class/usbtmc/usbtmc_device.c \
diff --git a/src/tusb.c b/src/tusb.c
index 5a3ea356b..083e6d861 100644
--- a/src/tusb.c
+++ b/src/tusb.c
@@ -55,6 +55,14 @@ TU_ATTR_WEAK void tusb_time_delay_ms_api(uint32_t ms) {
#endif
}
+TU_ATTR_WEAK void* tusb_app_virt_to_phys(void *virt_addr) {
+ return virt_addr;
+}
+
+TU_ATTR_WEAK void* tusb_app_phys_to_virt(void *phys_addr) {
+ return phys_addr;
+}
+
//--------------------------------------------------------------------+
// Public API
//--------------------------------------------------------------------+
diff --git a/src/tusb.h b/src/tusb.h
index e794a8b0b..6a469eef4 100644
--- a/src/tusb.h
+++ b/src/tusb.h
@@ -88,6 +88,10 @@
#include "class/msc/msc_device.h"
#endif
+ #if CFG_TUD_MTP
+ #include "class/mtp/mtp_device.h"
+ #endif
+
#if CFG_TUD_AUDIO
#include "class/audio/audio_device.h"
#endif
@@ -170,16 +174,6 @@ bool tusb_deinit(uint8_t rhport);
#endif
-//--------------------------------------------------------------------+
-// API Implemented by user
-//--------------------------------------------------------------------+
-
-// Get current milliseconds, required by some port/configuration without RTOS
-uint32_t tusb_time_millis_api(void);
-
-// Delay in milliseconds, use tusb_time_millis_api() by default. required by some port/configuration with no RTOS
-void tusb_time_delay_ms_api(uint32_t ms);
-
#ifdef __cplusplus
}
#endif
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 17bf556a3..378b5607e 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -31,7 +31,7 @@
// Version is release as major.minor.revision eg 1.0.0
#define TUSB_VERSION_MAJOR 0
-#define TUSB_VERSION_MINOR 18
+#define TUSB_VERSION_MINOR 19
#define TUSB_VERSION_REVISION 0
#define TUSB_VERSION_NUMBER (TUSB_VERSION_MAJOR * 10000 + TUSB_VERSION_MINOR * 100 + TUSB_VERSION_REVISION)
@@ -95,6 +95,7 @@
#define OPT_MCU_STM32H7RS 317 ///< ST F7RS
#define OPT_MCU_STM32C0 318 ///< ST C0
#define OPT_MCU_STM32N6 319 ///< ST N6
+#define OPT_MCU_STM32WBA 320 ///< ST WBA
// Sony
#define OPT_MCU_CXD56 400 ///< SONY CXD56
@@ -128,6 +129,9 @@
#define OPT_MCU_ESP32C2 905 ///< Espressif ESP32-C2
#define OPT_MCU_ESP32H2 906 ///< Espressif ESP32-H2
#define OPT_MCU_ESP32P4 907 ///< Espressif ESP32-P4
+#define OPT_MCU_ESP32C5 908 ///< Espressif ESP32-C5
+#define OPT_MCU_ESP32C61 909 ///< Espressif ESP32-C61
+#define OPT_MCU_ESP32H4 910 ///< Espressif ESP32-H4
#define TUSB_MCU_VENDOR_ESPRESSIF (CFG_TUSB_MCU >= 900 && CFG_TUSB_MCU < 1000) // check if Espressif MCU
#define TUP_MCU_ESPRESSIF TUSB_MCU_VENDOR_ESPRESSIF // for backward compatibility
@@ -513,6 +517,10 @@
#define CFG_TUD_MSC 0
#endif
+#ifndef CFG_TUD_MTP
+ #define CFG_TUD_MTP 0
+#endif
+
#ifndef CFG_TUD_HID
#define CFG_TUD_HID 0
#endif
diff --git a/src/typec/usbc.c b/src/typec/usbc.c
index fdf2a0cd6..20abd1700 100644
--- a/src/typec/usbc.c
+++ b/src/typec/usbc.c
@@ -60,6 +60,23 @@ bool parse_msg_data(uint8_t rhport, pd_header_t const* header, uint8_t const* do
bool parse_msg_control(uint8_t rhport, pd_header_t const* header);
//--------------------------------------------------------------------+
+// Weak stubs: invoked if no strong implementation is available
+//--------------------------------------------------------------------+
+TU_ATTR_WEAK bool tuc_pd_data_received_cb(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end) {
+ (void) rhport;
+ (void) header;
+ (void) dobj;
+ (void) p_end;
+ return false;
+}
+
+TU_ATTR_WEAK bool tuc_pd_control_received_cb(uint8_t rhport, pd_header_t const* header) {
+ (void) rhport;
+ (void) header;
+ return false;
+}
+
+//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
bool tuc_inited(uint8_t rhport) {
@@ -136,17 +153,13 @@ void tuc_task_ext(uint32_t timeout_ms, bool in_isr) {
}
bool parse_msg_data(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end) {
- if (tuc_pd_data_received_cb) {
- tuc_pd_data_received_cb(rhport, header, dobj, p_end);
- }
+ tuc_pd_data_received_cb(rhport, header, dobj, p_end);
return true;
}
bool parse_msg_control(uint8_t rhport, pd_header_t const* header) {
- if (tuc_pd_control_received_cb) {
- tuc_pd_control_received_cb(rhport, header);
- }
+ tuc_pd_control_received_cb(rhport, header);
return true;
}
diff --git a/src/typec/usbc.h b/src/typec/usbc.h
index 9fbff9bc6..448542aab 100644
--- a/src/typec/usbc.h
+++ b/src/typec/usbc.h
@@ -74,8 +74,8 @@ extern void tcd_int_handler(uint8_t rhport);
// Callbacks
//--------------------------------------------------------------------+
-TU_ATTR_WEAK bool tuc_pd_data_received_cb(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end);
-TU_ATTR_WEAK bool tuc_pd_control_received_cb(uint8_t rhport, pd_header_t const* header);
+bool tuc_pd_data_received_cb(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end);
+bool tuc_pd_control_received_cb(uint8_t rhport, pd_header_t const* header);
//--------------------------------------------------------------------+
//
diff --git a/test/fuzz/device/cdc/src/usb_descriptors.cc b/test/fuzz/device/cdc/src/usb_descriptors.cc
index 0f636f05d..c26bd18c3 100644
--- a/test/fuzz/device/cdc/src/usb_descriptors.cc
+++ b/test/fuzz/device/cdc/src/usb_descriptors.cc
@@ -148,7 +148,7 @@ uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
(void)index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
- // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
+ // Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG
memcpy(desc_other_speed_config,
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration
: desc_hs_configuration,
diff --git a/test/fuzz/device/msc/src/usb_descriptors.cc b/test/fuzz/device/msc/src/usb_descriptors.cc
index efe4d0a3c..6d9c4cd96 100644
--- a/test/fuzz/device/msc/src/usb_descriptors.cc
+++ b/test/fuzz/device/msc/src/usb_descriptors.cc
@@ -142,7 +142,7 @@ uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
(void)index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
- // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
+ // Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG
memcpy(desc_other_speed_config,
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration
: desc_hs_configuration,
diff --git a/test/fuzz/device/net/src/usb_descriptors.cc b/test/fuzz/device/net/src/usb_descriptors.cc
index 5597d49d5..e57a791b6 100644
--- a/test/fuzz/device/net/src/usb_descriptors.cc
+++ b/test/fuzz/device/net/src/usb_descriptors.cc
@@ -148,7 +148,7 @@ uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
(void)index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
- // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG
+ // Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG
memcpy(desc_other_speed_config,
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration
: desc_hs_configuration,
diff --git a/test/fuzz/rules.mk b/test/fuzz/rules.mk
index 562969663..b32f8d695 100644
--- a/test/fuzz/rules.mk
+++ b/test/fuzz/rules.mk
@@ -31,6 +31,7 @@ SRC_C += \
src/class/hid/hid_device.c \
src/class/midi/midi_device.c \
src/class/msc/msc_device.c \
+ src/class/mtp/mtp_device.c \
src/class/net/ecm_rndis_device.c \
src/class/net/ncm_device.c \
src/class/usbtmc/usbtmc_device.c \
diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py
index 93cc0a750..fc8255f1b 100755
--- a/test/hil/hil_test.py
+++ b/test/hil/hil_test.py
@@ -28,6 +28,7 @@
import argparse
import os
+import random
import re
import sys
import time
@@ -37,6 +38,9 @@ import json
import glob
from multiprocessing import Pool
import fs
+import hashlib
+import ctypes
+from pymtp import MTP
ENUM_TIMEOUT = 30
@@ -45,6 +49,7 @@ STATUS_FAILED = "\033[31mFailed\033[0m"
STATUS_SKIPPED = "\033[33mSkipped\033[0m"
verbose = False
+test_only = []
WCH_RISCV_CONTENT = """
adapter driver wlinke
@@ -134,6 +139,23 @@ def read_disk_file(uid, lun, fname):
return None
+def open_mtp_dev(uid):
+ mtp = MTP()
+ timeout = ENUM_TIMEOUT
+ while timeout > 0:
+ # run_cmd(f"gio mount -u mtp://TinyUsb_TinyUsb_Device_{uid}/")
+ for raw in mtp.detect_devices():
+ mtp.device = mtp.mtp.LIBMTP_Open_Raw_Device(ctypes.byref(raw))
+ if mtp.device:
+ sn = mtp.get_serialnumber().decode('utf-8')
+ #print(f'mtp serial = {sn}')
+ if sn == uid:
+ return mtp
+ time.sleep(1)
+ timeout -= 1
+ return None
+
+
# -------------------------------------------------------------
# Flashing firmware
# -------------------------------------------------------------
@@ -456,7 +478,6 @@ def test_device_dfu(board):
def test_device_dfu_runtime(board):
uid = board['uid']
-
# Wait device enum
timeout = ENUM_TIMEOUT
while timeout > 0:
@@ -491,6 +512,65 @@ def test_device_hid_composite_freertos(id):
pass
+def test_device_mtp(board):
+ uid = board['uid']
+
+ # --- BEFORE: mute C-level stderr for libmtp vid/pid warnings ---
+ fd = sys.stderr.fileno()
+ _saved = os.dup(fd)
+ _null = os.open(os.devnull, os.O_WRONLY)
+ os.dup2(_null, fd)
+
+ mtp = open_mtp_dev(uid)
+
+ # --- AFTER: restore stderr ---
+ os.dup2(_saved, fd)
+ os.close(_null)
+ os.close(_saved)
+
+ if mtp is None or mtp.device is None:
+ assert False, 'MTP device not found'
+
+ try:
+ assert b"TinyUSB" == mtp.get_manufacturer(), 'MTP wrong manufacturer'
+ assert b"MTP Example" == mtp.get_modelname(), 'MTP wrong model'
+ assert b'1.0' == mtp.get_deviceversion(), 'MTP wrong version'
+ assert b'TinyUSB MTP' == mtp.get_devicename(), 'MTP wrong device name'
+
+ # read and compare readme.txt and logo.png
+ f1_expect = b'TinyUSB MTP Filesystem example'
+ f2_md5_expect = '40ef23fc2891018d41a05d4a0d5f822f' # md5sum of logo.png
+ f1 = uid.encode("utf-8") + b'_file1'
+ f2 = uid.encode("utf-8") + b'_file2'
+ f3 = uid.encode("utf-8") + b'_file3'
+ mtp.get_file_to_file(1, f1)
+ with open(f1, 'rb') as file:
+ f1_data = file.read()
+ os.remove(f1)
+ assert f1_data == f1_expect, 'MTP file1 wrong data'
+ mtp.get_file_to_file(2, f2)
+ with open(f2, 'rb') as file:
+ f2_data = file.read()
+ os.remove(f2)
+ assert f2_md5_expect == hashlib.md5(f2_data).hexdigest(), 'MTP file2 wrong data'
+ # test send file
+ with open(f3, "wb") as file:
+ f3_data = os.urandom(random.randint(1024, 3*1024))
+ file.write(f3_data)
+ file.close()
+ fid = mtp.send_file_from_file(f3, b'file3')
+ f3_readback = f3 + b'_readback'
+ mtp.get_file_to_file(fid, f3_readback)
+ with open(f3_readback, 'rb') as f:
+ f3_rb_data = f.read()
+ os.remove(f3_readback)
+ assert f3_rb_data == f3_data, 'MTP file3 wrong data'
+ os.remove(f3)
+ mtp.delete_object(fid)
+ finally:
+ mtp.disconnect()
+
+
# -------------------------------------------------------------
# Main
# -------------------------------------------------------------
@@ -503,6 +583,7 @@ device_tests = [
'device/dfu_runtime',
'device/cdc_msc_freertos',
'device/hid_boot_interface',
+ 'device/mtp'
]
dual_tests = [
@@ -579,21 +660,24 @@ def test_board(board):
# default to all tests
test_list = []
- if 'tests' in board:
- board_tests = board['tests']
- if 'device' in board_tests and board_tests['device'] == True:
- test_list += list(device_tests)
- if 'dual' in board_tests and board_tests['dual'] == True:
- test_list += dual_tests
- if 'host' in board_tests and board_tests['host'] == True:
- test_list += host_test
- if 'only' in board_tests:
- test_list = board_tests['only']
- if 'skip' in board_tests:
- for skip in board_tests['skip']:
- if skip in test_list:
- test_list.remove(skip)
- print(f'{name:25} {skip:30} ... Skip')
+ if len(test_only) > 0:
+ test_list = test_only
+ else:
+ if 'tests' in board:
+ board_tests = board['tests']
+ if 'device' in board_tests and board_tests['device'] == True:
+ test_list += list(device_tests)
+ if 'dual' in board_tests and board_tests['dual'] == True:
+ test_list += dual_tests
+ if 'host' in board_tests and board_tests['host'] == True:
+ test_list += host_test
+ if 'only' in board_tests:
+ test_list = board_tests['only']
+ if 'skip' in board_tests:
+ for skip in board_tests['skip']:
+ if skip in test_list:
+ test_list.remove(skip)
+ print(f'{name:25} {skip:30} ... Skip')
err_count = 0
flags_on_list = [""]
@@ -615,6 +699,7 @@ def main():
Hardware test on specified boards
"""
global verbose
+ global test_only
duration = time.time()
@@ -622,6 +707,7 @@ def main():
parser.add_argument('config_file', help='Configuration JSON file')
parser.add_argument('-b', '--board', action='append', default=[], help='Boards to test, all if not specified')
parser.add_argument('-s', '--skip', action='append', default=[], help='Skip boards from test')
+ parser.add_argument('-t', '--test-only', action='append', default=[], help='Tests to run, all if not specified')
parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
args = parser.parse_args()
@@ -629,6 +715,7 @@ def main():
boards = args.board
skip_boards = args.skip
verbose = args.verbose
+ test_only = args.test_only
# if config file is not found, try to find it in the same directory as this script
if not os.path.exists(config_file):
diff --git a/test/hil/pymtp.py b/test/hil/pymtp.py
new file mode 100644
index 000000000..8b694df94
--- /dev/null
+++ b/test/hil/pymtp.py
@@ -0,0 +1,1290 @@
+#!/usr/bin/env python
+#
+# A Ctypes wrapper to LibMTP
+# Developed by: Nick Devito ([email protected])
+# (c) 2008 Nick Devito
+# Released under the GPLv3 or later.
+#
+
+"""
+ PyMTP is a pythonic wrapper around libmtp, making it a bit more
+ friendly to use in python
+
+ Example Usage (or see examples/):
+ >>> import pymtp
+ >>> mtp = pymtp.MTP()
+ >>> mtp.connect()
+ PTP: Opening session
+ >>> print mtp.get_devicename()
+ Device name
+ >>> mtp.disconnect()
+ PTP: Closing session
+ >>>
+"""
+
+__VERSION__ = "0.0.5"
+__VERSION_MACRO__ = 5
+__VERSION_MINOR__ = 0
+__VERSION_MAJOR__ = 0
+__VERSION_TUPLE__ = (__VERSION_MAJOR__, __VERSION_MINOR__, __VERSION_MACRO__)
+__AUTHOR__ = "Nick Devito ([email protected])"
+__LICENSE__ = "GPL-3"
+__DEBUG__ = 1
+
+import os
+import ctypes
+import ctypes.util
+
+# NOTE: This code *may* work on windows, I don't have a win32 system to test
+# this on.
+_module_path = ctypes.util.find_library("mtp")
+_libmtp = ctypes.CDLL(_module_path)
+
+# ----------
+# Error Definitions
+# ----------
+class NoDeviceConnected(Exception):
+ """
+ Raised when there isn't a device connected to the USB bus
+ """
+
+ pass
+
+class AlreadyConnected(Exception):
+ """
+ Raised when we're already connected to a device and there is
+ an attempt to connect
+ """
+
+ pass
+
+class UnsupportedCommand(Exception):
+ """
+ Raised when the connected device does not support the command
+ issued
+ """
+
+ pass
+
+class CommandFailed(Exception):
+ """
+ Raised when the connected device returned an error when trying
+ to execute a command
+ """
+
+ pass
+
+class NotConnected(Exception):
+ """
+ Raised when a command is called and the device is not connected
+ """
+
+ pass
+
+class ObjectNotFound(Exception):
+ """
+ Raised when a command tries to get an object that doesn't exist
+ """
+
+ pass
+
+# ----------
+# End Error Definitions
+# ----------
+
+# ----------
+# Data Model Definitions
+# ----------
+
+class LIBMTP_Error(ctypes.Structure):
+ """
+ LIBMTP_Error
+ Contains the ctypes structure for LIBMTP_error_t
+ """
+
+ def __repr__(self):
+ return self.errornumber
+
+LIBMTP_Error._fields_ = [("errornumber", ctypes.c_int),
+ ("error_text", ctypes.c_char_p),
+ ("next", ctypes.POINTER(LIBMTP_Error))]
+
+class LIBMTP_DeviceStorage(ctypes.Structure):
+ """
+ LIBMTP_DeviceStorage
+ Contains the ctypes structure for LIBMTP_devicestorage_t
+ """
+
+ def __repr__(self):
+ return self.id
+
+LIBMTP_DeviceStorage._fields_ = [("id", ctypes.c_uint32),
+ ("StorageType", ctypes.c_uint16),
+ ("FilesystemType", ctypes.c_uint16),
+ ("AccessCapability", ctypes.c_uint16),
+ ("MaxCapacity", ctypes.c_uint64),
+ ("FreeSpaceInBytes", ctypes.c_uint64),
+ ("FreeSpaceInObjects", ctypes.c_uint64),
+ ("StorageDescription", ctypes.c_char_p),
+ ("VolumeIdentifier", ctypes.c_char_p),
+ ("next", ctypes.POINTER(LIBMTP_DeviceStorage)),
+ ("prev", ctypes.POINTER(LIBMTP_DeviceStorage))]
+
+class LIBMTP_DeviceEntry(ctypes.Structure):
+ """
+ LIBMTP_DeviceEntry
+ Contains the ctypes structure for LIBMTP_device_entry_t
+ """
+
+ def __repr__(self):
+ return self.vendor
+
+LIBMTP_DeviceEntry._fields_ = [("vendor", ctypes.c_char_p),
+ ("vendor_id", ctypes.c_uint16),
+ ("product", ctypes.c_char_p),
+ ("product_id", ctypes.c_uint16),
+ ("device_flags", ctypes.c_uint32)]
+
+class LIBMTP_RawDevice(ctypes.Structure):
+ """
+ LIBMTP_RawDevice
+ Contains the ctypes structure for LIBMTP_raw_device_t
+ """
+
+ def __repr__(self):
+ return self.device_entry
+
+LIBMTP_RawDevice._fields_ = [("device_entry", LIBMTP_DeviceEntry),
+ ("bus_location", ctypes.c_uint32),
+ ("devnum", ctypes.c_uint8)]
+
+class LIBMTP_MTPDevice(ctypes.Structure):
+ """
+ LIBMTP_MTPDevice
+ Contains the ctypes structure for LIBMTP_mtpdevice_t
+ """
+
+ def __repr__(self):
+ return self.interface_number
+
+LIBMTP_MTPDevice._fields_ = [("interface_number", ctypes.c_uint8),
+ ("params", ctypes.c_void_p),
+ ("usbinfo", ctypes.c_void_p),
+ ("storage", ctypes.POINTER(LIBMTP_DeviceStorage)),
+ ("errorstack", ctypes.POINTER(LIBMTP_Error)),
+ ("maximum_battery_level", ctypes.c_uint8),
+ ("default_music_folder", ctypes.c_uint32),
+ ("default_playlist_folder", ctypes.c_uint32),
+ ("default_picture_folder", ctypes.c_uint32),
+ ("default_video_folder", ctypes.c_uint32),
+ ("default_organizer_folder", ctypes.c_uint32),
+ ("default_zencast_folder", ctypes.c_uint32),
+ ("default_album_folder", ctypes.c_uint32),
+ ("default_text_folder", ctypes.c_uint32),
+ ("cd", ctypes.c_void_p),
+ ("next", ctypes.POINTER(LIBMTP_MTPDevice))]
+
+class LIBMTP_File(ctypes.Structure):
+ """
+ LIBMTP_File
+ Contains the ctypes structure for LIBMTP_file_t
+ """
+
+ def __repr__(self):
+ return "%s (%s)" % (self.filename, self.item_id)
+
+LIBMTP_File._fields_ = [("item_id", ctypes.c_uint32),
+ ("parent_id", ctypes.c_uint32),
+ ("storage_id", ctypes.c_uint32),
+ ("filename", ctypes.c_char_p),
+ ("filesize", ctypes.c_uint64),
+ ("modificationdate", ctypes.c_uint64),
+ ("filetype", ctypes.c_int), # LIBMTP_filetype_t enum
+ ("next", ctypes.POINTER(LIBMTP_File))]
+
+class LIBMTP_Track(ctypes.Structure):
+ """
+ LIBMTP_Track
+ Contains the ctypes structure for LIBMTP_track_t
+ """
+
+ def __repr__(self):
+ return "%s - %s (%s)" % (self.artist, self.title, self.item_id)
+
+LIBMTP_Track._fields_ = [("item_id", ctypes.c_uint32),
+ ("parent_id", ctypes.c_uint32),
+ ("storage_id", ctypes.c_uint32),
+ ("title", ctypes.c_char_p),
+ ("artist", ctypes.c_char_p),
+ ("composer", ctypes.c_char_p),
+ ("genre", ctypes.c_char_p),
+ ("album", ctypes.c_char_p),
+ ("date", ctypes.c_char_p),
+ ("filename", ctypes.c_char_p),
+ ("tracknumber", ctypes.c_uint16),
+ ("duration", ctypes.c_uint32),
+ ("samplerate", ctypes.c_uint32),
+ ("nochannels", ctypes.c_uint16),
+ ("wavecodec", ctypes.c_uint32),
+ ("bitrate", ctypes.c_uint32),
+ ("bitratetype", ctypes.c_uint16),
+ ("rating", ctypes.c_uint16),
+ ("usecount", ctypes.c_uint32),
+ ("filesize", ctypes.c_uint64),
+ ("modificationdate", ctypes.c_uint64),
+ ("filetype", ctypes.c_int), # LIBMTP_filetype_t enum
+ ("next", ctypes.POINTER(LIBMTP_Track))]
+
+class LIBMTP_Playlist(ctypes.Structure):
+ """
+ LIBMTP_Playlist
+ Contains the ctypes structure for LIBMTP_playlist_t
+ """
+
+ def __init__(self):
+ self.tracks = ctypes.pointer(ctypes.c_uint32(0))
+ self.no_tracks = ctypes.c_uint32(0)
+ def __repr__(self):
+ return "%s (%s)" % (self.name, self.playlist_id)
+
+ def __iter__(self):
+ """
+ This allows the playlist object to act like a list with
+ a generator.
+ """
+ for track in xrange(self.no_tracks):
+ yield self.tracks[track]
+
+ def __getitem__(self, key):
+ """
+ This allows the playlist to return tracks like a list
+ """
+
+ if (key > (self.no_tracks - 1)):
+ raise IndexError
+
+ return self.tracks[key]
+
+ def __setitem__(self, key, value):
+ """
+ This allows the user to manipulate the playlist like a
+ list. However, this will only modify existing objects,
+ you can't try to set a key outside of the current size.
+ """
+
+ if (key > (self.no_tracks - 1)):
+ raise IndexError
+
+ self.tracks[key] = value
+
+ def __delitem__(self, key):
+ """
+ This allows the user to delete an object
+ from the playlist
+ """
+
+ if (key > (self.no_tracks - 1)):
+ raise IndexError
+
+ for i in range(key, (self.no_tracks - 1)):
+ self.tracks[i] = self.tracks[i + 1]
+
+ self.no_tracks -= 1
+
+ def append(self, value):
+ """
+ This function appends a track to the end of the tracks
+ list.
+ """
+ if (self.tracks == None):
+ self.tracks = ctypes.pointer(ctypes.c_uint32(0))
+
+ self.no_tracks += 1
+ self.tracks[(self.no_tracks - 1)] = value
+
+ def __len__(self):
+ """
+ This returns the number of tracks in the playlist
+ """
+
+ return self.no_tracks
+
+LIBMTP_Playlist._fields_ = [("playlist_id", ctypes.c_uint32),
+ ("parent_id", ctypes.c_uint32),
+ ("storage_id", ctypes.c_uint32),
+ ("name", ctypes.c_char_p),
+ ("tracks", ctypes.POINTER(ctypes.c_uint32)),
+ ("no_tracks", ctypes.c_uint32),
+ ("next", ctypes.POINTER(LIBMTP_Playlist))]
+
+class LIBMTP_Folder(ctypes.Structure):
+ """
+ LIBMTP_Folder
+ Contains the ctypes structure for LIBMTP_folder_t
+ """
+
+ def __repr__(self):
+ return "%s (%s)" % (self.name, self.folder_id)
+
+LIBMTP_Folder._fields_ = [("folder_id", ctypes.c_uint32),
+ ("parent_id", ctypes.c_uint32),
+ ("storage_id", ctypes.c_uint32),
+ ("name", ctypes.c_char_p),
+ ("sibling", ctypes.POINTER(LIBMTP_Folder)),
+ ("child", ctypes.POINTER(LIBMTP_Folder))]
+
+# Abstracted from libmtp's LIBMTP_filetype_t. This must be kept in sync.
+# first checked in 0.2.6.1
+# last checked in version 1.1.6
+LIBMTP_Filetype = {
+ "WAV": ctypes.c_int(0),
+ "MP3": ctypes.c_int(1),
+ "WMA": ctypes.c_int(2),
+ "OGG": ctypes.c_int(3),
+ "AUDIBLE": ctypes.c_int(4),
+ "MP4": ctypes.c_int(5),
+ "UNDEF_AUDIO": ctypes.c_int(6),
+ "WMV": ctypes.c_int(7),
+ "AVI": ctypes.c_int(8),
+ "MPEG": ctypes.c_int(9),
+ "ASF": ctypes.c_int(10),
+ "QT": ctypes.c_int(11),
+ "UNDEF_VIDEO": ctypes.c_int(12),
+ "JPEG": ctypes.c_int(13),
+ "JFIF": ctypes.c_int(14),
+ "TIFF": ctypes.c_int(15),
+ "BMP": ctypes.c_int(16),
+ "GIF": ctypes.c_int(17),
+ "PICT": ctypes.c_int(18),
+ "PNG": ctypes.c_int(19),
+ "VCALENDAR1": ctypes.c_int(20),
+ "VCALENDAR2": ctypes.c_int(21),
+ "VCARD2": ctypes.c_int(22),
+ "VCARD3": ctypes.c_int(23),
+ "WINDOWSIMAGEFORMAT": ctypes.c_int(24),
+ "WINEXEC": ctypes.c_int(25),
+ "TEXT": ctypes.c_int(26),
+ "HTML": ctypes.c_int(27),
+ "FIRMWARE": ctypes.c_int(28),
+ "AAC": ctypes.c_int(29),
+ "MEDIACARD": ctypes.c_int(30),
+ "FLAC": ctypes.c_int(31),
+ "MP2": ctypes.c_int(32),
+ "M4A": ctypes.c_int(33),
+ "DOC": ctypes.c_int(34),
+ "XML": ctypes.c_int(35),
+ "XLS": ctypes.c_int(36),
+ "PPT": ctypes.c_int(37),
+ "MHT": ctypes.c_int(38),
+ "JP2": ctypes.c_int(39),
+ "JPX": ctypes.c_int(40),
+ "ALBUM": ctypes.c_int(41),
+ "PLAYLIST": ctypes.c_int(42),
+ "UNKNOWN": ctypes.c_int(43),
+}
+
+# Synced from libmtp 0.2.6.1's libmtp.h. Must be kept in sync.
+LIBMTP_Error_Number = {
+ "NONE": ctypes.c_int(0),
+ "GENERAL": ctypes.c_int(1),
+ "PTP_LAYER": ctypes.c_int(2),
+ "USB_LAYER": ctypes.c_int(3),
+ "MEMORY_ALLOCATION": ctypes.c_int(4),
+ "NO_DEVICE_ATTACHED": ctypes.c_int(5),
+ "STORAGE_FULL": ctypes.c_int(6),
+ "CONNECTING": ctypes.c_int(7),
+ "CANCELLED": ctypes.c_int(8),
+}
+
+# ----------
+# End Data Model Definitions
+# ----------
+
+# ----------
+# Type Definitions
+# ----------
+_libmtp.LIBMTP_Detect_Raw_Devices.restype = ctypes.c_int # actually LIBMTP_Error_Number enum
+_libmtp.LIBMTP_Get_Friendlyname.restype = ctypes.c_char_p
+_libmtp.LIBMTP_Get_Serialnumber.restype = ctypes.c_char_p
+_libmtp.LIBMTP_Get_Modelname.restype = ctypes.c_char_p
+_libmtp.LIBMTP_Get_Manufacturername.restype = ctypes.c_char_p
+_libmtp.LIBMTP_Get_Deviceversion.restype = ctypes.c_char_p
+_libmtp.LIBMTP_Get_Filelisting_With_Callback.restype = ctypes.POINTER(LIBMTP_File)
+_libmtp.LIBMTP_Get_Tracklisting_With_Callback.restype = ctypes.POINTER(LIBMTP_Track)
+_libmtp.LIBMTP_Get_Filetype_Description.restype = ctypes.c_char_p
+_libmtp.LIBMTP_Get_Filemetadata.restype = ctypes.POINTER(LIBMTP_File)
+_libmtp.LIBMTP_Get_Trackmetadata.restype = ctypes.POINTER(LIBMTP_Track)
+_libmtp.LIBMTP_Get_First_Device.restype = ctypes.POINTER(LIBMTP_MTPDevice)
+_libmtp.LIBMTP_Get_Playlist_List.restype = ctypes.POINTER(LIBMTP_Playlist)
+_libmtp.LIBMTP_Get_Playlist.restype = ctypes.POINTER(LIBMTP_Playlist)
+_libmtp.LIBMTP_Get_Folder_List.restype = ctypes.POINTER(LIBMTP_Folder)
+_libmtp.LIBMTP_Find_Folder.restype = ctypes.POINTER(LIBMTP_Folder)
+_libmtp.LIBMTP_Get_Errorstack.restype = ctypes.POINTER(LIBMTP_Error)
+
+_libmtp.LIBMTP_Open_Raw_Device.restype = ctypes.POINTER(LIBMTP_MTPDevice)
+_libmtp.LIBMTP_Open_Raw_Device.argtypes = [ctypes.POINTER(LIBMTP_RawDevice)]
+
+# This is for callbacks with the type of LIBMTP_progressfunc_t
+Progressfunc = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_uint64, ctypes.c_uint64)
+
+# ----------
+# End Type Definitions
+# ----------
+
+class MTP:
+ """
+ The MTP object
+ This is the main wrapper around libmtp
+ """
+
+ def __init__(self):
+ """
+ Initializes the MTP object
+
+ @rtype: None
+ @return: None
+ """
+
+ self.mtp = _libmtp
+ self.mtp.LIBMTP_Init()
+ self.device = None
+
+ def debug_stack(self):
+ """
+ Checks if __DEBUG__ is set, if so, prints and clears the
+ errorstack.
+
+ @rtype: None
+ @return: None
+ """
+
+ if __DEBUG__:
+ self.mtp.LIBMTP_Dump_Errorstack()
+ #self.mtp.LIBMTP_Clear_Errorstack()
+
+ def detect_devices(self):
+ """
+ Detect if any MTP devices are connected
+
+ @rtype: None
+ @return: a list of LIBMTP_RawDevice instances for devices found
+
+ """
+
+ devlist = []
+ device = LIBMTP_RawDevice()
+ devices = ctypes.pointer(device)
+ numdevs = ctypes.c_int(0)
+ err = self.mtp.LIBMTP_Detect_Raw_Devices(ctypes.byref(devices),
+ ctypes.byref(numdevs))
+ if err == LIBMTP_Error_Number['NO_DEVICE_ATTACHED']:
+ return devlist
+ elif err == LIBMTP_Error_Number['STORAGE_FULL']:
+ # ignore this, we're just trying to detect here, not do anything else
+ pass
+ elif err == LIBMTP_Error_Number['CONNECTING']:
+ raise AlreadyConnected('CONNECTING')
+ elif err == LIBMTP_Error_Number['GENERAL']:
+ raise CommandFailed('GENERAL')
+ elif err == LIBMTP_Error_Number['PTP_LAYER']:
+ raise CommandFailed('PTP_LAYER')
+ elif err == LIBMTP_Error_Number['USB_LAYER']:
+ raise CommandFailed('USB_LAYER')
+ elif err == LIBMTP_Error_Number['MEMORY_ALLOCATION']:
+ raise CommandFailed('MEMORY_ALLOCATION')
+ elif err == LIBMTP_Error_Number['CANCELLED']:
+ raise CommandFailed('CANCELLED')
+ if numdevs.value == 0:
+ return devlist
+ for i in range(numdevs.value):
+ devlist.append(devices[i])
+ return devlist
+
+ def connect(self):
+ """
+ Initializes the MTP connection to the device
+
+ @rtype: None
+ @return: None
+
+ """
+
+ if (self.device != None):
+ raise AlreadyConnected
+
+ self.device = self.mtp.LIBMTP_Get_First_Device()
+
+ if not self.device:
+ self.device = None
+ raise NoDeviceConnected
+
+ def disconnect(self):
+ """
+ Disconnects the MTP device and deletes the self.device object
+
+ @rtype: None
+ @return: None
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ self.mtp.LIBMTP_Release_Device(self.device)
+ del self.device
+ self.device = None
+
+ def get_devicename(self):
+ """
+ Returns the connected device's 'friendly name' (or
+ known as the owner name)
+
+ @rtype: string
+ @return: The connected device's 'friendly name'
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ return self.mtp.LIBMTP_Get_Friendlyname(self.device)
+
+ def set_devicename(self, name):
+ """
+ Changes the connected device's 'friendly name' to name
+
+ @type name: string
+ @param name: The name to change the connected device's
+ 'friendly name' to
+ @rtype: None
+ @return: None
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ ret = self.mtp.LIBMTP_Set_Friendlyname(self.device, name)
+ if (ret != 0):
+ self.debug_stack()
+ raise CommandFailed
+
+ def get_serialnumber(self):
+ """
+ Returns the connected device's serial number
+
+ @rtype: string
+ @return: The connected device's serial number
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ return self.mtp.LIBMTP_Get_Serialnumber(self.device)
+
+ def get_manufacturer(self):
+ """
+ Return the connected device's manufacturer
+
+ @rtype: string
+ @return: The connected device's manufacturer
+ """
+ if (self.device == None):
+ raise NotConnected
+
+ return self.mtp.LIBMTP_Get_Manufacturername(self.device)
+
+ def get_batterylevel(self):
+ """
+ Returns the connected device's maximum and current
+ battery levels
+
+ @rtype: tuple
+ @return: The connected device's maximum and current
+ battery levels ([0] is maximum, [1] is current)
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ maximum_level = ctypes.c_uint8()
+ current_level = ctypes.c_uint8()
+
+ ret = self.mtp.LIBMTP_Get_Batterylevel(self.device, \
+ ctypes.byref(maximum_level), ctypes.byref(current_level))
+
+ if (ret != 0):
+ raise CommandFailed
+
+ return (maximum_level.value, current_level.value)
+
+ def get_modelname(self):
+ """
+ Returns the connected device's model name (such
+ as "Zen V Plus")
+
+ @rtype: string
+ @return: The connected device's model name
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ return self.mtp.LIBMTP_Get_Modelname(self.device)
+
+ def get_deviceversion(self):
+ """
+ Returns the connected device's version (such as
+ firmware/hardware version)
+
+ @rtype: string
+ @return: Returns the connect device's version
+ information
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ return self.mtp.LIBMTP_Get_Deviceversion(self.device)
+
+ def get_filelisting(self, callback=None):
+ """
+ Returns the connected device's file listing as a tuple,
+ containing L{LIBMTP_File} objects.
+
+ @type callback: function or None
+ @param callback: The function provided to libmtp to
+ receive callbacks from ptp. Callback must take two
+ arguments, total and sent (in bytes)
+ @rtype: tuple
+ @return: Returns the connect device file listing tuple
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ if (callback != None):
+ callback = Progressfunc(callback)
+
+ files = self.mtp.LIBMTP_Get_Filelisting_With_Callback(self.device, callback, None)
+ ret = []
+ next = files
+
+ while next:
+ ret.append(next.contents)
+ if (next.contents.next == None):
+ break
+ next = next.contents.next
+
+ return ret
+
+ def get_filetype_description(self, filetype):
+ """
+ Returns the description of the filetype
+
+ @type filetype: int
+ @param filetype: The MTP filetype integer
+ @rtype: string
+ @return: The file type information
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ return self.mtp.LIBMTP_Get_Filetype_Description(filetype)
+
+ def get_file_metadata(self, file_id):
+ """
+ Returns the file metadata from the connected device
+
+ As per the libmtp documentation, calling this function
+ repeatedly is not recommended, as it is slow and creates
+ a large amount of USB traffic.
+
+ @type file_id: int
+ @param file_id: The unique numeric file id
+ @rtype: LIBMTP_File
+ @return: The file metadata
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ ret = self.mtp.LIBMTP_Get_Filemetadata(self.device, file_id)
+
+ if (not hasattr(ret, 'contents')):
+ raise ObjectNotFound
+
+ return ret.contents
+
+ def get_tracklisting(self, callback=None):
+ """
+ Returns tracks from the connected device
+
+ @type callback: function or None
+ @param callback: The function provided to libmtp to
+ receive callbacks from ptp. Callback must take two
+ arguments, total and sent (in bytes)
+ @rtype: tuple
+ @return: Returns a tuple full of L{LIBMTP_Track} objects
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ if (callback != None):
+ callback = Progressfunc(callback)
+
+ tracks = self.mtp.LIBMTP_Get_Tracklisting_With_Callback(self.device, callback, None)
+ ret = []
+ next = tracks
+
+ while next:
+ ret.append(next.contents)
+ if (next.contents.next == None):
+ break
+ next = next.contents.next
+
+ return ret
+
+ def get_track_metadata(self, track_id):
+ """
+ Returns the track metadata
+
+ As per the libmtp documentation, calling this function repeatedly is not
+ recommended, as it is slow and creates a large amount of USB traffic.
+
+ @type track_id: int
+ @param track_id: The unique numeric track id
+ @rtype: L{LIBMTP_Track}
+ @return: The track metadata
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ ret = self.mtp.LIBMTP_Get_Trackmetadata(self.device, track_id)
+
+ if (not hasattr(ret, 'contents')):
+ raise ObjectNotFound
+
+ return ret.contents
+
+ def get_file_to_file(self, file_id, target, callback=None):
+ """
+ Downloads the file from the connected device and stores it at the
+ target location
+
+ @type file_id: int
+ @param file_id: The unique numeric file id
+ @type target: str
+ @param target: The location to place the file
+ @type callback: function or None
+ @param callback: The function provided to libmtp to
+ receive callbacks from ptp. Callback must take two
+ arguments, total and sent (in bytes)
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ if (callback != None):
+ callback = Progressfunc(callback)
+
+ ret = self.mtp.LIBMTP_Get_File_To_File(self.device, file_id, target, callback, None)
+
+ if (ret != 0):
+ self.debug_stack()
+ raise CommandFailed
+
+ def get_track_to_file(self, track_id, target, callback=None):
+ """
+ Downloads the track from the connected device and stores it at
+ the target location
+
+ @type track_id: int
+ @param track_id: The unique numeric track id
+ @type target: str
+ @param target: The location to place the track
+ @type callback: function or None
+ @param callback: The function provided to libmtp to
+ receive callbacks from ptp. Callback must take two
+ arguments, total and sent (in bytes)
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ if (callback != None):
+ callback = Progressfunc(callback)
+
+ ret = self.mtp.LIBMTP_Get_Track_To_File(self.device, track_id, target, callback, None)
+
+ if (ret != 0):
+ self.debug_stack()
+ raise CommandFailed
+
+ def find_filetype(self, filename):
+ """
+ Attempts to guess the filetype off the filename. Kind of
+ inaccurate and should be trusted with a grain of salt. It
+ works in most situations, though.
+
+ @type filename: str
+ @param filename: The filename to attempt to guess from
+ @rtype: int
+ @return: The integer of the Filetype
+ """
+
+ fileext = filename.decode('utf-8').lower().split(".")[-1]
+
+ if (fileext == "wav" or fileext == "wave"):
+ return LIBMTP_Filetype["WAV"]
+ elif (fileext == "mp3"):
+ return LIBMTP_Filetype["MP3"]
+ elif (fileext == "wma"):
+ return LIBMTP_Filetype["WMA"]
+ elif (fileext == "ogg"):
+ return LIBMTP_Filetype["OGG"]
+ elif (fileext == "mp4"):
+ return LIBMTP_Filetype["MP4"]
+ elif (fileext == "wmv"):
+ return LIBMTP_Filetype["WMV"]
+ elif (fileext == "avi"):
+ return LIBMTP_Filetype["AVI"]
+ elif (fileext == "mpeg" or fileext == "mpg"):
+ return LIBMTP_Filetype["MPEG"]
+ elif (fileext == "asf"):
+ return LIBMTP_Filetype["ASF"]
+ elif (fileext == "qt" or fileext == "mov"):
+ return LIBMTP_Filetype["QT"]
+ elif (fileext == "jpeg" or fileext == "jpg"):
+ return LIBMTP_Filetype["JPEG"]
+ elif (fileext == "jfif"):
+ return LIBMTP_Filetype["JFIF"]
+ elif (fileext == "tif" or fileext == "tiff"):
+ return LIBMTP_Filetype["TIFF"]
+ elif (fileext == "bmp"):
+ return LIBMTP_Filetype["BMP"]
+ elif (fileext == "gif"):
+ return LIBMTP_Filetype["GIF"]
+ elif (fileext == "pic" or fileext == "pict"):
+ return LIBMTP_Filetype["PICT"]
+ elif (fileext == "png"):
+ return LIBMTP_Filetype["PNG"]
+ elif (fileext == "wmf"):
+ return LIBMTP_Filetype["WINDOWSIMAGEFORMAT"]
+ elif (fileext == "ics"):
+ return LIBMTP_Filetype["VCALENDAR2"]
+ elif (fileext == "exe" or fileext == "com" or fileext == "bat"\
+ or fileext == "dll" or fileext == "sys"):
+ return LIBMTP_Filetype["WINEXEC"]
+ elif (fileext == "aac"):
+ return LIBMTP_Filetype["AAC"]
+ elif (fileext == "mp2"):
+ return LIBMTP_Filetype["MP2"]
+ elif (fileext == "flac"):
+ return LIBMTP_Filetype["FLAC"]
+ elif (fileext == "m4a"):
+ return LIBMTP_Filetype["M4A"]
+ elif (fileext == "doc"):
+ return LIBMTP_Filetype["DOC"]
+ elif (fileext == "xml"):
+ return LIBMTP_Filetype["XML"]
+ elif (fileext == "xls"):
+ return LIBMTP_Filetype["XLS"]
+ elif (fileext == "ppt"):
+ return LIBMTP_Filetype["PPT"]
+ elif (fileext == "mht"):
+ return LIBMTP_Filetype["MHT"]
+ elif (fileext == "jp2"):
+ return LIBMTP_Filetype["JP2"]
+ elif (fileext == "jpx"):
+ return LIBMTP_Filetype["JPX"]
+ else:
+ return LIBMTP_Filetype["UNKNOWN"]
+
+ def send_file_from_file(self, source, target, callback=None):
+ """
+ Sends a file from the filesystem to the connected device
+ and stores it at the target filename inside the parent.
+
+ This will attempt to "guess" the filetype with
+ find_filetype()
+
+ @type source: str
+ @param source: The path on the filesystem where the file resides
+ @type target: str
+ @param target: The target filename on the device
+ @type callback: function or None
+ @param callback: The function provided to libmtp to
+ receive callbacks from ptp. Callback function must
+ take two arguments, sent and total (in bytes)
+ @rtype: int
+ @return: The object ID of the new file
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ if (os.path.isfile(source) == False):
+ raise IOError
+
+ if (callback != None):
+ callback = Progressfunc(callback)
+
+ metadata = LIBMTP_File(filename=target, \
+ filetype=self.find_filetype(source), \
+ filesize=os.stat(source).st_size)
+
+ ret = self.mtp.LIBMTP_Send_File_From_File(self.device, source, \
+ ctypes.pointer(metadata), callback, None)
+
+ if (ret != 0):
+ self.debug_stack()
+ raise CommandFailed
+
+ return metadata.item_id
+
+ def send_track_from_file(self, source, target, metadata, callback=None):
+ """
+ Sends a track from the filesystem to the connected
+ device
+
+ @type source: str
+ @param source: The path where the track resides
+ @type target: str
+ @param target: The target filename on the device
+ @type metadata: LIBMTP_Track
+ @param metadata: The track metadata
+ @type callback: function or None
+ @param callback: The function provided to libmtp to
+ receive callbacks from ptp. Callback function must
+ take two arguments, sent and total (in bytes)
+ @rtype: int
+ @return: The object ID of the new track
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ if (os.path.exists(source) == None):
+ raise IOError
+
+ if callback:
+ callback = Progressfunc(callback)
+
+ metadata.filename = target
+ metadata.filetype = self.find_filetype(source)
+ metadata.filesize = os.stat(source).st_size
+
+ ret = self.mtp.LIBMTP_Send_Track_From_File(self.device, source, \
+ ctypes.pointer(metadata), callback, None)
+
+ if (ret != 0):
+ self.debug_stack()
+ raise CommandFailed
+
+ return metadata.item_id
+
+ def get_freespace(self):
+ """
+ Returns the amount of free space on the connected device
+ @rtype: long
+ @return: The amount of free storage in bytes
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ self.mtp.LIBMTP_Get_Storage(self.device, 0)
+ return self.device.contents.storage.contents.FreeSpaceInBytes
+
+ def get_totalspace(self):
+ """
+ Returns the total space on the connected device
+ @rtype: long
+ @return: The amount of total storage in bytes
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ self.mtp.LIBMTP_Get_Storage(self.device, 0)
+ return self.device.contents.storage.contents.MaxCapacity
+
+ def get_usedspace(self):
+ """
+ Returns the amount of used space on the connected device
+
+ @rtype: long
+ @return: The amount of used storage in bytes
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ self.mtp.LIBMTP_Get_Storage(self.device, 0)
+ storage = self.device.contents.storage.contents
+ return (storage.MaxCapacity - storage.FreeSpaceInBytes)
+
+ def get_usedspace_percent(self):
+ """
+ Returns the amount of used space as a percentage
+
+ @rtype: float
+ @return: The percentage of used storage
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ self.mtp.LIBMTP_Get_Storage(self.device, 0)
+ storage = self.device.contents.storage.contents
+
+ # Why don't we call self.get_totalspace/self.get_usedspace
+ # here? That would require 3 *more* calls to
+ # LIBMTP_Get_Storage
+ usedspace = storage.MaxCapacity - storage.FreeSpaceInBytes
+ return ((float(usedspace) / float(storage.MaxCapacity)) * 100)
+
+ def delete_object(self, object_id):
+ """
+ Deletes the object off the connected device.
+
+ @type object_id: int
+ @param object_id: The unique object identifier
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ ret = self.mtp.LIBMTP_Delete_Object(self.device, object_id)
+
+ if (ret != 0):
+ self.debug_stack()
+ raise CommandFailed
+
+ def get_playlists(self):
+ """
+ Returns a tuple filled with L{LIBMTP_Playlist} objects
+ from the connected device.
+
+ The main gotcha of this function is that the tracks
+ variable of LIBMTP_Playlist isn't iterable (without
+ segfaults), so, you have to iterate over the no_tracks
+ (through range or xrange) and access it that way (i.e.
+ tracks[track_id]). Kind of sucks.
+
+ @rtype: tuple
+ @return: Tuple filled with LIBMTP_Playlist objects
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ playlists = self.mtp.LIBMTP_Get_Playlist_List(self.device)
+ ret = []
+ next = playlists
+
+ while next:
+ ret.append(next.contents)
+ if (next.contents.next == None):
+ break
+ next = next.contents.next
+
+ return ret
+
+ def get_playlist(self, playlist_id):
+ """
+ Returns a L{LIBMTP_Playlist} object of the requested
+ playlist_id from the connected device
+
+ @type playlist_id: int
+ @param playlist_id: The unique playlist identifier
+ @rtype: LIBMTP_Playlist
+ @return: The playlist object
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ try:
+ ret = self.mtp.LIBMTP_Get_Playlist(self.device, playlist_id).contents
+ except ValueError:
+ raise ObjectNotFound
+
+ return ret
+
+ def create_new_playlist(self, metadata):
+ """
+ Creates a new playlist based on the metadata object
+ passed.
+
+ @type metadata: LIBMTP_Playlist
+ @param metadata: A LIBMTP_Playlist object describing
+ the playlist
+ @rtype: int
+ @return: The object ID of the new playlist
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ ret = self.mtp.LIBMTP_Create_New_Playlist(self.device, ctypes.pointer(metadata))
+
+ if (ret != 0):
+ self.debug_stack()
+ raise CommandFailed
+
+ return metadata.playlist_id
+
+ def update_playlist(self, metadata):
+ """
+ Updates a playlist based on the supplied metadata.
+
+ When updating the tracks field in a playlist, this
+ function will replace the playlist's tracks with
+ the tracks supplied in the metadata object. This
+ means that the previous tracks in the playlist
+ will be overwritten.
+
+ @type metadata: LIBMTP_Playlist
+ @param metadata: A LIBMTP_Playlist object describing
+ the updates to the playlist.
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ ret = self.mtp.LIBMTP_Update_Playlist(self.device, ctypes.pointer(metadata))
+
+ if (ret != 0):
+ self.debug_stack()
+ raise CommandFailed
+
+ def get_folder_list(self):
+ """
+ Returns a pythonic dict of the folders on the
+ device.
+
+ @rtype: dict
+ @return: A dict of the folders on the device where
+ the folder ID is the key.
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ folders = self.mtp.LIBMTP_Get_Folder_List(self.device)
+ next = folders
+ # List of folders, key being the folder ID
+ ret = {}
+ # Iterate over the folders to grab the first-level parents
+ while True:
+ next = next.contents
+ scanned = True
+
+ # Check if this ID exists, if not, add it
+ # and trigger a scan of the children
+ if not (ret.has_key(next.folder_id)):
+ ret[next.folder_id] = next
+ scanned = False
+
+ if ((scanned == False) and (next.child)):
+ ## Scan the children
+ next = next.child
+
+ elif (next.sibling):
+ ## Scan the siblings
+ next = next.sibling
+
+ elif (next.parent_id != 0):
+ ## If we have no children/siblings to visit,
+ ## and we aren't at the parent, go back to
+ ## the parent.
+ next = self.mtp.LIBMTP_Find_Folder(folders, int(next.parent_id))
+
+ else:
+ ## We have scanned everything, let's go home.
+ break
+
+ return ret
+
+ def get_parent_folders(self):
+ """
+ Returns a list of only the parent folders.
+ @rtype: list
+ @return: Returns a list of the parent folders
+ """
+
+ if (self.device == None):
+ raise NotConnected
+ folders = self.mtp.LIBMTP_Get_Folder_List(self.device)
+ next = folders
+ # A temporary holding space, this makes checking folder
+ # IDs easier
+ tmp = {}
+
+ while True:
+ next = next.contents
+ ## Check if this folder is in the dict
+ if not (tmp.has_key(next.folder_id)):
+ tmp[next.folder_id] = next
+
+ # Check for siblings
+ if (next.sibling):
+ ## Scan the sibling
+ next = next.sibling
+ else:
+ ## We're done here.
+ break
+
+ ## convert the dict into a list
+ ret = []
+ for key in tmp:
+ ret.append(tmp[key])
+
+ return ret
+
+ def create_folder(self, name, parent=0, storage=0):
+ """
+ This creates a new folder in the parent. If the parent
+ is 0, it will go in the main directory.
+
+ @type name: str
+ @param name: The name for the folder
+ @type parent: int
+ @param parent: The parent ID or 0 for main directory
+ @type storage: int
+ @param storage: The storage id or 0 to create the new folder
+ on the primary storage
+ @rtype: int
+ @return: Returns the object ID of the new folder
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ ret = self.mtp.LIBMTP_Create_Folder(self.device, name, parent, storage)
+
+ if (ret == 0):
+ self.debug_stack()
+ raise CommandFailed
+
+ return ret
+
+ def get_errorstack(self):
+ """
+ Returns the connected device's errorstack from
+ LIBMTP.
+ @rtype: L{LIBMTP_Error}
+ @return: An array of LIBMTP_Errors.
+ """
+
+ if (self.device == None):
+ raise NotConnected
+
+ ret = self.mtp.LIBMTP_Get_Errorstack(self.device)
+
+ if (ret != 0):
+ raise CommandFailed
+
+ return ret
diff --git a/tools/file2carray.py b/tools/file2carray.py
new file mode 100644
index 000000000..7150364bf
--- /dev/null
+++ b/tools/file2carray.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+import argparse
+import random
+import os
+import sys
+import time
+import subprocess
+from pathlib import Path
+from multiprocessing import Pool
+from weakref import finalize
+
+
+def print_carray(f, payload):
+ while len(payload) > 0:
+ f.write('\n ')
+ f.write(', '.join('0x{:02x}'.format(x) for x in payload[0:16]))
+ f.write(',')
+ payload = payload[16:]
+ f.write('\n')
+
+
+def main():
+ parser = argparse.ArgumentParser(description='Convert binary files to C array format')
+ parser.add_argument('files', nargs='+', help='Binary files to convert')
+ args = parser.parse_args()
+
+ files = args.files
+ for fin_name in files:
+ if not os.path.isfile(fin_name):
+ print(f"File {fin_name} does not exist")
+ continue
+
+ with open(fin_name, 'rb') as fin:
+ contents = fin.read()
+ fout_name = fin_name + '.h'
+ with open(fout_name, 'w') as fout:
+ print(f"Converting {fin_name} to {fout_name}")
+ fout.write(f'enum {{ BINDATA_LEN = {len(contents)} }};\n')
+ fout.write(f'const size_t bindata_len = BINDATA_LEN;\n')
+ fout.write(f'const uint8_t bindata[] __attribute__((aligned(16))) = {{')
+ print_carray(fout, contents)
+ fout.write('};\n')
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/tools/get_deps.py b/tools/get_deps.py
index ce838e427..36ed98a62 100755
--- a/tools/get_deps.py
+++ b/tools/get_deps.py
@@ -59,7 +59,7 @@ deps_optional = {
'a1bdae309a14ec95a4f64a96d3315a4f89c397c6',
'kinetis_k kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx imxrt'],
'hw/mcu/raspberry_pi/Pico-PIO-USB': ['https://github.com/sekigon-gonnoc/Pico-PIO-USB.git',
- '3c1eec341a5232640e4c00628b889b641af34b28',
+ '675543bcc9baa8170f868ab7ba316d418dbcf41f',
'rp2040'],
'hw/mcu/renesas/fsp': ['https://github.com/renesas/fsp.git',
'edcc97d684b6f716728a60d7a6fea049d9870bd6',
@@ -74,62 +74,68 @@ deps_optional = {
'2ec2a1538362696118dc3fdf56f33dacaf8f4067',
'spresense'],
'hw/mcu/st/cmsis_device_c0': ['https://github.com/STMicroelectronics/cmsis_device_c0.git',
- 'fb56b1b70c73b74eacda2a4bcc36886444364ab3',
+ '517611273f835ffe95318947647bc1408f69120d',
'stm32c0'],
'hw/mcu/st/cmsis_device_f0': ['https://github.com/STMicroelectronics/cmsis_device_f0.git',
- '2fc25ee22264bc27034358be0bd400b893ef837e',
+ 'cbb5da5d48b4b5f2efacdc2f033be30f9d29889f',
'stm32f0'],
'hw/mcu/st/cmsis_device_f1': ['https://github.com/STMicroelectronics/cmsis_device_f1.git',
- '6601104a6397299b7304fd5bcd9a491f56cb23a6',
+ 'c8e9a4a4f16b6d2cb2a2083cbe5161025280fb22',
'stm32f1'],
'hw/mcu/st/cmsis_device_f2': ['https://github.com/STMicroelectronics/cmsis_device_f2.git',
- '182fcb3681ce116816feb41b7764f1b019ce796f',
+ '49321f1e4d2bd3e65687b37f2652a28ea7983674',
'stm32f2'],
'hw/mcu/st/cmsis_device_f3': ['https://github.com/STMicroelectronics/cmsis_device_f3.git',
- '5e4ee5ed7a7b6c85176bb70a9fd3c72d6eb99f1b',
+ '5558e64e3675a1e1fcb1c71f468c7c407c1b1134',
'stm32f3'],
'hw/mcu/st/cmsis_device_f4': ['https://github.com/STMicroelectronics/cmsis_device_f4.git',
- '2615e866fa48fe1ff1af9e31c348813f2b19e7ec',
+ '3c77349ce04c8af401454cc51f85ea9a50e34fc1',
'stm32f4'],
'hw/mcu/st/cmsis_device_f7': ['https://github.com/STMicroelectronics/cmsis_device_f7.git',
- '25b0463439303b7a38f0d27b161f7d2f3c096e79',
+ '2352e888e821aa0f4fe549bd5ea81d29c67a3222',
'stm32f7'],
'hw/mcu/st/cmsis_device_g0': ['https://github.com/STMicroelectronics/cmsis_device_g0.git',
- '3a23e1224417f3f2d00300ecd620495e363f2094',
+ 'f484fe852535f913a02ee79787eafa74dd7f9488',
'stm32g0'],
'hw/mcu/st/cmsis_device_g4': ['https://github.com/STMicroelectronics/cmsis_device_g4.git',
- 'ce822adb1dc552b3aedd13621edbc7fdae124878',
+ '7c39c32593b03764aaa57531588b8bf7cdd443a5',
'stm32g4'],
'hw/mcu/st/cmsis_device_h7': ['https://github.com/STMicroelectronics/cmsis_device_h7.git',
- '60dc2c913203dc8629dc233d4384dcc41c91e77f',
+ '45b818cab6ee2806e3a27c80e330957223424392',
'stm32h7'],
'hw/mcu/st/cmsis_device_h7rs': ['https://github.com/STMicroelectronics/cmsis_device_h7rs.git',
- '832649d1fd09bd901e9f68e979522e5c209ebf20',
+ '57ea11f70ebf1850e1048989d665c9070f0bb863',
'stm32h7rs'],
'hw/mcu/st/cmsis_device_h5': ['https://github.com/STMicroelectronics/cmsis_device_h5.git',
- 'cd2d1d579743de57b88ccaf61a968b9c05848ffc',
+ '5273b8f134ba65f5b8174c4141b711b5c0d295b2',
'stm32h5'],
'hw/mcu/st/cmsis_device_l0': ['https://github.com/STMicroelectronics/cmsis_device_l0.git',
- '69cd5999fd40ae6e546d4905b21635c6ca1bcb92',
+ '7b7ae8cd71437331e1d7824f157d00c7bb4a5044',
'stm32l0'],
'hw/mcu/st/cmsis_device_l1': ['https://github.com/STMicroelectronics/cmsis_device_l1.git',
- '7f16ec0a1c4c063f84160b4cc6bf88ad554a823e',
+ 'a23ade4ccf14012085fedf862e33a536ab7ed8be',
'stm32l1'],
'hw/mcu/st/cmsis_device_l4': ['https://github.com/STMicroelectronics/cmsis_device_l4.git',
- '6ca7312fa6a5a460b5a5a63d66da527fdd8359a6',
+ 'a2530753e86dd326a75467d28feb92e2ba7d0df2',
'stm32l4'],
'hw/mcu/st/cmsis_device_l5': ['https://github.com/STMicroelectronics/cmsis_device_l5.git',
- 'd922865fc0326a102c26211c44b8e42f52c1e53d',
+ '7d9a51481f0e6c376e62c3c849e6caf652c66482',
'stm32l5'],
'hw/mcu/st/cmsis_device_n6': ['https://github.com/STMicroelectronics/cmsis-device-n6.git',
- 'f818b00f775444e8d19ef6cad822534c345e054f',
+ '7bcdc944fbf7cf5928d3c1d14054ca13261d33ec',
'stm32n6'],
+ 'hw/mcu/st/cmsis-device-u0': ['https://github.com/STMicroelectronics/cmsis-device-u0.git',
+ 'e3a627c6a5bc4eb2388e1885a95cc155e1672253',
+ 'stm32u0'],
'hw/mcu/st/cmsis_device_u5': ['https://github.com/STMicroelectronics/cmsis_device_u5.git',
- '5ad9797c54ec3e55eff770fc9b3cd4a1aefc1309',
+ '6e67187dec98035893692ab2923914cb5f4e0117',
'stm32u5'],
'hw/mcu/st/cmsis_device_wb': ['https://github.com/STMicroelectronics/cmsis_device_wb.git',
- 'd6a7fa2e7de084f5e5e47f2ab88b022fe9b50e5a',
+ 'cda2cb9fc4a5232ab18efece0bb06b0b60910083',
'stm32wb'],
+ 'hw/mcu/st/cmsis-device-wba': ['https://github.com/STMicroelectronics/cmsis-device-wba.git',
+ '647d8522e5fd15049e9a1cc30ed19d85e5911eaf',
+ 'stm32wba'],
'hw/mcu/st/stm32-mfxstm32l152': ['https://github.com/STMicroelectronics/stm32-mfxstm32l152.git',
'7f4389efee9c6a655b55e5df3fceef5586b35f9b',
'stm32h7'],
@@ -137,62 +143,68 @@ deps_optional = {
'9918655bff176ac3046ccf378b5c7bbbc6a38d15',
'stm32h7rs stm32n6'],
'hw/mcu/st/stm32c0xx_hal_driver': ['https://github.com/STMicroelectronics/stm32c0xx_hal_driver.git',
- '41253e2f1d7ae4a4d0c379cf63f5bcf71fcf8eb3',
+ 'c283b143bef6bdaacf64240ee6f15eb61dad6125',
'stm32c0'],
'hw/mcu/st/stm32f0xx_hal_driver': ['https://github.com/STMicroelectronics/stm32f0xx_hal_driver.git',
- '0e95cd88657030f640a11e690a8a5186c7712ea5',
+ '94399697cb5eeaf8511b81b7f50dc62f0a5a3f6c',
'stm32f0'],
'hw/mcu/st/stm32f1xx_hal_driver': ['https://github.com/STMicroelectronics/stm32f1xx_hal_driver.git',
- '1dd9d3662fb7eb2a7f7d3bc0a4c1dc7537915a29',
+ '18074e3e5ecad0b380a5cf5a9131fe4b5ed1b2b7',
'stm32f1'],
'hw/mcu/st/stm32f2xx_hal_driver': ['https://github.com/STMicroelectronics/stm32f2xx_hal_driver.git',
- 'c75ace9b908a9aca631193ebf2466963b8ea33d0',
+ 'ae7b47fe41cf75ccaf65cbf8ee8749b18ba0e0f3',
'stm32f2'],
'hw/mcu/st/stm32f3xx_hal_driver': ['https://github.com/STMicroelectronics/stm32f3xx_hal_driver.git',
- '1761b6207318ede021706e75aae78f452d72b6fa',
+ 'e098c8c8ce6f426bcee7db3a37c0932ea881eb0b',
'stm32f3'],
'hw/mcu/st/stm32f4xx_hal_driver': ['https://github.com/STMicroelectronics/stm32f4xx_hal_driver.git',
- '04e99fbdabd00ab8f370f377c66b0a4570365b58',
+ 'b6f0ed3829f3829eb358a2e7417d80bba1a42db7',
'stm32f4'],
'hw/mcu/st/stm32f7xx_hal_driver': ['https://github.com/STMicroelectronics/stm32f7xx_hal_driver.git',
- 'f7ffdf6bf72110e58b42c632b0a051df5997e4ee',
+ 'e1446fa12ffda80ea1016faf349e45b2047fff12',
'stm32f7'],
'hw/mcu/st/stm32g0xx_hal_driver': ['https://github.com/STMicroelectronics/stm32g0xx_hal_driver.git',
- 'e911b12c7f67084d7f6b76157a4c0d4e2ec3779c',
+ 'a248a9e484d58943b46c68f6c49b4b276778bd59',
'stm32g0'],
'hw/mcu/st/stm32g4xx_hal_driver': ['https://github.com/STMicroelectronics/stm32g4xx_hal_driver.git',
- '8b4518417706d42eef5c14e56a650005abf478a8',
+ '10138a41749ea62d53ecab65b2bc2a950acc04d2',
'stm32g4'],
'hw/mcu/st/stm32h7xx_hal_driver': ['https://github.com/STMicroelectronics/stm32h7xx_hal_driver.git',
- 'd8461b980b59b1625207d8c4f2ce0a9c2a7a3b04',
+ 'dbfb749f229e1aa89e50b54229ca87766e180d2d',
'stm32h7'],
'hw/mcu/st/stm32h7rsxx_hal_driver': ['https://github.com/STMicroelectronics/stm32h7rsxx-hal-driver.git',
- '7ca2e07ca21bc66b53654e845b4c85c884343b60',
+ '9e83b95ae0f70faa067eddce2da617d180937f9b',
'stm32h7rs'],
'hw/mcu/st/stm32h5xx_hal_driver': ['https://github.com/STMicroelectronics/stm32h5xx_hal_driver.git',
- '2cf77de584196d619cec1b4586c3b9e2820a254e',
+ '3c84eaa6000ab620be01afbcfba2735389afe09b',
'stm32h5'],
'hw/mcu/st/stm32l0xx_hal_driver': ['https://github.com/STMicroelectronics/stm32l0xx_hal_driver.git',
- 'fbdacaf6f8c82a4e1eb9bd74ba650b491e97e17b',
+ '65da4cd8a10ad859ec8d9cd71f3f6c50735bd473',
'stm32l0'],
'hw/mcu/st/stm32l1xx_hal_driver': ['https://github.com/STMicroelectronics/stm32l1xx_hal_driver.git',
- '44efc446fa69ed8344e7fd966e68ed11043b35d9',
+ '54f0b7568ce2acb33d090c70c897ee32229c1d32',
'stm32l1'],
'hw/mcu/st/stm32l4xx_hal_driver': ['https://github.com/STMicroelectronics/stm32l4xx_hal_driver.git',
- 'aee3d5bf283ae5df87532b781bdd01b7caf256fc',
+ '3e039bbf62f54bbd834d578185521cff80596efe',
'stm32l4'],
'hw/mcu/st/stm32l5xx_hal_driver': ['https://github.com/STMicroelectronics/stm32l5xx_hal_driver.git',
- '675c32a75df37f39d50d61f51cb0dcf53f07e1cb',
+ '3340b9a597bcf75cc173345a90a74aa2a4a37510',
'stm32l5'],
'hw/mcu/st/stm32n6xx_hal_driver': ['https://github.com/STMicroelectronics/stm32n6xx-hal-driver.git',
- '49f9989d10cf6817d4b07ac01848956b46bd0fd6',
+ 'bc6c41f8f67d61b47af26695d0bf67762a000666',
'stm32n6'],
+ 'hw/mcu/st/stm32u0xx_hal_driver': ['https://github.com/STMicroelectronics/stm32u0xx-hal-driver.git',
+ 'cbfb5ac654256445237fd32b3587ac6a238d24f1',
+ 'stm32u0'],
'hw/mcu/st/stm32u5xx_hal_driver': ['https://github.com/STMicroelectronics/stm32u5xx_hal_driver.git',
- '4d93097a67928e9377e655ddd14622adc31b9770',
+ '2c5e2568fbdb1900a13ca3b2901fdd302cac3444',
'stm32u5'],
'hw/mcu/st/stm32wbxx_hal_driver': ['https://github.com/STMicroelectronics/stm32wbxx_hal_driver.git',
- '2c5f06638be516c1b772f768456ba637f077bac8',
+ 'd60dd46996876506f1d2e9abd6b1cc110c8004cd',
'stm32wb'],
+ 'hw/mcu/st/stm32wbaxx_hal_driver': ['https://github.com/STMicroelectronics/stm32wbaxx_hal_driver.git',
+ '9442fbb71f855ff2e64fbf662b7726beba511a24',
+ 'stm32wba'],
'hw/mcu/ti': ['https://github.com/hathach/ti_driver.git',
'143ed6cc20a7615d042b03b21e070197d473e6e5',
'msp430 msp432e4 tm4c'],
@@ -234,7 +246,7 @@ deps_optional = {
'imxrt kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx mm32 msp432e4 nrf saml2x '
'lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43 '
'stm32c0 stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32g0 stm32g4 stm32h5 '
- 'stm32h7 stm32h7rs stm32l0 stm32l1 stm32l4 stm32l5 stm32n6 stm32u5 stm32wb '
+ 'stm32h7 stm32h7rs stm32l0 stm32l1 stm32l4 stm32l5 stm32n6 stm32u0 stm32u5 stm32wb stm32wba'
'sam3x samd11 samd21 samd51 samd5x_e5x same5x same7x saml2x samg '
'tm4c '],
'lib/CMSIS_6': ['https://github.com/ARM-software/CMSIS_6.git',
diff --git a/tools/iar_gen.py b/tools/iar_gen.py
index 8d45659db..571febb2c 100755
--- a/tools/iar_gen.py
+++ b/tools/iar_gen.py
@@ -74,7 +74,7 @@ def ListPath(path, blacklist=[]):
print('</group>')
def List():
- ListPath('src', [ 'template.c', 'dcd_synopsys.c', 'dcd_esp32sx.c' ])
+ ListPath('src', [ 'template.c' ])
ListPath('lib/SEGGER_RTT')
if __name__ == "__main__":
diff --git a/tools/iar_template.ipcf b/tools/iar_template.ipcf
index 33a6ef045..2581a4702 100644
--- a/tools/iar_template.ipcf
+++ b/tools/iar_template.ipcf
@@ -58,6 +58,11 @@
<path>$TUSB_DIR$/src/class/msc/msc_device.h</path>
<path>$TUSB_DIR$/src/class/msc/msc_host.h</path>
</group>
+ <group name="src/class/mtp">
+ <path>$TUSB_DIR$/src/class/mtp/mtp_device.c</path>
+ <path>$TUSB_DIR$/src/class/mtp/mtp.h</path>
+ <path>$TUSB_DIR$/src/class/mtp/mtp_device.h</path>
+ </group>
<group name="src/class/net">
<path>$TUSB_DIR$/src/class/net/ecm_rndis_device.c</path>
<path>$TUSB_DIR$/src/class/net/ncm_device.c</path>
diff --git a/tools/make_release.py b/tools/make_release.py
index c1caf3300..488ad4901 100755
--- a/tools/make_release.py
+++ b/tools/make_release.py
@@ -2,7 +2,7 @@
import re
import gen_doc
-version = '0.18.0'
+version = '0.19.0'
print('version {}'.format(version))
ver_id = version.split('.')