summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2024-04-01 12:35:57 +0200
committerHiFiPhile <[email protected]>2024-04-01 12:35:57 +0200
commita1f01fcbe0fecb8d1783a105d7f22cba032dfced (patch)
treec8174923ef0bdd1016f55ed731df4c2df3257940 /examples
parentdd0350f5499de586a3405fdcec632f059fd7534e (diff)
parent82dfe95655c7b7564363a2d5cb2f5e32d431b223 (diff)
Merge remote-tracking branch 'upstream/master' into pr/1702
Diffstat (limited to 'examples')
-rw-r--r--examples/CMakeLists.txt11
-rw-r--r--examples/build_system/cmake/cpu/cortex-m0.cmake17
-rw-r--r--examples/build_system/cmake/cpu/cortex-m0plus.cmake17
-rw-r--r--examples/build_system/cmake/cpu/cortex-m23.cmake17
-rw-r--r--examples/build_system/cmake/cpu/cortex-m3.cmake16
-rw-r--r--examples/build_system/cmake/cpu/cortex-m33.cmake19
-rw-r--r--examples/build_system/cmake/cpu/cortex-m4.cmake23
-rw-r--r--examples/build_system/cmake/cpu/cortex-m7.cmake19
-rw-r--r--examples/build_system/cmake/toolchain/arm_gcc.cmake52
-rw-r--r--examples/build_system/cmake/toolchain/arm_iar.cmake32
-rw-r--r--examples/build_system/cmake/toolchain/set_flags.cmake17
-rw-r--r--examples/build_system/make/cpu/arm1176.mk9
-rw-r--r--examples/build_system/make/cpu/cortex-a53.mk12
-rw-r--r--examples/build_system/make/cpu/cortex-a72.mk12
-rw-r--r--examples/build_system/make/cpu/cortex-m0.mk14
-rw-r--r--examples/build_system/make/cpu/cortex-m0plus.mk14
-rw-r--r--examples/build_system/make/cpu/cortex-m23.mk14
-rw-r--r--examples/build_system/make/cpu/cortex-m3.mk17
-rw-r--r--examples/build_system/make/cpu/cortex-m33.mk19
-rw-r--r--examples/build_system/make/cpu/cortex-m4.mk13
-rw-r--r--examples/build_system/make/cpu/cortex-m7.mk19
-rw-r--r--examples/build_system/make/make.mk (renamed from examples/make.mk)111
-rw-r--r--examples/build_system/make/rules.mk (renamed from examples/rules.mk)156
-rw-r--r--examples/build_system/make/toolchain/arm_gcc.mk81
-rw-r--r--examples/build_system/make/toolchain/arm_gcc_rules.mk75
-rw-r--r--examples/build_system/make/toolchain/arm_iar.mk11
-rw-r--r--examples/build_system/make/toolchain/arm_iar_rules.mk44
-rw-r--r--examples/device/CMakeLists.txt7
-rw-r--r--examples/device/audio_4_channel_mic/CMakeLists.txt24
-rw-r--r--examples/device/audio_4_channel_mic/Makefile10
-rw-r--r--examples/device/audio_4_channel_mic/skip.txt4
-rw-r--r--examples/device/audio_4_channel_mic/src/main.c118
-rw-r--r--examples/device/audio_4_channel_mic/src/plot_audio_samples.py9
-rw-r--r--examples/device/audio_4_channel_mic/src/tusb_config.h19
-rw-r--r--examples/device/audio_4_channel_mic/src/usb_descriptors.c76
-rw-r--r--examples/device/audio_test/CMakeLists.txt19
-rw-r--r--examples/device/audio_test/Makefile5
-rw-r--r--examples/device/audio_test/skip.txt3
-rw-r--r--examples/device/audio_test/src/main.c21
-rw-r--r--examples/device/audio_test/src/plot_audio_samples.py5
-rw-r--r--examples/device/audio_test/src/tusb_config.h2
-rw-r--r--examples/device/audio_test/src/usb_descriptors.c74
-rw-r--r--examples/device/audio_test_multi_rate/CMakeLists.txt33
-rw-r--r--examples/device/audio_test_multi_rate/Makefile11
-rw-r--r--examples/device/audio_test_multi_rate/skip.txt4
-rw-r--r--examples/device/audio_test_multi_rate/src/main.c525
-rw-r--r--examples/device/audio_test_multi_rate/src/plot_audio_samples.py37
-rw-r--r--examples/device/audio_test_multi_rate/src/tusb_config.h141
-rw-r--r--examples/device/audio_test_multi_rate/src/usb_descriptors.c185
-rw-r--r--examples/device/audio_test_multi_rate/src/usb_descriptors.h102
-rw-r--r--examples/device/board_test/CMakeLists.txt54
-rw-r--r--examples/device/board_test/Makefile11
-rw-r--r--examples/device/board_test/src/CMakeLists.txt16
-rw-r--r--examples/device/board_test/src/main.c33
-rw-r--r--examples/device/board_test/src/tusb_config.h10
-rw-r--r--examples/device/cdc_dual_ports/CMakeLists.txt25
-rw-r--r--examples/device/cdc_dual_ports/Makefile5
-rw-r--r--examples/device/cdc_dual_ports/src/main.c80
-rw-r--r--examples/device/cdc_dual_ports/src/usb_descriptors.c78
-rw-r--r--examples/device/cdc_msc/CMakeLists.txt24
-rw-r--r--examples/device/cdc_msc/Makefile11
-rw-r--r--examples/device/cdc_msc/skip.txt3
-rw-r--r--examples/device/cdc_msc/src/main.c57
-rw-r--r--examples/device/cdc_msc/src/msc_disk.c4
-rw-r--r--examples/device/cdc_msc/src/usb_descriptors.c183
-rw-r--r--examples/device/cdc_msc_freertos/CMakeLists.txt35
-rw-r--r--examples/device/cdc_msc_freertos/Makefile30
-rw-r--r--examples/device/cdc_msc_freertos/skip.txt4
-rw-r--r--examples/device/cdc_msc_freertos/src/CMakeLists.txt35
-rw-r--r--examples/device/cdc_msc_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h44
-rw-r--r--examples/device/cdc_msc_freertos/src/main.c120
-rw-r--r--examples/device/cdc_msc_freertos/src/msc_disk.c12
-rw-r--r--examples/device/cdc_msc_freertos/src/tusb_config.h2
-rw-r--r--examples/device/cdc_msc_freertos/src/usb_descriptors.c65
-rw-r--r--examples/device/cdc_uac2/CMakeLists.txt38
-rw-r--r--examples/device/cdc_uac2/Makefile16
-rw-r--r--examples/device/cdc_uac2/README.md52
-rw-r--r--examples/device/cdc_uac2/src/cdc_app.c72
-rw-r--r--examples/device/cdc_uac2/src/common.h34
-rw-r--r--examples/device/cdc_uac2/src/main.c99
-rw-r--r--examples/device/cdc_uac2/src/tusb_config.h174
-rw-r--r--examples/device/cdc_uac2/src/uac2_app.c316
-rw-r--r--examples/device/cdc_uac2/src/usb_descriptors.c216
-rw-r--r--examples/device/cdc_uac2/src/usb_descriptors.h158
-rw-r--r--examples/device/dfu/CMakeLists.txt14
-rw-r--r--examples/device/dfu/Makefile10
-rw-r--r--examples/device/dfu/skip.txt1
-rw-r--r--examples/device/dfu/src/main.c10
-rw-r--r--examples/device/dfu/src/usb_descriptors.c66
-rw-r--r--examples/device/dfu_runtime/CMakeLists.txt14
-rw-r--r--examples/device/dfu_runtime/Makefile5
-rw-r--r--examples/device/dfu_runtime/src/main.c14
-rw-r--r--examples/device/dfu_runtime/src/usb_descriptors.c66
-rw-r--r--examples/device/dynamic_configuration/CMakeLists.txt14
-rw-r--r--examples/device/dynamic_configuration/Makefile5
-rw-r--r--examples/device/dynamic_configuration/skip.txt3
-rw-r--r--examples/device/dynamic_configuration/src/main.c12
-rw-r--r--examples/device/dynamic_configuration/src/msc_disk.c4
-rw-r--r--examples/device/dynamic_configuration/src/usb_descriptors.c83
-rw-r--r--examples/device/hid_boot_interface/CMakeLists.txt14
-rw-r--r--examples/device/hid_boot_interface/Makefile7
-rw-r--r--examples/device/hid_boot_interface/src/main.c18
-rw-r--r--examples/device/hid_boot_interface/src/usb_descriptors.c65
-rw-r--r--examples/device/hid_boot_interface/src/usb_descriptors.h2
-rw-r--r--examples/device/hid_composite/CMakeLists.txt14
-rw-r--r--examples/device/hid_composite/Makefile5
-rw-r--r--examples/device/hid_composite/src/main.c14
-rw-r--r--examples/device/hid_composite/src/usb_descriptors.c65
-rw-r--r--examples/device/hid_composite/src/usb_descriptors.h2
-rw-r--r--examples/device/hid_composite_freertos/CMakeLists.txt43
-rw-r--r--examples/device/hid_composite_freertos/Makefile28
-rw-r--r--examples/device/hid_composite_freertos/skip.txt4
-rw-r--r--examples/device/hid_composite_freertos/src/CMakeLists.txt34
-rw-r--r--examples/device/hid_composite_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h49
-rw-r--r--examples/device/hid_composite_freertos/src/main.c43
-rw-r--r--examples/device/hid_composite_freertos/src/tusb_config.h2
-rw-r--r--examples/device/hid_composite_freertos/src/usb_descriptors.c65
-rw-r--r--examples/device/hid_composite_freertos/src/usb_descriptors.h2
-rw-r--r--examples/device/hid_generic_inout/CMakeLists.txt14
-rw-r--r--examples/device/hid_generic_inout/Makefile5
-rw-r--r--examples/device/hid_generic_inout/hid_test.js3
-rw-r--r--examples/device/hid_generic_inout/hid_test.py4
-rw-r--r--examples/device/hid_generic_inout/src/main.c12
-rw-r--r--examples/device/hid_generic_inout/src/usb_descriptors.c67
-rw-r--r--examples/device/hid_multiple_interface/CMakeLists.txt14
-rw-r--r--examples/device/hid_multiple_interface/Makefile5
-rw-r--r--examples/device/hid_multiple_interface/src/main.c10
-rw-r--r--examples/device/hid_multiple_interface/src/usb_descriptors.c63
-rw-r--r--examples/device/midi_test/CMakeLists.txt15
-rw-r--r--examples/device/midi_test/Makefile5
-rw-r--r--examples/device/midi_test/src/main.c13
-rw-r--r--examples/device/midi_test/src/usb_descriptors.c67
-rw-r--r--examples/device/msc_dual_lun/CMakeLists.txt27
-rw-r--r--examples/device/msc_dual_lun/Makefile5
-rw-r--r--examples/device/msc_dual_lun/skip.txt3
-rw-r--r--examples/device/msc_dual_lun/src/main.c12
-rw-r--r--examples/device/msc_dual_lun/src/msc_disk_dual.c4
-rw-r--r--examples/device/msc_dual_lun/src/usb_descriptors.c71
-rw-r--r--examples/device/net_lwip_webserver/CMakeLists.txt154
-rw-r--r--examples/device/net_lwip_webserver/Makefile7
-rw-r--r--examples/device/net_lwip_webserver/skip.txt6
-rw-r--r--examples/device/net_lwip_webserver/src/arch/bpstruct.h35
-rw-r--r--examples/device/net_lwip_webserver/src/arch/cc.h32
-rw-r--r--examples/device/net_lwip_webserver/src/arch/epstruct.h35
-rw-r--r--examples/device/net_lwip_webserver/src/lwipopts.h28
-rw-r--r--examples/device/net_lwip_webserver/src/main.c14
-rw-r--r--examples/device/net_lwip_webserver/src/usb_descriptors.c72
-rw-r--r--examples/device/uac2_headset/CMakeLists.txt15
-rw-r--r--examples/device/uac2_headset/Makefile5
-rw-r--r--examples/device/uac2_headset/skip.txt1
-rw-r--r--examples/device/uac2_headset/src/main.c18
-rw-r--r--examples/device/uac2_headset/src/tusb_config.h8
-rw-r--r--examples/device/uac2_headset/src/usb_descriptors.c76
-rw-r--r--examples/device/uac2_headset/src/usb_descriptors.h14
-rw-r--r--examples/device/usbtmc/CMakeLists.txt15
-rw-r--r--examples/device/usbtmc/Makefile5
-rw-r--r--examples/device/usbtmc/skip.txt1
-rw-r--r--examples/device/usbtmc/src/main.c12
-rw-r--r--examples/device/usbtmc/src/usb_descriptors.c66
-rw-r--r--examples/device/usbtmc/src/usbtmc_app.c23
-rw-r--r--examples/device/usbtmc/visaQuery.py26
-rw-r--r--examples/device/video_capture/CMakeLists.txt15
-rw-r--r--examples/device/video_capture/Makefile5
-rw-r--r--examples/device/video_capture/skip.txt1
-rw-r--r--examples/device/video_capture/src/CMakeLists.txt4
-rw-r--r--examples/device/video_capture/src/images.h5
-rw-r--r--examples/device/video_capture/src/main.c240
-rw-r--r--examples/device/video_capture/src/tusb_config.h13
-rw-r--r--examples/device/video_capture/src/usb_descriptors.c444
-rw-r--r--examples/device/video_capture/src/usb_descriptors.h144
-rw-r--r--examples/device/webusb_serial/CMakeLists.txt15
-rw-r--r--examples/device/webusb_serial/Makefile5
-rw-r--r--examples/device/webusb_serial/src/main.c16
-rw-r--r--examples/device/webusb_serial/src/usb_descriptors.c72
-rw-r--r--examples/device/webusb_serial/src/usb_descriptors.h2
-rw-r--r--examples/dual/CMakeLists.txt15
-rw-r--r--examples/dual/host_hid_to_device_cdc/CMakeLists.txt40
-rw-r--r--examples/dual/host_hid_to_device_cdc/Makefile5
-rw-r--r--examples/dual/host_hid_to_device_cdc/only.txt3
-rw-r--r--examples/dual/host_hid_to_device_cdc/src/main.c10
-rw-r--r--examples/dual/host_hid_to_device_cdc/src/tusb_config.h22
-rw-r--r--examples/dual/host_hid_to_device_cdc/src/usb_descriptors.c65
-rw-r--r--examples/host/CMakeLists.txt7
-rw-r--r--examples/host/bare_api/CMakeLists.txt18
-rw-r--r--examples/host/bare_api/Makefile18
-rw-r--r--examples/host/bare_api/only.txt5
-rw-r--r--examples/host/bare_api/src/main.c9
-rw-r--r--examples/host/bare_api/src/tusb_config.h68
-rw-r--r--examples/host/cdc_msc_hid/CMakeLists.txt31
-rw-r--r--examples/host/cdc_msc_hid/Makefile25
-rw-r--r--examples/host/cdc_msc_hid/only.txt5
-rw-r--r--examples/host/cdc_msc_hid/src/cdc_app.c109
-rw-r--r--examples/host/cdc_msc_hid/src/hid_app.c8
-rw-r--r--examples/host/cdc_msc_hid/src/main.c77
-rw-r--r--examples/host/cdc_msc_hid/src/msc_app.c48
-rw-r--r--examples/host/cdc_msc_hid/src/tusb_config.h88
-rw-r--r--examples/host/cdc_msc_hid_freertos/CMakeLists.txt36
-rw-r--r--examples/host/cdc_msc_hid_freertos/Makefile34
-rw-r--r--examples/host/cdc_msc_hid_freertos/only.txt12
-rw-r--r--examples/host/cdc_msc_hid_freertos/src/CMakeLists.txt6
-rw-r--r--examples/host/cdc_msc_hid_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h199
-rw-r--r--examples/host/cdc_msc_hid_freertos/src/cdc_app.c145
-rw-r--r--examples/host/cdc_msc_hid_freertos/src/freertos_hook.c111
-rw-r--r--examples/host/cdc_msc_hid_freertos/src/hid_app.c267
-rw-r--r--examples/host/cdc_msc_hid_freertos/src/main.c177
-rw-r--r--examples/host/cdc_msc_hid_freertos/src/msc_app.c67
-rw-r--r--examples/host/cdc_msc_hid_freertos/src/tusb_config.h140
-rw-r--r--examples/host/hid_controller/CMakeLists.txt28
-rw-r--r--examples/host/hid_controller/Makefile18
-rw-r--r--examples/host/hid_controller/only.txt5
-rw-r--r--examples/host/hid_controller/src/hid_app.c91
-rw-r--r--examples/host/hid_controller/src/main.c10
-rw-r--r--examples/host/hid_controller/src/tusb_config.h73
-rw-r--r--examples/host/msc_file_explorer/CMakeLists.txt47
-rw-r--r--examples/host/msc_file_explorer/Makefile27
-rw-r--r--examples/host/msc_file_explorer/only.txt14
-rw-r--r--examples/host/msc_file_explorer/src/main.c132
-rw-r--r--examples/host/msc_file_explorer/src/msc_app.c643
-rw-r--r--examples/host/msc_file_explorer/src/tusb_config.h120
-rw-r--r--examples/typec/CMakeLists.txt9
-rw-r--r--examples/typec/power_delivery/CMakeLists.txt32
-rw-r--r--examples/typec/power_delivery/Makefile11
-rw-r--r--examples/typec/power_delivery/only.txt1
-rw-r--r--examples/typec/power_delivery/src/main.c193
-rw-r--r--examples/typec/power_delivery/src/tusb_config.h83
225 files changed, 8568 insertions, 2115 deletions
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 000000000..c603d0c22
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.17)
+
+#set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../hw/bsp/family_support.cmake)
+
+project(tinyusb_examples C CXX ASM)
+
+add_subdirectory(device)
+add_subdirectory(dual)
+add_subdirectory(host)
+add_subdirectory(typec)
diff --git a/examples/build_system/cmake/cpu/cortex-m0.cmake b/examples/build_system/cmake/cpu/cortex-m0.cmake
new file mode 100644
index 000000000..bc2257048
--- /dev/null
+++ b/examples/build_system/cmake/cpu/cortex-m0.cmake
@@ -0,0 +1,17 @@
+if (TOOLCHAIN STREQUAL "gcc")
+ set(TOOLCHAIN_COMMON_FLAGS
+ -mthumb
+ -mcpu=cortex-m0plus
+ -mfloat-abi=soft
+ )
+
+ set(FREERTOS_PORT GCC_ARM_CM0 CACHE INTERNAL "")
+
+elseif (TOOLCHAIN STREQUAL "iar")
+ set(TOOLCHAIN_COMMON_FLAGS
+ --cpu cortex-m0
+ )
+
+ set(FREERTOS_PORT IAR_ARM_CM0 CACHE INTERNAL "")
+
+endif ()
diff --git a/examples/build_system/cmake/cpu/cortex-m0plus.cmake b/examples/build_system/cmake/cpu/cortex-m0plus.cmake
new file mode 100644
index 000000000..bc2257048
--- /dev/null
+++ b/examples/build_system/cmake/cpu/cortex-m0plus.cmake
@@ -0,0 +1,17 @@
+if (TOOLCHAIN STREQUAL "gcc")
+ set(TOOLCHAIN_COMMON_FLAGS
+ -mthumb
+ -mcpu=cortex-m0plus
+ -mfloat-abi=soft
+ )
+
+ set(FREERTOS_PORT GCC_ARM_CM0 CACHE INTERNAL "")
+
+elseif (TOOLCHAIN STREQUAL "iar")
+ set(TOOLCHAIN_COMMON_FLAGS
+ --cpu cortex-m0
+ )
+
+ set(FREERTOS_PORT IAR_ARM_CM0 CACHE INTERNAL "")
+
+endif ()
diff --git a/examples/build_system/cmake/cpu/cortex-m23.cmake b/examples/build_system/cmake/cpu/cortex-m23.cmake
new file mode 100644
index 000000000..3093dc99a
--- /dev/null
+++ b/examples/build_system/cmake/cpu/cortex-m23.cmake
@@ -0,0 +1,17 @@
+if (TOOLCHAIN STREQUAL "gcc")
+ set(TOOLCHAIN_COMMON_FLAGS
+ -mthumb
+ -mcpu=cortex-m23
+ -mfloat-abi=soft
+ )
+
+ set(FREERTOS_PORT GCC_ARM_CM0 CACHE INTERNAL "")
+
+elseif (TOOLCHAIN STREQUAL "iar")
+ set(TOOLCHAIN_COMMON_FLAGS
+ --cpu cortex-m23
+ )
+
+ set(FREERTOS_PORT IAR_ARM_CM0 CACHE INTERNAL "")
+
+endif ()
diff --git a/examples/build_system/cmake/cpu/cortex-m3.cmake b/examples/build_system/cmake/cpu/cortex-m3.cmake
new file mode 100644
index 000000000..f6f5a62f8
--- /dev/null
+++ b/examples/build_system/cmake/cpu/cortex-m3.cmake
@@ -0,0 +1,16 @@
+if (TOOLCHAIN STREQUAL "gcc")
+ set(TOOLCHAIN_COMMON_FLAGS
+ -mthumb
+ -mcpu=cortex-m3
+ )
+
+ set(FREERTOS_PORT GCC_ARM_CM3 CACHE INTERNAL "")
+
+elseif (TOOLCHAIN STREQUAL "iar")
+ set(TOOLCHAIN_COMMON_FLAGS
+ --cpu cortex-m3
+ )
+
+ set(FREERTOS_PORT IAR_ARM_CM3 CACHE INTERNAL "")
+
+endif ()
diff --git a/examples/build_system/cmake/cpu/cortex-m33.cmake b/examples/build_system/cmake/cpu/cortex-m33.cmake
new file mode 100644
index 000000000..7ebaf1748
--- /dev/null
+++ b/examples/build_system/cmake/cpu/cortex-m33.cmake
@@ -0,0 +1,19 @@
+if (TOOLCHAIN STREQUAL "gcc")
+ set(TOOLCHAIN_COMMON_FLAGS
+ -mthumb
+ -mcpu=cortex-m33
+ -mfloat-abi=hard
+ -mfpu=fpv5-sp-d16
+ )
+
+ set(FREERTOS_PORT GCC_ARM_CM33_NTZ_NONSECURE CACHE INTERNAL "")
+
+elseif (TOOLCHAIN STREQUAL "iar")
+ set(TOOLCHAIN_COMMON_FLAGS
+ --cpu cortex-m33
+ --fpu VFPv5-SP
+ )
+
+ set(FREERTOS_PORT IAR_ARM_CM4F CACHE INTERNAL "")
+
+endif ()
diff --git a/examples/build_system/cmake/cpu/cortex-m4.cmake b/examples/build_system/cmake/cpu/cortex-m4.cmake
new file mode 100644
index 000000000..db308aa83
--- /dev/null
+++ b/examples/build_system/cmake/cpu/cortex-m4.cmake
@@ -0,0 +1,23 @@
+if (TOOLCHAIN STREQUAL "gcc")
+ set(TOOLCHAIN_COMMON_FLAGS
+ -mthumb
+ -mcpu=cortex-m4
+ -mfloat-abi=hard
+ -mfpu=fpv4-sp-d16
+ )
+
+ if (NOT DEFINED FREERTOS_PORT)
+ set(FREERTOS_PORT GCC_ARM_CM4F CACHE INTERNAL "")
+ endif ()
+
+elseif (TOOLCHAIN STREQUAL "iar")
+ set(TOOLCHAIN_COMMON_FLAGS
+ --cpu cortex-m4
+ --fpu VFPv4_sp
+ )
+
+ if (NOT DEFINED FREERTOS_PORT)
+ set(FREERTOS_PORT IAR_ARM_CM4F CACHE INTERNAL "")
+ endif ()
+
+endif ()
diff --git a/examples/build_system/cmake/cpu/cortex-m7.cmake b/examples/build_system/cmake/cpu/cortex-m7.cmake
new file mode 100644
index 000000000..3e5f7f44b
--- /dev/null
+++ b/examples/build_system/cmake/cpu/cortex-m7.cmake
@@ -0,0 +1,19 @@
+if (TOOLCHAIN STREQUAL "gcc")
+ set(TOOLCHAIN_COMMON_FLAGS
+ -mthumb
+ -mcpu=cortex-m7
+ -mfloat-abi=hard
+ -mfpu=fpv5-d16
+ )
+
+ set(FREERTOS_PORT GCC_ARM_CM7 CACHE INTERNAL "")
+
+elseif (TOOLCHAIN STREQUAL "iar")
+ set(TOOLCHAIN_COMMON_FLAGS
+ --cpu cortex-m7
+ --fpu VFPv5_D16
+ )
+
+ set(FREERTOS_PORT IAR_ARM_CM7 CACHE INTERNAL "")
+
+endif ()
diff --git a/examples/build_system/cmake/toolchain/arm_gcc.cmake b/examples/build_system/cmake/toolchain/arm_gcc.cmake
new file mode 100644
index 000000000..d3fd5b557
--- /dev/null
+++ b/examples/build_system/cmake/toolchain/arm_gcc.cmake
@@ -0,0 +1,52 @@
+set(CMAKE_SYSTEM_NAME Generic)
+
+if (NOT DEFINED CMAKE_C_COMPILER)
+ set(CMAKE_C_COMPILER "arm-none-eabi-gcc")
+endif ()
+
+if (NOT DEFINED CMAKE_CXX_COMPILER)
+ set(CMAKE_CXX_COMPILER "arm-none-eabi-g++")
+endif ()
+
+set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
+
+set(CMAKE_SIZE "arm-none-eabi-size" CACHE FILEPATH "")
+set(CMAKE_OBJCOPY "arm-none-eabi-objcopy" CACHE FILEPATH "")
+set(CMAKE_OBJDUMP "arm-none-eabi-objdump" CACHE FILEPATH "")
+
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+
+# Look for includes and libraries only in the target system prefix.
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+
+# pass TOOLCHAIN_CPU to
+set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES CMAKE_SYSTEM_PROCESSOR)
+
+include(${CMAKE_CURRENT_LIST_DIR}/../cpu/${CMAKE_SYSTEM_PROCESSOR}.cmake)
+
+# enable all possible warnings for building examples
+list(APPEND TOOLCHAIN_COMMON_FLAGS
+ -fdata-sections
+ -ffunction-sections
+ -fsingle-precision-constant
+ -fno-strict-aliasing
+ )
+
+list(APPEND TOOLCHAIN_EXE_LINKER_FLAGS
+ -Wl,--print-memory-usage
+ -Wl,--gc-sections
+ -Wl,--cref
+ )
+
+include(${CMAKE_CURRENT_LIST_DIR}/set_flags.cmake)
+
+# try_compile is cmake test compiling its own example,
+# pass -nostdlib to skip stdlib linking
+get_property(IS_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE)
+if (IS_IN_TRY_COMPILE)
+ set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -nostdlib")
+ set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -nostdlib")
+endif ()
diff --git a/examples/build_system/cmake/toolchain/arm_iar.cmake b/examples/build_system/cmake/toolchain/arm_iar.cmake
new file mode 100644
index 000000000..1482624e5
--- /dev/null
+++ b/examples/build_system/cmake/toolchain/arm_iar.cmake
@@ -0,0 +1,32 @@
+set(CMAKE_SYSTEM_NAME Generic)
+
+set(CMAKE_C_COMPILER "iccarm")
+set(CMAKE_CXX_COMPILER "iccarm")
+set(CMAKE_ASM_COMPILER "iasmarm")
+
+set(CMAKE_SIZE "size" CACHE FILEPATH "")
+set(CMAKE_OBJCOPY "ielftool" CACHE FILEPATH "")
+set(CMAKE_OBJDUMP "iefdumparm" CACHE FILEPATH "")
+
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+
+# Look for includes and libraries only in the target system prefix.
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+
+# pass TOOLCHAIN_CPU to
+set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES CMAKE_SYSTEM_PROCESSOR)
+
+include(${CMAKE_CURRENT_LIST_DIR}/../cpu/${CMAKE_SYSTEM_PROCESSOR}.cmake)
+
+# enable all possible warnings for building examples
+list(APPEND TOOLCHAIN_COMMON_FLAGS
+ )
+
+list(APPEND TOOLCHAIN_EXE_LINKER_FLAGS
+ --diag_suppress=Li065
+ )
+
+include(${CMAKE_CURRENT_LIST_DIR}/set_flags.cmake)
diff --git a/examples/build_system/cmake/toolchain/set_flags.cmake b/examples/build_system/cmake/toolchain/set_flags.cmake
new file mode 100644
index 000000000..44930ef4d
--- /dev/null
+++ b/examples/build_system/cmake/toolchain/set_flags.cmake
@@ -0,0 +1,17 @@
+include(CMakePrintHelpers)
+
+# join the toolchain flags into a single string
+list(JOIN TOOLCHAIN_COMMON_FLAGS " " TOOLCHAIN_COMMON_FLAGS)
+
+foreach (LANG IN ITEMS C CXX ASM)
+ set(CMAKE_${LANG}_FLAGS_INIT ${TOOLCHAIN_COMMON_FLAGS})
+
+ #cmake_print_variables(CMAKE_${LANG}_FLAGS_INIT)
+
+ # optimization flags for LOG, LOGGER ?
+ #set(CMAKE_${LANG}_FLAGS_RELEASE_INIT "-Os")
+ #set(CMAKE_${LANG}_FLAGS_DEBUG_INIT "-O0")
+endforeach ()
+
+# Linker
+list(JOIN TOOLCHAIN_EXE_LINKER_FLAGS " " CMAKE_EXE_LINKER_FLAGS_INIT)
diff --git a/examples/build_system/make/cpu/arm1176.mk b/examples/build_system/make/cpu/arm1176.mk
new file mode 100644
index 000000000..022ccf7ad
--- /dev/null
+++ b/examples/build_system/make/cpu/arm1176.mk
@@ -0,0 +1,9 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mcpu=arm1176jzf-s \
+
+else ifeq ($(TOOLCHAIN),iar)
+ #CFLAGS += --cpu cortex-a53
+ #ASFLAGS += --cpu cortex-a53
+
+endif
diff --git a/examples/build_system/make/cpu/cortex-a53.mk b/examples/build_system/make/cpu/cortex-a53.mk
new file mode 100644
index 000000000..42e522ecf
--- /dev/null
+++ b/examples/build_system/make/cpu/cortex-a53.mk
@@ -0,0 +1,12 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mcpu=cortex-a53 \
+
+else ifeq ($(TOOLCHAIN),iar)
+ CFLAGS += \
+ --cpu cortex-a53 \
+
+ ASFLAGS += \
+ --cpu cortex-a53 \
+
+endif
diff --git a/examples/build_system/make/cpu/cortex-a72.mk b/examples/build_system/make/cpu/cortex-a72.mk
new file mode 100644
index 000000000..1b3d8da4a
--- /dev/null
+++ b/examples/build_system/make/cpu/cortex-a72.mk
@@ -0,0 +1,12 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mcpu=cortex-a72 \
+
+else ifeq ($(TOOLCHAIN),iar)
+ CFLAGS += \
+ --cpu cortex-a72 \
+
+ ASFLAGS += \
+ --cpu cortex-a72 \
+
+endif
diff --git a/examples/build_system/make/cpu/cortex-m0.mk b/examples/build_system/make/cpu/cortex-m0.mk
new file mode 100644
index 000000000..feb0f395b
--- /dev/null
+++ b/examples/build_system/make/cpu/cortex-m0.mk
@@ -0,0 +1,14 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mthumb \
+ -mcpu=cortex-m0 \
+ -mfloat-abi=soft \
+
+else ifeq ($(TOOLCHAIN),iar)
+ # IAR Flags
+ CFLAGS += --cpu cortex-m0
+ ASFLAGS += --cpu cortex-m0
+endif
+
+# For freeRTOS port source
+FREERTOS_PORTABLE_SRC ?= $(FREERTOS_PORTABLE_PATH)/ARM_CM0
diff --git a/examples/build_system/make/cpu/cortex-m0plus.mk b/examples/build_system/make/cpu/cortex-m0plus.mk
new file mode 100644
index 000000000..b416b7a4a
--- /dev/null
+++ b/examples/build_system/make/cpu/cortex-m0plus.mk
@@ -0,0 +1,14 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mthumb \
+ -mcpu=cortex-m0plus \
+ -mfloat-abi=soft \
+
+else ifeq ($(TOOLCHAIN),iar)
+ # IAR Flags
+ CFLAGS += --cpu cortex-m0+
+ ASFLAGS += --cpu cortex-m0+
+endif
+
+# For freeRTOS port source
+FREERTOS_PORTABLE_SRC ?= $(FREERTOS_PORTABLE_PATH)/ARM_CM0
diff --git a/examples/build_system/make/cpu/cortex-m23.mk b/examples/build_system/make/cpu/cortex-m23.mk
new file mode 100644
index 000000000..29542d8e8
--- /dev/null
+++ b/examples/build_system/make/cpu/cortex-m23.mk
@@ -0,0 +1,14 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mthumb \
+ -mcpu=cortex-m23 \
+ -mfloat-abi=soft \
+
+else ifeq ($(TOOLCHAIN),iar)
+ # IAR Flags
+ CFLAGS += --cpu cortex-m23
+ ASFLAGS += --cpu cortex-m23
+endif
+
+# For freeRTOS port source
+FREERTOS_PORTABLE_SRC ?= $(FREERTOS_PORTABLE_PATH)/ARM_CM23
diff --git a/examples/build_system/make/cpu/cortex-m3.mk b/examples/build_system/make/cpu/cortex-m3.mk
new file mode 100644
index 000000000..7a34b9e04
--- /dev/null
+++ b/examples/build_system/make/cpu/cortex-m3.mk
@@ -0,0 +1,17 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mthumb \
+ -mcpu=cortex-m3 \
+ -mfloat-abi=soft \
+
+else ifeq ($(TOOLCHAIN),iar)
+ # IAR Flags
+ CFLAGS += \
+ --cpu cortex-m3 \
+
+ ASFLAGS += \
+ --cpu cortex-m3
+endif
+
+# For freeRTOS port source
+FREERTOS_PORTABLE_SRC ?= $(FREERTOS_PORTABLE_PATH)/ARM_CM3
diff --git a/examples/build_system/make/cpu/cortex-m33.mk b/examples/build_system/make/cpu/cortex-m33.mk
new file mode 100644
index 000000000..fe5b7b380
--- /dev/null
+++ b/examples/build_system/make/cpu/cortex-m33.mk
@@ -0,0 +1,19 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mthumb \
+ -mcpu=cortex-m33 \
+ -mfloat-abi=hard \
+ -mfpu=fpv5-sp-d16 \
+
+else ifeq ($(TOOLCHAIN),iar)
+ CFLAGS += \
+ --cpu cortex-m33 \
+ --fpu VFPv5-SP \
+
+ ASFLAGS += \
+ --cpu cortex-m33 \
+ --fpu VFPv5-SP \
+
+endif
+
+FREERTOS_PORTABLE_SRC ?= $(FREERTOS_PORTABLE_PATH)/ARM_CM33_NTZ/non_secure
diff --git a/examples/build_system/make/cpu/cortex-m4.mk b/examples/build_system/make/cpu/cortex-m4.mk
new file mode 100644
index 000000000..d8776b5d8
--- /dev/null
+++ b/examples/build_system/make/cpu/cortex-m4.mk
@@ -0,0 +1,13 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mthumb \
+ -mcpu=cortex-m4 \
+ -mfloat-abi=hard \
+ -mfpu=fpv4-sp-d16 \
+
+else ifeq ($(TOOLCHAIN),iar)
+ CFLAGS += --cpu cortex-m4 --fpu VFPv4
+ ASFLAGS += --cpu cortex-m4 --fpu VFPv4
+endif
+
+FREERTOS_PORTABLE_SRC ?= $(FREERTOS_PORTABLE_PATH)/ARM_CM4F
diff --git a/examples/build_system/make/cpu/cortex-m7.mk b/examples/build_system/make/cpu/cortex-m7.mk
new file mode 100644
index 000000000..0e3461787
--- /dev/null
+++ b/examples/build_system/make/cpu/cortex-m7.mk
@@ -0,0 +1,19 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mthumb \
+ -mcpu=cortex-m7 \
+ -mfloat-abi=hard \
+ -mfpu=fpv5-d16 \
+
+else ifeq ($(TOOLCHAIN),iar)
+ CFLAGS += \
+ --cpu cortex-m7 \
+ --fpu VFPv5_D16 \
+
+ ASFLAGS += \
+ --cpu cortex-m7 \
+ --fpu VFPv5_D16 \
+
+endif
+
+FREERTOS_PORTABLE_SRC ?= $(FREERTOS_PORTABLE_PATH)/ARM_CM7/r0p1
diff --git a/examples/make.mk b/examples/build_system/make/make.mk
index 47520d660..e1113aa52 100644
--- a/examples/make.mk
+++ b/examples/build_system/make/make.mk
@@ -2,11 +2,29 @@
# Common make definition for all examples
# ---------------------------------------
-# Build directory
-BUILD := _build/$(BOARD)
+#-------------- TOP and CURRENT_PATH ------------
-PROJECT := $(notdir $(CURDIR))
-BIN := $(TOP)/_bin/$(BOARD)/$(notdir $(CURDIR))
+# Set TOP to be the path to get from the current directory (where make was invoked) to the top of the tree.
+# $(lastword $(MAKEFILE_LIST)) returns the name of this makefile relative to where make was invoked.
+THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST))
+
+# strip off /examples/build_system/make to get for example ../../..
+# and Set TOP to an absolute path
+TOP = $(abspath $(subst make.mk,../../..,$(THIS_MAKEFILE)))
+
+# Set CURRENT_PATH to the relative path from TOP to the current directory, ie examples/device/cdc_msc_freertos
+CURRENT_PATH = $(subst $(TOP)/,,$(abspath .))
+
+# Detect whether shell style is windows or not
+# https://stackoverflow.com/questions/714100/os-detecting-makefile/52062069#52062069
+ifeq '$(findstring ;,$(PATH))' ';'
+# PATH contains semicolon - so we're definitely on Windows.
+CMDEXE := 1
+
+# makefile shell commands should use syntax for DOS CMD, not unix sh
+# Force DOS command shell on Windows.
+SHELL := cmd.exe
+endif
# Handy check parameter function
check_defined = \
@@ -16,6 +34,12 @@ __check_defined = \
$(if $(value $1),, \
$(error Undefined make flag: $1$(if $2, ($2))))
+# Build directory
+BUILD := _build/$(BOARD)
+
+PROJECT := $(notdir $(CURDIR))
+BIN := $(TOP)/_bin/$(BOARD)/$(notdir $(CURDIR))
+
#-------------- Select the board to build for. ------------
# Board without family
@@ -41,81 +65,54 @@ ifeq ($(FAMILY),)
else
# Include Family and Board specific defs
include $(TOP)/$(FAMILY_PATH)/family.mk
-
SRC_C += $(subst $(TOP)/,,$(wildcard $(TOP)/$(FAMILY_PATH)/*.c))
endif
+#-------------- Toolchain ------------
+
+# Supported toolchain: gcc, iar
+TOOLCHAIN ?= gcc
-#-------------- Cross Compiler ------------
# Can be set by board, default to ARM GCC
CROSS_COMPILE ?= arm-none-eabi-
-# Allow for -Os to be changed by board makefiles in case -Os is not allowed
-CFLAGS_OPTIMIZED ?= -Os
-CC = $(CROSS_COMPILE)gcc
-CXX = $(CROSS_COMPILE)g++
-GDB = $(CROSS_COMPILE)gdb
-OBJCOPY = $(CROSS_COMPILE)objcopy
-SIZE = $(CROSS_COMPILE)size
-MKDIR = mkdir
+ifeq ($(TOOLCHAIN),iar)
+CC := iccarm
+USE_IAR = 1
+endif
ifeq ($(CMDEXE),1)
CP = copy
RM = del
+ MKDIR = mkdir
PYTHON = python
else
- SED = sed
CP = cp
RM = rm
+ MKDIR = mkdir
PYTHON = python3
endif
#-------------- Source files and compiler flags --------------
+# tinyusb makefile
+include $(TOP)/src/tinyusb.mk
+SRC_C += $(TINYUSB_SRC_C)
# Include all source C in family & board folder
SRC_C += hw/bsp/board.c
SRC_C += $(subst $(TOP)/,,$(wildcard $(TOP)/$(BOARD_PATH)/*.c))
-INC += $(TOP)/$(FAMILY_PATH)
+INC += \
+ $(TOP)/$(FAMILY_PATH) \
+ $(TOP)/src \
-# Compiler Flags
-CFLAGS += \
- -ggdb \
- -fdata-sections \
- -ffunction-sections \
- -fsingle-precision-constant \
- -fno-strict-aliasing \
- -Wall \
- -Wextra \
- -Werror \
- -Wfatal-errors \
- -Wdouble-promotion \
- -Wstrict-prototypes \
- -Wstrict-overflow \
- -Werror-implicit-function-declaration \
- -Wfloat-equal \
- -Wundef \
- -Wshadow \
- -Wwrite-strings \
- -Wsign-compare \
- -Wmissing-format-attribute \
- -Wunreachable-code \
- -Wcast-align \
- -Wcast-function-type \
- -Wcast-qual \
- -Wnull-dereference \
- -Wuninitialized \
- -Wunused \
- -Wredundant-decls
+BOARD_UPPER = $(subst a,A,$(subst b,B,$(subst c,C,$(subst d,D,$(subst e,E,$(subst f,F,$(subst g,G,$(subst h,H,$(subst i,I,$(subst j,J,$(subst k,K,$(subst l,L,$(subst m,M,$(subst n,N,$(subst o,O,$(subst p,P,$(subst q,Q,$(subst r,R,$(subst s,S,$(subst t,T,$(subst u,U,$(subst v,V,$(subst w,W,$(subst x,X,$(subst y,Y,$(subst z,Z,$(subst -,_,$(BOARD))))))))))))))))))))))))))))
+CFLAGS += -DBOARD_$(BOARD_UPPER)
-# conversion is too strict for most mcu driver, may be disable sign/int/arith-conversion
-# -Wconversion
-
-# Debugging/Optimization
-ifeq ($(DEBUG), 1)
- CFLAGS += -Og
-else
- CFLAGS += $(CFLAGS_OPTIMIZED)
+# use max3421 as host controller
+ifeq (${MAX3421_HOST},1)
+ SRC_C += src/portable/analog/max3421/hcd_max3421.c
+ CFLAGS += -DCFG_TUH_MAX3421=1
endif
# Log level is mapped to TUSB DEBUG option
@@ -137,3 +134,11 @@ ifeq ($(LOGGER),rtt)
else ifeq ($(LOGGER),swo)
CFLAGS += -DLOGGER_SWO
endif
+
+# CPU specific flags
+ifdef CPU_CORE
+ include ${TOP}/examples/build_system/make/cpu/$(CPU_CORE).mk
+endif
+
+# toolchain specific
+include ${TOP}/examples/build_system/make/toolchain/arm_$(TOOLCHAIN).mk
diff --git a/examples/rules.mk b/examples/build_system/make/rules.mk
index c3134056a..b02665cdd 100644
--- a/examples/rules.mk
+++ b/examples/build_system/make/rules.mk
@@ -7,71 +7,14 @@
# ---------------- GNU Make Start -----------------------
# ESP32-Sx and RP2040 has its own CMake build system
-ifeq (,$(findstring $(FAMILY),esp32s2 esp32s3 rp2040))
+ifeq (,$(findstring $(FAMILY),espressif rp2040))
# ---------------------------------------
# Compiler Flags
# ---------------------------------------
-LIBS_GCC ?= -lgcc -lm -lnosys
-
-# libc
-LIBS += $(LIBS_GCC)
-
-ifneq ($(BOARD), spresense)
-LIBS += -lc
-endif
-
-# TinyUSB Stack source
-SRC_C += \
- src/tusb.c \
- src/common/tusb_fifo.c \
- src/device/usbd.c \
- src/device/usbd_control.c \
- src/class/audio/audio_device.c \
- src/class/cdc/cdc_device.c \
- src/class/dfu/dfu_device.c \
- src/class/dfu/dfu_rt_device.c \
- src/class/hid/hid_device.c \
- src/class/midi/midi_device.c \
- src/class/msc/msc_device.c \
- src/class/net/ecm_rndis_device.c \
- src/class/net/ncm_device.c \
- src/class/usbtmc/usbtmc_device.c \
- src/class/video/video_device.c \
- src/class/vendor/vendor_device.c
-
-# TinyUSB stack include
-INC += $(TOP)/src
-
CFLAGS += $(addprefix -I,$(INC))
-# LTO makes it difficult to analyze map file for optimizing size purpose
-# We will run this option in ci
-ifeq ($(NO_LTO),1)
-CFLAGS := $(filter-out -flto,$(CFLAGS))
-endif
-
-ifneq ($(LD_FILE),)
-LDFLAGS_LD_FILE ?= -Wl,-T,$(TOP)/$(LD_FILE)
-endif
-
-LDFLAGS += $(CFLAGS) $(LDFLAGS_LD_FILE) -Wl,[email protected] -Wl,-cref -Wl,-gc-sections
-ifneq ($(SKIP_NANOLIB), 1)
-LDFLAGS += -specs=nosys.specs -specs=nano.specs
-endif
-
-ASFLAGS += $(CFLAGS)
-
-# Assembly files can be name with upper case .S, convert it to .s
-SRC_S := $(SRC_S:.S=.s)
-
-# Due to GCC LTO bug https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966
-# assembly file should be placed first in linking order
-# '_asm' suffix is added to object of assembly file
-OBJ += $(addprefix $(BUILD)/obj/, $(SRC_S:.s=_asm.o))
-OBJ += $(addprefix $(BUILD)/obj/, $(SRC_C:.c=.o))
-
# Verbose mode
ifeq ("$(V)","1")
$(info CFLAGS $(CFLAGS) ) $(info )
@@ -87,34 +30,27 @@ all: $(BUILD)/$(PROJECT).bin $(BUILD)/$(PROJECT).hex size
uf2: $(BUILD)/$(PROJECT).uf2
+# We set vpath to point to the top of the tree so that the source files
+# can be located. By following this scheme, it allows a single build rule
+# to be used to compile all .c files.
+vpath %.c . $(TOP)
+vpath %.s . $(TOP)
+vpath %.S . $(TOP)
+
+include ${TOP}/examples/build_system/make/toolchain/arm_$(TOOLCHAIN)_rules.mk
+
+
OBJ_DIRS = $(sort $(dir $(OBJ)))
$(OBJ): | $(OBJ_DIRS)
$(OBJ_DIRS):
ifeq ($(CMDEXE),1)
- @$(MKDIR) $(subst /,\,$@)
+ -@$(MKDIR) $(subst /,\,$@)
else
@$(MKDIR) -p $@
endif
-$(BUILD)/$(PROJECT).elf: $(OBJ)
- @echo LINK $@
- @$(CC) -o $@ $(LDFLAGS) $^ -Wl,--start-group $(LIBS) -Wl,--end-group
-
-$(BUILD)/$(PROJECT).bin: $(BUILD)/$(PROJECT).elf
- @echo CREATE $@
- @$(OBJCOPY) -O binary $^ $@
-
-$(BUILD)/$(PROJECT).hex: $(BUILD)/$(PROJECT).elf
- @echo CREATE $@
- @$(OBJCOPY) -O ihex $^ $@
-
# UF2 generation, iMXRT need to strip to text only before conversion
-ifeq ($(FAMILY),imxrt)
-$(BUILD)/$(PROJECT).uf2: $(BUILD)/$(PROJECT).elf
- @echo CREATE $@
- @$(OBJCOPY) -O ihex -R .flash_config -R .ivt $^ $(BUILD)/$(PROJECT)-textonly.hex
- $(PYTHON) $(TOP)/tools/uf2/utils/uf2conv.py -f $(UF2_FAMILY_ID) -c -o $@ $(BUILD)/$(PROJECT)-textonly.hex
-else
+ifneq ($(FAMILY),imxrt)
$(BUILD)/$(PROJECT).uf2: $(BUILD)/$(PROJECT).hex
@echo CREATE $@
$(PYTHON) $(TOP)/tools/uf2/utils/uf2conv.py -f $(UF2_FAMILY_ID) -c -o $@ $^
@@ -122,27 +58,8 @@ endif
copy-artifact: $(BUILD)/$(PROJECT).bin $(BUILD)/$(PROJECT).hex $(BUILD)/$(PROJECT).uf2
-# We set vpath to point to the top of the tree so that the source files
-# can be located. By following this scheme, it allows a single build rule
-# to be used to compile all .c files.
-vpath %.c . $(TOP)
-$(BUILD)/obj/%.o: %.c
- @echo CC $(notdir $@)
- @$(CC) $(CFLAGS) -c -MD -o $@ $<
-
-# ASM sources lower case .s
-vpath %.s . $(TOP)
-$(BUILD)/obj/%_asm.o: %.s
- @echo AS $(notdir $@)
- @$(CC) -x assembler-with-cpp $(ASFLAGS) -c -o $@ $<
-
-# ASM sources upper case .S
-vpath %.S . $(TOP)
-$(BUILD)/obj/%_asm.o: %.S
- @echo AS $(notdir $@)
- @$(CC) -x assembler-with-cpp $(ASFLAGS) -c -o $@ $<
-
endif
+# ---------------- GNU Make End -----------------------
.PHONY: clean
clean:
@@ -151,15 +68,13 @@ ifeq ($(CMDEXE),1)
else
$(RM) -rf $(BUILD)
endif
-# ---------------- GNU Make End -----------------------
# get depenecies
.PHONY: get-deps
get-deps:
- ifdef DEPS_SUBMODULES
- git -C $(TOP) submodule update --init $(DEPS_SUBMODULES)
- endif
+ $(PYTHON) $(TOP)/tools/get_deps.py ${FAMILY}
+.PHONY: size
size: $(BUILD)/$(PROJECT).elf
-@echo ''
@$(SIZE) $<
@@ -173,7 +88,7 @@ linkermap: $(BUILD)/$(PROJECT).elf
# Flash Targets
# ---------------------------------------
-# Jlink binary
+# --------------- Jlink -----------------
ifeq ($(OS),Windows_NT)
JLINKEXE = JLink.exe
else
@@ -183,20 +98,24 @@ endif
# Jlink Interface
JLINK_IF ?= swd
+# Jlink script
+$(BUILD)/$(BOARD).jlink: $(BUILD)/$(PROJECT).hex
+ @echo halt > $@
+ @echo loadfile $^ >> $@
+ @echo r >> $@
+ @echo go >> $@
+ @echo exit >> $@
+
# Flash using jlink
-flash-jlink: $(BUILD)/$(PROJECT).hex
- @echo halt > $(BUILD)/$(BOARD).jlink
- @echo r > $(BUILD)/$(BOARD).jlink
- @echo loadfile $^ >> $(BUILD)/$(BOARD).jlink
- @echo r >> $(BUILD)/$(BOARD).jlink
- @echo go >> $(BUILD)/$(BOARD).jlink
- @echo exit >> $(BUILD)/$(BOARD).jlink
- $(JLINKEXE) -device $(JLINK_DEVICE) -if $(JLINK_IF) -JTAGConf -1,-1 -speed auto -CommandFile $(BUILD)/$(BOARD).jlink
+flash-jlink: $(BUILD)/$(BOARD).jlink
+ $(JLINKEXE) -device $(JLINK_DEVICE) -if $(JLINK_IF) -JTAGConf -1,-1 -speed auto -CommandFile $<
+# --------------- stm32 cube programmer -----------------
# Flash STM32 MCU using stlink with STM32 Cube Programmer CLI
flash-stlink: $(BUILD)/$(PROJECT).elf
STM32_Programmer_CLI --connect port=swd --write $< --go
+# --------------- xfel -----------------
$(BUILD)/$(PROJECT)-sunxi.bin: $(BUILD)/$(PROJECT).bin
$(PYTHON) $(TOP)/tools/mksunxi.py $< $@
@@ -204,18 +123,23 @@ flash-xfel: $(BUILD)/$(PROJECT)-sunxi.bin
xfel spinor write 0 $<
xfel reset
-# Flash using pyocd
+# --------------- pyocd -----------------
PYOCD_OPTION ?=
flash-pyocd: $(BUILD)/$(PROJECT).hex
pyocd flash -t $(PYOCD_TARGET) $(PYOCD_OPTION) $<
#pyocd reset -t $(PYOCD_TARGET)
-# Flash using openocd
+# --------------- openocd -----------------
OPENOCD_OPTION ?=
flash-openocd: $(BUILD)/$(PROJECT).elf
openocd $(OPENOCD_OPTION) -c "program $< verify reset exit"
-# flash with Black Magic Probe
+# --------------- dfu-util -----------------
+DFU_UTIL_OPTION ?= -a 0
+flash-dfu-util: $(BUILD)/$(PROJECT).bin
+ dfu-util -R $(DFU_UTIL_OPTION) -D $<
+
+# --------------- Black Magic -----------------
# This symlink is created by https://github.com/blacksphere/blackmagic/blob/master/driver/99-blackmagic.rules
BMP ?= /dev/ttyBmpGdb
@@ -229,7 +153,11 @@ debug-bmp: $(BUILD)/$(PROJECT).elf
# Create binary directory
$(BIN):
+ifeq ($(CMDEXE),1)
+ @$(MKDIR) $(subst /,\,$@)
+else
@$(MKDIR) -p $@
+endif
# Copy binaries .elf, .bin, .hex, .uf2 to BIN for upload
# due to large size of combined artifacts, only uf2 is uploaded for now
@@ -242,4 +170,4 @@ copy-artifact: $(BIN)
# Print out the value of a make variable.
# https://stackoverflow.com/questions/16467718/how-to-print-out-a-variable-in-makefile
print-%:
- @echo $* = $($*) \ No newline at end of file
+ @echo $* = $($*)
diff --git a/examples/build_system/make/toolchain/arm_gcc.mk b/examples/build_system/make/toolchain/arm_gcc.mk
new file mode 100644
index 000000000..ed5ddc970
--- /dev/null
+++ b/examples/build_system/make/toolchain/arm_gcc.mk
@@ -0,0 +1,81 @@
+# makefile for arm gcc toolchain
+
+CC = $(CROSS_COMPILE)gcc
+CXX = $(CROSS_COMPILE)g++
+AS = $(CC) -x assembler-with-cpp
+LD = $(CC)
+
+GDB = $(CROSS_COMPILE)gdb
+OBJCOPY = $(CROSS_COMPILE)objcopy
+SIZE = $(CROSS_COMPILE)size
+
+CC_VERSION := $(shell $(CC) -dumpversion)
+CC_VERSION_MAJOR = $(firstword $(subst ., ,$(CC_VERSION)))
+
+# ---------------------------------------
+# Compiler Flags
+# ---------------------------------------
+CFLAGS += \
+ -MD \
+ -ggdb \
+ -fdata-sections \
+ -ffunction-sections \
+ -fsingle-precision-constant \
+ -fno-strict-aliasing \
+ -Wall \
+ -Wextra \
+ -Werror \
+ -Wfatal-errors \
+ -Wdouble-promotion \
+ -Wstrict-prototypes \
+ -Wstrict-overflow \
+ -Werror-implicit-function-declaration \
+ -Wfloat-equal \
+ -Wundef \
+ -Wshadow \
+ -Wwrite-strings \
+ -Wsign-compare \
+ -Wmissing-format-attribute \
+ -Wunreachable-code \
+ -Wcast-align \
+ -Wcast-function-type \
+ -Wcast-qual \
+ -Wnull-dereference \
+ -Wuninitialized \
+ -Wunused \
+ -Wreturn-type \
+ -Wredundant-decls \
+
+# conversion is too strict for most mcu driver, may be disable sign/int/arith-conversion
+# -Wconversion
+
+# Size Optimization as default
+CFLAGS_OPTIMIZED ?= -Os
+
+# Debugging/Optimization
+ifeq ($(DEBUG), 1)
+ CFLAGS += -O0
+ NO_LTO = 1
+else
+ CFLAGS += $(CFLAGS_OPTIMIZED)
+endif
+
+# ---------------------------------------
+# Linker Flags
+# ---------------------------------------
+LDFLAGS += \
+ -Wl,-cref \
+ -Wl,-gc-sections \
+
+# renesas rx does not support --print-memory-usage flags
+ifneq ($(FAMILY),rx)
+LDFLAGS += -Wl,--print-memory-usage
+endif
+
+# from version 12
+ifeq ($(strip $(if $(CMDEXE),\
+ $(shell if $(CC_VERSION_MAJOR) geq 12 (echo 1) else (echo 0)),\
+ $(shell expr $(CC_VERSION_MAJOR) \>= 12))), 1)
+LDFLAGS += -Wl,--no-warn-rwx-segment
+endif
diff --git a/examples/build_system/make/toolchain/arm_gcc_rules.mk b/examples/build_system/make/toolchain/arm_gcc_rules.mk
new file mode 100644
index 000000000..d295879d9
--- /dev/null
+++ b/examples/build_system/make/toolchain/arm_gcc_rules.mk
@@ -0,0 +1,75 @@
+SRC_S += $(SRC_S_GCC)
+
+# Assembly files can be name with upper case .S, convert it to .s
+SRC_S := $(SRC_S:.S=.s)
+
+# Due to GCC LTO bug https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966
+# assembly file should be placed first in linking order
+# '_asm' suffix is added to object of assembly file
+OBJ += $(addprefix $(BUILD)/obj/, $(SRC_S:.s=_asm.o))
+OBJ += $(addprefix $(BUILD)/obj/, $(SRC_C:.c=.o))
+
+CFLAGS += $(CFLAGS_GCC) -MD
+
+# LTO makes it difficult to analyze map file for optimizing size purpose
+# We will run this option in ci
+ifeq ($(NO_LTO),1)
+CFLAGS := $(filter-out -flto,$(CFLAGS))
+endif
+
+ifneq ($(CFLAGS_SKIP),)
+CFLAGS := $(filter-out $(CFLAGS_SKIP),$(CFLAGS))
+endif
+
+LDFLAGS += $(CFLAGS) $(LDFLAGS_GCC)
+
+ifdef LD_FILE
+LDFLAGS += -Wl,-T,$(TOP)/$(LD_FILE)
+endif
+
+ifdef LD_FILE_GCC
+LDFLAGS += -Wl,-T,$(TOP)/$(LD_FILE_GCC)
+endif
+
+ASFLAGS += $(CFLAGS)
+
+LIBS_GCC ?= -lgcc -lm -lnosys
+
+# libc
+LIBS += $(LIBS_GCC)
+
+ifneq ($(BOARD), spresense)
+LIBS += -lc
+endif
+
+# ---------------------------------------
+# Rules
+# ---------------------------------------
+
+# Compile .c file
+$(BUILD)/obj/%.o: %.c
+ @echo CC $(notdir $@)
+ @$(CC) $(CFLAGS) -c -o $@ $<
+
+# ASM sources lower case .s
+$(BUILD)/obj/%_asm.o: %.s
+ @echo AS $(notdir $@)
+ @$(AS) $(ASFLAGS) -c -o $@ $<
+
+# ASM sources upper case .S
+$(BUILD)/obj/%_asm.o: %.S
+ @echo AS $(notdir $@)
+ @$(AS) $(ASFLAGS) -c -o $@ $<
+
+OBJCOPY_BIN_OPTION ?=
+$(BUILD)/$(PROJECT).bin: $(BUILD)/$(PROJECT).elf
+ @echo CREATE $@
+ $(OBJCOPY) -O binary $(OBJCOPY_BIN_OPTION) $^ $@
+
+$(BUILD)/$(PROJECT).hex: $(BUILD)/$(PROJECT).elf
+ @echo CREATE $@
+ @$(OBJCOPY) -O ihex $^ $@
+
+$(BUILD)/$(PROJECT).elf: $(OBJ)
+ @echo LINK $@
+ @$(LD) -o $@ $(LDFLAGS) $^ -Wl,--start-group $(LIBS) -Wl,--end-group
diff --git a/examples/build_system/make/toolchain/arm_iar.mk b/examples/build_system/make/toolchain/arm_iar.mk
new file mode 100644
index 000000000..04c9f22b3
--- /dev/null
+++ b/examples/build_system/make/toolchain/arm_iar.mk
@@ -0,0 +1,11 @@
+# makefile for arm iar toolchain
+AS = iasmarm
+LD = ilinkarm
+OBJCOPY = ielftool --silent
+SIZE = size
+
+# Enable extension mode (gcc compatible)
+CFLAGS += -e --debug --silent
+
+# silent mode
+ASFLAGS += -S $(addprefix -I,$(INC))
diff --git a/examples/build_system/make/toolchain/arm_iar_rules.mk b/examples/build_system/make/toolchain/arm_iar_rules.mk
new file mode 100644
index 000000000..2c066f6da
--- /dev/null
+++ b/examples/build_system/make/toolchain/arm_iar_rules.mk
@@ -0,0 +1,44 @@
+SRC_S += $(SRC_S_IAR)
+
+# Assembly files can be name with upper case .S, convert it to .s
+SRC_S := $(SRC_S:.S=.s)
+
+# Due to GCC LTO bug https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966
+# assembly file should be placed first in linking order
+# '_asm' suffix is added to object of assembly file
+OBJ += $(addprefix $(BUILD)/obj/, $(SRC_S:.s=_asm.o))
+OBJ += $(addprefix $(BUILD)/obj/, $(SRC_C:.c=.o))
+
+# Linker script
+LDFLAGS += --config $(TOP)/$(LD_FILE_IAR)
+
+# ---------------------------------------
+# Rules
+# ---------------------------------------
+
+# Compile .c file
+$(BUILD)/obj/%.o: %.c
+ @echo CC $(notdir $@)
+ @$(CC) $(CFLAGS) -c -o $@ $<
+
+# ASM sources lower case .s
+$(BUILD)/obj/%_asm.o: %.s
+ @echo AS $(notdir $@)
+ @$(AS) $(ASFLAGS) -c -o $@ $<
+
+# ASM sources upper case .S
+$(BUILD)/obj/%_asm.o: %.S
+ @echo AS $(notdir $@)
+ @$(AS) $(ASFLAGS) -c -o $@ $<
+
+$(BUILD)/$(PROJECT).bin: $(BUILD)/$(PROJECT).elf
+ @echo CREATE $@
+ @$(OBJCOPY) --bin $^ $@
+
+$(BUILD)/$(PROJECT).hex: $(BUILD)/$(PROJECT).elf
+ @echo CREATE $@
+ @$(OBJCOPY) --ihex $^ $@
+
+$(BUILD)/$(PROJECT).elf: $(OBJ)
+ @echo LINK $@
+ @$(LD) -o $@ $(LDFLAGS) $^
diff --git a/examples/device/CMakeLists.txt b/examples/device/CMakeLists.txt
index edf5ab805..0a2e49ef0 100644
--- a/examples/device/CMakeLists.txt
+++ b/examples/device/CMakeLists.txt
@@ -1,20 +1,23 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/family_support.cmake)
-project(tinyusb_device_examples)
+project(tinyusb_device_examples C CXX ASM)
family_initialize_project(tinyusb_device_examples ${CMAKE_CURRENT_LIST_DIR})
# family_add_subdirectory will filter what to actually add based on selected FAMILY
family_add_subdirectory(audio_4_channel_mic)
family_add_subdirectory(audio_test)
+family_add_subdirectory(audio_test_multi_rate)
family_add_subdirectory(board_test)
family_add_subdirectory(cdc_dual_ports)
family_add_subdirectory(cdc_msc)
family_add_subdirectory(cdc_msc_freertos)
+family_add_subdirectory(cdc_uac2)
family_add_subdirectory(dfu)
family_add_subdirectory(dfu_runtime)
family_add_subdirectory(dynamic_configuration)
+family_add_subdirectory(hid_boot_interface)
family_add_subdirectory(hid_composite)
family_add_subdirectory(hid_composite_freertos)
family_add_subdirectory(hid_generic_inout)
diff --git a/examples/device/audio_4_channel_mic/CMakeLists.txt b/examples/device/audio_4_channel_mic/CMakeLists.txt
index f6e10e2ea..0f5d36193 100644
--- a/examples/device/audio_4_channel_mic/CMakeLists.txt
+++ b/examples/device/audio_4_channel_mic/CMakeLists.txt
@@ -1,28 +1,38 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
+
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
-)
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
-)
+ )
+
+# Add libm for GCC
+if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_link_libraries(${PROJECT} PUBLIC m)
+endif()
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT})
+# 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(${PROJECT} noos)
diff --git a/examples/device/audio_4_channel_mic/Makefile b/examples/device/audio_4_channel_mic/Makefile
index 5a455078e..2c825bbf7 100644
--- a/examples/device/audio_4_channel_mic/Makefile
+++ b/examples/device/audio_4_channel_mic/Makefile
@@ -1,12 +1,14 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
$(TOP)/hw \
# Example source
-EXAMPLE_SOURCE += $(wildcard src/*.c)
+EXAMPLE_SOURCE += \
+ src/main.c \
+ src/usb_descriptors.c \
+
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/audio_4_channel_mic/skip.txt b/examples/device/audio_4_channel_mic/skip.txt
index ae9b57f1f..157605df1 100644
--- a/examples/device/audio_4_channel_mic/skip.txt
+++ b/examples/device/audio_4_channel_mic/skip.txt
@@ -1,3 +1,5 @@
mcu:SAMD11
mcu:SAME5X
-mcu:SAMG \ No newline at end of file
+mcu:SAMG
+family:broadcom_64bit
+family:espressif
diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c
index a6af5fd19..1de4f9dac 100644
--- a/examples/device/audio_4_channel_mic/src/main.c
+++ b/examples/device/audio_4_channel_mic/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Reinhard Panhuber
@@ -34,17 +34,16 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <math.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
+#include "tusb_config.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
-
-#ifndef AUDIO_SAMPLE_RATE
-#define AUDIO_SAMPLE_RATE 48000
-#endif
+#define AUDIO_SAMPLE_RATE CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE
/* Blink pattern
* - 250 ms : device not mounted
@@ -70,8 +69,13 @@ uint8_t clkValid;
audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; // Volume range state
audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state
-// Audio test data
-uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ/2]; // Ensure half word aligned
+#if CFG_TUD_AUDIO_ENABLE_ENCODING
+// Audio test data, each buffer contains 2 channels, buffer[0] for CH0-1, buffer[1] for CH1-2
+uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX*CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE/1000/CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
+#else
+// Audio test data, 4 channels muxed together, buffer[0] for CH0, buffer[1] for CH1, buffer[2] for CH2, buffer[3] for CH3
+uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX*CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE/1000];
+#endif
void led_blinking_task(void);
void audio_task(void);
@@ -84,6 +88,10 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
// Init values
sampFreq = AUDIO_SAMPLE_RATE;
clkValid = 1;
@@ -93,15 +101,51 @@ int main(void)
sampleFreqRng.subrange[0].bMax = AUDIO_SAMPLE_RATE;
sampleFreqRng.subrange[0].bRes = 0;
+ // Generate dummy data
+#if CFG_TUD_AUDIO_ENABLE_ENCODING
+ uint16_t * p_buff = i2s_dummy_buffer[0];
+ uint16_t dataVal = 1;
+ for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++)
+ {
+ // CH0 saw wave
+ *p_buff++ = dataVal;
+ // CH1 inverted saw wave
+ *p_buff++ = 60 + AUDIO_SAMPLE_RATE/1000 - dataVal;
+ dataVal++;
+ }
+ p_buff = i2s_dummy_buffer[1];
+ for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++)
+ {
+ // CH3 square wave
+ *p_buff++ = cnt < (AUDIO_SAMPLE_RATE/1000/2) ? 120:170;
+ // CH4 sinus wave
+ float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000);
+ *p_buff++ = (uint16_t)(sinf(t) * 25) + 200;
+ }
+#else
+ uint16_t * p_buff = i2s_dummy_buffer;
+ uint16_t dataVal = 1;
+ for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++)
+ {
+ // CH0 saw wave
+ *p_buff++ = dataVal;
+ // CH1 inverted saw wave
+ *p_buff++ = 60 + AUDIO_SAMPLE_RATE/1000 - dataVal;
+ dataVal++;
+ // CH3 square wave
+ *p_buff++ = cnt < (AUDIO_SAMPLE_RATE/1000/2) ? 120:170;
+ // CH4 sinus wave
+ float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000);
+ *p_buff++ = (uint16_t)(sinf(t) * 25) + 200;
+ }
+#endif
+
while (1)
{
tud_task(); // tinyusb device task
led_blinking_task();
audio_task();
}
-
-
- return 0;
}
//--------------------------------------------------------------------+
@@ -132,7 +176,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
@@ -141,8 +185,21 @@ void tud_resume_cb(void)
void audio_task(void)
{
- // Yet to be filled - e.g. put meas data into TX FIFOs etc.
- // asm("nop");
+ // Yet to be filled - e.g. read audio from I2S buffer.
+ // Here we simulate a I2S receive callback every 1ms.
+ static uint32_t start_ms = 0;
+ uint32_t curr_ms = board_millis();
+ if ( start_ms == curr_ms ) return; // not enough time
+ start_ms = curr_ms;
+#if CFG_TUD_AUDIO_ENABLE_ENCODING
+ // Write I2S buffer into FIFO
+ for (uint8_t cnt=0; cnt < 2; cnt++)
+ {
+ tud_audio_write_support_ff(cnt, i2s_dummy_buffer[cnt], AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX);
+ }
+#else
+ tud_audio_write(i2s_dummy_buffer, AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX);
+#endif
}
//--------------------------------------------------------------------+
@@ -290,7 +347,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *
// Those are dummy values for now
ret.bNrChannels = 1;
- ret.bmChannelConfig = 0;
+ ret.bmChannelConfig = (audio_channel_config_t) 0;
ret.iChannelNames = 0;
TU_LOG2(" Get terminal connector\r\n");
@@ -363,7 +420,8 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *
{
case AUDIO_CS_REQ_CUR:
TU_LOG2(" Get Sample Freq.\r\n");
- return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
+ // Buffered control transfer is needed for IN flow control to work
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
case AUDIO_CS_REQ_RANGE:
TU_LOG2(" Get Sample Freq. range\r\n");
@@ -399,10 +457,14 @@ bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, u
(void) ep_in;
(void) cur_alt_setting;
- for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++)
- {
- tud_audio_write_support_ff(cnt, i2s_dummy_buffer[cnt], AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX);
- }
+
+ // In read world application data flow is driven by I2S clock,
+ // both tud_audio_tx_done_pre_load_cb() & tud_audio_tx_done_post_load_cb() are hardly used.
+ // For example in your I2S receive callback:
+ // void I2S_Rx_Callback(int channel, const void* data, uint16_t samples)
+ // {
+ // tud_audio_write_support_ff(channel, data, samples * N_BYTES_PER_SAMPLE * N_CHANNEL_PER_FIFO);
+ // }
return true;
}
@@ -415,22 +477,6 @@ bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uin
(void) ep_in;
(void) cur_alt_setting;
- uint16_t dataVal;
-
- // Generate dummy data
- for (uint16_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++)
- {
- uint16_t * p_buff = i2s_dummy_buffer[cnt]; // 2 bytes per sample
- dataVal = 1;
- for (uint16_t cnt2 = 0; cnt2 < AUDIO_SAMPLE_RATE/1000; cnt2++)
- {
- for (uint8_t cnt3 = 0; cnt3 < CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX; cnt3++)
- {
- *p_buff++ = dataVal;
- }
- dataVal++;
- }
- }
return true;
}
diff --git a/examples/device/audio_4_channel_mic/src/plot_audio_samples.py b/examples/device/audio_4_channel_mic/src/plot_audio_samples.py
index 9ab15135d..d17a908b6 100644
--- a/examples/device/audio_4_channel_mic/src/plot_audio_samples.py
+++ b/examples/device/audio_4_channel_mic/src/plot_audio_samples.py
@@ -10,11 +10,11 @@ if __name__ == '__main__':
# print(sd.query_devices())
fs = 48000 # Sample rate
- duration = 100e-3 # Duration of recording
+ duration = 1 # Duration of recording
if platform.system() == 'Windows':
# WDM-KS is needed since there are more than one MicNode device APIs (at least in Windows)
- device = 'Microphone (MicNode_4_Ch), Windows WDM-KS'
+ device = 'Microphone (MicNode_4_Ch), Windows WASAPI'
elif platform.system() == 'Darwin':
device = 'MicNode_4_Ch'
else:
@@ -25,10 +25,13 @@ if __name__ == '__main__':
sd.wait() # Wait until recording is finished
print('Done!')
+
time = np.arange(0, duration, 1 / fs) # time vector
+ # strip starting zero
+
plt.plot(time, myrecording)
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.title('MicNode 4 Channel')
+ plt.legend(['CH-1', 'CH-2', 'CH-3','CH-4'])
plt.show()
- \ No newline at end of file
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 5cf6d07c3..46484f847 100644
--- a/examples/device/audio_4_channel_mic/src/tusb_config.h
+++ b/examples/device/audio_4_channel_mic/src/tusb_config.h
@@ -103,6 +103,7 @@ extern "C" {
//--------------------------------------------------------------------
// Have a look into audio_device.h for all configurations
+#define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_FOUR_CH_DESC_LEN
@@ -112,15 +113,27 @@ extern "C" {
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 4 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
-#define CFG_TUD_AUDIO_EP_SZ_IN (48 + 1) * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x CFG_TUD_AUDIO_N_CHANNELS_TX Channels - the Windows driver always needs an extra sample per channel of space more, otherwise it complains... found by trial and error
+#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)
+
+#define CFG_TUD_AUDIO_ENABLE_ENCODING 1
+#define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 1
+
+#if CFG_TUD_AUDIO_ENABLE_ENCODING
+
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN
-#define CFG_TUD_AUDIO_ENABLE_ENCODING 1
#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 1
#define CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX 2 // One I2S stream contains two channels, each stream is saved within one support FIFO - this value is currently fixed, the driver does not support a changing value
#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX)
-#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO)
+#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO) // Example write FIFO every 1ms, so it should be 8 times larger for HS device
+
+#else
+
+#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN
+#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_EP_SZ_IN // Example write FIFO every 1ms, so it should be 8 times larger for HS device
+
+#endif
#ifdef __cplusplus
}
diff --git a/examples/device/audio_4_channel_mic/src/usb_descriptors.c b/examples/device/audio_4_channel_mic/src/usb_descriptors.c
index 8929f3057..728a5f9ce 100644
--- a/examples/device/audio_4_channel_mic/src/usb_descriptors.c
+++ b/examples/device/audio_4_channel_mic/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,6 +23,7 @@
*
*/
+#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.
@@ -44,7 +45,7 @@ tusb_desc_device_t const desc_device =
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
- // Use Interface Association Descriptor (IAD) for CDC
+ // Use Interface Association Descriptor (IAD) for Audio
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
@@ -96,7 +97,7 @@ enum
uint8_t const desc_configuration[] =
{
- // Interface count, string index, total length, attribute, power in mA
+ // 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 Out & EP In address, EP size
@@ -116,50 +117,63 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
-{
- (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
- "PaniRCorp", // 1: Manufacturer
- "MicNode_4_Ch", // 2: Product
- "123458", // 3: Serials, should use chip ID
- "UAC2", // 4: Audio Interface
+char const* string_desc_arr [] = {
+ (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
+ "PaniRCorp", // 1: Manufacturer
+ "MicNode_4_Ch", // 2: Product
+ NULL, // 3: Serials will use unique ID if possible
+ "UAC2", // 4: Audio Interface
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // Convert ASCII string into UTF-16
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
+ if ( chr_count > max_count ) chr_count = max_count;
- for(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/audio_test/CMakeLists.txt b/examples/device/audio_test/CMakeLists.txt
index cb321f9a8..f61e1b640 100644
--- a/examples/device/audio_test/CMakeLists.txt
+++ b/examples/device/audio_test/CMakeLists.txt
@@ -1,28 +1,33 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
+
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
-)
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
-)
+ )
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/audio_test/Makefile b/examples/device/audio_test/Makefile
index 5a455078e..7fa475da5 100644
--- a/examples/device/audio_test/Makefile
+++ b/examples/device/audio_test/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,4 +8,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/audio_test/skip.txt b/examples/device/audio_test/skip.txt
index ae9b57f1f..65b137814 100644
--- a/examples/device/audio_test/skip.txt
+++ b/examples/device/audio_test/skip.txt
@@ -1,3 +1,4 @@
mcu:SAMD11
mcu:SAME5X
-mcu:SAMG \ No newline at end of file
+mcu:SAMG
+family:espressif
diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c
index d0849c7ac..06783ccfb 100644
--- a/examples/device/audio_test/src/main.c
+++ b/examples/device/audio_test/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Reinhard Panhuber
@@ -35,7 +35,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
//--------------------------------------------------------------------+
@@ -71,7 +71,7 @@ audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1];
audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state
// Audio test data
-uint16_t test_buffer_audio[CFG_TUD_AUDIO_EP_SZ_IN/2];
+uint16_t test_buffer_audio[(CFG_TUD_AUDIO_EP_SZ_IN - 2) / 2];
uint16_t startVal = 0;
void led_blinking_task(void);
@@ -85,6 +85,10 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
// Init values
sampFreq = AUDIO_SAMPLE_RATE;
clkValid = 1;
@@ -100,9 +104,6 @@ int main(void)
led_blinking_task();
audio_task();
}
-
-
- return 0;
}
//--------------------------------------------------------------------+
@@ -133,7 +134,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
@@ -291,7 +292,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *
// Those are dummy values for now
ret.bNrChannels = 1;
- ret.bmChannelConfig = 0;
+ ret.bmChannelConfig = (audio_channel_config_t) 0;
ret.iChannelNames = 0;
TU_LOG2(" Get terminal connector\r\n");
@@ -400,7 +401,7 @@ bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, u
(void) ep_in;
(void) cur_alt_setting;
- tud_audio_write ((uint8_t *)test_buffer_audio, CFG_TUD_AUDIO_EP_SZ_IN);
+ tud_audio_write ((uint8_t *)test_buffer_audio, CFG_TUD_AUDIO_EP_SZ_IN - 2);
return true;
}
@@ -413,7 +414,7 @@ bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uin
(void) ep_in;
(void) cur_alt_setting;
- for (size_t cnt = 0; cnt < CFG_TUD_AUDIO_EP_SZ_IN/2; cnt++)
+ for (size_t cnt = 0; cnt < (CFG_TUD_AUDIO_EP_SZ_IN - 2) / 2; cnt++)
{
test_buffer_audio[cnt] = startVal++;
}
diff --git a/examples/device/audio_test/src/plot_audio_samples.py b/examples/device/audio_test/src/plot_audio_samples.py
index 6e3c4978e..1504684a6 100644
--- a/examples/device/audio_test/src/plot_audio_samples.py
+++ b/examples/device/audio_test/src/plot_audio_samples.py
@@ -2,6 +2,7 @@ import sounddevice as sd
import matplotlib.pyplot as plt
import numpy as np
import platform
+import csv
if __name__ == '__main__':
@@ -31,4 +32,6 @@ if __name__ == '__main__':
plt.ylabel('Amplitude')
plt.title('MicNode')
plt.show()
- \ No newline at end of file
+
+ samples = np.array(myrecording)
+ np.savetxt('Output.csv', samples, delimiter=",", fmt='%s')
diff --git a/examples/device/audio_test/src/tusb_config.h b/examples/device/audio_test/src/tusb_config.h
index 355ed1011..9f38612a9 100644
--- a/examples/device/audio_test/src/tusb_config.h
+++ b/examples/device/audio_test/src/tusb_config.h
@@ -114,7 +114,7 @@ extern "C" {
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor!
-#define CFG_TUD_AUDIO_EP_SZ_IN 48 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channel
+#define CFG_TUD_AUDIO_EP_SZ_IN (48 + 1) * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x CFG_TUD_AUDIO_N_CHANNELS_TX Channels - One extra sample is needed for asynchronous transfer adjustment, see feedback EP
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN // Maximum EP IN size for all AS alternate settings used
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN + 1
diff --git a/examples/device/audio_test/src/usb_descriptors.c b/examples/device/audio_test/src/usb_descriptors.c
index da3e203d7..9864377f6 100644
--- a/examples/device/audio_test/src/usb_descriptors.c
+++ b/examples/device/audio_test/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,6 +23,7 @@
*
*/
+#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.
@@ -44,7 +45,7 @@ tusb_desc_device_t const desc_device =
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
- // Use Interface Association Descriptor (IAD) for CDC
+ // Use Interface Association Descriptor (IAD) for Audio
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
@@ -96,7 +97,7 @@ enum
uint8_t const desc_configuration[] =
{
- // Interface count, string index, total length, attribute, power in mA
+ // 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 Out & EP In address, EP size
@@ -116,50 +117,65 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
- (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
- "PaniRCorp", // 1: Manufacturer
- "MicNode", // 2: Product
- "123456", // 3: Serials, should use chip ID
- "UAC2", // 4: Audio Interface
+ (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
+ "PaniRCorp", // 1: Manufacturer
+ "MicNode", // 2: Product
+ NULL, // 3: Serials will use unique ID if possible
+ "UAC2", // 4: Audio Interface
+
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // Convert ASCII string into UTF-16
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
+ if ( chr_count > max_count ) chr_count = max_count;
- for(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/audio_test_multi_rate/CMakeLists.txt b/examples/device/audio_test_multi_rate/CMakeLists.txt
new file mode 100644
index 000000000..f61e1b640
--- /dev/null
+++ b/examples/device/audio_test_multi_rate/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 3.17)
+
+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()
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
+
+# Example include
+target_include_directories(${PROJECT} 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(${PROJECT} noos)
diff --git a/examples/device/audio_test_multi_rate/Makefile b/examples/device/audio_test_multi_rate/Makefile
new file mode 100644
index 000000000..7fa475da5
--- /dev/null
+++ b/examples/device/audio_test_multi_rate/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/audio_test_multi_rate/skip.txt b/examples/device/audio_test_multi_rate/skip.txt
new file mode 100644
index 000000000..65b137814
--- /dev/null
+++ b/examples/device/audio_test_multi_rate/skip.txt
@@ -0,0 +1,4 @@
+mcu:SAMD11
+mcu:SAME5X
+mcu:SAMG
+family:espressif
diff --git a/examples/device/audio_test_multi_rate/src/main.c b/examples/device/audio_test_multi_rate/src/main.c
new file mode 100644
index 000000000..3e7f40dac
--- /dev/null
+++ b/examples/device/audio_test_multi_rate/src/main.c
@@ -0,0 +1,525 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Reinhard Panhuber
+ * Copyright (c) 2022 HiFiPhile
+ *
+ * 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.
+ *
+ */
+
+/* plot_audio_samples.py requires following modules:
+ * $ sudo apt install libportaudio
+ * $ pip3 install sounddevice matplotlib
+ *
+ * Then run
+ * $ python3 plot_audio_samples.py
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bsp/board_api.h"
+#include "tusb.h"
+#include "usb_descriptors.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;
+
+// Audio controls
+// Current states
+bool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
+uint16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
+uint32_t sampFreq;
+uint8_t bytesPerSample;
+uint8_t clkValid;
+
+// Range states
+// List of supported sample rates
+static const uint32_t sampleRatesList[] =
+{
+ 32000, 48000, 96000
+};
+
+#define N_sampleRates TU_ARRAY_SIZE(sampleRatesList)
+
+// Bytes per format of every Alt settings
+static const uint8_t bytesPerSampleAltList[CFG_TUD_AUDIO_FUNC_1_N_FORMATS] =
+{
+ CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX,
+ CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX,
+};
+
+audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; // Volume range state
+
+
+// Audio test data
+CFG_TUSB_MEM_ALIGN uint8_t test_buffer_audio[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
+uint16_t startVal = 0;
+
+void led_blinking_task(void);
+void audio_task(void);
+
+/*------------- MAIN -------------*/
+int main(void)
+{
+ board_init();
+
+ // init device stack on configured roothub port
+ tud_init(BOARD_TUD_RHPORT);
+
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
+ // Init values
+ sampFreq = sampleRatesList[0];
+ clkValid = 1;
+
+ while (1)
+ {
+ tud_task(); // tinyusb device task
+ led_blinking_task();
+ audio_task();
+ }
+
+
+ return 0;
+}
+
+//--------------------------------------------------------------------+
+// 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;
+}
+
+//--------------------------------------------------------------------+
+// AUDIO Task
+//--------------------------------------------------------------------+
+
+void audio_task(void)
+{
+ // Yet to be filled - e.g. put meas data into TX FIFOs etc.
+ // asm("nop");
+}
+
+//--------------------------------------------------------------------+
+// Application Callback API Implementations
+//--------------------------------------------------------------------+
+
+// Invoked when set interface is called, typically on start/stop streaming or format change
+bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+ (void)rhport;
+ //uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex));
+ uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue));
+
+ // Clear buffer when streaming format is changed
+ if(alt != 0)
+ {
+ bytesPerSample = bytesPerSampleAltList[alt-1];
+ }
+ return true;
+}
+
+// Invoked when audio class specific set request received for an EP
+bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
+{
+ (void) rhport;
+ (void) pBuff;
+
+ // We do not support any set range requests here, only current value requests
+ TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
+
+ // Page 91 in UAC2 specification
+ uint8_t channelNum = TU_U16_LOW(p_request->wValue);
+ uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
+ uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+ (void) channelNum; (void) ctrlSel; (void) ep;
+
+ return false; // Yet not implemented
+}
+
+// Invoked when audio class specific set request received for an interface
+bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
+{
+ (void) rhport;
+ (void) pBuff;
+
+ // We do not support any set range requests here, only current value requests
+ TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
+
+ // Page 91 in UAC2 specification
+ uint8_t channelNum = TU_U16_LOW(p_request->wValue);
+ uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
+ uint8_t itf = TU_U16_LOW(p_request->wIndex);
+
+ (void) channelNum; (void) ctrlSel; (void) itf;
+
+ return false; // Yet not implemented
+}
+
+// Invoked when audio class specific set request received for an entity
+bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
+{
+ (void) rhport;
+
+ // Page 91 in UAC2 specification
+ uint8_t channelNum = TU_U16_LOW(p_request->wValue);
+ uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
+ uint8_t itf = TU_U16_LOW(p_request->wIndex);
+ uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+ (void) itf;
+
+ // We do not support any set range requests here, only current value requests
+ TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
+
+ // If request is for our feature unit
+ if ( entityID == UAC2_ENTITY_FEATURE_UNIT )
+ {
+ switch ( ctrlSel )
+ {
+ case AUDIO_FU_CTRL_MUTE:
+ // Request uses format layout 1
+ TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t));
+
+ mute[channelNum] = ((audio_control_cur_1_t*) pBuff)->bCur;
+
+ TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum);
+ return true;
+
+ case AUDIO_FU_CTRL_VOLUME:
+ // Request uses format layout 2
+ TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t));
+
+ volume[channelNum] = (uint16_t) ((audio_control_cur_2_t*) pBuff)->bCur;
+
+ TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum);
+ return true;
+
+ // Unknown/Unsupported control
+ default:
+ TU_BREAKPOINT();
+ return false;
+ }
+ }
+
+ // Clock Source unit
+ if ( entityID == UAC2_ENTITY_CLOCK )
+ {
+ switch ( ctrlSel )
+ {
+ case AUDIO_CS_CTRL_SAM_FREQ:
+ TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_4_t));
+
+ sampFreq = (uint32_t)((audio_control_cur_4_t *)pBuff)->bCur;
+
+ TU_LOG2("Clock set current freq: %lu\r\n", sampFreq);
+
+ return true;
+ break;
+
+ // Unknown/Unsupported control
+ default:
+ TU_BREAKPOINT();
+ return false;
+ }
+ }
+
+ return false; // Yet not implemented
+}
+
+// Invoked when audio class specific get request received for an EP
+bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+ (void) rhport;
+
+ // Page 91 in UAC2 specification
+ uint8_t channelNum = TU_U16_LOW(p_request->wValue);
+ uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
+ uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+ (void) channelNum; (void) ctrlSel; (void) ep;
+
+ // return tud_control_xfer(rhport, p_request, &tmp, 1);
+
+ return false; // Yet not implemented
+}
+
+// Invoked when audio class specific get request received for an interface
+bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+ (void) rhport;
+
+ // Page 91 in UAC2 specification
+ uint8_t channelNum = TU_U16_LOW(p_request->wValue);
+ uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
+ uint8_t itf = TU_U16_LOW(p_request->wIndex);
+
+ (void) channelNum; (void) ctrlSel; (void) itf;
+
+ return false; // Yet not implemented
+}
+
+// Invoked when audio class specific get request received for an entity
+bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+ (void) rhport;
+
+ // Page 91 in UAC2 specification
+ uint8_t channelNum = TU_U16_LOW(p_request->wValue);
+ uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
+ // uint8_t itf = TU_U16_LOW(p_request->wIndex); // Since we have only one audio function implemented, we do not need the itf value
+ uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+ // Input terminal (Microphone input)
+ if (entityID == UAC2_ENTITY_INPUT_TERMINAL)
+ {
+ switch ( ctrlSel )
+ {
+ case AUDIO_TE_CTRL_CONNECTOR:
+ {
+ // The terminal connector control only has a get request with only the CUR attribute.
+ audio_desc_channel_cluster_t ret;
+
+ // Those are dummy values for now
+ ret.bNrChannels = 1;
+ ret.bmChannelConfig = 0;
+ ret.iChannelNames = 0;
+
+ TU_LOG2(" Get terminal connector\r\n");
+
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret));
+ }
+ break;
+
+ // Unknown/Unsupported control selector
+ default:
+ TU_BREAKPOINT();
+ return false;
+ }
+ }
+
+ // Feature unit
+ if (entityID == UAC2_ENTITY_FEATURE_UNIT)
+ {
+ switch ( ctrlSel )
+ {
+ case AUDIO_FU_CTRL_MUTE:
+ // Audio control mute cur parameter block consists of only one byte - we thus can send it right away
+ // There does not exist a range parameter block for mute
+ TU_LOG2(" Get Mute of channel: %u\r\n", channelNum);
+ return tud_control_xfer(rhport, p_request, &mute[channelNum], 1);
+
+ case AUDIO_FU_CTRL_VOLUME:
+ switch ( p_request->bRequest )
+ {
+ case AUDIO_CS_REQ_CUR:
+ TU_LOG2(" Get Volume of channel: %u\r\n", channelNum);
+ return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum]));
+
+ case AUDIO_CS_REQ_RANGE:
+ TU_LOG2(" Get Volume range of channel: %u\r\n", channelNum);
+
+ // Copy values - only for testing - better is version below
+ audio_control_range_2_n_t(1)
+ ret;
+
+ ret.wNumSubRanges = 1;
+ ret.subrange[0].bMin = -90; // -90 dB
+ ret.subrange[0].bMax = 30; // +30 dB
+ ret.subrange[0].bRes = 1; // 1 dB steps
+
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret));
+
+ // Unknown/Unsupported control
+ default:
+ TU_BREAKPOINT();
+ return false;
+ }
+ break;
+
+ // Unknown/Unsupported control
+ default:
+ TU_BREAKPOINT();
+ return false;
+ }
+ }
+
+ // Clock Source unit
+ if ( entityID == UAC2_ENTITY_CLOCK )
+ {
+ switch ( ctrlSel )
+ {
+ case AUDIO_CS_CTRL_SAM_FREQ:
+ // channelNum is always zero in this case
+ switch ( p_request->bRequest )
+ {
+ case AUDIO_CS_REQ_CUR:
+ TU_LOG2(" Get Sample Freq.\r\n");
+ return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
+
+ case AUDIO_CS_REQ_RANGE:
+ {
+ TU_LOG2(" Get Sample Freq. range\r\n");
+ audio_control_range_4_n_t(N_sampleRates) rangef =
+ {
+ .wNumSubRanges = tu_htole16(N_sampleRates)
+ };
+ TU_LOG1("Clock get %d freq ranges\r\n", N_sampleRates);
+ for(uint8_t i = 0; i < N_sampleRates; i++)
+ {
+ rangef.subrange[i].bMin = (int32_t)sampleRatesList[i];
+ rangef.subrange[i].bMax = (int32_t)sampleRatesList[i];
+ rangef.subrange[i].bRes = 0;
+ TU_LOG1("Range %d (%d, %d, %d)\r\n", i, (int)rangef.subrange[i].bMin, (int)rangef.subrange[i].bMax, (int)rangef.subrange[i].bRes);
+ }
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &rangef, sizeof(rangef));
+ }
+ // Unknown/Unsupported control
+ default:
+ TU_BREAKPOINT();
+ return false;
+ }
+ break;
+
+ case AUDIO_CS_CTRL_CLK_VALID:
+ // Only cur attribute exists for this request
+ TU_LOG2(" Get Sample Freq. valid\r\n");
+ return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid));
+
+ // Unknown/Unsupported control
+ default:
+ TU_BREAKPOINT();
+ return false;
+ }
+ }
+
+ TU_LOG2(" Unsupported entity: %d\r\n", entityID);
+ return false; // Yet not implemented
+}
+
+bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting)
+{
+ (void) rhport;
+ (void) itf;
+ (void) ep_in;
+ (void) cur_alt_setting;
+
+ tud_audio_write((uint8_t *)test_buffer_audio, (uint16_t)(sampFreq / (TUD_OPT_HIGH_SPEED ? 8000 : 1000) * bytesPerSample));
+
+ return true;
+}
+
+bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting)
+{
+ (void) rhport;
+ (void) n_bytes_copied;
+ (void) itf;
+ (void) ep_in;
+ (void) cur_alt_setting;
+
+ // 16bit
+ if(bytesPerSample == 2)
+ {
+ uint16_t* pData_16 = (uint16_t*)((void*)test_buffer_audio);
+ for (size_t cnt = 0; cnt < sampFreq / (TUD_OPT_HIGH_SPEED ? 8000 : 1000); cnt++)
+ {
+ pData_16[cnt] = startVal++;
+ }
+ }
+ // 24bit in 32bit slot
+ else if(bytesPerSample == 4)
+ {
+ uint32_t* pData_32 = (uint32_t*)((void*)test_buffer_audio);
+ for (size_t cnt = 0; cnt < sampFreq / (TUD_OPT_HIGH_SPEED ? 8000 : 1000); cnt++)
+ {
+ pData_32[cnt] = (uint32_t)startVal++ << 16U;
+ }
+ }
+
+ return true;
+}
+
+bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+ (void) rhport;
+ (void) p_request;
+ startVal = 0;
+
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// 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/audio_test_multi_rate/src/plot_audio_samples.py b/examples/device/audio_test_multi_rate/src/plot_audio_samples.py
new file mode 100644
index 000000000..c92e49957
--- /dev/null
+++ b/examples/device/audio_test_multi_rate/src/plot_audio_samples.py
@@ -0,0 +1,37 @@
+import sounddevice as sd
+import matplotlib.pyplot as plt
+import numpy as np
+import platform
+import csv
+
+if __name__ == '__main__':
+
+ # If you got "ValueError: No input device matching", that is because your PC name example device
+ # differently from tested list below. Uncomment the next line to see full list and try to pick correct one
+ # print(sd.query_devices())
+
+ fs = 96000 # Sample rate
+ duration = 100e-3 # Duration of recording
+
+ if platform.system() == 'Windows':
+ # MME is needed since there are more than one MicNode device APIs (at least in Windows)
+ device = 'Microphone (MicNode) MME'
+ elif platform.system() == 'Darwin':
+ device = 'MicNode'
+ else:
+ device ='default'
+
+ myrecording = sd.rec(int(duration * fs), samplerate=fs, channels=1, dtype='int16', device=device)
+ print('Waiting...')
+ sd.wait() # Wait until recording is finished
+ print('Done!')
+
+ time = np.arange(0, duration, 1 / fs) # time vector
+ plt.plot(time, myrecording)
+ plt.xlabel('Time [s]')
+ plt.ylabel('Amplitude')
+ plt.title('MicNode')
+ plt.show()
+
+ samples = np.array(myrecording)
+ np.savetxt('Output.csv', samples, delimiter=",", fmt='%s')
diff --git a/examples/device/audio_test_multi_rate/src/tusb_config.h b/examples/device/audio_test_multi_rate/src/tusb_config.h
new file mode 100644
index 000000000..1c8288bce
--- /dev/null
+++ b/examples/device/audio_test_multi_rate/src/tusb_config.h
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "usb_descriptors.h"
+
+//--------------------------------------------------------------------+
+// 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
+
+// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
+// #define CFG_TUSB_DEBUG 0
+
+/* 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_AUDIO 1
+#define CFG_TUD_CDC 0
+#define CFG_TUD_MSC 0
+#define CFG_TUD_HID 0
+#define CFG_TUD_MIDI 0
+#define CFG_TUD_VENDOR 0
+
+//--------------------------------------------------------------------
+// AUDIO CLASS DRIVER CONFIGURATION
+//--------------------------------------------------------------------
+
+#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE 96000
+
+// How many formats are used, need to adjust USB descriptor if changed
+#define CFG_TUD_AUDIO_FUNC_1_N_FORMATS 2
+
+// 16bit in 16bit slots
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX 2
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX 16
+
+// 24bit in 32bit slots
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX 4
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX 24
+
+// 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
+#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor!
+
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)
+
+#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN) // Maximum EP IN size for all AS alternate settings used
+#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */
diff --git a/examples/device/audio_test_multi_rate/src/usb_descriptors.c b/examples/device/audio_test_multi_rate/src/usb_descriptors.c
new file mode 100644
index 000000000..f50e70a25
--- /dev/null
+++ b/examples/device/audio_test_multi_rate/src/usb_descriptors.c
@@ -0,0 +1,185 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ * Copyright (c) 2022 HiFiPhile
+ *
+ * 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 "usb_descriptors.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] AUDIO | 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(AUDIO, 4) | _PID_MAP(VENDOR, 5) )
+
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
+tusb_desc_device_t const desc_device =
+{
+ .bLength = sizeof(tusb_desc_device_t),
+ .bDescriptorType = TUSB_DESC_DEVICE,
+ .bcdUSB = 0x0200,
+
+ // Use Interface Association Descriptor (IAD) for Audio
+ // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
+ .bDeviceClass = TUSB_CLASS_MISC,
+ .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+ .bDeviceProtocol = MISC_PROTOCOL_IAD,
+ .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+
+ .idVendor = 0xCafe,
+ .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_AUDIO_CONTROL = 0,
+ ITF_NUM_AUDIO_STREAMING,
+ ITF_NUM_TOTAL
+};
+
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_ONE_CH_2_FORMAT_DESC_LEN)
+
+#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 etc ...
+ #define EPNUM_AUDIO 0x03
+
+#elif TU_CHECK_MCU(OPT_MCU_NRF5X)
+ // nRF5x ISO can only be endpoint 8
+ #define EPNUM_AUDIO 0x08
+
+#else
+ #define EPNUM_AUDIO 0x01
+#endif
+
+uint8_t const desc_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 Out & EP In address, EP size
+ TUD_AUDIO_MIC_ONE_CH_2_FORMAT_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_epin*/ 0x80 | EPNUM_AUDIO)
+};
+
+TU_VERIFY_STATIC(sizeof(desc_configuration) == CONFIG_TOTAL_LEN, "Incorrect size");
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
+{
+ (void) index; // for multiple configurations
+ return desc_configuration;
+}
+
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
+// array of pointer to string descriptors
+char const* string_desc_arr [] =
+{
+ (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
+ "PaniRCorp", // 1: Manufacturer
+ "MicNode", // 2: Product
+ NULL, // 3: Serials will use unique ID if possible
+ "UAC2", // 4: Audio 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);
+ size_t const 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/audio_test_multi_rate/src/usb_descriptors.h b/examples/device/audio_test_multi_rate/src/usb_descriptors.h
new file mode 100644
index 000000000..8381e31f5
--- /dev/null
+++ b/examples/device/audio_test_multi_rate/src/usb_descriptors.h
@@ -0,0 +1,102 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 HiFiPhile
+ *
+ * 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 _USB_DESCRIPTORS_H_
+#define _USB_DESCRIPTORS_H_
+
+// #include "tusb.h"
+
+// Unit numbers are arbitrary selected
+#define UAC2_ENTITY_CLOCK 0x04
+#define UAC2_ENTITY_INPUT_TERMINAL 0x01
+#define UAC2_ENTITY_OUTPUT_TERMINAL 0x03
+#define UAC2_ENTITY_FEATURE_UNIT 0x02
+
+
+#define TUD_AUDIO_MIC_ONE_CH_2_FORMAT_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\
+ + TUD_AUDIO_DESC_STD_AC_LEN\
+ + TUD_AUDIO_DESC_CS_AC_LEN\
+ + TUD_AUDIO_DESC_CLK_SRC_LEN\
+ + TUD_AUDIO_DESC_INPUT_TERM_LEN\
+ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
+ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\
+ /* Interface 1, Alternate 0 */\
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ /* Interface 1, Alternate 1 */\
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ + TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\
+ /* Interface 1, Alternate 2 */\
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ + TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN)
+
+
+#define TUD_AUDIO_MIC_ONE_CH_2_FORMAT_DESCRIPTOR(_itfnum, _stridx, _epin) \
+ /* Standard Interface Association Descriptor (IAD) */\
+ TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
+ /* Standard AC Interface Descriptor(4.7.1) */\
+ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
+ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\
+ TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\
+ /* Clock Source Descriptor(4.7.2.1) */\
+ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_PRO_CLK, /*_ctrl*/ AUDIO_CTRL_RW << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS | AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_VAL_POS, /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\
+ /* Input Terminal Descriptor(4.7.2.4) */\
+ TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ UAC2_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\
+ /* Output Terminal Descriptor(4.7.2.5) */\
+ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ UAC2_ENTITY_INPUT_TERMINAL, /*_srcid*/ UAC2_ENTITY_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
+ /* Feature Unit Descriptor(4.7.2.8) */\
+ TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ UAC2_ENTITY_FEATURE_UNIT, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\
+ /* Standard AS Interface Descriptor(4.9.1) */\
+ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\
+ /* Standard AS Interface Descriptor(4.9.1) */\
+ /* Interface 1, Alternate 1 - alternate interface for data streaming */\
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\
+ /* Class-Specific AS Interface Descriptor(4.9.2) */\
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN, /*_interval*/ 0x01),\
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\
+ /* Interface 1, Alternate 2 - alternate interface for data streaming */\
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\
+ /* Class-Specific AS Interface Descriptor(4.9.2) */\
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX),\
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN, /*_interval*/ 0x01),\
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
+
+
+#endif
diff --git a/examples/device/board_test/CMakeLists.txt b/examples/device/board_test/CMakeLists.txt
index 37113578e..012eff095 100644
--- a/examples/device/board_test/CMakeLists.txt
+++ b/examples/device/board_test/CMakeLists.txt
@@ -1,42 +1,32 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
-# Check for -DFAMILY=
-if(FAMILY MATCHES "^esp32s[2-3]")
- # use BOARD-Directory name for project id
- get_filename_component(PROJECT ${CMAKE_CURRENT_SOURCE_DIR} NAME)
- set(PROJECT ${BOARD}-${PROJECT})
+# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
+family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
- # TOP is absolute path to root directory of TinyUSB git repo
- set(TOP "../../..")
- get_filename_component(TOP "${TOP}" REALPATH)
+project(${PROJECT} C CXX ASM)
- project(${PROJECT})
+# Checks this example is valid for the family and initializes the project
+family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
-else()
-
- # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
- family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-
- project(${PROJECT})
-
- # 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()
- add_executable(${PROJECT})
+add_executable(${PROJECT})
- # Example source
- target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- )
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ )
- # Example include
- target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
- # Configure compilation flags and libraries for the example... see the corresponding function
- # in hw/bsp/FAMILY/family.cmake for details.
- family_configure_device_example(${PROJECT})
-endif()
+# 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(${PROJECT} noos)
diff --git a/examples/device/board_test/Makefile b/examples/device/board_test/Makefile
index b65575ce6..7fa475da5 100644
--- a/examples/device/board_test/Makefile
+++ b/examples/device/board_test/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,10 +8,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-# board_test example is special example that doesn't enable device or host stack
-# This can cause some TinyUSB API missing, this hack to allow us to fill those API
-# to pass the compilation process
-CFLAGS += \
- -D"tud_int_handler(x)= " \
-
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/board_test/src/CMakeLists.txt b/examples/device/board_test/src/CMakeLists.txt
index e4e1f4e9a..8d85dcafd 100644
--- a/examples/device/board_test/src/CMakeLists.txt
+++ b/examples/device/board_test/src/CMakeLists.txt
@@ -1,17 +1,3 @@
-# FAMILY = esp32sx
idf_component_register(SRCS "main.c"
INCLUDE_DIRS "."
- REQUIRES freertos soc)
-
-file(TO_NATIVE_PATH "${TOP}/hw/bsp/${FAMILY}/boards/${BOARD}/board.cmake" board_cmake)
-
-if(EXISTS ${board_cmake})
- include(${board_cmake})
-endif()
-
-idf_component_get_property( FREERTOS_ORIG_INCLUDE_PATH freertos ORIG_INCLUDE_PATH)
-target_include_directories(${COMPONENT_TARGET} PUBLIC
- "${FREERTOS_ORIG_INCLUDE_PATH}"
- "${TOP}/hw"
- "${TOP}/src"
-)
+ REQUIRES boards tinyusb_src)
diff --git a/examples/device/board_test/src/main.c b/examples/device/board_test/src/main.c
index 5e28cbb27..91799eb89 100644
--- a/examples/device/board_test/src/main.c
+++ b/examples/device/board_test/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -26,39 +26,31 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-
-#include "bsp/board.h"
-
-//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF PROTYPES
-//--------------------------------------------------------------------+
+#include "bsp/board_api.h"
/* Blink pattern
* - 250 ms : button is not pressed
* - 1000 ms : button is pressed (and hold)
*/
-enum {
+enum {
BLINK_PRESSED = 250,
BLINK_UNPRESSED = 1000
};
#define HELLO_STR "Hello from TinyUSB\r\n"
-int main(void)
-{
+int main(void) {
board_init();
board_led_write(true);
uint32_t start_ms = 0;
bool led_state = false;
- while (1)
- {
+ while (1) {
uint32_t interval_ms = board_button_read() ? BLINK_PRESSED : BLINK_UNPRESSED;
- // Blink every interval ms
- if ( !(board_millis() - start_ms < interval_ms) )
- {
+ // Blink and print every interval ms
+ if (!(board_millis() - start_ms < interval_ms)) {
board_uart_write(HELLO_STR, strlen(HELLO_STR));
start_ms = board_millis();
@@ -66,14 +58,17 @@ int main(void)
board_led_write(led_state);
led_state = 1 - led_state; // toggle
}
- }
- return 0;
+ // echo
+ uint8_t ch;
+ if (board_uart_read(&ch, 1) > 0) {
+ board_uart_write(&ch, 1);
+ }
+ }
}
#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
-void app_main(void)
-{
+void app_main(void) {
main();
}
#endif
diff --git a/examples/device/board_test/src/tusb_config.h b/examples/device/board_test/src/tusb_config.h
index 5aea4fd2c..1a27cc87f 100644
--- a/examples/device/board_test/src/tusb_config.h
+++ b/examples/device/board_test/src/tusb_config.h
@@ -30,6 +30,11 @@
extern "C" {
#endif
+// board_test example is special example that doesn't enable device or host stack
+// This can cause some TinyUSB API missing, this define hack to allow us to fill those API
+// to pass the compilation process
+#define tud_int_handler(x)
+
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
@@ -43,6 +48,11 @@
#define CFG_TUSB_OS OPT_OS_NONE
#endif
+// Espressif IDF requires "freertos/" prefix in include path
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+#define CFG_TUSB_OS_INC_PATH freertos/
+#endif
+
// This example only test LED & GPIO, disable both device and host stack
#define CFG_TUD_ENABLED 0
#define CFG_TUH_ENABLED 0
diff --git a/examples/device/cdc_dual_ports/CMakeLists.txt b/examples/device/cdc_dual_ports/CMakeLists.txt
index abc4d91da..f61e1b640 100644
--- a/examples/device/cdc_dual_ports/CMakeLists.txt
+++ b/examples/device/cdc_dual_ports/CMakeLists.txt
@@ -1,28 +1,33 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
+
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/cdc_dual_ports/Makefile b/examples/device/cdc_dual_ports/Makefile
index 5a455078e..7fa475da5 100644
--- a/examples/device/cdc_dual_ports/Makefile
+++ b/examples/device/cdc_dual_ports/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,4 +8,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/cdc_dual_ports/src/main.c b/examples/device/cdc_dual_ports/src/main.c
index 0264f0566..1167a5d50 100644
--- a/examples/device/cdc_dual_ports/src/main.c
+++ b/examples/device/cdc_dual_ports/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -28,44 +28,53 @@
#include <string.h>
#include <ctype.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
-//------------- prototypes -------------//
+/* 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;
+
+static void led_blinking_task(void);
static void cdc_task(void);
/*------------- MAIN -------------*/
-int main(void)
-{
+int main(void) {
board_init();
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
- while (1)
- {
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
+ while (1) {
tud_task(); // tinyusb device task
cdc_task();
+ led_blinking_task();
}
-
- return 0;
}
// echo to either Serial0 or Serial1
// with Serial0 as all lower case, Serial1 as all upper case
-static void echo_serial_port(uint8_t itf, uint8_t buf[], uint32_t count)
-{
+static void echo_serial_port(uint8_t itf, uint8_t buf[], uint32_t count) {
uint8_t const case_diff = 'a' - 'A';
- for(uint32_t i=0; i<count; i++)
- {
- if (itf == 0)
- {
+ for (uint32_t i = 0; i < count; i++) {
+ if (itf == 0) {
// echo back 1st port as lower case
if (isupper(buf[i])) buf[i] += case_diff;
- }
- else
- {
+ } else {
// echo back 2nd port as upper case
if (islower(buf[i])) buf[i] -= case_diff;
}
@@ -75,21 +84,29 @@ static void echo_serial_port(uint8_t itf, uint8_t buf[], uint32_t count)
tud_cdc_n_write_flush(itf);
}
+// 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;
+}
+
+
//--------------------------------------------------------------------+
// USB CDC
//--------------------------------------------------------------------+
-static void cdc_task(void)
-{
+static void cdc_task(void) {
uint8_t itf;
- for (itf = 0; itf < CFG_TUD_CDC; itf++)
- {
+ for (itf = 0; itf < CFG_TUD_CDC; itf++) {
// connected() check for DTR bit
// Most but not all terminal client set this when making connection
// if ( tud_cdc_n_connected(itf) )
{
- if ( tud_cdc_n_available(itf) )
- {
+ if (tud_cdc_n_available(itf)) {
uint8_t buf[64];
uint32_t count = tud_cdc_n_read(itf, buf, sizeof(buf));
@@ -101,3 +118,18 @@ static void cdc_task(void)
}
}
}
+
+//--------------------------------------------------------------------+
+// 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/cdc_dual_ports/src/usb_descriptors.c b/examples/device/cdc_dual_ports/src/usb_descriptors.c
index cda1b63b6..de2505c07 100644
--- a/examples/device/cdc_dual_ports/src/usb_descriptors.c
+++ b/examples/device/cdc_dual_ports/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,13 +23,14 @@
*
*/
+#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] MIDI | HID | MSC | CDC [LSB]
+ * [MSB] 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) | \
@@ -108,6 +109,17 @@ enum
#define EPNUM_CDC_1_OUT 0x05
#define EPNUM_CDC_1_IN 0x86
+#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X
+ // FT9XX doesn't support a same endpoint number with different direction IN and OUT
+ // e.g EP1 OUT & EP1 IN cannot exist together
+ #define EPNUM_CDC_0_NOTIF 0x81
+ #define EPNUM_CDC_0_OUT 0x02
+ #define EPNUM_CDC_0_IN 0x83
+
+ #define EPNUM_CDC_1_NOTIF 0x84
+ #define EPNUM_CDC_1_OUT 0x05
+ #define EPNUM_CDC_1_IN 0x86
+
#else
#define EPNUM_CDC_0_NOTIF 0x81
#define EPNUM_CDC_0_OUT 0x02
@@ -202,52 +214,64 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
"TinyUSB CDC", // 4: CDC Interface
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/cdc_msc/CMakeLists.txt b/examples/device/cdc_msc/CMakeLists.txt
index fa6e83b7e..9415f8c68 100644
--- a/examples/device/cdc_msc/CMakeLists.txt
+++ b/examples/device/cdc_msc/CMakeLists.txt
@@ -1,29 +1,35 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
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})
+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()
+
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+family_configure_device_example(${PROJECT} noos)
diff --git a/examples/device/cdc_msc/Makefile b/examples/device/cdc_msc/Makefile
index 69b633fea..0c2e37180 100644
--- a/examples/device/cdc_msc/Makefile
+++ b/examples/device/cdc_msc/Makefile
@@ -1,12 +1,15 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
$(TOP)/hw \
# Example source
-EXAMPLE_SOURCE += $(wildcard src/*.c)
+EXAMPLE_SOURCE += \
+ src/main.c \
+ src/msc_disk.c \
+ src/usb_descriptors.c \
+
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/cdc_msc/skip.txt b/examples/device/cdc_msc/skip.txt
index d844feae8..833fd072c 100644
--- a/examples/device/cdc_msc/skip.txt
+++ b/examples/device/cdc_msc/skip.txt
@@ -1 +1,2 @@
-mcu:SAMD11 \ No newline at end of file
+mcu:SAMD11
+family:espressif
diff --git a/examples/device/cdc_msc/src/main.c b/examples/device/cdc_msc/src/main.c
index c3666763b..0d3f97c8f 100644
--- a/examples/device/cdc_msc/src/main.c
+++ b/examples/device/cdc_msc/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -27,7 +27,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
//--------------------------------------------------------------------+
@@ -39,7 +39,7 @@
* - 1000 ms : device mounted
* - 2500 ms : device is suspended
*/
-enum {
+enum {
BLINK_NOT_MOUNTED = 250,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
@@ -51,22 +51,22 @@ void led_blinking_task(void);
void cdc_task(void);
/*------------- MAIN -------------*/
-int main(void)
-{
+int main(void) {
board_init();
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
- while (1)
- {
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
+ while (1) {
tud_task(); // tinyusb device task
led_blinking_task();
cdc_task();
}
-
- return 0;
}
//--------------------------------------------------------------------+
@@ -74,46 +74,40 @@ int main(void)
//--------------------------------------------------------------------+
// Invoked when device is mounted
-void tud_mount_cb(void)
-{
+void tud_mount_cb(void) {
blink_interval_ms = BLINK_MOUNTED;
}
// Invoked when device is unmounted
-void tud_umount_cb(void)
-{
+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 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 = BLINK_MOUNTED;
+void tud_resume_cb(void) {
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
// USB CDC
//--------------------------------------------------------------------+
-void cdc_task(void)
-{
+void cdc_task(void) {
// connected() check for DTR bit
// Most but not all terminal client set this when making connection
// if ( tud_cdc_connected() )
{
// connected and there are data available
- if ( tud_cdc_available() )
- {
- // read datas
+ if (tud_cdc_available()) {
+ // read data
char buf[64];
uint32_t count = tud_cdc_read(buf, sizeof(buf));
(void) count;
@@ -129,37 +123,32 @@ void cdc_task(void)
}
// Invoked when cdc when line state changed e.g connected/disconnected
-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) {
(void) itf;
(void) rts;
// TODO set some indicator
- if ( dtr )
- {
+ if (dtr) {
// Terminal connected
- }else
- {
+ } else {
// Terminal disconnected
}
}
// Invoked when CDC interface received data from host
-void tud_cdc_rx_cb(uint8_t itf)
-{
+void tud_cdc_rx_cb(uint8_t itf) {
(void) itf;
}
//--------------------------------------------------------------------+
// BLINKING TASK
//--------------------------------------------------------------------+
-void led_blinking_task(void)
-{
+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
+ if (board_millis() - start_ms < blink_interval_ms) return; // not enough time
start_ms += blink_interval_ms;
board_led_write(led_state);
diff --git a/examples/device/cdc_msc/src/msc_disk.c b/examples/device/cdc_msc/src/msc_disk.c
index e67e381ce..d2f8628f1 100644
--- a/examples/device/cdc_msc/src/msc_disk.c
+++ b/examples/device/cdc_msc/src/msc_disk.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,7 +23,7 @@
*
*/
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
#if CFG_TUD_MSC
diff --git a/examples/device/cdc_msc/src/usb_descriptors.c b/examples/device/cdc_msc/src/usb_descriptors.c
index 6b59ed50f..2afa24903 100644
--- a/examples/device/cdc_msc/src/usb_descriptors.c
+++ b/examples/device/cdc_msc/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,6 +23,7 @@
*
*/
+#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.
@@ -41,35 +42,33 @@
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
-tusb_desc_device_t const desc_device =
-{
- .bLength = sizeof(tusb_desc_device_t),
- .bDescriptorType = TUSB_DESC_DEVICE,
- .bcdUSB = USB_BCD,
+tusb_desc_device_t const desc_device = {
+ .bLength = sizeof(tusb_desc_device_t),
+ .bDescriptorType = TUSB_DESC_DEVICE,
+ .bcdUSB = USB_BCD,
- // Use Interface Association Descriptor (IAD) for CDC
- // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
- .bDeviceClass = TUSB_CLASS_MISC,
- .bDeviceSubClass = MISC_SUBCLASS_COMMON,
- .bDeviceProtocol = MISC_PROTOCOL_IAD,
+ // Use Interface Association Descriptor (IAD) for CDC
+ // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
+ .bDeviceClass = TUSB_CLASS_MISC,
+ .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+ .bDeviceProtocol = MISC_PROTOCOL_IAD,
- .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+ .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
- .idVendor = USB_VID,
- .idProduct = USB_PID,
- .bcdDevice = 0x0100,
+ .idVendor = USB_VID,
+ .idProduct = USB_PID,
+ .bcdDevice = 0x0100,
- .iManufacturer = 0x01,
- .iProduct = 0x02,
- .iSerialNumber = 0x03,
+ .iManufacturer = 0x01,
+ .iProduct = 0x02,
+ .iSerialNumber = 0x03,
- .bNumConfigurations = 0x01
+ .bNumConfigurations = 0x01
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
-uint8_t const * tud_descriptor_device_cb(void)
-{
+uint8_t const *tud_descriptor_device_cb(void) {
return (uint8_t const *) &desc_device;
}
@@ -77,8 +76,7 @@ uint8_t const * tud_descriptor_device_cb(void)
// Configuration Descriptor
//--------------------------------------------------------------------+
-enum
-{
+enum {
ITF_NUM_CDC = 0,
ITF_NUM_CDC_DATA,
ITF_NUM_MSC,
@@ -95,7 +93,7 @@ enum
#define EPNUM_MSC_OUT 0x05
#define EPNUM_MSC_IN 0x85
-#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
+#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_CDC_NOTIF 0x81
@@ -140,67 +138,62 @@ enum
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN)
// full speed configuration
-uint8_t const 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),
+uint8_t const 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 notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
+ // Interface number, string index, EP notification address and size, EP data address (out, in) and size.
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
- // Interface number, string index, EP Out & EP In address, EP size
- TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
+ // Interface number, string index, EP Out & EP In address, EP size
+ TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_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),
+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 notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
+ // Interface number, string index, EP notification address and size, EP data address (out, in) and size.
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
- // Interface number, string index, EP Out & EP In address, EP size
- TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
+ // Interface number, string index, EP Out & EP In address, EP size
+ TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_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,
+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,
+ .bDeviceClass = TUSB_CLASS_MISC,
+ .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+ .bDeviceProtocol = MISC_PROTOCOL_IAD,
- .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
- .bNumConfigurations = 0x01,
- .bReserved = 0x00
+ .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;
+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)
-{
+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
@@ -220,13 +213,12 @@ uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
-uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
-{
+uint8_t const *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;
+ return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
#else
return desc_fs_configuration;
#endif
@@ -236,53 +228,64 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// 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
- "123456789012", // 3: Serials, should use chip ID
- "TinyUSB CDC", // 4: CDC Interface
- "TinyUSB MSC", // 5: MSC Interface
+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 CDC", // 4: CDC Interface
+ "TinyUSB MSC", // 5: MSC Interface
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/cdc_msc_freertos/CMakeLists.txt b/examples/device/cdc_msc_freertos/CMakeLists.txt
index 639dde99a..33c7a1ec0 100644
--- a/examples/device/cdc_msc_freertos/CMakeLists.txt
+++ b/examples/device/cdc_msc_freertos/CMakeLists.txt
@@ -1,22 +1,35 @@
-cmake_minimum_required(VERSION 3.5)
-
-# TOP is absolute path to root directory of TinyUSB git repo
-# needed for esp32sx build. TOOD could be removed later on
-set(TOP "../../..")
-get_filename_component(TOP "${TOP}" REALPATH)
+cmake_minimum_required(VERSION 3.17)
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})
+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})
-# Check for -DFAMILY=
-if(FAMILY MATCHES "^esp32s[2-3]")
-else()
- message(FATAL_ERROR "Invalid FAMILY specified: ${FAMILY}")
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
endif()
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/freertos_hook.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
+
+# Configure compilation flags and libraries for the example with FreeRTOS.
+# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
+family_configure_device_example(${PROJECT} freertos)
diff --git a/examples/device/cdc_msc_freertos/Makefile b/examples/device/cdc_msc_freertos/Makefile
index 3352dd37d..13f336f99 100644
--- a/examples/device/cdc_msc_freertos/Makefile
+++ b/examples/device/cdc_msc_freertos/Makefile
@@ -1,17 +1,15 @@
-DEPS_SUBMODULES += lib/FreeRTOS-Kernel
-
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
FREERTOS_SRC = lib/FreeRTOS-Kernel
+FREERTOS_PORTABLE_PATH= $(FREERTOS_SRC)/portable/$(if $(USE_IAR),IAR,GCC)
INC += \
src \
src/FreeRTOSConfig \
$(TOP)/hw \
$(TOP)/$(FREERTOS_SRC)/include \
- $(TOP)/$(FREERTOS_SRC)/portable/GCC/$(FREERTOS_PORT)
-
+ $(TOP)/$(FREERTOS_PORTABLE_SRC) \
+
# Example source
EXAMPLE_SOURCE = \
src/freertos_hook.c \
@@ -27,12 +25,22 @@ SRC_C += \
$(FREERTOS_SRC)/queue.c \
$(FREERTOS_SRC)/tasks.c \
$(FREERTOS_SRC)/timers.c \
- $(subst ../../../,,$(wildcard ../../../$(FREERTOS_SRC)/portable/GCC/$(FREERTOS_PORT)/*.c))
+ $(subst $(TOP)/,,$(wildcard $(TOP)/$(FREERTOS_PORTABLE_SRC)/*.c))
+
+SRC_S += \
+ $(subst $(TOP)/,,$(wildcard $(TOP)/$(FREERTOS_PORTABLE_SRC)/*.s))
+
+# include heap manage if configSUPPORT_DYNAMIC_ALLOCATION = 1
+# SRC_C += $(FREERTOS_SRC)/portable/MemMang/heap_1.c
+# CFLAGS += -Wno-error=sign-compare
+
+# Suppress FreeRTOSConfig.h warnings
+CFLAGS_GCC += -Wno-error=redundant-decls
-# Suppress FreeRTOS warnings
-CFLAGS += -Wno-error=cast-qual -Wno-error=redundant-decls
+# Suppress FreeRTOS source warnings
+CFLAGS_GCC += -Wno-error=cast-qual
# FreeRTOS (lto + Os) linker issue
-LDFLAGS += -Wl,--undefined=vTaskSwitchContext
+LDFLAGS_GCC += -Wl,--undefined=vTaskSwitchContext
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/cdc_msc_freertos/skip.txt b/examples/device/cdc_msc_freertos/skip.txt
index 1ee51a9d4..a6f96b288 100644
--- a/examples/device/cdc_msc_freertos/skip.txt
+++ b/examples/device/cdc_msc_freertos/skip.txt
@@ -1,3 +1,4 @@
+mcu:CH32V307
mcu:CXD56
mcu:F1C100S
mcu:GD32VF103
@@ -7,5 +8,6 @@ mcu:RP2040
mcu:SAMD11
mcu:SAMX7X
mcu:VALENTYUSB_EPTRI
+mcu:RAXXX
family:broadcom_32bit
-family:broadcom_64bit \ No newline at end of file
+family:broadcom_64bit
diff --git a/examples/device/cdc_msc_freertos/src/CMakeLists.txt b/examples/device/cdc_msc_freertos/src/CMakeLists.txt
index 9216e2b49..fee264363 100644
--- a/examples/device/cdc_msc_freertos/src/CMakeLists.txt
+++ b/examples/device/cdc_msc_freertos/src/CMakeLists.txt
@@ -1,35 +1,4 @@
+# This file is for ESP-IDF only
idf_component_register(SRCS "main.c" "usb_descriptors.c" "msc_disk.c"
INCLUDE_DIRS "."
- REQUIRES freertos soc)
-
-file(TO_NATIVE_PATH "${TOP}/hw/bsp/${FAMILY}/boards/${BOARD}/board.cmake" board_cmake)
-
-if(EXISTS ${board_cmake})
- include(${board_cmake})
-endif()
-
-target_include_directories(${COMPONENT_TARGET} PUBLIC
- "${TOP}/hw"
- "${TOP}/src"
-)
-
-target_compile_definitions(${COMPONENT_TARGET} PUBLIC
- ESP_PLATFORM
-)
-
-target_sources(${COMPONENT_TARGET} PUBLIC
- "${TOP}/src/tusb.c"
- "${TOP}/src/common/tusb_fifo.c"
- "${TOP}/src/device/usbd.c"
- "${TOP}/src/device/usbd_control.c"
- "${TOP}/src/class/cdc/cdc_device.c"
- "${TOP}/src/class/dfu/dfu_rt_device.c"
- "${TOP}/src/class/hid/hid_device.c"
- "${TOP}/src/class/midi/midi_device.c"
- "${TOP}/src/class/msc/msc_device.c"
- "${TOP}/src/class/net/ecm_rndis_device.c"
- "${TOP}/src/class/net/ncm_device.c"
- "${TOP}/src/class/usbtmc/usbtmc_device.c"
- "${TOP}/src/class/vendor/vendor_device.c"
- "${TOP}/src/portable/synopsys/dwc2/dcd_dwc2.c"
-)
+ REQUIRES boards tinyusb_src)
diff --git a/examples/device/cdc_msc_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h b/examples/device/cdc_msc_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h
index 6a3630dbc..6cc7a6577 100644
--- a/examples/device/cdc_msc_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h
+++ b/examples/device/cdc_msc_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h
@@ -42,6 +42,9 @@
* See http://www.freertos.org/a00110.html.
*----------------------------------------------------------*/
+// skip if included from IAR assembler
+#ifndef __IASMARM__
+
// Include MCU header
#include "bsp/board_mcu.h"
@@ -57,6 +60,8 @@
extern uint32_t SystemCoreClock;
#endif
+#endif
+
/* Cortex M23/M33 port configuration. */
#define configENABLE_MPU 0
#define configENABLE_FPU 1
@@ -69,14 +74,14 @@
#define configTICK_RATE_HZ ( 1000 )
#define configMAX_PRIORITIES ( 5 )
#define configMINIMAL_STACK_SIZE ( 128 )
-#define configTOTAL_HEAP_SIZE ( 0*1024 ) // dynamic is not used
+#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 2
+#define configQUEUE_REGISTRY_SIZE 4
#define configUSE_QUEUE_SETS 0
#define configUSE_TIME_SLICING 0
#define configUSE_NEWLIB_REENTRANT 0
@@ -91,6 +96,7 @@
#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
@@ -125,29 +131,12 @@
#define INCLUDE_xEventGroupSetBitFromISR 0
#define INCLUDE_xTimerPendFunctionCall 0
-/* Define to trap errors during development. */
-// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7
-#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
- #define configASSERT(_exp) \
- do {\
- if ( !(_exp) ) { \
- volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
- if ( (*ARM_CM_DHCSR) & 1UL ) { /* Only halt mcu if debugger is attached */ \
- taskDISABLE_INTERRUPTS(); \
- __asm("BKPT #0\n"); \
- }\
- }\
- } while(0)
-#else
- #define configASSERT( x )
-#endif
-
#ifdef __RX__
/* Renesas RX series */
-#define vSoftwareInterruptISR INT_Excep_ICU_SWINT
-#define vTickISR INT_Excep_CMT0_CMI0
-#define configPERIPHERAL_CLOCK_HZ (configCPU_CLOCK_HZ/2)
-#define configKERNEL_INTERRUPT_PRIORITY 1
+#define vSoftwareInterruptISR INT_Excep_ICU_SWINT
+#define vTickISR INT_Excep_CMT0_CMI0
+#define configPERIPHERAL_CLOCK_HZ (configCPU_CLOCK_HZ/2)
+#define configKERNEL_INTERRUPT_PRIORITY 1
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 4
#else
@@ -163,9 +152,18 @@
#if defined(__NVIC_PRIO_BITS)
// For Cortex-M specific: __NVIC_PRIO_BITS is defined in core_cmx.h
#define configPRIO_BITS __NVIC_PRIO_BITS
+
#elif defined(__ECLIC_INTCTLBITS)
// RISC-V Bumblebee core from nuclei
#define configPRIO_BITS __ECLIC_INTCTLBITS
+
+#elif defined(__IASMARM__)
+ // FIXME: IAR Assembler cannot include mcu header directly to get __NVIC_PRIO_BITS.
+ // Therefore we will hard coded it to minimum value of 2 to get pass ci build.
+ // IAR user must update this to correct value of the target MCU
+ #message "configPRIO_BITS is hard coded to 2 to pass IAR build only. User should update it per MCU"
+ #define configPRIO_BITS 2
+
#else
#error "FreeRTOS configPRIO_BITS to be defined"
#endif
diff --git a/examples/device/cdc_msc_freertos/src/main.c b/examples/device/cdc_msc_freertos/src/main.c
index 755220c13..e94e8eaec 100644
--- a/examples/device/cdc_msc_freertos/src/main.c
+++ b/examples/device/cdc_msc_freertos/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -27,7 +27,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
@@ -41,6 +41,7 @@
#define USBD_STACK_SIZE 4096
#else
+
#include "FreeRTOS.h"
#include "semphr.h"
#include "queue.h"
@@ -51,8 +52,11 @@
#define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1)
#endif
+#define CDC_STACK_SIZE configMINIMAL_STACK_SIZE
+#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE
+
//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF PROTYPES
+// MACRO CONSTANT TYPEDEF PROTOTYPES
//--------------------------------------------------------------------+
/* Blink pattern
@@ -60,47 +64,51 @@
* - 1000 ms : device mounted
* - 2500 ms : device is suspended
*/
-enum {
+enum {
BLINK_NOT_MOUNTED = 250,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
};
-// static timer
-StaticTimer_t blinky_tmdef;
-TimerHandle_t blinky_tm;
-
// static task
+#if configSUPPORT_STATIC_ALLOCATION
+StackType_t blinky_stack[BLINKY_STACK_SIZE];
+StaticTask_t blinky_taskdef;
+
StackType_t usb_device_stack[USBD_STACK_SIZE];
StaticTask_t usb_device_taskdef;
-// static task for cdc
-#define CDC_STACK_SZIE configMINIMAL_STACK_SIZE
-StackType_t cdc_stack[CDC_STACK_SZIE];
+StackType_t cdc_stack[CDC_STACK_SIZE];
StaticTask_t cdc_taskdef;
+#endif
+static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
-void led_blinky_cb(TimerHandle_t xTimer);
-void usb_device_task(void* param);
-void cdc_task(void* params);
+static void usb_device_task(void *param);
+void led_blinking_task(void* param);
+void cdc_task(void *params);
//--------------------------------------------------------------------+
// Main
//--------------------------------------------------------------------+
-int main(void)
-{
+int main(void) {
board_init();
- // soft timer for blinky
- blinky_tm = xTimerCreateStatic(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb, &blinky_tmdef);
- xTimerStart(blinky_tm, 0);
+#if configSUPPORT_STATIC_ALLOCATION
+ // blinky task
+ xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef);
// Create a task for tinyusb device stack
- (void) xTaskCreateStatic( usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_device_stack, &usb_device_taskdef);
+ xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_device_stack, &usb_device_taskdef);
// Create CDC task
- (void) xTaskCreateStatic( cdc_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES-2, cdc_stack, &cdc_taskdef);
+ xTaskCreateStatic(cdc_task, "cdc", CDC_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, cdc_stack, &cdc_taskdef);
+#else
+ xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL);
+ xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL);
+ xTaskCreate(cdc_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES - 2, NULL);
+#endif
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#if !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
@@ -111,16 +119,14 @@ int main(void)
}
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
-void app_main(void)
-{
+void app_main(void) {
main();
}
#endif
// USB Device Driver task
// This top level thread process all usb events and invoke callbacks
-void usb_device_task(void* param)
-{
+static void usb_device_task(void *param) {
(void) param;
// init device stack on configured roothub port
@@ -128,9 +134,12 @@ void usb_device_task(void* param)
// Otherwise it could cause kernel issue since USB IRQ handler does use RTOS queue API.
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
// RTOS forever loop
- while (1)
- {
+ while (1) {
// put this thread to waiting state until there is new events
tud_task();
@@ -144,49 +153,42 @@ void usb_device_task(void* param)
//--------------------------------------------------------------------+
// Invoked when device is mounted
-void tud_mount_cb(void)
-{
- xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
+void tud_mount_cb(void) {
+ blink_interval_ms = BLINK_MOUNTED;
}
// Invoked when device is unmounted
-void tud_umount_cb(void)
-{
- xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0);
+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 tud_suspend_cb(bool remote_wakeup_en) {
(void) remote_wakeup_en;
- xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_SUSPENDED), 0);
+ blink_interval_ms = BLINK_SUSPENDED;
}
// Invoked when usb bus is resumed
-void tud_resume_cb(void)
-{
- xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
+void tud_resume_cb(void) {
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
// USB CDC
//--------------------------------------------------------------------+
-void cdc_task(void* params)
-{
+void cdc_task(void *params) {
(void) params;
// RTOS forever loop
- while ( 1 )
- {
+ while (1) {
// connected() check for DTR bit
// Most but not all terminal client set this when making connection
// if ( tud_cdc_connected() )
{
// There are data available
- while ( tud_cdc_available() )
- {
+ while (tud_cdc_available()) {
uint8_t buf[64];
// read and echo back
@@ -209,35 +211,37 @@ void cdc_task(void* params)
}
// Invoked when cdc when line state changed e.g connected/disconnected
-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) {
(void) itf;
(void) rts;
// TODO set some indicator
- if ( dtr )
- {
+ if (dtr) {
// Terminal connected
- }else
- {
+ } else {
// Terminal disconnected
}
}
// Invoked when CDC interface received data from host
-void tud_cdc_rx_cb(uint8_t itf)
-{
+void tud_cdc_rx_cb(uint8_t itf) {
(void) itf;
}
//--------------------------------------------------------------------+
// BLINKING TASK
//--------------------------------------------------------------------+
-void led_blinky_cb(TimerHandle_t xTimer)
-{
- (void) xTimer;
+void led_blinking_task(void* param) {
+ (void) param;
+ static uint32_t start_ms = 0;
static bool led_state = false;
- board_led_write(led_state);
- led_state = 1 - led_state; // toggle
+ 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 a895f4738..c8a04bb74 100644
--- a/examples/device/cdc_msc_freertos/src/msc_disk.c
+++ b/examples/device/cdc_msc_freertos/src/msc_disk.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,7 +23,7 @@
*
*/
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
#if CFG_TUD_MSC
@@ -184,7 +184,7 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buff
uint8_t const* addr = msc_disk[lba] + offset;
memcpy(buffer, addr, bufsize);
- return bufsize;
+ return (int32_t) bufsize;
}
// Callback invoked when received WRITE10 command.
@@ -203,7 +203,7 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
(void) lba; (void) offset; (void) buffer;
#endif
- return bufsize;
+ return (int32_t) bufsize;
}
// Callback invoked when received an SCSI command not in built-in list below
@@ -237,14 +237,14 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
{
if(in_xfer)
{
- memcpy(buffer, response, resplen);
+ memcpy(buffer, response, (size_t) resplen);
}else
{
// SCSI output
}
}
- return resplen;
+ return (int32_t) resplen;
}
#endif
diff --git a/examples/device/cdc_msc_freertos/src/tusb_config.h b/examples/device/cdc_msc_freertos/src/tusb_config.h
index 0ec8896b9..91efe7d40 100644
--- a/examples/device/cdc_msc_freertos/src/tusb_config.h
+++ b/examples/device/cdc_msc_freertos/src/tusb_config.h
@@ -54,7 +54,9 @@
#endif
// This examples use FreeRTOS
+#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_FREERTOS
+#endif
// Espressif IDF requires "freertos/" prefix in include path
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
diff --git a/examples/device/cdc_msc_freertos/src/usb_descriptors.c b/examples/device/cdc_msc_freertos/src/usb_descriptors.c
index 30a712275..9c29701c7 100644
--- a/examples/device/cdc_msc_freertos/src/usb_descriptors.c
+++ b/examples/device/cdc_msc_freertos/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,6 +23,7 @@
*
*/
+#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.
@@ -212,53 +213,65 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456789012", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
"TinyUSB CDC", // 4: CDC Interface
"TinyUSB MSC", // 5: MSC Interface
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/cdc_uac2/CMakeLists.txt b/examples/device/cdc_uac2/CMakeLists.txt
new file mode 100644
index 000000000..64e4374e9
--- /dev/null
+++ b/examples/device/cdc_uac2/CMakeLists.txt
@@ -0,0 +1,38 @@
+cmake_minimum_required(VERSION 3.17)
+
+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()
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/uac2_app.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
+
+# Configure compilation flags and libraries for the example... see the corresponding function
+# in hw/bsp/FAMILY/family.cmake for details.
+family_configure_device_example(${PROJECT} noos)
+
+# Uncomment me to enable UART based debugging
+# pico_enable_stdio_uart(${PROJECT} 1)
diff --git a/examples/device/cdc_uac2/Makefile b/examples/device/cdc_uac2/Makefile
new file mode 100644
index 000000000..21dcdb0b2
--- /dev/null
+++ b/examples/device/cdc_uac2/Makefile
@@ -0,0 +1,16 @@
+include ../../build_system/make/make.mk
+
+INC += \
+ src \
+ $(TOP)/hw \
+
+# Example source
+EXAMPLE_SOURCE += \
+ src/cdc_app.c \
+ src/main.c \
+ src/uac2_app.c \
+ src/usb_descriptors.c \
+
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
+
+include ../../build_system/make/rules.mk
diff --git a/examples/device/cdc_uac2/README.md b/examples/device/cdc_uac2/README.md
new file mode 100644
index 000000000..5d120be7d
--- /dev/null
+++ b/examples/device/cdc_uac2/README.md
@@ -0,0 +1,52 @@
+#### Composite CDC + UAC2 on Pico
+
+This example provides a composite CDC + UAC2 device on top of a Raspberry Pi
+Pico board.
+
+
+#### Use Cases
+
+- The CDC + UAC2 composite device happens to be important, especially in the
+ amateur radio community.
+
+ Modern radios (`rigs`) like Icom IC-7300 + IC-705 expose a sound card and a
+ serial device (`composite device`) to the computer over a single USB cable.
+ This allows for Audio I/O and CAT control over a single USB cable which is
+ very convenient.
+
+ By including and maintaining this example in TinyUSB repository, we enable
+ the amateur radio community to build (`homebrew`) radios with similar
+ functionality as the (expensive) commercial rigs.
+
+ This PR is important in bridging this specific gap between the commercial
+ rigs and homebrew equipment.
+
+- https://digirig.net/digirig-mobile-rev-1-9/ is a digital interface for
+ interfacing radios (that lack an inbuilt digital interface) with computers.
+ Digirig Mobile works brilliantly (is OSS!) and is a big improvement over
+ traditional digital interfaces (like the SignaLink USB Interface). By using a
+ Raspberry Pi Pico powered CDC + UAC2 composite device, we can simplify the
+ Digirig Mobile schematic, drastically reduce the manufacturing cost, and
+ (again) enable the homebrewers community to homebrew a modern digital interface
+ with ease themselves.
+
+
+#### Build Steps
+
+```
+cd examples/device/cdc_uac2
+
+export PICO_SDK_PATH=$HOME/pico-sdk
+
+cmake -DFAMILY=rp2040 pico .
+
+cmake -DFAMILY=rp2040 -DCMAKE_BUILD_TYPE=Debug # use this for debugging
+
+make BOARD=raspberry_pi_pico all
+```
+
+
+#### Development Notes
+
+Please try to keep this code synchronized with the `uac2_headset` example
+included in this repository.
diff --git a/examples/device/cdc_uac2/src/cdc_app.c b/examples/device/cdc_uac2/src/cdc_app.c
new file mode 100644
index 000000000..2166c1d6b
--- /dev/null
+++ b/examples/device/cdc_uac2/src/cdc_app.c
@@ -0,0 +1,72 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ * Copyright (c) 2022 Angel Molina ([email protected])
+ *
+ * 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 "common.h"
+
+// Invoked when cdc when line state changed e.g connected/disconnected
+void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
+{
+ (void) itf;
+ (void) rts;
+
+ if (dtr)
+ {
+ // Terminal connected
+ }
+ else
+ {
+ // Terminal disconnected
+ }
+}
+
+// Invoked when CDC interface received data from host
+void tud_cdc_rx_cb(uint8_t itf)
+{
+ uint8_t buf[64];
+ uint32_t count;
+
+ // connected() check for DTR bit
+ // Most but not all terminal client set this when making connection
+ if (tud_cdc_connected())
+ {
+ if (tud_cdc_available()) // data is available
+ {
+ count = tud_cdc_n_read(itf, buf, sizeof(buf));
+ (void) count;
+
+ tud_cdc_n_write(itf, buf, count);
+ tud_cdc_n_write_flush(itf);
+ // dummy code to check that cdc serial is responding
+ board_led_write(0);
+ board_delay(50);
+ board_led_write(1);
+ board_delay(50);
+ board_led_write(0);
+ }
+ }
+}
diff --git a/examples/device/cdc_uac2/src/common.h b/examples/device/cdc_uac2/src/common.h
new file mode 100644
index 000000000..f281024c7
--- /dev/null
+++ b/examples/device/cdc_uac2/src/common.h
@@ -0,0 +1,34 @@
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+/* Blink pattern
+ * - 25 ms : streaming data
+ * - 250 ms : device not mounted
+ * - 1000 ms : device mounted
+ * - 2500 ms : device is suspended
+ */
+enum
+{
+ BLINK_STREAMING = 25,
+ BLINK_NOT_MOUNTED = 250,
+ BLINK_MOUNTED = 1000,
+ BLINK_SUSPENDED = 2500,
+};
+
+enum
+{
+ VOLUME_CTRL_0_DB = 0,
+ VOLUME_CTRL_10_DB = 2560,
+ VOLUME_CTRL_20_DB = 5120,
+ VOLUME_CTRL_30_DB = 7680,
+ VOLUME_CTRL_40_DB = 10240,
+ VOLUME_CTRL_50_DB = 12800,
+ VOLUME_CTRL_60_DB = 15360,
+ VOLUME_CTRL_70_DB = 17920,
+ VOLUME_CTRL_80_DB = 20480,
+ VOLUME_CTRL_90_DB = 23040,
+ VOLUME_CTRL_100_DB = 25600,
+ VOLUME_CTRL_SILENCE = 0x8000,
+};
+
+#endif
diff --git a/examples/device/cdc_uac2/src/main.c b/examples/device/cdc_uac2/src/main.c
new file mode 100644
index 000000000..25b2cd9a5
--- /dev/null
+++ b/examples/device/cdc_uac2/src/main.c
@@ -0,0 +1,99 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jerzy Kasenberg
+ * Copyright (c) 2022 Angel Molina <[email protected]>
+ * Copyright (c) 2023 Dhiru Kholia <[email protected]>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "bsp/board_api.h"
+#include "tusb.h"
+#include "common.h"
+
+extern uint32_t blink_interval_ms;
+
+#if (CFG_TUSB_MCU == OPT_MCU_RP2040)
+#include "pico/stdlib.h"
+#endif
+
+void led_blinking_task(void);
+
+/*------------- MAIN -------------*/
+int main(void)
+{
+ board_init();
+
+ // init device stack on configured roothub port
+ tud_init(BOARD_TUD_RHPORT);
+
+#if (CFG_TUSB_MCU == OPT_MCU_RP2040)
+ stdio_init_all();
+#endif
+
+ TU_LOG1("CDC UAC2 example running\r\n");
+
+ while (1)
+ {
+ tud_task(); // TinyUSB device task
+ led_blinking_task();
+
+#if (CFG_TUSB_MCU == OPT_MCU_RP2040)
+ // printf("Hello, world!\r\n");
+#endif
+ }
+
+ return 0;
+}
+
+//--------------------------------------------------------------------+
+// 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 = BLINK_MOUNTED;
+}
diff --git a/examples/device/cdc_uac2/src/tusb_config.h b/examples/device/cdc_uac2/src/tusb_config.h
new file mode 100644
index 000000000..93489cf62
--- /dev/null
+++ b/examples/device/cdc_uac2/src/tusb_config.h
@@ -0,0 +1,174 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Ha Thach (tinyusb.org)
+ * Copyright (c) 2020 Jerzy Kasenberg
+ *
+ * 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
+
+#include "usb_descriptors.h"
+
+//--------------------------------------------------------------------+
+// 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_CDC 1
+#define CFG_TUD_MSC 0
+#define CFG_TUD_HID 0
+#define CFG_TUD_MIDI 0
+#define CFG_TUD_AUDIO 1
+#define CFG_TUD_VENDOR 0
+
+//--------------------------------------------------------------------
+// AUDIO CLASS DRIVER CONFIGURATION
+//--------------------------------------------------------------------
+
+#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN
+
+// How many formats are used, need to adjust USB descriptor if changed
+#define CFG_TUD_AUDIO_FUNC_1_N_FORMATS 2
+
+// Audio format type I specifications
+#if defined(__RX__)
+#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE 48000 // 16bit/48kHz is the best quality for Renesas RX
+#else
+#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE 96000 // 24bit/96kHz is the best quality for full-speed, high-speed is needed beyond this
+#endif
+#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1
+#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX 1 // Changed
+
+// 16bit in 16bit slots
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX 2
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX 16
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX 2
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX 16
+
+#if defined(__RX__)
+// 8bit in 8bit slots
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX 1
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX 8
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX 1
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX 8
+#else
+// 24bit in 32bit slots
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX 4
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX 24
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX 4
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX 24
+#endif
+
+// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
+#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
+
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)
+
+#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN)
+#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN) // Maximum EP IN size for all AS alternate settings used
+
+// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
+#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1
+
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX)
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_OUT TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX)
+
+#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT)
+#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
+
+// 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
+
+// CDC FIFO size of TX and RX
+#define CFG_TUD_CDC_RX_BUFSIZE 64
+#define CFG_TUD_CDC_TX_BUFSIZE 64
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */
diff --git a/examples/device/cdc_uac2/src/uac2_app.c b/examples/device/cdc_uac2/src/uac2_app.c
new file mode 100644
index 000000000..98659ea68
--- /dev/null
+++ b/examples/device/cdc_uac2/src/uac2_app.c
@@ -0,0 +1,316 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jerzy Kasenberg
+ * Copyright (c) 2022 Angel Molina ([email protected])
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "bsp/board_api.h"
+#include "tusb.h"
+#include "usb_descriptors.h"
+#include "common.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTOTYPES
+//--------------------------------------------------------------------+
+
+// List of supported sample rates
+const uint32_t sample_rates[] = {44100, 48000};
+uint32_t current_sample_rate = 44100;
+
+#define N_SAMPLE_RATES TU_ARRAY_SIZE(sample_rates)
+
+uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
+
+// Audio controls
+// Current states
+int8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; // +1 for master channel 0
+int16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; // +1 for master channel 0
+
+// Buffer for microphone data
+int32_t mic_buf[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ / 4];
+// Buffer for speaker data
+int32_t spk_buf[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ / 4];
+// Speaker data size received in the last frame
+int spk_data_size;
+// Resolution per format
+const uint8_t resolutions_per_format[CFG_TUD_AUDIO_FUNC_1_N_FORMATS] = {CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX};
+// Current resolution, update on format change
+uint8_t current_resolution;
+
+// Helper for clock get requests
+static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t const *request)
+{
+ TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK);
+
+ if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ)
+ {
+ if (request->bRequest == AUDIO_CS_REQ_CUR)
+ {
+ TU_LOG1("Clock get current freq %lu\r\n", current_sample_rate);
+
+ audio_control_cur_4_t curf = { (int32_t) tu_htole32(current_sample_rate) };
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &curf, sizeof(curf));
+ }
+ else if (request->bRequest == AUDIO_CS_REQ_RANGE)
+ {
+ audio_control_range_4_n_t(N_SAMPLE_RATES) rangef =
+ {
+ .wNumSubRanges = tu_htole16(N_SAMPLE_RATES)
+ };
+ TU_LOG1("Clock get %d freq ranges\r\n", N_SAMPLE_RATES);
+ for(uint8_t i = 0; i < N_SAMPLE_RATES; i++)
+ {
+ rangef.subrange[i].bMin = (int32_t) sample_rates[i];
+ rangef.subrange[i].bMax = (int32_t) sample_rates[i];
+ rangef.subrange[i].bRes = 0;
+ TU_LOG1("Range %d (%d, %d, %d)\r\n", i, (int)rangef.subrange[i].bMin, (int)rangef.subrange[i].bMax, (int)rangef.subrange[i].bRes);
+ }
+
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &rangef, sizeof(rangef));
+ }
+ }
+ else if (request->bControlSelector == AUDIO_CS_CTRL_CLK_VALID &&
+ request->bRequest == AUDIO_CS_REQ_CUR)
+ {
+ audio_control_cur_1_t cur_valid = { .bCur = 1 };
+ TU_LOG1("Clock get is valid %u\r\n", cur_valid.bCur);
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &cur_valid, sizeof(cur_valid));
+ }
+ TU_LOG1("Clock get request not supported, entity = %u, selector = %u, request = %u\r\n",
+ request->bEntityID, request->bControlSelector, request->bRequest);
+ return false;
+}
+
+// Helper for clock set requests
+static bool tud_audio_clock_set_request(uint8_t rhport, audio_control_request_t const *request, uint8_t const *buf)
+{
+ (void)rhport;
+
+ TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK);
+ TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR);
+
+ if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ)
+ {
+ TU_VERIFY(request->wLength == sizeof(audio_control_cur_4_t));
+
+ current_sample_rate = (uint32_t) ((audio_control_cur_4_t const *)buf)->bCur;
+
+ TU_LOG1("Clock set current freq: %ld\r\n", current_sample_rate);
+
+ return true;
+ }
+ else
+ {
+ TU_LOG1("Clock set request not supported, entity = %u, selector = %u, request = %u\r\n",
+ request->bEntityID, request->bControlSelector, request->bRequest);
+ return false;
+ }
+}
+
+// Helper for feature unit get requests
+static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_request_t const *request)
+{
+ TU_ASSERT(request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT);
+
+ if (request->bControlSelector == AUDIO_FU_CTRL_MUTE && request->bRequest == AUDIO_CS_REQ_CUR)
+ {
+ audio_control_cur_1_t mute1 = { .bCur = mute[request->bChannelNumber] };
+ TU_LOG1("Get channel %u mute %d\r\n", request->bChannelNumber, mute1.bCur);
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &mute1, sizeof(mute1));
+ }
+ else if (UAC2_ENTITY_SPK_FEATURE_UNIT && request->bControlSelector == AUDIO_FU_CTRL_VOLUME)
+ {
+ if (request->bRequest == AUDIO_CS_REQ_RANGE)
+ {
+ audio_control_range_2_n_t(1) range_vol = {
+ .wNumSubRanges = tu_htole16(1),
+ .subrange[0] = { .bMin = tu_htole16(-VOLUME_CTRL_50_DB), tu_htole16(VOLUME_CTRL_0_DB), tu_htole16(256) }
+ };
+ TU_LOG1("Get channel %u volume range (%d, %d, %u) dB\r\n", request->bChannelNumber,
+ range_vol.subrange[0].bMin / 256, range_vol.subrange[0].bMax / 256, range_vol.subrange[0].bRes / 256);
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &range_vol, sizeof(range_vol));
+ }
+ else if (request->bRequest == AUDIO_CS_REQ_CUR)
+ {
+ audio_control_cur_2_t cur_vol = { .bCur = tu_htole16(volume[request->bChannelNumber]) };
+ TU_LOG1("Get channel %u volume %d dB\r\n", request->bChannelNumber, cur_vol.bCur / 256);
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &cur_vol, sizeof(cur_vol));
+ }
+ }
+ TU_LOG1("Feature unit get request not supported, entity = %u, selector = %u, request = %u\r\n",
+ request->bEntityID, request->bControlSelector, request->bRequest);
+
+ return false;
+}
+
+// Helper for feature unit set requests
+static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_request_t const *request, uint8_t const *buf)
+{
+ (void)rhport;
+
+ TU_ASSERT(request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT);
+ TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR);
+
+ if (request->bControlSelector == AUDIO_FU_CTRL_MUTE)
+ {
+ TU_VERIFY(request->wLength == sizeof(audio_control_cur_1_t));
+
+ mute[request->bChannelNumber] = ((audio_control_cur_1_t const *)buf)->bCur;
+
+ TU_LOG1("Set channel %d Mute: %d\r\n", request->bChannelNumber, mute[request->bChannelNumber]);
+
+ return true;
+ }
+ else if (request->bControlSelector == AUDIO_FU_CTRL_VOLUME)
+ {
+ TU_VERIFY(request->wLength == sizeof(audio_control_cur_2_t));
+
+ volume[request->bChannelNumber] = ((audio_control_cur_2_t const *)buf)->bCur;
+
+ TU_LOG1("Set channel %d volume: %d dB\r\n", request->bChannelNumber, volume[request->bChannelNumber] / 256);
+
+ return true;
+ }
+ else
+ {
+ TU_LOG1("Feature unit set request not supported, entity = %u, selector = %u, request = %u\r\n",
+ request->bEntityID, request->bControlSelector, request->bRequest);
+ return false;
+ }
+}
+
+//--------------------------------------------------------------------+
+// Application Callback API Implementations
+//--------------------------------------------------------------------+
+
+// Invoked when audio class specific get request received for an entity
+bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request)
+{
+ audio_control_request_t const *request = (audio_control_request_t const *)p_request;
+
+ if (request->bEntityID == UAC2_ENTITY_CLOCK)
+ return tud_audio_clock_get_request(rhport, request);
+ if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT)
+ return tud_audio_feature_unit_get_request(rhport, request);
+ else
+ {
+ TU_LOG1("Get request not handled, entity = %d, selector = %d, request = %d\r\n",
+ request->bEntityID, request->bControlSelector, request->bRequest);
+ }
+ return false;
+}
+
+// Invoked when audio class specific set request received for an entity
+bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *buf)
+{
+ audio_control_request_t const *request = (audio_control_request_t const *)p_request;
+
+ if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT)
+ return tud_audio_feature_unit_set_request(rhport, request, buf);
+ if (request->bEntityID == UAC2_ENTITY_CLOCK)
+ return tud_audio_clock_set_request(rhport, request, buf);
+ TU_LOG1("Set request not handled, entity = %d, selector = %d, request = %d\r\n",
+ request->bEntityID, request->bControlSelector, request->bRequest);
+
+ return false;
+}
+
+bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+ (void)rhport;
+
+ uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex));
+ uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue));
+
+ if (ITF_NUM_AUDIO_STREAMING_SPK == itf && alt == 0) {
+ // Audio streaming stop
+ blink_interval_ms = BLINK_MOUNTED;
+ }
+
+ return true;
+}
+
+bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+ (void)rhport;
+ uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex));
+ uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue));
+
+ TU_LOG2("Set interface %d alt %d\r\n", itf, alt);
+ if (ITF_NUM_AUDIO_STREAMING_SPK == itf && alt != 0) {
+ // Audio streaming start
+ blink_interval_ms = BLINK_STREAMING;
+ }
+
+ // Clear buffer when streaming format is changed
+ spk_data_size = 0;
+ if(alt != 0)
+ {
+ current_resolution = resolutions_per_format[alt-1];
+ }
+
+ return true;
+}
+
+bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting)
+{
+ (void)rhport;
+ (void)func_id;
+ (void)ep_out;
+ (void)cur_alt_setting;
+
+ spk_data_size = tud_audio_read(spk_buf, n_bytes_received);
+ tud_audio_write(spk_buf, n_bytes_received);
+
+ return true;
+}
+
+bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting)
+{
+ (void)rhport;
+ (void)itf;
+ (void)ep_in;
+ (void)cur_alt_setting;
+
+ // This callback could be used to fill microphone data separately
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// 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;
+ start_ms += blink_interval_ms;
+
+ board_led_write(led_state);
+ led_state = 1 - led_state;
+}
diff --git a/examples/device/cdc_uac2/src/usb_descriptors.c b/examples/device/cdc_uac2/src/usb_descriptors.c
new file mode 100644
index 000000000..72a695622
--- /dev/null
+++ b/examples/device/cdc_uac2/src/usb_descriptors.c
@@ -0,0 +1,216 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Ha Thach (tinyusb.org)
+ * Copyright (c) 2020 Jerzy Kasenberg
+ * Copyright (c) 2022 Angel Molina ([email protected])
+ *
+ * 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 "usb_descriptors.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] AUDIO | 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(AUDIO, 4) | _PID_MAP(VENDOR, 5) )
+
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
+tusb_desc_device_t const desc_device =
+{
+ .bLength = sizeof(tusb_desc_device_t),
+ .bDescriptorType = TUSB_DESC_DEVICE,
+ .bcdUSB = 0x0200,
+
+ // Use Interface Association Descriptor (IAD)
+ // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
+ .bDeviceClass = TUSB_CLASS_MISC,
+ .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+ .bDeviceProtocol = MISC_PROTOCOL_IAD,
+ .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+
+ .idVendor = 0xCafe,
+ .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
+//--------------------------------------------------------------------+
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_HEADSET_STEREO_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN)
+
+#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 etc ...
+ #define EPNUM_AUDIO_IN 0x03
+ #define EPNUM_AUDIO_OUT 0x03
+
+ #define EPNUM_CDC_NOTIF 0x84
+ #define EPNUM_CDC_OUT 0x05
+ #define EPNUM_CDC_IN 0x85
+
+#elif CFG_TUSB_MCU == OPT_MCU_NRF5X
+ // ISO endpoints for NRF5x are fixed to 0x08 (0x88)
+ #define EPNUM_AUDIO_IN 0x08
+ #define EPNUM_AUDIO_OUT 0x08
+
+ #define EPNUM_CDC_NOTIF 0x81
+ #define EPNUM_CDC_OUT 0x02
+ #define EPNUM_CDC_IN 0x82
+
+#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
+ // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
+ // e.g EP1 OUT & EP1 IN cannot exist together
+ #define EPNUM_AUDIO_IN 0x01
+ #define EPNUM_AUDIO_OUT 0x02
+
+ #define EPNUM_CDC_NOTIF 0x83
+ #define EPNUM_CDC_OUT 0x04
+ #define EPNUM_CDC_IN 0x85
+
+#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X
+ // FT9XX doesn't support a same endpoint number with different direction IN and OUT
+ // e.g EP1 OUT & EP1 IN cannot exist together
+ #define EPNUM_AUDIO_IN 0x01
+ #define EPNUM_AUDIO_OUT 0x02
+
+ #define EPNUM_CDC_NOTIF 0x83
+ #define EPNUM_CDC_OUT 0x04
+ #define EPNUM_CDC_IN 0x85
+
+#else
+ #define EPNUM_AUDIO_IN 0x01
+ #define EPNUM_AUDIO_OUT 0x01
+
+ #define EPNUM_CDC_NOTIF 0x83
+ #define EPNUM_CDC_OUT 0x04
+ #define EPNUM_CDC_IN 0x84
+#endif
+
+uint8_t const desc_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 Out & EP In address, EP size
+ TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, EPNUM_AUDIO_OUT, EPNUM_AUDIO_IN | 0x80),
+
+ // CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 6, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64)
+};
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
+{
+ (void)index; // for multiple configurations
+ return desc_configuration;
+}
+
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
+// 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 headset", // 2: Product
+ NULL, // 3: Serials will use unique ID if possible
+ "TinyUSB Speakers", // 4: Audio Interface
+ "TinyUSB Microphone", // 5: Audio Interface
+ "TinyUSB CDC", // 6: Audio 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);
+ size_t const 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/cdc_uac2/src/usb_descriptors.h b/examples/device/cdc_uac2/src/usb_descriptors.h
new file mode 100644
index 000000000..736feeefe
--- /dev/null
+++ b/examples/device/cdc_uac2/src/usb_descriptors.h
@@ -0,0 +1,158 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jerzy Kasenbreg
+ * Copyright (c) 2022 Angel Molina ([email protected])
+ *
+ * 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 _USB_DESCRIPTORS_H_
+#define _USB_DESCRIPTORS_H_
+
+// #include "tusb.h"
+
+// Unit numbers are arbitrary selected
+#define UAC2_ENTITY_CLOCK 0x04
+// Speaker path
+#define UAC2_ENTITY_SPK_INPUT_TERMINAL 0x01
+#define UAC2_ENTITY_SPK_FEATURE_UNIT 0x02
+#define UAC2_ENTITY_SPK_OUTPUT_TERMINAL 0x03
+// Microphone path
+#define UAC2_ENTITY_MIC_INPUT_TERMINAL 0x11
+#define UAC2_ENTITY_MIC_OUTPUT_TERMINAL 0x13
+
+enum
+{
+ ITF_NUM_AUDIO_CONTROL = 0,
+ ITF_NUM_AUDIO_STREAMING_SPK,
+ ITF_NUM_AUDIO_STREAMING_MIC,
+ ITF_NUM_CDC,
+ ITF_NUM_CDC_DATA,
+ ITF_NUM_TOTAL
+};
+
+#define TUD_AUDIO_HEADSET_STEREO_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\
+ + TUD_AUDIO_DESC_STD_AC_LEN\
+ + TUD_AUDIO_DESC_CS_AC_LEN\
+ + TUD_AUDIO_DESC_CLK_SRC_LEN\
+ + TUD_AUDIO_DESC_INPUT_TERM_LEN\
+ + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN\
+ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
+ + TUD_AUDIO_DESC_INPUT_TERM_LEN\
+ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
+ /* Interface 1, Alternate 0 */\
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ /* Interface 1, Alternate 0 */\
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ + TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\
+ /* Interface 1, Alternate 2 */\
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ + TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\
+ /* Interface 2, Alternate 0 */\
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ /* Interface 2, Alternate 1 */\
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ + TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\
+ /* Interface 2, Alternate 2 */\
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ + TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN)
+
+#define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _epout, _epin) \
+ /* Standard Interface Association Descriptor (IAD) */\
+ TUD_AUDIO_DESC_IAD(/*_firstitfs*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ 3, /*_stridx*/ 0x00),\
+ /* Standard AC Interface Descriptor(4.7.1) */\
+ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
+ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\
+ TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\
+ /* Clock Source Descriptor(4.7.2.1) */\
+ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ 3, /*_ctrl*/ 7, /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \
+ /* Input Terminal Descriptor(4.7.2.4) */\
+ TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\
+ /* Feature Unit Descriptor(4.7.2.8) */\
+ TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrlch0master*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch2*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\
+ /* Output Terminal Descriptor(4.7.2.5) */\
+ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_HEADPHONES, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
+ /* Input Terminal Descriptor(4.7.2.4) */\
+ TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\
+ /* Output Terminal Descriptor(4.7.2.5) */\
+ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
+ /* Standard AS Interface Descriptor(4.9.1) */\
+ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x05),\
+ /* Standard AS Interface Descriptor(4.9.1) */\
+ /* Interface 1, Alternate 1 - alternate interface for data streaming */\
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x05),\
+ /* Class-Specific AS Interface Descriptor(4.9.2) */\
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\
+ /* Interface 1, Alternate 2 - alternate interface for data streaming */\
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x05),\
+ /* Class-Specific AS Interface Descriptor(4.9.2) */\
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX),\
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\
+ /* Standard AS Interface Descriptor(4.9.1) */\
+ /* Interface 2, Alternate 0 - default alternate setting with 0 bandwidth */\
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x04),\
+ /* Standard AS Interface Descriptor(4.9.1) */\
+ /* Interface 2, Alternate 1 - alternate interface for data streaming */\
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x04),\
+ /* Class-Specific AS Interface Descriptor(4.9.2) */\
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX),\
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\
+ /* Interface 2, Alternate 2 - alternate interface for data streaming */\
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x04),\
+ /* Class-Specific AS Interface Descriptor(4.9.2) */\
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX),\
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
+
+#endif
diff --git a/examples/device/dfu/CMakeLists.txt b/examples/device/dfu/CMakeLists.txt
index acaa54198..a01eb3456 100644
--- a/examples/device/dfu/CMakeLists.txt
+++ b/examples/device/dfu/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
add_executable(${PROJECT})
@@ -23,6 +27,6 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT})
+# 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(${PROJECT} noos)
diff --git a/examples/device/dfu/Makefile b/examples/device/dfu/Makefile
index 69b633fea..52a24cdb0 100644
--- a/examples/device/dfu/Makefile
+++ b/examples/device/dfu/Makefile
@@ -1,12 +1,14 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
$(TOP)/hw \
# Example source
-EXAMPLE_SOURCE += $(wildcard src/*.c)
+EXAMPLE_SOURCE = \
+ src/main.c \
+ src/usb_descriptors.c
+
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/dfu/skip.txt b/examples/device/dfu/skip.txt
index 9ac346bad..9dde06c30 100644
--- a/examples/device/dfu/skip.txt
+++ b/examples/device/dfu/skip.txt
@@ -1,2 +1,3 @@
mcu:TM4C123
mcu:BCM2835
+family:espressif
diff --git a/examples/device/dfu/src/main.c b/examples/device/dfu/src/main.c
index 6bb183819..81fc0a62c 100644
--- a/examples/device/dfu/src/main.c
+++ b/examples/device/dfu/src/main.c
@@ -42,7 +42,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
//--------------------------------------------------------------------+
@@ -77,13 +77,15 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
tud_task(); // tinyusb device task
led_blinking_task();
}
-
- return 0;
}
//--------------------------------------------------------------------+
@@ -114,7 +116,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
diff --git a/examples/device/dfu/src/usb_descriptors.c b/examples/device/dfu/src/usb_descriptors.c
index 51a0d09f5..fd469aaf2 100644
--- a/examples/device/dfu/src/usb_descriptors.c
+++ b/examples/device/dfu/src/usb_descriptors.c
@@ -23,6 +23,7 @@
*
*/
+#include "bsp/board_api.h"
#include "tusb.h"
#include "class/dfu/dfu_device.h"
@@ -116,56 +117,65 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
"FLASH", // 4: DFU Partition 1
"EEPROM", // 5: DFU Partition 2
};
-static uint16_t _desc_str[32];
+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)
-{
+uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void) langid;
-
size_t chr_count;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }
- else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) {
- chr_count = 31;
- }
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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)((((uint16_t)TUSB_DESC_STRING) << 8 ) | (2u*chr_count + 2u));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/dfu_runtime/CMakeLists.txt b/examples/device/dfu_runtime/CMakeLists.txt
index abc4d91da..a01eb3456 100644
--- a/examples/device/dfu_runtime/CMakeLists.txt
+++ b/examples/device/dfu_runtime/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
add_executable(${PROJECT})
@@ -23,6 +27,6 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/dfu_runtime/Makefile b/examples/device/dfu_runtime/Makefile
index 69b633fea..1b4d398cf 100644
--- a/examples/device/dfu_runtime/Makefile
+++ b/examples/device/dfu_runtime/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,4 +8,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/dfu_runtime/src/main.c b/examples/device/dfu_runtime/src/main.c
index 55b380353..170dde932 100644
--- a/examples/device/dfu_runtime/src/main.c
+++ b/examples/device/dfu_runtime/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -31,7 +31,7 @@
*
* $ dfu-util -e
*
- * This will send DETTACH command to put device into bootloader. Since this example
+ * This will send DETACH command to put device into bootloader. Since this example
* is minimal, it doesn't actually go into DFU mode but rather change the LED blinking
* pattern to fast rate as indicator.
*/
@@ -40,7 +40,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
//--------------------------------------------------------------------+
@@ -72,13 +72,15 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
tud_task(); // tinyusb device task
led_blinking_task();
}
-
- return 0;
}
//--------------------------------------------------------------------+
@@ -109,7 +111,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
// Invoked on DFU_DETACH request to reboot to the bootloader
diff --git a/examples/device/dfu_runtime/src/usb_descriptors.c b/examples/device/dfu_runtime/src/usb_descriptors.c
index 1b0a60551..7ac53d255 100644
--- a/examples/device/dfu_runtime/src/usb_descriptors.c
+++ b/examples/device/dfu_runtime/src/usb_descriptors.c
@@ -23,6 +23,7 @@
*
*/
+#include "bsp/board_api.h"
#include "tusb.h"
#include "class/dfu/dfu_rt_device.h"
@@ -112,55 +113,64 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
"TinyUSB DFU runtime", // 4: DFU runtime
};
-static uint16_t _desc_str[32];
+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)
-{
+uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void) langid;
-
size_t chr_count;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }
- else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) {
- chr_count = 31;
- }
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/dynamic_configuration/CMakeLists.txt b/examples/device/dynamic_configuration/CMakeLists.txt
index fa6e83b7e..2b20d2234 100644
--- a/examples/device/dynamic_configuration/CMakeLists.txt
+++ b/examples/device/dynamic_configuration/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
add_executable(${PROJECT})
@@ -24,6 +28,6 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/dynamic_configuration/Makefile b/examples/device/dynamic_configuration/Makefile
index 69b633fea..1b4d398cf 100644
--- a/examples/device/dynamic_configuration/Makefile
+++ b/examples/device/dynamic_configuration/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,4 +8,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/dynamic_configuration/skip.txt b/examples/device/dynamic_configuration/skip.txt
index d844feae8..833fd072c 100644
--- a/examples/device/dynamic_configuration/skip.txt
+++ b/examples/device/dynamic_configuration/skip.txt
@@ -1 +1,2 @@
-mcu:SAMD11 \ No newline at end of file
+mcu:SAMD11
+family:espressif
diff --git a/examples/device/dynamic_configuration/src/main.c b/examples/device/dynamic_configuration/src/main.c
index 33a603343..b6409c8e1 100644
--- a/examples/device/dynamic_configuration/src/main.c
+++ b/examples/device/dynamic_configuration/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -27,7 +27,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
//--------------------------------------------------------------------+
@@ -59,6 +59,10 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
tud_task(); // tinyusb device task
@@ -66,8 +70,6 @@ int main(void)
cdc_task();
midi_task();
}
-
- return 0;
}
//--------------------------------------------------------------------+
@@ -98,7 +100,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
diff --git a/examples/device/dynamic_configuration/src/msc_disk.c b/examples/device/dynamic_configuration/src/msc_disk.c
index e8cb03fdd..10c3ac6fe 100644
--- a/examples/device/dynamic_configuration/src/msc_disk.c
+++ b/examples/device/dynamic_configuration/src/msc_disk.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,7 +23,7 @@
*
*/
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
#if CFG_TUD_MSC
diff --git a/examples/device/dynamic_configuration/src/usb_descriptors.c b/examples/device/dynamic_configuration/src/usb_descriptors.c
index 457f774d0..7f35b4b22 100644
--- a/examples/device/dynamic_configuration/src/usb_descriptors.c
+++ b/examples/device/dynamic_configuration/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,8 +23,8 @@
*
*/
+#include "bsp/board_api.h"
#include "tusb.h"
-#include "bsp/board.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.
@@ -145,6 +145,19 @@ enum
#define EPNUM_1_MSC_OUT 0x01
#define EPNUM_1_MSC_IN 0x82
+#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X
+ // FT9XX doesn't support a same endpoint number with different direction IN and OUT
+ // e.g EP1 OUT & EP1 IN cannot exist together
+ #define EPNUM_0_CDC_NOTIF 0x81
+ #define EPNUM_0_CDC_OUT 0x02
+ #define EPNUM_0_CDC_IN 0x83
+
+ #define EPNUM_0_MIDI_OUT 0x04
+ #define EPNUM_0_MIDI_IN 0x85
+
+ #define EPNUM_1_MSC_OUT 0x01
+ #define EPNUM_1_MSC_IN 0x82
+
#else
#define EPNUM_0_CDC_NOTIF 0x81
#define EPNUM_0_CDC_OUT 0x02
@@ -170,7 +183,7 @@ uint8_t const desc_configuration_0[] =
};
-uint8_t const desc_configuraiton_1[] =
+uint8_t const desc_configuration_1[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_1_NUM_TOTAL, 0, CONFIG_1_TOTAL_LEN, 0x00, 100),
@@ -186,58 +199,70 @@ uint8_t const desc_configuraiton_1[] =
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
- return mode ? desc_configuraiton_1 : desc_configuration_0;
+ return mode ? desc_configuration_1 : desc_configuration_0;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/hid_boot_interface/CMakeLists.txt b/examples/device/hid_boot_interface/CMakeLists.txt
index abc4d91da..a01eb3456 100644
--- a/examples/device/hid_boot_interface/CMakeLists.txt
+++ b/examples/device/hid_boot_interface/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
add_executable(${PROJECT})
@@ -23,6 +27,6 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/hid_boot_interface/Makefile b/examples/device/hid_boot_interface/Makefile
index c6a9c5b21..52a24cdb0 100644
--- a/examples/device/hid_boot_interface/Makefile
+++ b/examples/device/hid_boot_interface/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,7 +8,7 @@ INC += \
EXAMPLE_SOURCE = \
src/main.c \
src/usb_descriptors.c
-
+
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/hid_boot_interface/src/main.c b/examples/device/hid_boot_interface/src/main.c
index 71afa3f46..7ad5c53c2 100644
--- a/examples/device/hid_boot_interface/src/main.c
+++ b/examples/device/hid_boot_interface/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -27,7 +27,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
#include "usb_descriptors.h"
@@ -59,6 +59,10 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
tud_task(); // tinyusb device task
@@ -98,7 +102,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
@@ -157,11 +161,11 @@ void hid_task(void)
{
uint8_t const report_id = 0;
uint8_t const button_mask = 0;
- uint8_t const veritical = 0;
+ uint8_t const vertical = 0;
uint8_t const horizontal = 0;
int8_t const delta = 5;
- tud_hid_n_mouse_report(ITF_NUM_MOUSE, report_id, button_mask, delta, delta, veritical, horizontal);
+ tud_hid_n_mouse_report(ITF_NUM_MOUSE, report_id, button_mask, delta, delta, vertical, horizontal);
}
}
}
@@ -175,13 +179,13 @@ void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol)
(void) protocol;
// nothing to do since we use the same compatible boot report for both Boot and Report mode.
- // TOOD set a indicator for user
+ // TODO set a indicator for user
}
// Invoked when sent REPORT successfully to host
// Application can use this to send the next report
// Note: For composite reports, report[0] is report ID
-void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, /*uint16_t*/ uint8_t len)
+void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len)
{
(void) instance;
(void) report;
diff --git a/examples/device/hid_boot_interface/src/usb_descriptors.c b/examples/device/hid_boot_interface/src/usb_descriptors.c
index a0d7e9f15..d68ef16d9 100644
--- a/examples/device/hid_boot_interface/src/usb_descriptors.c
+++ b/examples/device/hid_boot_interface/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,6 +23,7 @@
*
*/
+#include "bsp/board_api.h"
#include "tusb.h"
#include "usb_descriptors.h"
@@ -130,51 +131,63 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/hid_boot_interface/src/usb_descriptors.h b/examples/device/hid_boot_interface/src/usb_descriptors.h
index 57cf0e2c0..6fee9e223 100644
--- a/examples/device/hid_boot_interface/src/usb_descriptors.h
+++ b/examples/device/hid_boot_interface/src/usb_descriptors.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
diff --git a/examples/device/hid_composite/CMakeLists.txt b/examples/device/hid_composite/CMakeLists.txt
index abc4d91da..a01eb3456 100644
--- a/examples/device/hid_composite/CMakeLists.txt
+++ b/examples/device/hid_composite/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
add_executable(${PROJECT})
@@ -23,6 +27,6 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/hid_composite/Makefile b/examples/device/hid_composite/Makefile
index 69b633fea..1b4d398cf 100644
--- a/examples/device/hid_composite/Makefile
+++ b/examples/device/hid_composite/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,4 +8,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/hid_composite/src/main.c b/examples/device/hid_composite/src/main.c
index f7d76cfc7..dcf13079f 100644
--- a/examples/device/hid_composite/src/main.c
+++ b/examples/device/hid_composite/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -27,7 +27,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
#include "usb_descriptors.h"
@@ -60,6 +60,10 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
tud_task(); // tinyusb device task
@@ -67,8 +71,6 @@ int main(void)
hid_task();
}
-
- return 0;
}
//--------------------------------------------------------------------+
@@ -99,7 +101,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
@@ -225,7 +227,7 @@ void hid_task(void)
// Invoked when sent REPORT successfully to host
// Application can use this to send the next report
// Note: For composite reports, report[0] is report ID
-void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, /*uint16_t*/ uint8_t len)
+void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len)
{
(void) instance;
(void) len;
diff --git a/examples/device/hid_composite/src/usb_descriptors.c b/examples/device/hid_composite/src/usb_descriptors.c
index 2988baee2..e174db46d 100644
--- a/examples/device/hid_composite/src/usb_descriptors.c
+++ b/examples/device/hid_composite/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,6 +23,7 @@
*
*/
+#include "bsp/board_api.h"
#include "tusb.h"
#include "usb_descriptors.h"
@@ -177,51 +178,63 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/hid_composite/src/usb_descriptors.h b/examples/device/hid_composite/src/usb_descriptors.h
index ca8925ad9..e733d31dd 100644
--- a/examples/device/hid_composite/src/usb_descriptors.h
+++ b/examples/device/hid_composite/src/usb_descriptors.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
diff --git a/examples/device/hid_composite_freertos/CMakeLists.txt b/examples/device/hid_composite_freertos/CMakeLists.txt
index ed734b954..eb22014fb 100644
--- a/examples/device/hid_composite_freertos/CMakeLists.txt
+++ b/examples/device/hid_composite_freertos/CMakeLists.txt
@@ -1,17 +1,34 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
-# use BOARD-Directory name for project id
-get_filename_component(PROJECT ${CMAKE_CURRENT_SOURCE_DIR} NAME)
-set(PROJECT ${BOARD}-${PROJECT})
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
-# TOP is absolute path to root directory of TinyUSB git repo
-set(TOP "../../..")
-get_filename_component(TOP "${TOP}" REALPATH)
+# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
+family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-# Check for -DFAMILY=
-if(FAMILY MATCHES "^esp32s[2-3]")
- include(${TOP}/hw/bsp/${FAMILY}/family.cmake)
- project(${PROJECT})
-else()
- message(FATAL_ERROR "Invalid FAMILY specified: ${FAMILY}")
+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()
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/freertos_hook.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
+
+# Configure compilation flags and libraries for the example with FreeRTOS.
+# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
+family_configure_device_example(${PROJECT} freertos)
diff --git a/examples/device/hid_composite_freertos/Makefile b/examples/device/hid_composite_freertos/Makefile
index 6c8c43ddd..add9e9814 100644
--- a/examples/device/hid_composite_freertos/Makefile
+++ b/examples/device/hid_composite_freertos/Makefile
@@ -1,23 +1,23 @@
DEPS_SUBMODULES += lib/FreeRTOS-Kernel
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
FREERTOS_SRC = lib/FreeRTOS-Kernel
+FREERTOS_PORTABLE_PATH= $(FREERTOS_SRC)/portable/$(if $(USE_IAR),IAR,GCC)
INC += \
src \
src/FreeRTOSConfig \
$(TOP)/hw \
$(TOP)/$(FREERTOS_SRC)/include \
- $(TOP)/$(FREERTOS_SRC)/portable/GCC/$(FREERTOS_PORT)
+ $(TOP)/$(FREERTOS_PORTABLE_SRC)
# Example source
EXAMPLE_SOURCE = \
src/freertos_hook.c \
src/main.c \
src/usb_descriptors.c
-
+
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
# FreeRTOS source, all files in port folder
@@ -26,12 +26,22 @@ SRC_C += \
$(FREERTOS_SRC)/queue.c \
$(FREERTOS_SRC)/tasks.c \
$(FREERTOS_SRC)/timers.c \
- $(subst ../../../,,$(wildcard ../../../$(FREERTOS_SRC)/portable/GCC/$(FREERTOS_PORT)/*.c))
+ $(subst $(TOP)/,,$(wildcard $(TOP)/$(FREERTOS_PORTABLE_SRC)/*.c))
+
+SRC_S += \
+ $(subst $(TOP)/,,$(wildcard $(TOP)/$(FREERTOS_PORTABLE_SRC)/*.s))
+
+# include heap manage if configSUPPORT_DYNAMIC_ALLOCATION = 1
+# SRC_C += $(FREERTOS_SRC)/portable/MemMang/heap_1.c
+# CFLAGS += -Wno-error=sign-compare
+
+# Suppress FreeRTOSConfig.h warnings
+CFLAGS_GCC += -Wno-error=redundant-decls
-# Suppress FreeRTOS warnings
-CFLAGS += -Wno-error=cast-qual -Wno-error=redundant-decls
+# Suppress FreeRTOS source warnings
+CFLAGS_GCC += -Wno-error=cast-qual
# FreeRTOS (lto + Os) linker issue
-LDFLAGS += -Wl,--undefined=vTaskSwitchContext
+LDFLAGS_GCC += -Wl,--undefined=vTaskSwitchContext
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/hid_composite_freertos/skip.txt b/examples/device/hid_composite_freertos/skip.txt
index 1ee51a9d4..a6f96b288 100644
--- a/examples/device/hid_composite_freertos/skip.txt
+++ b/examples/device/hid_composite_freertos/skip.txt
@@ -1,3 +1,4 @@
+mcu:CH32V307
mcu:CXD56
mcu:F1C100S
mcu:GD32VF103
@@ -7,5 +8,6 @@ mcu:RP2040
mcu:SAMD11
mcu:SAMX7X
mcu:VALENTYUSB_EPTRI
+mcu:RAXXX
family:broadcom_32bit
-family:broadcom_64bit \ No newline at end of file
+family:broadcom_64bit
diff --git a/examples/device/hid_composite_freertos/src/CMakeLists.txt b/examples/device/hid_composite_freertos/src/CMakeLists.txt
index 25da8fcd7..6d912854f 100644
--- a/examples/device/hid_composite_freertos/src/CMakeLists.txt
+++ b/examples/device/hid_composite_freertos/src/CMakeLists.txt
@@ -1,35 +1,3 @@
idf_component_register(SRCS "main.c" "usb_descriptors.c"
INCLUDE_DIRS "."
- REQUIRES freertos soc)
-
-file(TO_NATIVE_PATH "${TOP}/hw/bsp/${FAMILY}/boards/${BOARD}/board.cmake" board_cmake)
-
-if(EXISTS ${board_cmake})
- include(${board_cmake})
-endif()
-
-target_include_directories(${COMPONENT_TARGET} PUBLIC
- "${TOP}/hw"
- "${TOP}/src"
-)
-
-target_compile_definitions(${COMPONENT_TARGET} PUBLIC
- ESP_PLATFORM
-)
-
-target_sources(${COMPONENT_TARGET} PUBLIC
- "${TOP}/src/tusb.c"
- "${TOP}/src/common/tusb_fifo.c"
- "${TOP}/src/device/usbd.c"
- "${TOP}/src/device/usbd_control.c"
- "${TOP}/src/class/cdc/cdc_device.c"
- "${TOP}/src/class/dfu/dfu_rt_device.c"
- "${TOP}/src/class/hid/hid_device.c"
- "${TOP}/src/class/midi/midi_device.c"
- "${TOP}/src/class/msc/msc_device.c"
- "${TOP}/src/class/net/ecm_rndis_device.c"
- "${TOP}/src/class/net/ncm_device.c"
- "${TOP}/src/class/usbtmc/usbtmc_device.c"
- "${TOP}/src/class/vendor/vendor_device.c"
- "${TOP}/src/portable/synopsys/dwc2/dcd_dwc2.c"
-)
+ REQUIRES boards tinyusb_src)
diff --git a/examples/device/hid_composite_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h b/examples/device/hid_composite_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h
index bfdf1e926..6cc7a6577 100644
--- a/examples/device/hid_composite_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h
+++ b/examples/device/hid_composite_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h
@@ -42,20 +42,26 @@
* See http://www.freertos.org/a00110.html.
*----------------------------------------------------------*/
+// skip if included from IAR assembler
+#ifndef __IASMARM__
+
// Include MCU header
#include "bsp/board_mcu.h"
#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
-#error "ESP32-Sx should use IDF's FreeRTOSConfig.h"
+ #error "ESP32-Sx should use IDF's FreeRTOSConfig.h"
#endif
+// TODO fix later
#if CFG_TUSB_MCU == OPT_MCU_MM32F327X
- // TODO fix/remove later
extern u32 SystemCoreClock;
#else
+ // FIXME cause redundant-decls warnings
extern uint32_t SystemCoreClock;
#endif
+#endif
+
/* Cortex M23/M33 port configuration. */
#define configENABLE_MPU 0
#define configENABLE_FPU 1
@@ -68,14 +74,14 @@
#define configTICK_RATE_HZ ( 1000 )
#define configMAX_PRIORITIES ( 5 )
#define configMINIMAL_STACK_SIZE ( 128 )
-#define configTOTAL_HEAP_SIZE ( 0*1024 ) // dynamic is not used
+#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 2
+#define configQUEUE_REGISTRY_SIZE 4
#define configUSE_QUEUE_SETS 0
#define configUSE_TIME_SLICING 0
#define configUSE_NEWLIB_REENTRANT 0
@@ -90,6 +96,7 @@
#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
@@ -124,29 +131,12 @@
#define INCLUDE_xEventGroupSetBitFromISR 0
#define INCLUDE_xTimerPendFunctionCall 0
-/* Define to trap errors during development. */
-// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7
-#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
- #define configASSERT(_exp) \
- do {\
- if ( !(_exp) ) { \
- volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
- if ( (*ARM_CM_DHCSR) & 1UL ) { /* Only halt mcu if debugger is attached */ \
- taskDISABLE_INTERRUPTS(); \
- __asm("BKPT #0\n"); \
- }\
- }\
- } while(0)
-#else
- #define configASSERT( x )
-#endif
-
#ifdef __RX__
/* Renesas RX series */
-#define vSoftwareInterruptISR INT_Excep_ICU_SWINT
-#define vTickISR INT_Excep_CMT0_CMI0
-#define configPERIPHERAL_CLOCK_HZ (configCPU_CLOCK_HZ/2)
-#define configKERNEL_INTERRUPT_PRIORITY 1
+#define vSoftwareInterruptISR INT_Excep_ICU_SWINT
+#define vTickISR INT_Excep_CMT0_CMI0
+#define configPERIPHERAL_CLOCK_HZ (configCPU_CLOCK_HZ/2)
+#define configKERNEL_INTERRUPT_PRIORITY 1
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 4
#else
@@ -162,9 +152,18 @@
#if defined(__NVIC_PRIO_BITS)
// For Cortex-M specific: __NVIC_PRIO_BITS is defined in core_cmx.h
#define configPRIO_BITS __NVIC_PRIO_BITS
+
#elif defined(__ECLIC_INTCTLBITS)
// RISC-V Bumblebee core from nuclei
#define configPRIO_BITS __ECLIC_INTCTLBITS
+
+#elif defined(__IASMARM__)
+ // FIXME: IAR Assembler cannot include mcu header directly to get __NVIC_PRIO_BITS.
+ // Therefore we will hard coded it to minimum value of 2 to get pass ci build.
+ // IAR user must update this to correct value of the target MCU
+ #message "configPRIO_BITS is hard coded to 2 to pass IAR build only. User should update it per MCU"
+ #define configPRIO_BITS 2
+
#else
#error "FreeRTOS configPRIO_BITS to be defined"
#endif
diff --git a/examples/device/hid_composite_freertos/src/main.c b/examples/device/hid_composite_freertos/src/main.c
index b67c10937..ff2cb635e 100644
--- a/examples/device/hid_composite_freertos/src/main.c
+++ b/examples/device/hid_composite_freertos/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -27,7 +27,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
#include "usb_descriptors.h"
@@ -53,6 +53,8 @@
#define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1)
#endif
+#define HID_STACK_SZIE configMINIMAL_STACK_SIZE
+
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
@@ -68,19 +70,18 @@ enum {
BLINK_SUSPENDED = 2500,
};
-// static timer
+// static timer & task
+#if configSUPPORT_STATIC_ALLOCATION
StaticTimer_t blinky_tmdef;
-TimerHandle_t blinky_tm;
-// static task
StackType_t usb_device_stack[USBD_STACK_SIZE];
StaticTask_t usb_device_taskdef;
-// static task for hid
-#define HID_STACK_SZIE configMINIMAL_STACK_SIZE
StackType_t hid_stack[HID_STACK_SZIE];
StaticTask_t hid_taskdef;
+#endif
+TimerHandle_t blinky_tm;
void led_blinky_cb(TimerHandle_t xTimer);
void usb_device_task(void* param);
@@ -94,15 +95,22 @@ int main(void)
{
board_init();
+#if configSUPPORT_STATIC_ALLOCATION
// soft timer for blinky
blinky_tm = xTimerCreateStatic(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb, &blinky_tmdef);
- xTimerStart(blinky_tm, 0);
// Create a task for tinyusb device stack
- (void) xTaskCreateStatic( usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_device_stack, &usb_device_taskdef);
+ xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_device_stack, &usb_device_taskdef);
// Create HID task
- (void) xTaskCreateStatic( hid_task, "hid", HID_STACK_SZIE, NULL, configMAX_PRIORITIES-2, hid_stack, &hid_taskdef);
+ xTaskCreateStatic(hid_task, "hid", HID_STACK_SZIE, NULL, configMAX_PRIORITIES-2, hid_stack, &hid_taskdef);
+#else
+ blinky_tm = xTimerCreate(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb);
+ xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, NULL);
+ xTaskCreate(hid_task, "hid", HID_STACK_SZIE, NULL, configMAX_PRIORITIES-2, NULL);
+#endif
+
+ xTimerStart(blinky_tm, 0);
// skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
#if !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
@@ -130,6 +138,10 @@ void usb_device_task(void* param)
// Otherwise it could cause kernel issue since USB IRQ handler does use RTOS queue API.
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
// RTOS forever loop
while (1)
{
@@ -168,7 +180,14 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
+ if (tud_mounted())
+ {
+ xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
+ }
+ else
+ {
+ xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0);
+ }
}
//--------------------------------------------------------------------+
@@ -294,7 +313,7 @@ void hid_task(void* param)
// Invoked when sent REPORT successfully to host
// Application can use this to send the next report
// Note: For composite reports, report[0] is report ID
-void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, /*uint16_t*/ uint8_t len)
+void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len)
{
(void) instance;
(void) len;
diff --git a/examples/device/hid_composite_freertos/src/tusb_config.h b/examples/device/hid_composite_freertos/src/tusb_config.h
index 935ae9453..3ba9bf311 100644
--- a/examples/device/hid_composite_freertos/src/tusb_config.h
+++ b/examples/device/hid_composite_freertos/src/tusb_config.h
@@ -54,7 +54,9 @@
#endif
// This examples use FreeRTOS
+#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_FREERTOS
+#endif
// Espressif IDF requires "freertos/" prefix in include path
#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
diff --git a/examples/device/hid_composite_freertos/src/usb_descriptors.c b/examples/device/hid_composite_freertos/src/usb_descriptors.c
index 4df12d3db..85820de55 100644
--- a/examples/device/hid_composite_freertos/src/usb_descriptors.c
+++ b/examples/device/hid_composite_freertos/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,6 +23,7 @@
*
*/
+#include "bsp/board_api.h"
#include "tusb.h"
#include "usb_descriptors.h"
@@ -175,51 +176,63 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/hid_composite_freertos/src/usb_descriptors.h b/examples/device/hid_composite_freertos/src/usb_descriptors.h
index ca8925ad9..e733d31dd 100644
--- a/examples/device/hid_composite_freertos/src/usb_descriptors.h
+++ b/examples/device/hid_composite_freertos/src/usb_descriptors.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
diff --git a/examples/device/hid_generic_inout/CMakeLists.txt b/examples/device/hid_generic_inout/CMakeLists.txt
index abc4d91da..a01eb3456 100644
--- a/examples/device/hid_generic_inout/CMakeLists.txt
+++ b/examples/device/hid_generic_inout/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
add_executable(${PROJECT})
@@ -23,6 +27,6 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/hid_generic_inout/Makefile b/examples/device/hid_generic_inout/Makefile
index 69b633fea..1b4d398cf 100644
--- a/examples/device/hid_generic_inout/Makefile
+++ b/examples/device/hid_generic_inout/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,4 +8,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/hid_generic_inout/hid_test.js b/examples/device/hid_generic_inout/hid_test.js
index daa958fd5..16bc723e2 100644
--- a/examples/device/hid_generic_inout/hid_test.js
+++ b/examples/device/hid_generic_inout/hid_test.js
@@ -48,7 +48,7 @@ if( deviceInfo ) {
function anySupportedBoard(d) {
-
+
for (var key in boards) {
if (boards.hasOwnProperty(key)) {
if (isDevice(boards[key],d)) {
@@ -65,4 +65,3 @@ function isDevice(board,d){
// product id 0xff is matches all
return d.vendorId==board[0] && (d.productId==board[1] || board[1] == 0xFFFF);
}
-
diff --git a/examples/device/hid_generic_inout/hid_test.py b/examples/device/hid_generic_inout/hid_test.py
index 21fd3f421..5bdba9db0 100644
--- a/examples/device/hid_generic_inout/hid_test.py
+++ b/examples/device/hid_generic_inout/hid_test.py
@@ -13,8 +13,8 @@ for vid in USB_VID:
if dev:
while True:
# Get input from console and encode to UTF8 for array of chars.
- # hid generic inout is single report therefore by HIDAPI requirement
- # it must be preceeded with 0x00 as dummy reportID
+ # hid generic in/out is single report therefore by HIDAPI requirement
+ # it must be preceded, with 0x00 as dummy reportID
str_out = b'\x00'
str_out += input("Send text to HID Device : ").encode('utf-8')
dev.write(str_out)
diff --git a/examples/device/hid_generic_inout/src/main.c b/examples/device/hid_generic_inout/src/main.c
index 5b7daf118..cfa9f6283 100644
--- a/examples/device/hid_generic_inout/src/main.c
+++ b/examples/device/hid_generic_inout/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -27,7 +27,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
/* This example demonstrate HID Generic raw Input & Output.
@@ -83,13 +83,15 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
tud_task(); // tinyusb device task
led_blinking_task();
}
-
- return 0;
}
//--------------------------------------------------------------------+
@@ -120,7 +122,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
diff --git a/examples/device/hid_generic_inout/src/usb_descriptors.c b/examples/device/hid_generic_inout/src/usb_descriptors.c
index c2b4792c8..64f6d17ae 100644
--- a/examples/device/hid_generic_inout/src/usb_descriptors.c
+++ b/examples/device/hid_generic_inout/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,6 +23,7 @@
*
*/
+#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.
@@ -103,7 +104,7 @@ uint8_t const desc_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, protocol, report descriptor len, EP In & Out address, size & polling interval
+ // Interface number, string index, protocol, report descriptor len, EP Out & In address, size & polling interval
TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, 0x80 | EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10)
};
@@ -120,51 +121,63 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/hid_multiple_interface/CMakeLists.txt b/examples/device/hid_multiple_interface/CMakeLists.txt
index abc4d91da..a01eb3456 100644
--- a/examples/device/hid_multiple_interface/CMakeLists.txt
+++ b/examples/device/hid_multiple_interface/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
add_executable(${PROJECT})
@@ -23,6 +27,6 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/hid_multiple_interface/Makefile b/examples/device/hid_multiple_interface/Makefile
index 69b633fea..1b4d398cf 100644
--- a/examples/device/hid_multiple_interface/Makefile
+++ b/examples/device/hid_multiple_interface/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,4 +8,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/hid_multiple_interface/src/main.c b/examples/device/hid_multiple_interface/src/main.c
index 29ba74398..30b4ae055 100644
--- a/examples/device/hid_multiple_interface/src/main.c
+++ b/examples/device/hid_multiple_interface/src/main.c
@@ -27,7 +27,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
//--------------------------------------------------------------------+
@@ -64,6 +64,10 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
tud_task(); // tinyusb device task
@@ -71,8 +75,6 @@ int main(void)
hid_task();
}
-
- return 0;
}
//--------------------------------------------------------------------+
@@ -103,7 +105,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
diff --git a/examples/device/hid_multiple_interface/src/usb_descriptors.c b/examples/device/hid_multiple_interface/src/usb_descriptors.c
index 42471a961..86f567e8e 100644
--- a/examples/device/hid_multiple_interface/src/usb_descriptors.c
+++ b/examples/device/hid_multiple_interface/src/usb_descriptors.c
@@ -23,6 +23,7 @@
*
*/
+#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.
@@ -136,53 +137,65 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
"Keyboard Interface", // 4: Interface 1 String
"Mouse Interface", // 5: Interface 2 String
};
-static uint16_t _desc_str[32];
+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)
-{
+uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void) langid;
+ size_t chr_count;
- uint8_t chr_count;
+ switch ( index ) {
+ case STRID_LANGID:
+ memcpy(&_desc_str[1], string_desc_arr[0], 2);
+ chr_count = 1;
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/midi_test/CMakeLists.txt b/examples/device/midi_test/CMakeLists.txt
index abc4d91da..e51f14c02 100644
--- a/examples/device/midi_test/CMakeLists.txt
+++ b/examples/device/midi_test/CMakeLists.txt
@@ -1,17 +1,20 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
add_executable(${PROJECT})
-
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
@@ -23,6 +26,6 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/midi_test/Makefile b/examples/device/midi_test/Makefile
index 5a455078e..7fa475da5 100644
--- a/examples/device/midi_test/Makefile
+++ b/examples/device/midi_test/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,4 +8,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/midi_test/src/main.c b/examples/device/midi_test/src/main.c
index 3310348bd..b1d51598f 100644
--- a/examples/device/midi_test/src/main.c
+++ b/examples/device/midi_test/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -27,7 +27,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
/* This MIDI example send sequence of note (on/off) repeatedly. To test on PC, you need to install
@@ -65,15 +65,16 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
tud_task(); // tinyusb device task
led_blinking_task();
midi_task();
}
-
-
- return 0;
}
//--------------------------------------------------------------------+
@@ -104,7 +105,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
diff --git a/examples/device/midi_test/src/usb_descriptors.c b/examples/device/midi_test/src/usb_descriptors.c
index c84a873b1..9781d3d6f 100644
--- a/examples/device/midi_test/src/usb_descriptors.c
+++ b/examples/device/midi_test/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,13 +23,14 @@
*
*/
+#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] MIDI | HID | MSC | CDC [LSB]
+ * [MSB] 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) | \
@@ -133,51 +134,63 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/msc_dual_lun/CMakeLists.txt b/examples/device/msc_dual_lun/CMakeLists.txt
index 9e834ae21..e69fead35 100644
--- a/examples/device/msc_dual_lun/CMakeLists.txt
+++ b/examples/device/msc_dual_lun/CMakeLists.txt
@@ -1,29 +1,34 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
+
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk_dual.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk_dual.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/msc_dual_lun/Makefile b/examples/device/msc_dual_lun/Makefile
index 5a455078e..7fa475da5 100644
--- a/examples/device/msc_dual_lun/Makefile
+++ b/examples/device/msc_dual_lun/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,4 +8,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/msc_dual_lun/skip.txt b/examples/device/msc_dual_lun/skip.txt
index 3549c702a..a9e3a99b1 100644
--- a/examples/device/msc_dual_lun/skip.txt
+++ b/examples/device/msc_dual_lun/skip.txt
@@ -1,2 +1,3 @@
mcu:SAMD11
-mcu:MKL25ZXX \ No newline at end of file
+mcu:MKL25ZXX
+family:espressif
diff --git a/examples/device/msc_dual_lun/src/main.c b/examples/device/msc_dual_lun/src/main.c
index 96790d20c..de402d3da 100644
--- a/examples/device/msc_dual_lun/src/main.c
+++ b/examples/device/msc_dual_lun/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -27,7 +27,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
//--------------------------------------------------------------------+
@@ -57,13 +57,15 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
tud_task(); // tinyusb device task
led_blinking_task();
}
-
- return 0;
}
//--------------------------------------------------------------------+
@@ -94,7 +96,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
diff --git a/examples/device/msc_dual_lun/src/msc_disk_dual.c b/examples/device/msc_dual_lun/src/msc_disk_dual.c
index 2b773b43b..4f0f6410f 100644
--- a/examples/device/msc_dual_lun/src/msc_disk_dual.c
+++ b/examples/device/msc_dual_lun/src/msc_disk_dual.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,7 +23,7 @@
*
*/
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
#if CFG_TUD_MSC
diff --git a/examples/device/msc_dual_lun/src/usb_descriptors.c b/examples/device/msc_dual_lun/src/usb_descriptors.c
index 68a671c91..c0610945f 100644
--- a/examples/device/msc_dual_lun/src/usb_descriptors.c
+++ b/examples/device/msc_dual_lun/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,6 +23,7 @@
*
*/
+#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.
@@ -90,6 +91,12 @@ enum
#define EPNUM_MSC_OUT 0x01
#define EPNUM_MSC_IN 0x82
+#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X
+ // FT9XX doesn't support a same endpoint number with different direction IN and OUT
+ // e.g EP1 OUT & EP1 IN cannot exist together
+ #define EPNUM_MSC_OUT 0x01
+ #define EPNUM_MSC_IN 0x82
+
#else
#define EPNUM_MSC_OUT 0x01
#define EPNUM_MSC_IN 0x81
@@ -135,51 +142,63 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456789012", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/net_lwip_webserver/CMakeLists.txt b/examples/device/net_lwip_webserver/CMakeLists.txt
index 9fe1a325e..a16b8bd71 100644
--- a/examples/device/net_lwip_webserver/CMakeLists.txt
+++ b/examples/device/net_lwip_webserver/CMakeLists.txt
@@ -1,83 +1,93 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
-set(TOP "../../..")
-get_filename_component(TOP "${TOP}" REALPATH)
+include(${CMAKE_CURRENT_LIST_DIR}/../../../hw/bsp/family_support.cmake)
-if (EXISTS ${TOP}/lib/lwip/src)
- include(${TOP}/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})
- # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
- family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
+set(LWIP ${TOP}/lib/lwip)
+if (NOT EXISTS ${LWIP}/src)
+ family_example_missing_dependency(${PROJECT} "lib/lwip")
+ return()
+endif()
- project(${PROJECT})
+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})
+# Checks this example is valid for the family and initializes the project
+family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
- add_executable(${PROJECT})
+add_executable(${PROJECT})
- # Example source
- target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
- )
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_LIST_DIR}/src/main.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/usb_descriptors.c
+ )
- # Example include
- target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- ${TOP}/lib/lwip/src/include
- ${TOP}/lib/lwip/src/include/ipv4
- ${TOP}/lib/lwip/src/include/lwip/apps
- ${TOP}/lib/networking
- )
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_LIST_DIR}/src
+ ${LWIP}/src/include
+ ${LWIP}/src/include/ipv4
+ ${LWIP}/src/include/lwip/apps
+ ${TOP}/lib/networking
+ )
- target_sources(${PROJECT} PUBLIC
- ${TOP}/lib/lwip/src/core/altcp.c
- ${TOP}/lib/lwip/src/core/altcp_alloc.c
- ${TOP}/lib/lwip/src/core/altcp_tcp.c
- ${TOP}/lib/lwip/src/core/def.c
- ${TOP}/lib/lwip/src/core/dns.c
- ${TOP}/lib/lwip/src/core/inet_chksum.c
- ${TOP}/lib/lwip/src/core/init.c
- ${TOP}/lib/lwip/src/core/ip.c
- ${TOP}/lib/lwip/src/core/mem.c
- ${TOP}/lib/lwip/src/core/memp.c
- ${TOP}/lib/lwip/src/core/netif.c
- ${TOP}/lib/lwip/src/core/pbuf.c
- ${TOP}/lib/lwip/src/core/raw.c
- ${TOP}/lib/lwip/src/core/stats.c
- ${TOP}/lib/lwip/src/core/sys.c
- ${TOP}/lib/lwip/src/core/tcp.c
- ${TOP}/lib/lwip/src/core/tcp_in.c
- ${TOP}/lib/lwip/src/core/tcp_out.c
- ${TOP}/lib/lwip/src/core/timeouts.c
- ${TOP}/lib/lwip/src/core/udp.c
- ${TOP}/lib/lwip/src/core/ipv4/autoip.c
- ${TOP}/lib/lwip/src/core/ipv4/dhcp.c
- ${TOP}/lib/lwip/src/core/ipv4/etharp.c
- ${TOP}/lib/lwip/src/core/ipv4/icmp.c
- ${TOP}/lib/lwip/src/core/ipv4/igmp.c
- ${TOP}/lib/lwip/src/core/ipv4/ip4.c
- ${TOP}/lib/lwip/src/core/ipv4/ip4_addr.c
- ${TOP}/lib/lwip/src/core/ipv4/ip4_frag.c
- ${TOP}/lib/lwip/src/netif/ethernet.c
- ${TOP}/lib/lwip/src/netif/slipif.c
- ${TOP}/lib/lwip/src/apps/http/httpd.c
- ${TOP}/lib/lwip/src/apps/http/fs.c
- ${TOP}/lib/networking/dhserver.c
- ${TOP}/lib/networking/dnserver.c
- ${TOP}/lib/networking/rndis_reports.c
- )
+# lib/networking sources
+target_sources(${PROJECT} PUBLIC
+ ${TOP}/lib/networking/dhserver.c
+ ${TOP}/lib/networking/dnserver.c
+ ${TOP}/lib/networking/rndis_reports.c
+ )
- # due to warnings from other net source, we need to prevent error from some of the warnings options
- target_compile_options(${PROJECT} PUBLIC
- -Wno-error=null-dereference
- -Wno-error=conversion
- -Wno-error=sign-conversion
- -Wno-error=sign-compare
- )
+# lwip sources
+target_sources(${PROJECT} PUBLIC
+ ${LWIP}/src/core/altcp.c
+ ${LWIP}/src/core/altcp_alloc.c
+ ${LWIP}/src/core/altcp_tcp.c
+ ${LWIP}/src/core/def.c
+ ${LWIP}/src/core/dns.c
+ ${LWIP}/src/core/inet_chksum.c
+ ${LWIP}/src/core/init.c
+ ${LWIP}/src/core/ip.c
+ ${LWIP}/src/core/mem.c
+ ${LWIP}/src/core/memp.c
+ ${LWIP}/src/core/netif.c
+ ${LWIP}/src/core/pbuf.c
+ ${LWIP}/src/core/raw.c
+ ${LWIP}/src/core/stats.c
+ ${LWIP}/src/core/sys.c
+ ${LWIP}/src/core/tcp.c
+ ${LWIP}/src/core/tcp_in.c
+ ${LWIP}/src/core/tcp_out.c
+ ${LWIP}/src/core/timeouts.c
+ ${LWIP}/src/core/udp.c
+ ${LWIP}/src/core/ipv4/autoip.c
+ ${LWIP}/src/core/ipv4/dhcp.c
+ ${LWIP}/src/core/ipv4/etharp.c
+ ${LWIP}/src/core/ipv4/icmp.c
+ ${LWIP}/src/core/ipv4/igmp.c
+ ${LWIP}/src/core/ipv4/ip4.c
+ ${LWIP}/src/core/ipv4/ip4_addr.c
+ ${LWIP}/src/core/ipv4/ip4_frag.c
+ ${LWIP}/src/netif/ethernet.c
+ ${LWIP}/src/netif/slipif.c
+ ${LWIP}/src/apps/http/httpd.c
+ ${LWIP}/src/apps/http/fs.c
+ )
- # Configure compilation flags and libraries for the example... see the corresponding function
- # in hw/bsp/FAMILY/family.cmake for details.
- family_configure_device_example(${PROJECT})
-endif() \ No newline at end of file
+# due to warnings from other net source, we need to prevent error from some of the warnings options
+if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(${PROJECT} PUBLIC
+ -Wno-error=null-dereference
+ -Wno-error=conversion
+ -Wno-error=sign-conversion
+ -Wno-error=sign-compare
+ )
+elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
+
+endif ()
+
+# 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(${PROJECT} noos)
diff --git a/examples/device/net_lwip_webserver/Makefile b/examples/device/net_lwip_webserver/Makefile
index 881866a56..22426ba0d 100644
--- a/examples/device/net_lwip_webserver/Makefile
+++ b/examples/device/net_lwip_webserver/Makefile
@@ -1,10 +1,9 @@
DEPS_SUBMODULES += lib/lwip
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
# suppress warning caused by lwip
-CFLAGS += \
+CFLAGS_GCC += \
-Wno-error=null-dereference \
-Wno-error=unused-parameter \
-Wno-error=unused-variable
@@ -68,4 +67,4 @@ SRC_C += \
lib/networking/dnserver.c \
lib/networking/rndis_reports.c
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/net_lwip_webserver/skip.txt b/examples/device/net_lwip_webserver/skip.txt
index 68761b058..75aa2ef14 100644
--- a/examples/device/net_lwip_webserver/skip.txt
+++ b/examples/device/net_lwip_webserver/skip.txt
@@ -4,7 +4,9 @@ mcu:MSP430x5xx
mcu:NUC121
mcu:SAMD11
mcu:STM32L0
-mcu:MKL25ZXX
+mcu:KINETIS_KL
family:broadcom_64bit
family:broadcom_32bit
-board:curiosity_nano \ No newline at end of file
+board:curiosity_nano
+board:frdm_kl25z
+family:espressif
diff --git a/examples/device/net_lwip_webserver/src/arch/bpstruct.h b/examples/device/net_lwip_webserver/src/arch/bpstruct.h
new file mode 100644
index 000000000..74ead358f
--- /dev/null
+++ b/examples/device/net_lwip_webserver/src/arch/bpstruct.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <[email protected]>
+ *
+ */
+
+#if defined(__ICCARM__)
+#pragma pack(1)
+#endif
diff --git a/examples/device/net_lwip_webserver/src/arch/cc.h b/examples/device/net_lwip_webserver/src/arch/cc.h
index 56a0cacf7..9f30b91cb 100644
--- a/examples/device/net_lwip_webserver/src/arch/cc.h
+++ b/examples/device/net_lwip_webserver/src/arch/cc.h
@@ -1,8 +1,8 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
+ * 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,
@@ -11,21 +11,21 @@
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
+ * derived from this software without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
- *
+ *
* Author: Adam Dunkels <[email protected]>
*
*/
@@ -42,7 +42,7 @@ typedef int sys_prot_t;
#if defined (__ICCARM__)
#define PACK_STRUCT_BEGIN
-#define PACK_STRUCT_STRUCT
+#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_USE_INCLUDES
@@ -50,7 +50,7 @@ typedef int sys_prot_t;
#elif defined (__CC_ARM)
#define PACK_STRUCT_BEGIN __packed
-#define PACK_STRUCT_STRUCT
+#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
diff --git a/examples/device/net_lwip_webserver/src/arch/epstruct.h b/examples/device/net_lwip_webserver/src/arch/epstruct.h
new file mode 100644
index 000000000..f6390959e
--- /dev/null
+++ b/examples/device/net_lwip_webserver/src/arch/epstruct.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <[email protected]>
+ *
+ */
+
+#if defined(__ICCARM__)
+#pragma pack()
+#endif
diff --git a/examples/device/net_lwip_webserver/src/lwipopts.h b/examples/device/net_lwip_webserver/src/lwipopts.h
index a215017c7..336c9243d 100644
--- a/examples/device/net_lwip_webserver/src/lwipopts.h
+++ b/examples/device/net_lwip_webserver/src/lwipopts.h
@@ -1,8 +1,8 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
+ * 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,
@@ -11,21 +11,21 @@
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
+ * derived from this software without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
- *
+ *
* Author: Simon Goldschmidt
*
*/
diff --git a/examples/device/net_lwip_webserver/src/main.c b/examples/device/net_lwip_webserver/src/main.c
index 33b4d38b6..7d98aacbc 100644
--- a/examples/device/net_lwip_webserver/src/main.c
+++ b/examples/device/net_lwip_webserver/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Peter Lawrence
@@ -39,11 +39,11 @@ and likely their manufacturer has not tested such functionality. Some code work
The smartphone may only have an ECM driver, but refuse to automatically pick ECM (unlike the OSes above);
try modifying ./examples/devices/net_lwip_webserver/usb_descriptors.c so that CONFIG_ID_ECM is default.
-The smartphone may be artificially picky about which Ethernet MAC address to recognize; if this happens,
+The smartphone may be artificially picky about which Ethernet MAC address to recognize; if this happens,
try changing the first byte of tud_network_mac_address[] below from 0x02 to 0x00 (clearing bit 1).
*/
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
#include "dhserver.h"
@@ -64,7 +64,7 @@ static struct pbuf *received_frame;
/* this is used by this code, ./class/net/net_driver.c, and usb_descriptors.c */
/* ideally speaking, this should be generated from the hardware's unique ID (if available) */
/* it is suggested that the first byte is 0x02 to indicate a link-local address */
-const uint8_t tud_network_mac_address[6] = {0x02,0x02,0x84,0x6A,0x96,0x00};
+uint8_t tud_network_mac_address[6] = {0x02,0x02,0x84,0x6A,0x96,0x00};
/* network parameters of this MCU */
static const ip4_addr_t ipaddr = INIT_IP4(192, 168, 7, 1);
@@ -170,7 +170,7 @@ bool dns_query_proc(const char *name, ip4_addr_t *addr)
bool tud_network_recv_cb(const uint8_t *src, uint16_t size)
{
- /* this shouldn't happen, but if we get another packet before
+ /* this shouldn't happen, but if we get another packet before
parsing the previous, we must signal our inability to accept it */
if (received_frame) return false;
@@ -232,6 +232,10 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
/* initialize lwip, dhcp-server, dns-server, and http */
init_lwip();
while (!netif_is_up(&netif_data));
diff --git a/examples/device/net_lwip_webserver/src/usb_descriptors.c b/examples/device/net_lwip_webserver/src/usb_descriptors.c
index bee51790a..da628c8be 100644
--- a/examples/device/net_lwip_webserver/src/usb_descriptors.c
+++ b/examples/device/net_lwip_webserver/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,6 +23,7 @@
*
*/
+#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.
@@ -77,7 +78,7 @@ tusb_desc_device_t const desc_device =
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
-
+
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0xCafe,
@@ -190,55 +191,56 @@ static char const* string_desc_arr [] =
[STRID_LANGID] = (const char[]) { 0x09, 0x04 }, // supported language is English (0x0409)
[STRID_MANUFACTURER] = "TinyUSB", // Manufacturer
[STRID_PRODUCT] = "TinyUSB Device", // Product
- [STRID_SERIAL] = "123456", // Serial
+ [STRID_SERIAL] = NULL, // Serials will use unique ID if possible
[STRID_INTERFACE] = "TinyUSB Network Interface" // Interface Description
// STRID_MAC index is handled separately
};
-static uint16_t _desc_str[32];
+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)
-{
+uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void) langid;
-
unsigned int chr_count = 0;
- if (STRID_LANGID == index)
- {
- memcpy(&_desc_str[1], string_desc_arr[STRID_LANGID], 2);
- chr_count = 1;
- }
- else if (STRID_MAC == index)
- {
- // Convert MAC address into UTF-16
+ switch ( index ) {
+ case STRID_LANGID:
+ memcpy(&_desc_str[1], string_desc_arr[0], 2);
+ chr_count = 1;
+ break;
- for (unsigned i=0; i<sizeof(tud_network_mac_address); i++)
- {
- _desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 4) & 0xf];
- _desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 0) & 0xf];
- }
- }
- else
- {
- // 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
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
+
+ case STRID_MAC:
+ // Convert MAC address into UTF-16
+ for (unsigned i=0; i<sizeof(tud_network_mac_address); i++) {
+ _desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 4) & 0xf];
+ _desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 0) & 0xf];
+ }
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > (TU_ARRAY_SIZE(_desc_str) - 1)) chr_count = TU_ARRAY_SIZE(_desc_str) - 1;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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 (unsigned int i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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
diff --git a/examples/device/uac2_headset/CMakeLists.txt b/examples/device/uac2_headset/CMakeLists.txt
index abc4d91da..e92a57148 100644
--- a/examples/device/uac2_headset/CMakeLists.txt
+++ b/examples/device/uac2_headset/CMakeLists.txt
@@ -1,15 +1,20 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
+
add_executable(${PROJECT})
# Example source
@@ -23,6 +28,6 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/uac2_headset/Makefile b/examples/device/uac2_headset/Makefile
index 5a455078e..7fa475da5 100644
--- a/examples/device/uac2_headset/Makefile
+++ b/examples/device/uac2_headset/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,4 +8,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/uac2_headset/skip.txt b/examples/device/uac2_headset/skip.txt
index 70d8e8838..a2a76af0e 100644
--- a/examples/device/uac2_headset/skip.txt
+++ b/examples/device/uac2_headset/skip.txt
@@ -5,3 +5,4 @@ mcu:SAMD11
mcu:SAME5X
mcu:SAMG
board:stm32l052dap52
+family:espressif
diff --git a/examples/device/uac2_headset/src/main.c b/examples/device/uac2_headset/src/main.c
index 003dc2a74..0ab72b2f3 100644
--- a/examples/device/uac2_headset/src/main.c
+++ b/examples/device/uac2_headset/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jerzy Kasenberg
@@ -26,7 +26,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
#include "usb_descriptors.h"
@@ -79,8 +79,8 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
// Audio controls
// Current states
-int8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
-int16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
+int8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; // +1 for master channel 0
+int16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; // +1 for master channel 0
// Buffer for microphone data
int32_t mic_buf[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ / 4];
@@ -105,6 +105,10 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
TU_LOG1("Headset running\r\n");
while (1)
@@ -113,8 +117,6 @@ int main(void)
audio_task();
led_blinking_task();
}
-
- return 0;
}
//--------------------------------------------------------------------+
@@ -145,7 +147,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
// Helper for clock get requests
@@ -176,7 +178,7 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t
rangef.subrange[i].bRes = 0;
TU_LOG1("Range %d (%d, %d, %d)\r\n", i, (int)rangef.subrange[i].bMin, (int)rangef.subrange[i].bMax, (int)rangef.subrange[i].bRes);
}
-
+
return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &rangef, sizeof(rangef));
}
}
diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h
index 1a3e23e95..b770483dc 100644
--- a/examples/device/uac2_headset/src/tusb_config.h
+++ b/examples/device/uac2_headset/src/tusb_config.h
@@ -151,11 +151,11 @@ extern "C" {
// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1
-#define CFG_TUD_AUDIO_UNC_1_FORMAT_1_EP_SZ_OUT TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX)
-#define CFG_TUD_AUDIO_UNC_1_FORMAT_2_EP_SZ_OUT TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX)
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX)
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_OUT TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX)
-#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ TU_MAX(CFG_TUD_AUDIO_UNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_UNC_1_FORMAT_2_EP_SZ_OUT)*2
-#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TU_MAX(CFG_TUD_AUDIO_UNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_UNC_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 TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_OUT)*2
+#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
// 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
diff --git a/examples/device/uac2_headset/src/usb_descriptors.c b/examples/device/uac2_headset/src/usb_descriptors.c
index 10f5cbd27..6d1e6a23f 100644
--- a/examples/device/uac2_headset/src/usb_descriptors.c
+++ b/examples/device/uac2_headset/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Ha Thach (tinyusb.org)
@@ -24,6 +24,7 @@
*
*/
+#include "bsp/board_api.h"
#include "tusb.h"
#include "usb_descriptors.h"
@@ -46,7 +47,7 @@ tusb_desc_device_t const desc_device =
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
- // Use Interface Association Descriptor (IAD) for CDC
+ // Use Interface Association Descriptor (IAD) for Audio
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
@@ -93,6 +94,12 @@ uint8_t const * tud_descriptor_device_cb(void)
#define EPNUM_AUDIO_IN 0x01
#define EPNUM_AUDIO_OUT 0x02
+#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X
+ // FT9XX doesn't support a same endpoint number with different direction IN and OUT
+ // e.g EP1 OUT & EP1 IN cannot exist together
+ #define EPNUM_AUDIO_IN 0x01
+ #define EPNUM_AUDIO_OUT 0x02
+
#else
#define EPNUM_AUDIO_IN 0x01
#define EPNUM_AUDIO_OUT 0x01
@@ -100,7 +107,7 @@ uint8_t const * tud_descriptor_device_cb(void)
uint8_t const desc_configuration[] =
{
- // Interface count, string index, total length, attribute, power in mA
+ // 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 Out & EP In address, EP size
@@ -120,52 +127,65 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB headset", // 2: Product
- "000001", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
"TinyUSB Speakers", // 4: Audio Interface
"TinyUSB Microphone", // 5: Audio Interface
};
-static uint16_t _desc_str[32];
+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;
+uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
+ (void) langid;
+ size_t chr_count;
- uint8_t chr_count;
+ switch ( index ) {
+ case STRID_LANGID:
+ memcpy(&_desc_str[1], string_desc_arr[0], 2);
+ chr_count = 1;
+ break;
- if (index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }
- else
- {
- // Convert ASCII string into UTF-16
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if (chr_count > 31) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
+ if ( chr_count > max_count ) chr_count = max_count;
- for (uint8_t i = 0; i < chr_count; i++)
- {
- _desc_str[1 + i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/uac2_headset/src/usb_descriptors.h b/examples/device/uac2_headset/src/usb_descriptors.h
index 342b4fac1..d7e170162 100644
--- a/examples/device/uac2_headset/src/usb_descriptors.h
+++ b/examples/device/uac2_headset/src/usb_descriptors.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jerzy Kasenbreg
@@ -57,7 +57,7 @@ enum
+ TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
/* Interface 1, Alternate 0 */\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
- /* Interface 1, Alternate 0 */\
+ /* Interface 1, Alternate 1 */\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
@@ -86,7 +86,7 @@ enum
#define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _epout, _epin) \
/* Standard Interface Association Descriptor (IAD) */\
- TUD_AUDIO_DESC_IAD(/*_firstitfs*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ 3, /*_stridx*/ 0x00),\
+ TUD_AUDIO_DESC_IAD(/*_firstitf*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ ITF_NUM_TOTAL, /*_stridx*/ 0x00),\
/* Standard AC Interface Descriptor(4.7.1) */\
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
@@ -114,7 +114,7 @@ enum
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
- TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\
/* Interface 1, Alternate 2 - alternate interface for data streaming */\
@@ -124,7 +124,7 @@ enum
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
- TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\
/* Standard AS Interface Descriptor(4.9.1) */\
@@ -138,7 +138,7 @@ enum
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
- TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\
/* Interface 2, Alternate 2 - alternate interface for data streaming */\
@@ -148,7 +148,7 @@ enum
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
- TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
diff --git a/examples/device/usbtmc/CMakeLists.txt b/examples/device/usbtmc/CMakeLists.txt
index c49603c26..a63ca2d81 100644
--- a/examples/device/usbtmc/CMakeLists.txt
+++ b/examples/device/usbtmc/CMakeLists.txt
@@ -1,15 +1,20 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
+
add_executable(${PROJECT})
# Example source
@@ -24,6 +29,6 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/usbtmc/Makefile b/examples/device/usbtmc/Makefile
index 69b633fea..1b4d398cf 100644
--- a/examples/device/usbtmc/Makefile
+++ b/examples/device/usbtmc/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,4 +8,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/usbtmc/skip.txt b/examples/device/usbtmc/skip.txt
index a43106cf0..ccff857ac 100644
--- a/examples/device/usbtmc/skip.txt
+++ b/examples/device/usbtmc/skip.txt
@@ -1 +1,2 @@
mcu:BCM2835
+family:espressif
diff --git a/examples/device/usbtmc/src/main.c b/examples/device/usbtmc/src/main.c
index 6945d8743..9d8f0783d 100644
--- a/examples/device/usbtmc/src/main.c
+++ b/examples/device/usbtmc/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -27,7 +27,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
#include "usbtmc_app.h"
//--------------------------------------------------------------------+
@@ -57,14 +57,16 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
tud_task(); // tinyusb device task
led_blinking_task();
usbtmc_app_task_iter();
}
-
- return 0;
}
//--------------------------------------------------------------------+
@@ -95,7 +97,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
diff --git a/examples/device/usbtmc/src/usb_descriptors.c b/examples/device/usbtmc/src/usb_descriptors.c
index ff682ff97..54948291e 100644
--- a/examples/device/usbtmc/src/usb_descriptors.c
+++ b/examples/device/usbtmc/src/usb_descriptors.c
@@ -23,6 +23,7 @@
*
*/
+#include "bsp/board_api.h"
#include "tusb.h"
#include "class/usbtmc/usbtmc.h"
#include "class/usbtmc/usbtmc_device.h"
@@ -188,55 +189,64 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
"TinyUSB USBTMC", // 4: USBTMC
};
-static uint16_t _desc_str[32];
+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)
-{
+uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void) langid;
-
size_t chr_count;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }
- else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) {
- chr_count = 31;
- }
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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)((((uint16_t)TUSB_DESC_STRING) << 8 ) | (2u*chr_count + 2u));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/usbtmc/src/usbtmc_app.c b/examples/device/usbtmc/src/usbtmc_app.c
index 8f87a6dca..fb25982c7 100644
--- a/examples/device/usbtmc/src/usbtmc_app.c
+++ b/examples/device/usbtmc/src/usbtmc_app.c
@@ -23,10 +23,10 @@
*
*/
-#include <strings.h>
+#include <string.h>
#include <stdlib.h> /* atoi */
#include "tusb.h"
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "main.h"
#if (CFG_TUD_USBTMC_ENABLE_488)
@@ -88,14 +88,6 @@ static size_t buffer_tx_ix; // for transmitting using multiple transfers
static uint8_t buffer[225]; // A few packets long should be enough.
-static usbtmc_msg_dev_dep_msg_in_header_t rspMsg = {
- .bmTransferAttributes =
- {
- .EOM = 1,
- .UsingTermChar = 0
- }
-};
-
void tud_usbtmc_open_cb(uint8_t interface_id)
{
(void)interface_id;
@@ -148,11 +140,14 @@ bool tud_usbtmc_msg_data_cb(void *data, size_t len, bool transfer_complete)
queryState = transfer_complete;
idnQuery = 0;
- if(transfer_complete && (len >=4) && !strncasecmp("*idn?",data,4))
+ if ( transfer_complete && (len >= 4) &&
+ (!strncmp("*idn?", data, 4) || !strncmp("*IDN?", data, 4)) )
{
idnQuery = 1;
}
- if(transfer_complete && !strncasecmp("delay ",data,5))
+
+ if ( transfer_complete &&
+ (!strncmp("delay ", data, 5) || !strncmp("DELAY ", data, 5)) )
{
queryState = 0;
int d = atoi((char*)data + 5);
@@ -184,9 +179,6 @@ static unsigned int msgReqLen;
bool tud_usbtmc_msgBulkIn_request_cb(usbtmc_msg_request_dev_dep_in const * request)
{
- rspMsg.header.MsgID = request->header.MsgID,
- rspMsg.header.bTag = request->header.bTag,
- rspMsg.header.bTagInverse = request->header.bTagInverse;
msgReqLen = request->TransferSize;
#ifdef xDEBUG
@@ -250,7 +242,6 @@ void usbtmc_app_task_iter(void) {
break;
default:
TU_ASSERT(false,);
- return;
}
}
diff --git a/examples/device/usbtmc/visaQuery.py b/examples/device/usbtmc/visaQuery.py
index c4e5ad2b9..ca65daf97 100644
--- a/examples/device/usbtmc/visaQuery.py
+++ b/examples/device/usbtmc/visaQuery.py
@@ -36,8 +36,8 @@ def test_trig():
time.sleep(0.3) # SRQ may have some delay
assert (inst.read_stb() & 0x40), "SRQ not set after 0.3 seconds"
assert (inst.read_stb() == 0)
-
-
+
+
def test_mav():
inst.write("delay 50")
inst.read_stb() # clear STB
@@ -45,15 +45,15 @@ def test_mav():
inst.write("123")
time.sleep(0.3)
assert (inst.read_stb() & 0x10), "MAV not set after 0.5 seconds"
-
+
rsp = inst.read()
assert(rsp == "123\r\n")
-
-
+
+
def test_srq():
assert (inst.read_stb() == 0)
inst.write("123")
-
+
#inst.enable_event(pyvisa.constants.VI_EVENT_SERVICE_REQ, pyvisa.constants.VI_QUEUE)
#waitrsp = inst.wait_on_event(pyvisa.constants.VI_EVENT_SERVICE_REQ, 5000)
#inst.discard_events(pyvisa.constants.VI_EVENT_SERVICE_REQ, pyvisa.constants.VI_QUEUE)
@@ -64,7 +64,7 @@ def test_srq():
assert (stb == 0x50),msg
assert (inst.read_stb() == 0x10), "SRQ set at second read!"
-
+
rsp = inst.read()
assert(rsp == "123\r\n")
@@ -110,7 +110,7 @@ def test_abort_in():
inst.timeout = 800
y = inst.read()
assert(y == "xxx\r\n")
-
+
def test_indicate():
# perform indicator pulse
usb_iface = inst.get_visa_attribute(pyvisa.constants.VI_ATTR_USB_INTFC_NUM)
@@ -120,8 +120,8 @@ def test_indicate():
assert(retv == b'\x01')
else:
assert((retv[1] == pyvisa.constants.StatusCode(0)) and (retv[0] == b'\x01')), f"indicator pulse failed: retv={retv}"
-
-
+
+
def test_multi_read():
old_chunk_size = inst.chunk_size
longstr = "0123456789abcdefghijklmnopqrstuvwxyz" * 10
@@ -133,7 +133,7 @@ def test_multi_read():
y = inst.read()
assert (x + "\r\n" == y)
#inst.chunk_size = old_chunk_size
-
+
def test_stall_ep0():
usb_iface = inst.get_visa_attribute(pyvisa.constants.VI_ATTR_USB_INTFC_NUM)
inst.read_stb()
@@ -143,7 +143,7 @@ def test_stall_ep0():
assert(False)
except pyvisa.VisaIOError:
pass
-
+
assert (inst.read_stb() == 0)
@@ -153,7 +153,7 @@ print(reslist)
if (len(reslist) == 0):
sys.exit()
-
+
inst = rm.open_resource(reslist[0]);
inst.timeout = 3000
diff --git a/examples/device/video_capture/CMakeLists.txt b/examples/device/video_capture/CMakeLists.txt
index b92a2b804..80dc39ca5 100644
--- a/examples/device/video_capture/CMakeLists.txt
+++ b/examples/device/video_capture/CMakeLists.txt
@@ -1,15 +1,20 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
+
add_executable(${PROJECT})
if (FORCE_READONLY)
@@ -29,6 +34,6 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/video_capture/Makefile b/examples/device/video_capture/Makefile
index fda66bcc1..d698a848d 100644
--- a/examples/device/video_capture/Makefile
+++ b/examples/device/video_capture/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
ifeq ($(DISABLE_MJPEG),1)
CFLAGS += -DCFG_EXAMPLE_VIDEO_DISABLE_MJPEG
@@ -16,4 +15,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/video_capture/skip.txt b/examples/device/video_capture/skip.txt
index 5898664a2..db64cc639 100644
--- a/examples/device/video_capture/skip.txt
+++ b/examples/device/video_capture/skip.txt
@@ -1,3 +1,4 @@
mcu:MSP430x5xx
mcu:NUC121
mcu:SAMD11
+family:espressif
diff --git a/examples/device/video_capture/src/CMakeLists.txt b/examples/device/video_capture/src/CMakeLists.txt
new file mode 100644
index 000000000..cef2b46ee
--- /dev/null
+++ b/examples/device/video_capture/src/CMakeLists.txt
@@ -0,0 +1,4 @@
+# This file is for ESP-IDF only
+idf_component_register(SRCS "main.c" "usb_descriptors.c"
+ INCLUDE_DIRS "."
+ REQUIRES boards tinyusb_src)
diff --git a/examples/device/video_capture/src/images.h b/examples/device/video_capture/src/images.h
index 0398428b3..ac372cb16 100644
--- a/examples/device/video_capture/src/images.h
+++ b/examples/device/video_capture/src/images.h
@@ -1,4 +1,5 @@
-#if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPG)
+#if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG)
+// uncopmressed frame
static const unsigned char frame_buffer[128 * (96 + 1) * 2] = {
/* 0 */
0xeb, 0x80, 0xeb, 0x80, 0xeb, 0x80, 0xeb, 0x80, 0xeb, 0x80, 0xeb, 0x80, 0xeb, 0x80, 0xeb, 0x80,
@@ -1650,8 +1651,10 @@ static const unsigned char frame_buffer[128 * (96 + 1) * 2] = {
0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80,
0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80, 0x10, 0x80,
};
+
#else
+// mpeg compressed data (not CFG_EXAMPLE_VIDEO_DISABLE_MJPEG)
#define color_bar_0_jpg_len 511
#define color_bar_1_jpg_len 512
#define color_bar_2_jpg_len 511
diff --git a/examples/device/video_capture/src/main.c b/examples/device/video_capture/src/main.c
index 3ceebe821..2a2b0961f 100644
--- a/examples/device/video_capture/src/main.c
+++ b/examples/device/video_capture/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -27,7 +27,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
#include "usb_descriptors.h"
@@ -40,7 +40,7 @@
* - 1000 ms : device mounted
* - 2500 ms : device is suspended
*/
-enum {
+enum {
BLINK_NOT_MOUNTED = 250,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
@@ -48,26 +48,38 @@ enum {
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
-void led_blinking_task(void);
-void video_task(void);
+void led_blinking_task(void* param);
+void usb_device_task(void *param);
+void video_task(void* param);
-/*------------- MAIN -------------*/
-int main(void)
-{
+#if CFG_TUSB_OS == OPT_OS_FREERTOS
+void freertos_init_task(void);
+#endif
+
+
+//--------------------------------------------------------------------+
+// Main
+//--------------------------------------------------------------------+
+int main(void) {
board_init();
+ // If using FreeRTOS: create blinky, tinyusb device, video task
+#if CFG_TUSB_OS == OPT_OS_FREERTOS
+ freertos_init_task();
+#else
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
- while (1)
- {
- tud_task(); // tinyusb device task
- led_blinking_task();
-
- video_task();
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
}
- return 0;
+ while (1) {
+ tud_task(); // tinyusb device task
+ led_blinking_task(NULL);
+ video_task(NULL);
+ }
+#endif
}
//--------------------------------------------------------------------+
@@ -75,33 +87,28 @@ int main(void)
//--------------------------------------------------------------------+
// Invoked when device is mounted
-void tud_mount_cb(void)
-{
+void tud_mount_cb(void) {
blink_interval_ms = BLINK_MOUNTED;
}
// Invoked when device is unmounted
-void tud_umount_cb(void)
-{
+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 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 = BLINK_MOUNTED;
+void tud_resume_cb(void) {
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
-
//--------------------------------------------------------------------+
// USB Video
//--------------------------------------------------------------------+
@@ -109,11 +116,12 @@ static unsigned frame_num = 0;
static unsigned tx_busy = 0;
static unsigned interval_ms = 1000 / FRAME_RATE;
-/* YUY2 frame buffer */
#ifdef CFG_EXAMPLE_VIDEO_READONLY
+// For mcus that does not have enough SRAM for frame buffer, we use fixed frame data.
+// To further reduce the size, we use MJPEG format instead of YUY2.
#include "images.h"
-# if !defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPG)
+#if !defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG)
static struct {
uint32_t size;
uint8_t const *buffer;
@@ -127,29 +135,30 @@ static struct {
{color_bar_6_jpg_len, color_bar_6_jpg},
{color_bar_7_jpg_len, color_bar_7_jpg},
};
-# endif
+#endif
#else
+
+// YUY2 frame buffer
static uint8_t frame_buffer[FRAME_WIDTH * FRAME_HEIGHT * 16 / 8];
-static void fill_color_bar(uint8_t *buffer, unsigned start_position)
-{
- /* EBU color bars
- * See also https://stackoverflow.com/questions/6939422 */
+
+static void fill_color_bar(uint8_t* buffer, unsigned start_position) {
+ /* EBU color bars: https://stackoverflow.com/questions/6939422 */
static uint8_t const bar_color[8][4] = {
- /* Y, U, Y, V */
- { 235, 128, 235, 128}, /* 100% White */
- { 219, 16, 219, 138}, /* Yellow */
- { 188, 154, 188, 16}, /* Cyan */
- { 173, 42, 173, 26}, /* Green */
- { 78, 214, 78, 230}, /* Magenta */
- { 63, 102, 63, 240}, /* Red */
- { 32, 240, 32, 118}, /* Blue */
- { 16, 128, 16, 128}, /* Black */
+ /* Y, U, Y, V */
+ { 235, 128, 235, 128}, /* 100% White */
+ { 219, 16, 219, 138}, /* Yellow */
+ { 188, 154, 188, 16}, /* Cyan */
+ { 173, 42, 173, 26}, /* Green */
+ { 78, 214, 78, 230}, /* Magenta */
+ { 63, 102, 63, 240}, /* Red */
+ { 32, 240, 32, 118}, /* Blue */
+ { 16, 128, 16, 128}, /* Black */
};
- uint8_t *p;
+ uint8_t* p;
/* Generate the 1st line */
- uint8_t *end = &buffer[FRAME_WIDTH * 2];
+ uint8_t* end = &buffer[FRAME_WIDTH * 2];
unsigned idx = (FRAME_WIDTH / 2 - 1) - (start_position % (FRAME_WIDTH / 2));
p = &buffer[idx * 4];
for (unsigned i = 0; i < 8; ++i) {
@@ -161,6 +170,7 @@ static void fill_color_bar(uint8_t *buffer, unsigned start_position)
}
}
}
+
/* Duplicate the 1st line to the others */
p = &buffer[FRAME_WIDTH * 2];
for (unsigned i = 1; i < FRAME_HEIGHT; ++i) {
@@ -168,32 +178,33 @@ static void fill_color_bar(uint8_t *buffer, unsigned start_position)
p += FRAME_WIDTH * 2;
}
}
+
#endif
-void video_task(void)
-{
+void video_send_frame(void) {
static unsigned start_ms = 0;
static unsigned already_sent = 0;
if (!tud_video_n_streaming(0, 0)) {
- already_sent = 0;
- frame_num = 0;
+ already_sent = 0;
+ frame_num = 0;
return;
}
if (!already_sent) {
already_sent = 1;
+ tx_busy = 1;
start_ms = board_millis();
#ifdef CFG_EXAMPLE_VIDEO_READONLY
-# if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPG)
+ #if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG)
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4],
FRAME_WIDTH * FRAME_HEIGHT * 16/8);
-# else
+ #else
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)frames[frame_num % 8].buffer, frames[frame_num % 8].size);
-# endif
+ #endif
#else
fill_color_bar(frame_buffer, frame_num);
- tud_video_n_frame_xfer(0, 0, (void*)frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16/8);
+ tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8);
#endif
}
@@ -201,49 +212,140 @@ void video_task(void)
if (cur - start_ms < interval_ms) return; // not enough time
if (tx_busy) return;
start_ms += interval_ms;
+ tx_busy = 1;
#ifdef CFG_EXAMPLE_VIDEO_READONLY
-# if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPG)
+ #if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG)
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4],
FRAME_WIDTH * FRAME_HEIGHT * 16/8);
-# else
+ #else
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)frames[frame_num % 8].buffer, frames[frame_num % 8].size);
-# endif
+ #endif
#else
fill_color_bar(frame_buffer, frame_num);
- tud_video_n_frame_xfer(0, 0, (void*)frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16/8);
+ tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8);
#endif
}
-void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
-{
- (void)ctl_idx; (void)stm_idx;
+
+void video_task(void* param) {
+ (void) param;
+
+ while(1) {
+ video_send_frame();
+
+ #if CFG_TUSB_OS == OPT_OS_FREERTOS
+ vTaskDelay(interval_ms / portTICK_PERIOD_MS);
+ #else
+ return;
+ #endif
+ }
+}
+
+void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) {
+ (void) ctl_idx;
+ (void) stm_idx;
tx_busy = 0;
/* flip buffer */
++frame_num;
}
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;
+ video_probe_and_commit_control_t const* parameters) {
+ (void) ctl_idx;
+ (void) stm_idx;
/* convert unit to ms from 100 ns */
interval_ms = parameters->dwFrameInterval / 10000;
return VIDEO_ERROR_NONE;
}
//--------------------------------------------------------------------+
-// BLINKING TASK
+// Blinking Task
//--------------------------------------------------------------------+
-void led_blinking_task(void)
-{
+void led_blinking_task(void* param) {
+ (void) param;
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;
+ while (1) {
+ #if CFG_TUSB_OS == OPT_OS_FREERTOS
+ vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS);
+ #else
+ if (board_millis() - start_ms < blink_interval_ms) return; // not enough time
+ #endif
- board_led_write(led_state);
- led_state = 1 - led_state; // toggle
+ start_ms += blink_interval_ms;
+ board_led_write(led_state);
+ led_state = 1 - led_state; // toggle
+ }
}
+
+//--------------------------------------------------------------------+
+// FreeRTOS
+//--------------------------------------------------------------------+
+#if CFG_TUSB_OS == OPT_OS_FREERTOS
+
+#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE
+#define VIDEO_STACK_SIZE (configMINIMAL_STACK_SIZE*4)
+
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+ #define USBD_STACK_SIZE 4096
+ int main(void);
+ void app_main(void) {
+ main();
+ }
+#else
+ // Increase stack size when debug log is enabled
+ #define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1)
+#endif
+
+// static task
+#if configSUPPORT_STATIC_ALLOCATION
+StackType_t blinky_stack[BLINKY_STACK_SIZE];
+StaticTask_t blinky_taskdef;
+
+StackType_t usb_device_stack[USBD_STACK_SIZE];
+StaticTask_t usb_device_taskdef;
+
+StackType_t video_stack[VIDEO_STACK_SIZE];
+StaticTask_t video_taskdef;
+#endif
+
+// USB Device Driver task
+// This top level thread process all usb events and invoke callbacks
+void usb_device_task(void *param) {
+ (void) param;
+
+ // init device stack on configured roothub port
+ // This should be called after scheduler/kernel is started.
+ // Otherwise, it could cause kernel issue since USB IRQ handler does use RTOS queue API.
+ tud_init(BOARD_TUD_RHPORT);
+
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
+ // RTOS forever loop
+ while (1) {
+ // put this thread to waiting state until there is new events
+ tud_task();
+ }
+}
+
+void freertos_init_task(void) {
+ #if configSUPPORT_STATIC_ALLOCATION
+ xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef);
+ xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_device_stack, &usb_device_taskdef);
+ xTaskCreateStatic(video_task, "cdc", VIDEO_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, video_stack, &video_taskdef);
+ #else
+ xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL);
+ xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL);
+ xTaskCreate(video_task, "video", VIDEO_STACK_SZIE, NULL, configMAX_PRIORITIES - 2, NULL);
+ #endif
+
+ // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
+ #if !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+ vTaskStartScheduler();
+ #endif
+}
+#endif
diff --git a/examples/device/video_capture/src/tusb_config.h b/examples/device/video_capture/src/tusb_config.h
index e567ba669..bdfc37d87 100644
--- a/examples/device/video_capture/src/tusb_config.h
+++ b/examples/device/video_capture/src/tusb_config.h
@@ -57,6 +57,11 @@
#define CFG_TUSB_OS OPT_OS_NONE
#endif
+// Espressif IDF requires "freertos/" prefix in include path
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+#define CFG_TUSB_OS_INC_PATH freertos/
+#endif
+
#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0
#endif
@@ -97,9 +102,15 @@
// The number of video streaming interfaces
#define CFG_TUD_VIDEO_STREAMING 1
-// video streaming endpoint size
+// video streaming endpoint buffer size
#define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE 256
+// use bulk endpoint for streaming interface
+#define CFG_TUD_VIDEO_STREAMING_BULK 1
+
+//#define CFG_EXAMPLE_VIDEO_READONLY
+//#define CFG_EXAMPLE_VIDEO_DISABLE_MJPEG
+
#ifdef __cplusplus
}
#endif
diff --git a/examples/device/video_capture/src/usb_descriptors.c b/examples/device/video_capture/src/usb_descriptors.c
index 499ee311c..f308c75a7 100644
--- a/examples/device/video_capture/src/usb_descriptors.c
+++ b/examples/device/video_capture/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,6 +23,7 @@
*
*/
+#include "bsp/board_api.h"
#include "tusb.h"
#include "usb_descriptors.h"
@@ -36,14 +37,36 @@
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(AUDIO, 4) | _PID_MAP(VIDEO, 5) | _PID_MAP(VENDOR, 6) )
+#define USB_VID 0xCafe
+#define USB_BCD 0x0200
+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+ STRID_UVC_CONTROL,
+ STRID_UVC_STREAMING,
+};
+
+// 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 UVC Control", // 4: UVC Interface
+ "TinyUSB UVC Streaming", // 5: UVC Interface
+};
+
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
-tusb_desc_device_t const desc_device =
-{
+tusb_desc_device_t const desc_device = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
- .bcdUSB = 0x0200,
+ .bcdUSB = USB_BCD,
// Use Interface Association Descriptor (IAD) for Video
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
@@ -53,124 +76,409 @@ tusb_desc_device_t const desc_device =
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
- .idVendor = 0xCafe,
+ .idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
- .iManufacturer = 0x01,
- .iProduct = 0x02,
- .iSerialNumber = 0x03,
+ .iManufacturer = STRID_MANUFACTURER,
+ .iProduct = STRID_PRODUCT,
+ .iSerialNumber = STRID_SERIAL,
.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;
+uint8_t const* tud_descriptor_device_cb(void) {
+ return (uint8_t const*) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
-#if defined(CFG_EXAMPLE_VIDEO_READONLY) && !defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG)
-#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_VIDEO_CAPTURE_DESC_MJPEG_LEN)
-#else
-#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_VIDEO_CAPTURE_DESC_UNCOMPR_LEN)
-#endif
+/* Time stamp base clock. It is a deprecated parameter. */
+#define UVC_CLOCK_FREQUENCY 27000000
+/* video capture path */
+#define UVC_ENTITY_CAP_INPUT_TERMINAL 0x01
+#define UVC_ENTITY_CAP_OUTPUT_TERMINAL 0x02
+
+enum {
+ ITF_NUM_VIDEO_CONTROL,
+ ITF_NUM_VIDEO_STREAMING,
+ ITF_NUM_TOTAL
+};
+
+// Select appropriate endpoint number
#if TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, 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_VIDEO_IN 0x83
-
+ #define EPNUM_VIDEO_IN (CFG_TUD_VIDEO_STREAMING_BULK ? 0x82 : 0x83)
#elif TU_CHECK_MCU(OPT_MCU_NRF5X)
// nRF5x ISO can only be endpoint 8
- #define EPNUM_VIDEO_IN 0x88
-
+ #define EPNUM_VIDEO_IN (CFG_TUD_VIDEO_STREAMING_BULK ? 0x81 : 0x88)
#else
#define EPNUM_VIDEO_IN 0x81
-
#endif
-uint8_t const 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, 0, 500),
- // IAD for Video Control
#if defined(CFG_EXAMPLE_VIDEO_READONLY) && !defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG)
- TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG(4, EPNUM_VIDEO_IN,
- FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE,
- CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE)
+ #define USE_MJPEG 1
+#else
+ #define USE_MJPEG 0
+#endif
+
+#define USE_ISO_STREAMING (!CFG_TUD_VIDEO_STREAMING_BULK)
+
+typedef struct TU_ATTR_PACKED {
+ tusb_desc_interface_t itf;
+ tusb_desc_video_control_header_1itf_t header;
+ tusb_desc_video_control_camera_terminal_t camera_terminal;
+ tusb_desc_video_control_output_terminal_t output_terminal;
+} uvc_control_desc_t;
+
+/* Windows support YUY2 and NV12
+ * https://docs.microsoft.com/en-us/windows-hardware/drivers/stream/usb-video-class-driver-overview */
+
+typedef struct TU_ATTR_PACKED {
+ tusb_desc_interface_t itf;
+ tusb_desc_video_streaming_input_header_1byte_t header;
+
+#if USE_MJPEG
+ tusb_desc_video_format_mjpeg_t format;
+ tusb_desc_video_frame_mjpeg_continuous_t frame;
+#else
+ tusb_desc_video_format_uncompressed_t format;
+ tusb_desc_video_frame_uncompressed_continuous_t frame;
+#endif
+
+ tusb_desc_video_streaming_color_matching_t color;
+
+#if USE_ISO_STREAMING
+ // For ISO streaming, USB spec requires to alternate interface
+ tusb_desc_interface_t itf_alt;
+#endif
+
+ tusb_desc_endpoint_t ep;
+} uvc_streaming_desc_t;
+
+typedef struct TU_ATTR_PACKED {
+ tusb_desc_configuration_t config;
+ tusb_desc_interface_assoc_t iad;
+ uvc_control_desc_t video_control;
+ uvc_streaming_desc_t video_streaming;
+} uvc_cfg_desc_t;
+
+const uvc_cfg_desc_t desc_fs_configuration = {
+ .config = {
+ .bLength = sizeof(tusb_desc_configuration_t),
+ .bDescriptorType = TUSB_DESC_CONFIGURATION,
+
+ .wTotalLength = sizeof(uvc_cfg_desc_t),
+ .bNumInterfaces = ITF_NUM_TOTAL,
+ .bConfigurationValue = 1,
+ .iConfiguration = 0,
+ .bmAttributes = TU_BIT(7),
+ .bMaxPower = 100 / 2
+ },
+ .iad = {
+ .bLength = sizeof(tusb_desc_interface_assoc_t),
+ .bDescriptorType = TUSB_DESC_INTERFACE_ASSOCIATION,
+
+ .bFirstInterface = ITF_NUM_VIDEO_CONTROL,
+ .bInterfaceCount = 2,
+ .bFunctionClass = TUSB_CLASS_VIDEO,
+ .bFunctionSubClass = VIDEO_SUBCLASS_INTERFACE_COLLECTION,
+ .bFunctionProtocol = VIDEO_ITF_PROTOCOL_UNDEFINED,
+ .iFunction = 0
+ },
+
+ .video_control = {
+ .itf = {
+ .bLength = sizeof(tusb_desc_interface_t),
+ .bDescriptorType = TUSB_DESC_INTERFACE,
+
+ .bInterfaceNumber = ITF_NUM_VIDEO_CONTROL,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = TUSB_CLASS_VIDEO,
+ .bInterfaceSubClass = VIDEO_SUBCLASS_CONTROL,
+ .bInterfaceProtocol = VIDEO_ITF_PROTOCOL_15,
+ .iInterface = STRID_UVC_CONTROL
+ },
+ .header = {
+ .bLength = sizeof(tusb_desc_video_control_header_1itf_t),
+ .bDescriptorType = TUSB_DESC_CS_INTERFACE,
+ .bDescriptorSubType = VIDEO_CS_ITF_VC_HEADER,
+
+ .bcdUVC = VIDEO_BCD_1_50,
+ .wTotalLength = sizeof(uvc_control_desc_t) - sizeof(tusb_desc_interface_t), // CS VC descriptors only
+ .dwClockFrequency = UVC_CLOCK_FREQUENCY,
+ .bInCollection = 1,
+ .baInterfaceNr = { ITF_NUM_VIDEO_STREAMING }
+ },
+ .camera_terminal = {
+ .bLength = sizeof(tusb_desc_video_control_camera_terminal_t),
+ .bDescriptorType = TUSB_DESC_CS_INTERFACE,
+ .bDescriptorSubType = VIDEO_CS_ITF_VC_INPUT_TERMINAL,
+
+ .bTerminalID = UVC_ENTITY_CAP_INPUT_TERMINAL,
+ .wTerminalType = VIDEO_ITT_CAMERA,
+ .bAssocTerminal = 0,
+ .iTerminal = 0,
+ .wObjectiveFocalLengthMin = 0,
+ .wObjectiveFocalLengthMax = 0,
+ .wOcularFocalLength = 0,
+ .bControlSize = 3,
+ .bmControls = { 0, 0, 0 }
+ },
+ .output_terminal = {
+ .bLength = sizeof(tusb_desc_video_control_output_terminal_t),
+ .bDescriptorType = TUSB_DESC_CS_INTERFACE,
+ .bDescriptorSubType = VIDEO_CS_ITF_VC_OUTPUT_TERMINAL,
+
+ .bTerminalID = UVC_ENTITY_CAP_OUTPUT_TERMINAL,
+ .wTerminalType = VIDEO_TT_STREAMING,
+ .bAssocTerminal = 0,
+ .bSourceID = UVC_ENTITY_CAP_INPUT_TERMINAL,
+ .iTerminal = 0
+ }
+ },
+
+ .video_streaming = {
+ .itf = {
+ .bLength = sizeof(tusb_desc_interface_t),
+ .bDescriptorType = TUSB_DESC_INTERFACE,
+
+ .bInterfaceNumber = ITF_NUM_VIDEO_STREAMING,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = CFG_TUD_VIDEO_STREAMING_BULK, // bulk 1, iso 0
+ .bInterfaceClass = TUSB_CLASS_VIDEO,
+ .bInterfaceSubClass = VIDEO_SUBCLASS_STREAMING,
+ .bInterfaceProtocol = VIDEO_ITF_PROTOCOL_15,
+ .iInterface = STRID_UVC_STREAMING
+ },
+ .header = {
+ .bLength = sizeof(tusb_desc_video_streaming_input_header_1byte_t),
+ .bDescriptorType = TUSB_DESC_CS_INTERFACE,
+ .bDescriptorSubType = VIDEO_CS_ITF_VS_INPUT_HEADER,
+
+ .bNumFormats = 1,
+ .wTotalLength = sizeof(uvc_streaming_desc_t) - sizeof(tusb_desc_interface_t)
+ - sizeof(tusb_desc_endpoint_t) - (USE_ISO_STREAMING ? sizeof(tusb_desc_interface_t) : 0) , // CS VS descriptors only
+ .bEndpointAddress = EPNUM_VIDEO_IN,
+ .bmInfo = 0,
+ .bTerminalLink = UVC_ENTITY_CAP_OUTPUT_TERMINAL,
+ .bStillCaptureMethod = 0,
+ .bTriggerSupport = 0,
+ .bTriggerUsage = 0,
+ .bControlSize = 1,
+ .bmaControls = { 0 }
+ },
+ .format = {
+#if USE_MJPEG
+ .bLength = sizeof(tusb_desc_video_format_mjpeg_t),
+ .bDescriptorType = TUSB_DESC_CS_INTERFACE,
+ .bDescriptorSubType = VIDEO_CS_ITF_VS_FORMAT_MJPEG,
+ .bFormatIndex = 1, // 1-based index
+ .bNumFrameDescriptors = 1,
+ .bmFlags = 0,
+#else
+ .bLength = sizeof(tusb_desc_video_format_uncompressed_t),
+ .bDescriptorType = TUSB_DESC_CS_INTERFACE,
+ .bDescriptorSubType = VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED,
+ .bFormatIndex = 1, // 1-based index
+ .bNumFrameDescriptors = 1,
+ .guidFormat = { TUD_VIDEO_GUID_YUY2 },
+ .bBitsPerPixel = 16,
+#endif
+ .bDefaultFrameIndex = 1,
+ .bAspectRatioX = 0,
+ .bAspectRatioY = 0,
+ .bmInterlaceFlags = 0,
+ .bCopyProtect = 0
+ },
+ .frame = {
+#if USE_MJPEG
+ .bLength = sizeof(tusb_desc_video_frame_mjpeg_continuous_t),
+ .bDescriptorType = TUSB_DESC_CS_INTERFACE,
+ .bDescriptorSubType = VIDEO_CS_ITF_VS_FRAME_MJPEG,
#else
- TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR(4, EPNUM_VIDEO_IN,
- FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE,
- CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE)
+ .bLength = sizeof(tusb_desc_video_frame_uncompressed_continuous_t),
+ .bDescriptorType = TUSB_DESC_CS_INTERFACE,
+ .bDescriptorSubType = VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED,
#endif
+ .bFrameIndex = 1, // 1-based index
+ .bmCapabilities = 0,
+ .wWidth = FRAME_WIDTH,
+ .wHeight = FRAME_HEIGHT,
+ .dwMinBitRate = FRAME_WIDTH * FRAME_HEIGHT * 16 * 1,
+ .dwMaxBitRate = FRAME_WIDTH * FRAME_HEIGHT * 16 * FRAME_RATE,
+ .dwMaxVideoFrameBufferSize = FRAME_WIDTH * FRAME_HEIGHT * 16 / 8,
+ .dwDefaultFrameInterval = 10000000 / FRAME_RATE,
+ .bFrameIntervalType = 0, // continuous
+ .dwFrameInterval = {
+ 10000000 / FRAME_RATE, // min
+ 10000000, // max
+ 10000000 / FRAME_RATE // step
+ }
+ },
+ .color = {
+ .bLength = sizeof(tusb_desc_video_streaming_color_matching_t),
+ .bDescriptorType = TUSB_DESC_CS_INTERFACE,
+ .bDescriptorSubType = VIDEO_CS_ITF_VS_COLORFORMAT,
+
+ .bColorPrimaries = VIDEO_COLOR_PRIMARIES_BT709,
+ .bTransferCharacteristics = VIDEO_COLOR_XFER_CH_BT709,
+ .bMatrixCoefficients = VIDEO_COLOR_COEF_SMPTE170M
+ },
+
+#if USE_ISO_STREAMING
+ .itf_alt = {
+ .bLength = sizeof(tusb_desc_interface_t),
+ .bDescriptorType = TUSB_DESC_INTERFACE,
+
+ .bInterfaceNumber = ITF_NUM_VIDEO_STREAMING,
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = TUSB_CLASS_VIDEO,
+ .bInterfaceSubClass = VIDEO_SUBCLASS_STREAMING,
+ .bInterfaceProtocol = VIDEO_ITF_PROTOCOL_15,
+ .iInterface = STRID_UVC_STREAMING
+ },
+#endif
+
+ .ep = {
+ .bLength = sizeof(tusb_desc_endpoint_t),
+ .bDescriptorType = TUSB_DESC_ENDPOINT,
+
+ .bEndpointAddress = EPNUM_VIDEO_IN,
+ .bmAttributes = {
+ .xfer = CFG_TUD_VIDEO_STREAMING_BULK ? TUSB_XFER_BULK : TUSB_XFER_ISOCHRONOUS,
+ .sync = CFG_TUD_VIDEO_STREAMING_BULK ? 0 : 1 // asynchronous
+ },
+ .wMaxPacketSize = CFG_TUD_VIDEO_STREAMING_BULK ? 64 : CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE,
+ .bInterval = 1
+ }
+ }
};
+#if TUD_OPT_HIGH_SPEED
+uvc_cfg_desc_t desc_hs_configuration;
+
+static uint8_t * get_hs_configuration_desc(void) {
+ static bool init = false;
+
+ if (!init) {
+ desc_hs_configuration = desc_fs_configuration;
+ // change endpoint bulk size to 512 if bulk streaming
+ if (CFG_TUD_VIDEO_STREAMING_BULK) {
+ desc_hs_configuration.video_streaming.ep.wMaxPacketSize = 512;
+ }
+ }
+ init = true;
+
+ return (uint8_t *) &desc_hs_configuration;
+}
+
+// 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_t),
+ .bDescriptorType = TUSB_DESC_DEVICE,
+ .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
+ if (tud_speed_get() == TUSB_SPEED_HIGH) {
+ return (uint8_t const*) &desc_fs_configuration;
+ } else {
+ return get_hs_configuration_desc();
+ }
+}
+#endif // highspeed
+
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
-uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
-{
+uint8_t const* tud_descriptor_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
- return desc_fs_configuration;
+#if TUD_OPT_HIGH_SPEED
+ // Although we are highspeed, host may be fullspeed.
+ if (tud_speed_get() == TUSB_SPEED_HIGH) {
+ return get_hs_configuration_desc();
+ } else
+#endif
+ {
+ return (uint8_t const*) &desc_fs_configuration;
+ }
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
-// 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
- "123456", // 3: Serials, should use chip ID
- "TinyUSB UVC", // 4: UVC Interface
-};
-
-static uint16_t _desc_str[32];
+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)
-{
+uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void) langid;
+ size_t chr_count;
- uint8_t chr_count;
+ switch (index) {
+ case STRID_LANGID:
+ memcpy(&_desc_str[1], string_desc_arr[0], 2);
+ chr_count = 1;
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
+ 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
- const char* str = string_desc_arr[index];
+ if (index >= sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) return NULL;
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ const char* str = string_desc_arr[index];
- // Convert ASCII string into UTF-16
- for(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/video_capture/src/usb_descriptors.h b/examples/device/video_capture/src/usb_descriptors.h
index f1ed3c8e9..12d41b2f3 100644
--- a/examples/device/video_capture/src/usb_descriptors.h
+++ b/examples/device/video_capture/src/usb_descriptors.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jerzy Kasenbreg
@@ -27,21 +27,11 @@
#ifndef _USB_DESCRIPTORS_H_
#define _USB_DESCRIPTORS_H_
-/* Time stamp base clock. It is a deprecated parameter. */
-#define UVC_CLOCK_FREQUENCY 27000000
-/* video capture path */
-#define UVC_ENTITY_CAP_INPUT_TERMINAL 0x01
-#define UVC_ENTITY_CAP_OUTPUT_TERMINAL 0x02
-
#define FRAME_WIDTH 128
#define FRAME_HEIGHT 96
#define FRAME_RATE 10
-enum {
- ITF_NUM_VIDEO_CONTROL,
- ITF_NUM_VIDEO_STREAMING,
- ITF_NUM_TOTAL
-};
+// NOTE: descriptor template is not used but leave here as reference
#define TUD_VIDEO_CAPTURE_DESC_UNCOMPR_LEN (\
TUD_VIDEO_DESC_IAD_LEN\
@@ -79,6 +69,38 @@ enum {
+ 7/* Endpoint */\
)
+#define TUD_VIDEO_CAPTURE_DESC_UNCOMPR_BULK_LEN (\
+ TUD_VIDEO_DESC_IAD_LEN\
+ /* control */\
+ + TUD_VIDEO_DESC_STD_VC_LEN\
+ + (TUD_VIDEO_DESC_CS_VC_LEN + 1/*bInCollection*/)\
+ + TUD_VIDEO_DESC_CAMERA_TERM_LEN\
+ + TUD_VIDEO_DESC_OUTPUT_TERM_LEN\
+ /* Interface 1, Alternate 0 */\
+ + TUD_VIDEO_DESC_STD_VS_LEN\
+ + (TUD_VIDEO_DESC_CS_VS_IN_LEN + 1/*bNumFormats x bControlSize*/)\
+ + TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN\
+ + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN\
+ + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN\
+ + 7/* Endpoint */\
+ )
+
+#define TUD_VIDEO_CAPTURE_DESC_MJPEG_BULK_LEN (\
+ TUD_VIDEO_DESC_IAD_LEN\
+ /* control */\
+ + TUD_VIDEO_DESC_STD_VC_LEN\
+ + (TUD_VIDEO_DESC_CS_VC_LEN + 1/*bInCollection*/)\
+ + TUD_VIDEO_DESC_CAMERA_TERM_LEN\
+ + TUD_VIDEO_DESC_OUTPUT_TERM_LEN\
+ /* Interface 1, Alternate 0 */\
+ + TUD_VIDEO_DESC_STD_VS_LEN\
+ + (TUD_VIDEO_DESC_CS_VS_IN_LEN + 1/*bNumFormats x bControlSize*/)\
+ + TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN\
+ + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN\
+ + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN\
+ + 7/* Endpoint */\
+ )
+
/* Windows support YUY2 and NV12
* https://docs.microsoft.com/en-us/windows-hardware/drivers/stream/usb-video-class-driver-overview */
@@ -94,23 +116,17 @@ enum {
#define TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR(_stridx, _epin, _width, _height, _fps, _epsize) \
TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \
/* Video control 0 */ \
- TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \
- TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \
- /* wTotalLength - bLength */ \
- TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \
- UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \
- TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\
- /*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\
- /*wObjectiveFocalLength*/0, /*bmControls*/0), \
+ TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \
+ /* Header: UVC 1.5, length of followed descs, clock (deprecated), streaming interfaces */ \
+ TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \
+ /* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \
+ TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \
TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \
/* Video stream alt. 0 */ \
TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 0, _stridx), \
/* Video stream header for without still image capture */ \
TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \
- /*wTotalLength - bLength */\
- TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN\
- + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN\
- + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\
+ /*wTotalLength - bLength */ TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\
_epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \
/*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \
/*bmaControls(1)*/0), \
@@ -120,7 +136,7 @@ enum {
/* Video stream frame format */ \
TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT(/*bFrameIndex */1, 0, _width, _height, \
_width * _height * 16, _width * _height * 16 * _fps, \
- _width * _height * 16, \
+ _width * _height * 16 / 8, \
(10000000/_fps), (10000000/_fps), (10000000/_fps)*_fps, (10000000/_fps)), \
TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(VIDEO_COLOR_PRIMARIES_BT709, VIDEO_COLOR_XFER_CH_BT709, VIDEO_COLOR_COEF_SMPTE170M), \
/* VS alt 1 */\
@@ -131,23 +147,17 @@ enum {
#define TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG(_stridx, _epin, _width, _height, _fps, _epsize) \
TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \
/* Video control 0 */ \
- TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \
- TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \
- /* wTotalLength - bLength */ \
- TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \
- UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \
- TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\
- /*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\
- /*wObjectiveFocalLength*/0, /*bmControls*/0), \
+ TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \
+ /* Header: UVC 1.5, length of followed descs, clock (deprecated), streaming interfaces */ \
+ TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \
+ /* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \
+ TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \
TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \
/* Video stream alt. 0 */ \
TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 0, _stridx), \
/* Video stream header for without still image capture */ \
TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \
- /*wTotalLength - bLength */\
- TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN\
- + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN\
- + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\
+ /*wTotalLength - bLength */ TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\
_epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \
/*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \
/*bmaControls(1)*/0), \
@@ -165,4 +175,64 @@ enum {
/* EP */ \
TUD_VIDEO_DESC_EP_ISO(_epin, _epsize, 1)
+
+#define TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR_BULK(_stridx, _epin, _width, _height, _fps, _epsize) \
+ TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \
+ /* Video control 0 */ \
+ TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \
+ /* Header: UVC 1.5, length of followed descs, clock (deprecated), streaming interfaces */ \
+ TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \
+ /* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \
+ TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \
+ TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \
+ /* Video stream alt. 0 */ \
+ TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 1, _stridx), \
+ /* Video stream header for without still image capture */ \
+ TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \
+ /*wTotalLength - bLength */\
+ TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\
+ _epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \
+ /*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \
+ /*bmaControls(1)*/0), \
+ /* Video stream format */ \
+ TUD_VIDEO_DESC_CS_VS_FMT_YUY2(/*bFormatIndex*/1, /*bNumFrameDescriptors*/1, \
+ /*bDefaultFrameIndex*/1, 0, 0, 0, /*bCopyProtect*/0), \
+ /* Video stream frame format */ \
+ TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT(/*bFrameIndex */1, 0, _width, _height, \
+ _width * _height * 16, _width * _height * 16 * _fps, \
+ _width * _height * 16 / 8, \
+ (10000000/_fps), (10000000/_fps), (10000000/_fps)*_fps, (10000000/_fps)), \
+ TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(VIDEO_COLOR_PRIMARIES_BT709, VIDEO_COLOR_XFER_CH_BT709, VIDEO_COLOR_COEF_SMPTE170M), \
+ TUD_VIDEO_DESC_EP_BULK(_epin, _epsize, 1)
+
+#define TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG_BULK(_stridx, _epin, _width, _height, _fps, _epsize) \
+ TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \
+ /* Video control 0 */ \
+ TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \
+ /* Header: UVC 1.5, length of followed descs, clock (deprecated), streaming interfaces */ \
+ TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \
+ /* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \
+ TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \
+ TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, UVC_ENTITY_CAP_INPUT_TERMINAL, 0), \
+ /* Video stream alt. 0 */ \
+ TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 1, _stridx), \
+ /* Video stream header for without still image capture */ \
+ TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \
+ /*wTotalLength - bLength */ TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN + TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\
+ _epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \
+ /*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \
+ /*bmaControls(1)*/0), \
+ /* Video stream format */ \
+ TUD_VIDEO_DESC_CS_VS_FMT_MJPEG(/*bFormatIndex*/1, /*bNumFrameDescriptors*/1, \
+ /*bmFlags*/0, /*bDefaultFrameIndex*/1, 0, 0, 0, /*bCopyProtect*/0), \
+ /* Video stream frame format */ \
+ TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT(/*bFrameIndex */1, 0, _width, _height, \
+ _width * _height * 16, _width * _height * 16 * _fps, \
+ _width * _height * 16 / 8, \
+ (10000000/_fps), (10000000/_fps), (10000000/_fps)*_fps, (10000000/_fps)), \
+ TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(VIDEO_COLOR_PRIMARIES_BT709, VIDEO_COLOR_XFER_CH_BT709, VIDEO_COLOR_COEF_SMPTE170M), \
+ /* EP */ \
+ TUD_VIDEO_DESC_EP_BULK(_epin, _epsize, 1)
+
+
#endif
diff --git a/examples/device/webusb_serial/CMakeLists.txt b/examples/device/webusb_serial/CMakeLists.txt
index abc4d91da..e92a57148 100644
--- a/examples/device/webusb_serial/CMakeLists.txt
+++ b/examples/device/webusb_serial/CMakeLists.txt
@@ -1,15 +1,20 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
+
add_executable(${PROJECT})
# Example source
@@ -23,6 +28,6 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_device_example(${PROJECT}) \ No newline at end of file
+# 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(${PROJECT} noos)
diff --git a/examples/device/webusb_serial/Makefile b/examples/device/webusb_serial/Makefile
index 5a455078e..7fa475da5 100644
--- a/examples/device/webusb_serial/Makefile
+++ b/examples/device/webusb_serial/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -9,4 +8,4 @@ INC += \
EXAMPLE_SOURCE += $(wildcard src/*.c)
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/device/webusb_serial/src/main.c b/examples/device/webusb_serial/src/main.c
index 604d30a83..800d435b8 100644
--- a/examples/device/webusb_serial/src/main.c
+++ b/examples/device/webusb_serial/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -47,7 +47,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
#include "usb_descriptors.h"
@@ -96,6 +96,10 @@ int main(void)
// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
tud_task(); // tinyusb device task
@@ -103,8 +107,6 @@ int main(void)
webserial_task();
led_blinking_task();
}
-
- return 0;
}
// send characters to both CDC and WebUSB
@@ -114,7 +116,7 @@ void echo_all(uint8_t buf[], uint32_t count)
if ( web_serial_connected )
{
tud_vendor_write(buf, count);
- tud_vendor_flush();
+ tud_vendor_write_flush();
}
// echo to cdc
@@ -158,7 +160,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
//--------------------------------------------------------------------+
@@ -213,7 +215,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ
blink_interval_ms = BLINK_ALWAYS_ON;
tud_vendor_write_str("\r\nWebUSB interface connected\r\n");
- tud_vendor_flush();
+ tud_vendor_write_flush();
}else
{
blink_interval_ms = BLINK_MOUNTED;
diff --git a/examples/device/webusb_serial/src/usb_descriptors.c b/examples/device/webusb_serial/src/usb_descriptors.c
index cafe2c22b..b01fae8e3 100644
--- a/examples/device/webusb_serial/src/usb_descriptors.c
+++ b/examples/device/webusb_serial/src/usb_descriptors.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,6 +23,7 @@
*
*/
+#include "bsp/board_api.h"
#include "tusb.h"
#include "usb_descriptors.h"
@@ -97,6 +98,13 @@ enum
#define EPNUM_CDC_OUT 3
#define EPNUM_VENDOR_IN 4
#define EPNUM_VENDOR_OUT 5
+#elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X
+ // FT9XX doesn't support a same endpoint number with different direction IN and OUT
+ // e.g EP1 OUT & EP1 IN cannot exist together
+ #define EPNUM_CDC_IN 2
+ #define EPNUM_CDC_OUT 3
+ #define EPNUM_VENDOR_IN 4
+ #define EPNUM_VENDOR_OUT 5
#else
#define EPNUM_CDC_IN 2
#define EPNUM_CDC_OUT 2
@@ -200,53 +208,65 @@ TU_VERIFY_STATIC(sizeof(desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size");
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
"TinyUSB CDC", // 4: CDC Interface
"TinyUSB WebUSB" // 5: Vendor Interface
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/device/webusb_serial/src/usb_descriptors.h b/examples/device/webusb_serial/src/usb_descriptors.h
index 19f1ff3f3..a1c4a2cf1 100644
--- a/examples/device/webusb_serial/src/usb_descriptors.h
+++ b/examples/device/webusb_serial/src/usb_descriptors.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
diff --git a/examples/dual/CMakeLists.txt b/examples/dual/CMakeLists.txt
index d2f9a42f0..15081cf26 100644
--- a/examples/dual/CMakeLists.txt
+++ b/examples/dual/CMakeLists.txt
@@ -1,12 +1,13 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/family_support.cmake)
-project(tinyusb_dual_examples)
+project(tinyusb_dual_examples C CXX ASM)
family_initialize_project(tinyusb_dual_examples ${CMAKE_CURRENT_LIST_DIR})
+
if (FAMILY STREQUAL "rp2040" AND NOT TARGET tinyusb_pico_pio_usb)
- message("Skipping dual host/device mode examples as Pico-PIO-USB is not available")
-else()
- # family_add_subdirectory will filter what to actually add based on selected FAMILY
- family_add_subdirectory(host_hid_to_device_cdc)
-endif()
+ message("Skipping dual host/device mode examples as Pico-PIO-USB is not available")
+else ()
+ # family_add_subdirectory will filter what to actually add based on selected FAMILY
+ family_add_subdirectory(host_hid_to_device_cdc)
+endif ()
diff --git a/examples/dual/host_hid_to_device_cdc/CMakeLists.txt b/examples/dual/host_hid_to_device_cdc/CMakeLists.txt
index fc9bbfc13..a6557c2d0 100644
--- a/examples/dual/host_hid_to_device_cdc/CMakeLists.txt
+++ b/examples/dual/host_hid_to_device_cdc/CMakeLists.txt
@@ -1,11 +1,11 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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})
@@ -14,27 +14,27 @@ add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_dual_usb_example(${PROJECT})
+# Configure compilation flags and libraries for the example without RTOS.
+# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
+family_configure_dual_usb_example(${PROJECT} noos)
-# due to warnings from other net source, we need to prevent error from some of the warnings options
+# due to warnings from Pico-PIO-USB
target_compile_options(${PROJECT} PUBLIC
- -Wno-error=shadow
- -Wno-error=cast-align
- -Wno-error=cast-qual
- -Wno-error=redundant-decls
- -Wno-error=sign-conversion
- -Wno-error=conversion
- -Wno-error=sign-compare
- -Wno-error=unused-function
- )
+ -Wno-error=shadow
+ -Wno-error=cast-align
+ -Wno-error=cast-qual
+ -Wno-error=redundant-decls
+ -Wno-error=sign-conversion
+ -Wno-error=conversion
+ -Wno-error=sign-compare
+ -Wno-error=unused-function
+ )
diff --git a/examples/dual/host_hid_to_device_cdc/Makefile b/examples/dual/host_hid_to_device_cdc/Makefile
index 3fe9b0888..2c2168f5d 100644
--- a/examples/dual/host_hid_to_device_cdc/Makefile
+++ b/examples/dual/host_hid_to_device_cdc/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -16,4 +15,4 @@ SRC_C += \
src/host/hub.c \
src/host/usbh.c
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/dual/host_hid_to_device_cdc/only.txt b/examples/dual/host_hid_to_device_cdc/only.txt
index 6ee8e3fde..cfc87eb4e 100644
--- a/examples/dual/host_hid_to_device_cdc/only.txt
+++ b/examples/dual/host_hid_to_device_cdc/only.txt
@@ -1,3 +1,6 @@
board:mimxrt1060_evk
board:mimxrt1064_evk
+board:mcb1800
mcu:RP2040
+mcu:ra6m5
+mcu:MAX3421
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 bd7870274..96a2beff5 100644
--- a/examples/dual/host_hid_to_device_cdc/src/main.c
+++ b/examples/dual/host_hid_to_device_cdc/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -30,7 +30,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
//--------------------------------------------------------------------+
@@ -83,6 +83,10 @@ int main(void)
tud_init(BOARD_TUD_RHPORT);
tuh_init(BOARD_TUH_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
tud_task(); // tinyusb device task
@@ -121,7 +125,7 @@ void tud_suspend_cb(bool remote_wakeup_en)
// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
- blink_interval_ms = BLINK_MOUNTED;
+ blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
// Invoked when CDC interface received data from host
diff --git a/examples/dual/host_hid_to_device_cdc/src/tusb_config.h b/examples/dual/host_hid_to_device_cdc/src/tusb_config.h
index f749bd712..8133ed418 100644
--- a/examples/dual/host_hid_to_device_cdc/src/tusb_config.h
+++ b/examples/dual/host_hid_to_device_cdc/src/tusb_config.h
@@ -84,10 +84,6 @@
#define CFG_TUH_RPI_PIO_USB 1
#endif
-
-// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
-// #define CFG_TUSB_DEBUG 0
-
/* 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.
@@ -95,12 +91,12 @@
* - 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
+#ifndef CFG_TUD_MEM_SECTION
+#define CFG_TUD_MEM_SECTION
#endif
-#ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
+#ifndef CFG_TUD_MEM_ALIGN
+#define CFG_TUD_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
@@ -128,11 +124,19 @@
// Size of buffer to hold descriptors and other data used for enumeration
#define CFG_TUH_ENUMERATION_BUFSIZE 256
+#ifndef CFG_TUH_MEM_SECTION
+#define CFG_TUH_MEM_SECTION
+#endif
+
+#ifndef CFG_TUH_MEM_ALIGN
+#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
+#endif
+
#define CFG_TUH_HUB 1
// max device support (excluding hub device)
#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports
-#define CFG_TUH_HID 4
+#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX)
#define CFG_TUH_HID_EPIN_BUFSIZE 64
#define CFG_TUH_HID_EPOUT_BUFSIZE 64
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 6b0a89127..293620042 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
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -23,6 +23,7 @@
*
*/
+#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.
@@ -214,52 +215,64 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
// String Descriptors
//--------------------------------------------------------------------+
+// String Descriptor Index
+enum {
+ STRID_LANGID = 0,
+ STRID_MANUFACTURER,
+ STRID_PRODUCT,
+ STRID_SERIAL,
+};
+
// array of pointer to string descriptors
-char const* string_desc_arr [] =
+char const *string_desc_arr[] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
- "123456789012", // 3: Serials, should use chip ID
+ NULL, // 3: Serials will use unique ID if possible
"TinyUSB CDC", // 4: CDC Interface
};
-static uint16_t _desc_str[32];
+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)
-{
+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;
- uint8_t chr_count;
+ case STRID_SERIAL:
+ chr_count = board_usb_get_serial(_desc_str + 1, 32);
+ break;
- if ( index == 0)
- {
- memcpy(&_desc_str[1], string_desc_arr[0], 2);
- chr_count = 1;
- }else
- {
- // 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
+ 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;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
- const char* str = string_desc_arr[index];
+ const char *str = string_desc_arr[index];
- // Cap at max char
- chr_count = (uint8_t) strlen(str);
- if ( chr_count > 31 ) chr_count = 31;
+ // Cap at max char
+ chr_count = strlen(str);
+ size_t const 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(uint8_t i=0; i<chr_count; i++)
- {
- _desc_str[1+i] = str[i];
- }
+ // 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));
+ _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
return _desc_str;
}
diff --git a/examples/host/CMakeLists.txt b/examples/host/CMakeLists.txt
index 5c63ec0c0..e6a2ece14 100644
--- a/examples/host/CMakeLists.txt
+++ b/examples/host/CMakeLists.txt
@@ -1,10 +1,13 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/family_support.cmake)
-project(tinyusb_host_examples)
+project(tinyusb_host_examples C CXX ASM)
family_initialize_project(tinyusb_host_examples ${CMAKE_CURRENT_LIST_DIR})
# family_add_subdirectory will filter what to actually add based on selected FAMILY
+family_add_subdirectory(bare_api)
family_add_subdirectory(cdc_msc_hid)
+family_add_subdirectory(cdc_msc_hid_freertos)
family_add_subdirectory(hid_controller)
+family_add_subdirectory(msc_file_explorer)
diff --git a/examples/host/bare_api/CMakeLists.txt b/examples/host/bare_api/CMakeLists.txt
index bc04b01a7..76182d6fa 100644
--- a/examples/host/bare_api/CMakeLists.txt
+++ b/examples/host/bare_api/CMakeLists.txt
@@ -1,15 +1,20 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+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()
+
add_executable(${PROJECT})
# Example source
@@ -22,9 +27,6 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_host_example(${PROJECT})
-
-# For rp2040, un-comment to enable pico-pio-usb
-# family_add_pico_pio_usb(${PROJECT}) \ No newline at end of file
+# Configure compilation flags and libraries for the example without RTOS.
+# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
+family_configure_host_example(${PROJECT} noos)
diff --git a/examples/host/bare_api/Makefile b/examples/host/bare_api/Makefile
index 13e14df53..0235e08c3 100644
--- a/examples/host/bare_api/Makefile
+++ b/examples/host/bare_api/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -11,17 +10,4 @@ EXAMPLE_SOURCE += \
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-# TODO: suppress warning caused by host stack
-CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference
-
-# TinyUSB Host Stack source
-SRC_C += \
- src/class/cdc/cdc_host.c \
- src/class/hid/hid_host.c \
- src/class/msc/msc_host.c \
- src/host/hub.c \
- src/host/usbh.c \
- src/portable/ohci/ohci.c \
- src/portable/nxp/lpc17_40/hcd_lpc17_40.c
-
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/host/bare_api/only.txt b/examples/host/bare_api/only.txt
index fa9c14857..fee10f9e2 100644
--- a/examples/host/bare_api/only.txt
+++ b/examples/host/bare_api/only.txt
@@ -1,11 +1,14 @@
+mcu:KINETIS_KL
mcu:LPC175X_6X
mcu:LPC177X_8X
mcu:LPC18XX
mcu:LPC40XX
mcu:LPC43XX
-mcu:MIMXRT
+mcu:MIMXRT1XXX
mcu:MIMXRT10XX
mcu:MIMXRT11XX
mcu:RP2040
mcu:MSP432E4
mcu:RX65X
+mcu:RAXXX
+mcu:MAX3421
diff --git a/examples/host/bare_api/src/main.c b/examples/host/bare_api/src/main.c
index 51cab2de0..14725996d 100644
--- a/examples/host/bare_api/src/main.c
+++ b/examples/host/bare_api/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -32,7 +32,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
// English
@@ -67,6 +67,10 @@ int main(void)
// init host stack on configured roothub port
tuh_init(BOARD_TUH_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
// tinyusb host task
@@ -410,6 +414,7 @@ static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
}
static void print_utf16(uint16_t *temp_buf, size_t buf_len) {
+ if ((temp_buf[0] & 0xff) == 0) return; // empty
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
size_t utf8_len = (size_t) _count_utf8_bytes(temp_buf + 1, utf16_len);
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len);
diff --git a/examples/host/bare_api/src/tusb_config.h b/examples/host/bare_api/src/tusb_config.h
index ed0aaf7da..432446e94 100644
--- a/examples/host/bare_api/src/tusb_config.h
+++ b/examples/host/bare_api/src/tusb_config.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -30,22 +30,8 @@
extern "C" {
#endif
-//--------------------------------------------------------------------+
-// Board Specific Configuration
-//--------------------------------------------------------------------+
-
-// RHPort number used for host can be defined by board.mk, default to port 0
-#ifndef BOARD_TUH_RHPORT
-#define BOARD_TUH_RHPORT 0
-#endif
-
-// RHPort max operational speed can defined by board.mk
-#ifndef BOARD_TUH_MAX_SPEED
-#define BOARD_TUH_MAX_SPEED OPT_MODE_DEFAULT_SPEED
-#endif
-
//--------------------------------------------------------------------
-// COMMON CONFIGURATION
+// Common Configuration
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
@@ -61,12 +47,6 @@
#define CFG_TUSB_DEBUG 0
#endif
-// Enable Host stack
-#define CFG_TUH_ENABLED 1
-
-// Default is max speed that hardware controller could support with on-chip PHY
-#define CFG_TUH_MAX_SPEED BOARD_TUH_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.
@@ -74,16 +54,48 @@
* - 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
+#ifndef CFG_TUH_MEM_SECTION
+#define CFG_TUH_MEM_SECTION
+#endif
+
+#ifndef CFG_TUH_MEM_ALIGN
+#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// Host Configuration
+//--------------------------------------------------------------------
+
+// Enable Host stack
+#define CFG_TUH_ENABLED 1
+
+#if CFG_TUSB_MCU == OPT_MCU_RP2040
+ // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller
+ // #define CFG_TUH_MAX3421 1 // use max3421 as host controller
+
+ // host roothub port is 1 if using either pio-usb or max3421
+ #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)
+ #define BOARD_TUH_RHPORT 1
+ #endif
+#endif
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUH_MAX_SPEED BOARD_TUH_MAX_SPEED
+
+//------------------------- Board Specific --------------------------
+
+// RHPort number used for host can be defined by board.mk, default to port 0
+#ifndef BOARD_TUH_RHPORT
+#define BOARD_TUH_RHPORT 0
#endif
-#ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
+// RHPort max operational speed can defined by board.mk
+#ifndef BOARD_TUH_MAX_SPEED
+#define BOARD_TUH_MAX_SPEED OPT_MODE_DEFAULT_SPEED
#endif
//--------------------------------------------------------------------
-// CONFIGURATION
+// Driver Configuration
//--------------------------------------------------------------------
// Size of buffer to hold descriptors and other data used for enumeration
@@ -94,7 +106,7 @@
// max device support (excluding hub device)
// 1 hub typically has 4 ports
-#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1)
+#define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1)
// Max endpoint per device
#define CFG_TUH_ENDPOINT_MAX 8
diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt
index c4a4d8e63..a7c372a34 100644
--- a/examples/host/cdc_msc_hid/CMakeLists.txt
+++ b/examples/host/cdc_msc_hid/CMakeLists.txt
@@ -1,32 +1,35 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
+
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
-
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_host_example(${PROJECT})
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
-# For rp2040, un-comment to enable pico-pio-usb
-# family_add_pico_pio_usb(${PROJECT})
+# Configure compilation flags and libraries for the example without RTOS.
+# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
+family_configure_host_example(${PROJECT} noos)
diff --git a/examples/host/cdc_msc_hid/Makefile b/examples/host/cdc_msc_hid/Makefile
index 272acbac8..213c02f9c 100644
--- a/examples/host/cdc_msc_hid/Makefile
+++ b/examples/host/cdc_msc_hid/Makefile
@@ -1,25 +1,16 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
$(TOP)/hw \
# Example source
-EXAMPLE_SOURCE += $(wildcard src/*.c)
-SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-
-# TODO: suppress warning caused by host stack
-CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference
+EXAMPLE_SOURCE = \
+ src/cdc_app.c \
+ src/hid_app.c \
+ src/main.c \
+ src/msc_app.c \
-# TinyUSB Host Stack source
-SRC_C += \
- src/class/cdc/cdc_host.c \
- src/class/hid/hid_host.c \
- src/class/msc/msc_host.c \
- src/host/hub.c \
- src/host/usbh.c \
- src/portable/ohci/ohci.c \
- src/portable/nxp/lpc17_40/hcd_lpc17_40.c
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/host/cdc_msc_hid/only.txt b/examples/host/cdc_msc_hid/only.txt
index fa9c14857..fee10f9e2 100644
--- a/examples/host/cdc_msc_hid/only.txt
+++ b/examples/host/cdc_msc_hid/only.txt
@@ -1,11 +1,14 @@
+mcu:KINETIS_KL
mcu:LPC175X_6X
mcu:LPC177X_8X
mcu:LPC18XX
mcu:LPC40XX
mcu:LPC43XX
-mcu:MIMXRT
+mcu:MIMXRT1XXX
mcu:MIMXRT10XX
mcu:MIMXRT11XX
mcu:RP2040
mcu:MSP432E4
mcu:RX65X
+mcu:RAXXX
+mcu:MAX3421
diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c
new file mode 100644
index 000000000..e275e7943
--- /dev/null
+++ b/examples/host/cdc_msc_hid/src/cdc_app.c
@@ -0,0 +1,109 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022, 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.
+ */
+
+#include "tusb.h"
+#include "bsp/board_api.h"
+
+size_t get_console_inputs(uint8_t* buf, size_t bufsize) {
+ size_t count = 0;
+ while (count < bufsize) {
+ int ch = board_getchar();
+ if (ch <= 0) break;
+
+ buf[count] = (uint8_t) ch;
+ count++;
+ }
+
+ return count;
+}
+
+void cdc_app_task(void) {
+ uint8_t buf[64 + 1]; // +1 for extra null character
+ uint32_t const bufsize = sizeof(buf) - 1;
+
+ uint32_t count = get_console_inputs(buf, bufsize);
+ buf[count] = 0;
+
+ // loop over all mounted interfaces
+ for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) {
+ if (tuh_cdc_mounted(idx)) {
+ // console --> cdc interfaces
+ if (count) {
+ tuh_cdc_write(idx, buf, count);
+ tuh_cdc_write_flush(idx);
+ }
+ }
+ }
+}
+
+//--------------------------------------------------------------------+
+// TinyUSB callbacks
+//--------------------------------------------------------------------+
+
+// Invoked when received new data
+void tuh_cdc_rx_cb(uint8_t idx) {
+ uint8_t buf[64 + 1]; // +1 for extra null character
+ uint32_t const bufsize = sizeof(buf) - 1;
+
+ // forward cdc interfaces -> console
+ uint32_t count = tuh_cdc_read(idx, buf, bufsize);
+ buf[count] = 0;
+
+ printf((char*) buf);
+}
+
+// Invoked when a device with CDC interface is mounted
+// idx is index of cdc interface in the internal pool.
+void tuh_cdc_mount_cb(uint8_t idx) {
+ tuh_itf_info_t itf_info = {0};
+ tuh_cdc_itf_get_info(idx, &itf_info);
+
+ printf("CDC Interface is mounted: address = %u, itf_num = %u\r\n", itf_info.daddr,
+ itf_info.desc.bInterfaceNumber);
+
+#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
+ // If CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined, line coding will be set by tinyusb stack
+ // while eneumerating new cdc device
+ cdc_line_coding_t line_coding = {0};
+ if (tuh_cdc_get_local_line_coding(idx, &line_coding)) {
+ printf(" Baudrate: %lu, Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits);
+ printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity, line_coding.data_bits);
+ }
+#else
+ // Set Line Coding upon mounted
+ cdc_line_coding_t new_line_coding = { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 };
+ tuh_cdc_set_line_coding(idx, &new_line_coding, NULL, 0);
+#endif
+}
+
+// Invoked when a device with CDC interface is unmounted
+void tuh_cdc_umount_cb(uint8_t idx) {
+ tuh_itf_info_t itf_info = {0};
+ tuh_cdc_itf_get_info(idx, &itf_info);
+
+ printf("CDC Interface is unmounted: address = %u, itf_num = %u\r\n", itf_info.daddr,
+ itf_info.desc.bInterfaceNumber);
+}
diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c
index 11437c2b4..f0d42a08f 100644
--- a/examples/host/cdc_msc_hid/src/hid_app.c
+++ b/examples/host/cdc_msc_hid/src/hid_app.c
@@ -23,7 +23,7 @@
*
*/
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
//--------------------------------------------------------------------+
@@ -160,7 +160,9 @@ static void process_kbd_report(hid_keyboard_report_t const *report)
putchar(ch);
if ( ch == '\r' ) putchar('\n'); // added new line for enter key
+ #ifndef __ICCARM__ // TODO IAR doesn't support stream control ?
fflush(stdout); // flush right away, else nanolib will wait for newline
+ #endif
}
}
// TODO example skips key released
@@ -247,7 +249,7 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c
// Composite report, 1st byte is report ID, data starts from 2nd byte
uint8_t const rpt_id = report[0];
- // Find report id in the arrray
+ // Find report id in the array
for(uint8_t i=0; i<rpt_count; i++)
{
if (rpt_id == rpt_info_arr[i].report_id )
@@ -263,7 +265,7 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c
if (!rpt_info)
{
- printf("Couldn't find the report info for this report !\r\n");
+ printf("Couldn't find report info !\r\n");
return;
}
diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c
index 664cbf035..a3b80e030 100644
--- a/examples/host/cdc_msc_hid/src/main.c
+++ b/examples/host/cdc_msc_hid/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -27,20 +27,24 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
void led_blinking_task(void);
-
-extern void cdc_task(void);
+extern void cdc_app_task(void);
extern void hid_app_task(void);
+#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
+// API to read/rite MAX3421's register. Implemented by TinyUSB
+extern uint8_t tuh_max3421_reg_read(uint8_t rhport, uint8_t reg, bool in_isr);
+extern bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr);
+#endif
+
/*------------- MAIN -------------*/
-int main(void)
-{
+int main(void) {
board_init();
printf("TinyUSB Host CDC MSC HID Example\r\n");
@@ -48,62 +52,36 @@ int main(void)
// init host stack on configured roothub port
tuh_init(BOARD_TUH_RHPORT);
- while (1)
- {
- // tinyusb host task
- tuh_task();
- led_blinking_task();
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
-#if CFG_TUH_CDC
- cdc_task();
+#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
+ // FeatherWing MAX3421E use MAX3421E's GPIO0 for VBUS enable
+ enum { IOPINS1_ADDR = 20u << 3, /* 0xA0 */ };
+ tuh_max3421_reg_write(BOARD_TUH_RHPORT, IOPINS1_ADDR, 0x01, false);
#endif
-#if CFG_TUH_HID
+ while (1) {
+ // tinyusb host task
+ tuh_task();
+
+ led_blinking_task();
+ cdc_app_task();
hid_app_task();
-#endif
}
-
- return 0;
}
//--------------------------------------------------------------------+
-// USB CDC
-//--------------------------------------------------------------------+
-#if CFG_TUH_CDC
-CFG_TUSB_MEM_SECTION static char serial_in_buffer[64] = { 0 };
-
-// invoked ISR context
-void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes)
-{
- (void) event;
- (void) pipe_id;
- (void) xferred_bytes;
-
- printf(serial_in_buffer);
- tu_memclr(serial_in_buffer, sizeof(serial_in_buffer));
-
- tuh_cdc_receive(dev_addr, serial_in_buffer, sizeof(serial_in_buffer), true); // waiting for next data
-}
-
-void cdc_task(void)
-{
-
-}
-
-#endif
-
-//--------------------------------------------------------------------+
// TinyUSB Callbacks
//--------------------------------------------------------------------+
-void tuh_mount_cb(uint8_t dev_addr)
-{
+void tuh_mount_cb(uint8_t dev_addr) {
// application set-up
printf("A device with address %d is mounted\r\n", dev_addr);
}
-void tuh_umount_cb(uint8_t dev_addr)
-{
+void tuh_umount_cb(uint8_t dev_addr) {
// application tear-down
printf("A device with address %d is unmounted \r\n", dev_addr);
}
@@ -112,15 +90,14 @@ void tuh_umount_cb(uint8_t dev_addr)
//--------------------------------------------------------------------+
// Blinking Task
//--------------------------------------------------------------------+
-void led_blinking_task(void)
-{
+void led_blinking_task(void) {
const uint32_t interval_ms = 1000;
static uint32_t start_ms = 0;
static bool led_state = false;
// Blink every interval ms
- if ( board_millis() - start_ms < interval_ms) return; // not enough time
+ if (board_millis() - start_ms < interval_ms) return; // not enough time
start_ms += interval_ms;
board_led_write(led_state);
diff --git a/examples/host/cdc_msc_hid/src/msc_app.c b/examples/host/cdc_msc_hid/src/msc_app.c
index 77a72052d..e9c9676b8 100644
--- a/examples/host/cdc_msc_hid/src/msc_app.c
+++ b/examples/host/cdc_msc_hid/src/msc_app.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -25,15 +25,16 @@
#include "tusb.h"
-#if CFG_TUH_MSC
-
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
static scsi_inquiry_resp_t inquiry_resp;
-bool inquiry_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
+bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
{
+ msc_cbw_t const* cbw = cb_data->cbw;
+ msc_csw_t const* csw = cb_data->csw;
+
if (csw->status != 0)
{
printf("Inquiry failed\r\n");
@@ -59,48 +60,11 @@ void tuh_msc_mount_cb(uint8_t dev_addr)
printf("A MassStorage device is mounted\r\n");
uint8_t const lun = 0;
- tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb);
-//
-// //------------- file system (only 1 LUN support) -------------//
-// uint8_t phy_disk = dev_addr-1;
-// disk_initialize(phy_disk);
-//
-// if ( disk_is_ready(phy_disk) )
-// {
-// if ( f_mount(phy_disk, &fatfs[phy_disk]) != FR_OK )
-// {
-// puts("mount failed");
-// return;
-// }
-//
-// f_chdrive(phy_disk); // change to newly mounted drive
-// f_chdir("/"); // root as current dir
-//
-// cli_init();
-// }
+ tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb, 0);
}
void tuh_msc_umount_cb(uint8_t dev_addr)
{
(void) dev_addr;
printf("A MassStorage device is unmounted\r\n");
-
-// uint8_t phy_disk = dev_addr-1;
-//
-// f_mount(phy_disk, NULL); // unmount disk
-// disk_deinitialize(phy_disk);
-//
-// if ( phy_disk == f_get_current_drive() )
-// { // active drive is unplugged --> change to other drive
-// for(uint8_t i=0; i<CFG_TUH_DEVICE_MAX; i++)
-// {
-// if ( disk_is_ready(i) )
-// {
-// f_chdrive(i);
-// cli_init(); // refractor, rename
-// }
-// }
-// }
}
-
-#endif
diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h
index 33f34315b..a59a0ffb9 100644
--- a/examples/host/cdc_msc_hid/src/tusb_config.h
+++ b/examples/host/cdc_msc_hid/src/tusb_config.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -30,22 +30,8 @@
extern "C" {
#endif
-//--------------------------------------------------------------------+
-// Board Specific Configuration
-//--------------------------------------------------------------------+
-
-// RHPort number used for host can be defined by board.mk, default to port 0
-#ifndef BOARD_TUH_RHPORT
-#define BOARD_TUH_RHPORT 0
-#endif
-
-// RHPort max operational speed can defined by board.mk
-#ifndef BOARD_TUH_MAX_SPEED
-#define BOARD_TUH_MAX_SPEED OPT_MODE_DEFAULT_SPEED
-#endif
-
//--------------------------------------------------------------------
-// COMMON CONFIGURATION
+// Common Configuration
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
@@ -61,12 +47,6 @@
#define CFG_TUSB_DEBUG 0
#endif
-// Enable Host stack
-#define CFG_TUH_ENABLED 1
-
-// Default is max speed that hardware controller could support with on-chip PHY
-#define CFG_TUH_MAX_SPEED BOARD_TUH_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.
@@ -74,34 +54,80 @@
* - 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
+#ifndef CFG_TUH_MEM_SECTION
+#define CFG_TUH_MEM_SECTION
+#endif
+
+#ifndef CFG_TUH_MEM_ALIGN
+#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// Host Configuration
+//--------------------------------------------------------------------
+
+// Enable Host stack
+#define CFG_TUH_ENABLED 1
+
+#if CFG_TUSB_MCU == OPT_MCU_RP2040
+ // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller
+ // #define CFG_TUH_MAX3421 1 // use max3421 as host controller
+
+ // host roothub port is 1 if using either pio-usb or max3421
+ #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)
+ #define BOARD_TUH_RHPORT 1
+ #endif
+#endif
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUH_MAX_SPEED BOARD_TUH_MAX_SPEED
+
+//------------------------- Board Specific --------------------------
+
+// RHPort number used for host can be defined by board.mk, default to port 0
+#ifndef BOARD_TUH_RHPORT
+#define BOARD_TUH_RHPORT 0
#endif
-#ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
+// RHPort max operational speed can defined by board.mk
+#ifndef BOARD_TUH_MAX_SPEED
+#define BOARD_TUH_MAX_SPEED OPT_MODE_DEFAULT_SPEED
#endif
//--------------------------------------------------------------------
-// CONFIGURATION
+// Driver Configuration
//--------------------------------------------------------------------
// Size of buffer to hold descriptors and other data used for enumeration
#define CFG_TUH_ENUMERATION_BUFSIZE 256
#define CFG_TUH_HUB 1 // number of supported hubs
-#define CFG_TUH_CDC 1
-#define CFG_TUH_HID 4 // typical keyboard + mouse device can have 3-4 HID interfaces
+#define CFG_TUH_CDC 1 // CDC ACM
+#define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API
+#define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API
+#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API
+#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
#define CFG_TUH_MSC 1
#define CFG_TUH_VENDOR 0
-// max device support (excluding hub device)
-#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports
+// max device support (excluding hub device): 1 hub typically has 4 ports
+#define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1)
//------------- HID -------------//
#define CFG_TUH_HID_EPIN_BUFSIZE 64
#define CFG_TUH_HID_EPOUT_BUFSIZE 64
+//------------- CDC -------------//
+
+// Set Line Control state on enumeration/mounted:
+// DTR ( bit 0), RTS (bit 1)
+#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
+
+// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
+// bit rate = 115200, 1 stop bit, no parity, 8 bit data width
+#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
+
+
#ifdef __cplusplus
}
#endif
diff --git a/examples/host/cdc_msc_hid_freertos/CMakeLists.txt b/examples/host/cdc_msc_hid_freertos/CMakeLists.txt
new file mode 100644
index 000000000..2e95a18e0
--- /dev/null
+++ b/examples/host/cdc_msc_hid_freertos/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 3.17)
+
+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()
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/freertos_hook.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c
+ )
+
+# Example include
+target_include_directories(${PROJECT} 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_host_example(${PROJECT} freertos)
diff --git a/examples/host/cdc_msc_hid_freertos/Makefile b/examples/host/cdc_msc_hid_freertos/Makefile
new file mode 100644
index 000000000..5351a6248
--- /dev/null
+++ b/examples/host/cdc_msc_hid_freertos/Makefile
@@ -0,0 +1,34 @@
+include ../../build_system/make/make.mk
+
+FREERTOS_SRC = lib/FreeRTOS-Kernel
+FREERTOS_PORTABLE_PATH= $(FREERTOS_SRC)/portable/$(if $(USE_IAR),IAR,GCC)
+
+INC += \
+ src \
+ src/FreeRTOSConfig \
+ $(TOP)/hw \
+ $(TOP)/$(FREERTOS_SRC)/include \
+ $(TOP)/$(FREERTOS_PORTABLE_SRC) \
+
+# Example source
+EXAMPLE_SOURCE = \
+ src/cdc_app.c \
+ src/freertos_hook.c \
+ src/hid_app.c \
+ src/main.c \
+ src/msc_app.c \
+
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
+
+# FreeRTOS source, all files in port folder
+SRC_C += \
+ $(FREERTOS_SRC)/list.c \
+ $(FREERTOS_SRC)/queue.c \
+ $(FREERTOS_SRC)/tasks.c \
+ $(FREERTOS_SRC)/timers.c \
+ $(subst $(TOP)/,,$(wildcard $(TOP)/$(FREERTOS_PORTABLE_SRC)/*.c))
+
+SRC_S += \
+ $(subst $(TOP)/,,$(wildcard $(TOP)/$(FREERTOS_PORTABLE_SRC)/*.s))
+
+include ../../build_system/make/rules.mk
diff --git a/examples/host/cdc_msc_hid_freertos/only.txt b/examples/host/cdc_msc_hid_freertos/only.txt
new file mode 100644
index 000000000..81d993ffa
--- /dev/null
+++ b/examples/host/cdc_msc_hid_freertos/only.txt
@@ -0,0 +1,12 @@
+mcu:LPC175X_6X
+mcu:LPC177X_8X
+mcu:LPC18XX
+mcu:LPC40XX
+mcu:LPC43XX
+mcu:MIMXRT1XXX
+mcu:MIMXRT10XX
+mcu:MIMXRT11XX
+mcu:MSP432E4
+mcu:RX65X
+mcu:RAXXX
+mcu:MAX3421
diff --git a/examples/host/cdc_msc_hid_freertos/src/CMakeLists.txt b/examples/host/cdc_msc_hid_freertos/src/CMakeLists.txt
new file mode 100644
index 000000000..6f057c106
--- /dev/null
+++ b/examples/host/cdc_msc_hid_freertos/src/CMakeLists.txt
@@ -0,0 +1,6 @@
+# This file is for ESP-IDF only
+idf_component_register(SRCS "cdc_app.c" "hid_app.c" "main.c" "msc_app.c"
+ INCLUDE_DIRS "."
+ REQUIRES boards tinyusb_src)
+
+target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-error=format)
diff --git a/examples/host/cdc_msc_hid_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h b/examples/host/cdc_msc_hid_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h
new file mode 100644
index 000000000..bd754518d
--- /dev/null
+++ b/examples/host/cdc_msc_hid_freertos/src/FreeRTOSConfig/FreeRTOSConfig.h
@@ -0,0 +1,199 @@
+/*
+ * 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 MCU header
+#include "bsp/board_mcu.h"
+
+#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
+ #error "ESP32-Sx should use IDF's FreeRTOSConfig.h"
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+// TODO fix later
+// FIXME cause redundant-decls warnings
+#if CFG_TUSB_MCU == OPT_MCU_MM32F327X
+ extern u32 SystemCoreClock;
+#else
+ extern uint32_t SystemCoreClock;
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+#endif
+
+/* Cortex M23/M33 port configuration. */
+#define configENABLE_MPU 0
+#define configENABLE_FPU 1
+#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 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 0
+#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
+
+#ifdef __RX__
+/* Renesas RX series */
+#define vSoftwareInterruptISR INT_Excep_ICU_SWINT
+#define vTickISR INT_Excep_CMT0_CMI0
+#define configPERIPHERAL_CLOCK_HZ (configCPU_CLOCK_HZ/2)
+#define configKERNEL_INTERRUPT_PRIORITY 1
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY 4
+
+#else
+
+/* FreeRTOS hooks to NVIC vectors */
+#define xPortPendSVHandler PendSV_Handler
+#define xPortSysTickHandler SysTick_Handler
+#define vPortSVCHandler SVC_Handler
+
+//--------------------------------------------------------------------+
+// Interrupt nesting behavior configuration.
+//--------------------------------------------------------------------+
+#if defined(__NVIC_PRIO_BITS)
+ // For Cortex-M specific: __NVIC_PRIO_BITS is defined in core_cmx.h
+ #define configPRIO_BITS __NVIC_PRIO_BITS
+
+#elif defined(__ECLIC_INTCTLBITS)
+ // RISC-V Bumblebee core from nuclei
+ #define configPRIO_BITS __ECLIC_INTCTLBITS
+
+#elif defined(__IASMARM__)
+ // FIXME: IAR Assembler cannot include mcu header directly to get __NVIC_PRIO_BITS.
+ // Therefore we will hard coded it to minimum value of 2 to get pass ci build.
+ // IAR user must update this to correct value of the target MCU
+ #message "configPRIO_BITS is hard coded to 2 to pass IAR build only. User should update it per MCU"
+ #define configPRIO_BITS 2
+
+#else
+ #error "FreeRTOS configPRIO_BITS to be defined"
+#endif
+
+/* 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
+
+#endif /* __FREERTOS_CONFIG__H */
diff --git a/examples/host/cdc_msc_hid_freertos/src/cdc_app.c b/examples/host/cdc_msc_hid_freertos/src/cdc_app.c
new file mode 100644
index 000000000..6ff513be1
--- /dev/null
+++ b/examples/host/cdc_msc_hid_freertos/src/cdc_app.c
@@ -0,0 +1,145 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022, 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.
+ */
+
+#include "tusb.h"
+#include "bsp/board_api.h"
+
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+// ESP-IDF need "freertos/" prefix in include path.
+// CFG_TUSB_OS_INC_PATH should be defined accordingly.
+ #include "freertos/FreeRTOS.h"
+ #include "freertos/semphr.h"
+ #include "freertos/queue.h"
+ #include "freertos/task.h"
+ #include "freertos/timers.h"
+
+ #define CDC_STACK_SZIE 2048
+#else
+ #include "FreeRTOS.h"
+ #include "semphr.h"
+ #include "queue.h"
+ #include "task.h"
+ #include "timers.h"
+
+ #define CDC_STACK_SZIE (3*configMINIMAL_STACK_SIZE/2)
+#endif
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+#if configSUPPORT_STATIC_ALLOCATION
+StackType_t cdc_stack[CDC_STACK_SZIE];
+StaticTask_t cdc_taskdef;
+#endif
+
+static void cdc_app_task(void* param);
+
+void cdc_app_init(void) {
+ #if configSUPPORT_STATIC_ALLOCATION
+ xTaskCreateStatic(cdc_app_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES-2, cdc_stack, &cdc_taskdef);
+ #else
+ xTaskCreate(cdc_app_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES-2, NULL);
+ #endif
+}
+
+// helper
+size_t get_console_inputs(uint8_t *buf, size_t bufsize) {
+ size_t count = 0;
+ while (count < bufsize) {
+ int ch = board_getchar();
+ if (ch <= 0) break;
+
+ buf[count] = (uint8_t) ch;
+ count++;
+ }
+
+ return count;
+}
+
+static void cdc_app_task(void* param) {
+ (void) param;
+
+ uint8_t buf[64 + 1]; // +1 for extra null character
+ uint32_t const bufsize = sizeof(buf) - 1;
+
+ while (1) {
+ uint32_t count = get_console_inputs(buf, bufsize);
+ buf[count] = 0;
+
+ if (count) {
+ // loop over all mounted interfaces
+ for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) {
+ if (tuh_cdc_mounted(idx)) {
+ // console --> cdc interfaces
+ tuh_cdc_write(idx, buf, count);
+ tuh_cdc_write_flush(idx);
+ }
+ }
+ }
+
+ vTaskDelay(1);
+ }
+}
+
+//--------------------------------------------------------------------+
+// TinyUSB Callbacks
+//--------------------------------------------------------------------+
+
+// Invoked when received new data
+void tuh_cdc_rx_cb(uint8_t idx) {
+ uint8_t buf[64 + 1]; // +1 for extra null character
+ uint32_t const bufsize = sizeof(buf) - 1;
+
+ // forward cdc interfaces -> console
+ uint32_t count = tuh_cdc_read(idx, buf, bufsize);
+ buf[count] = 0;
+
+ printf((char *) buf);
+}
+
+void tuh_cdc_mount_cb(uint8_t idx) {
+ tuh_itf_info_t itf_info = { 0 };
+ tuh_cdc_itf_get_info(idx, &itf_info);
+
+ printf("CDC Interface is mounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.desc.bInterfaceNumber);
+
+#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
+ // CFG_TUH_CDC_LINE_CODING_ON_ENUM must be defined for line coding is set by tinyusb in enumeration
+ // otherwise you need to call tuh_cdc_set_line_coding() first
+ cdc_line_coding_t line_coding = { 0 };
+ if (tuh_cdc_get_local_line_coding(idx, &line_coding)) {
+ printf(" Baudrate: %lu, Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits);
+ printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity, line_coding.data_bits);
+ }
+#endif
+}
+
+void tuh_cdc_umount_cb(uint8_t idx) {
+ tuh_itf_info_t itf_info = { 0 };
+ tuh_cdc_itf_get_info(idx, &itf_info);
+
+ printf("CDC Interface is unmounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.desc.bInterfaceNumber);
+}
diff --git a/examples/host/cdc_msc_hid_freertos/src/freertos_hook.c b/examples/host/cdc_msc_hid_freertos/src/freertos_hook.c
new file mode 100644
index 000000000..07d159fd5
--- /dev/null
+++ b/examples/host/cdc_msc_hid_freertos/src/freertos_hook.c
@@ -0,0 +1,111 @@
+/*
+ * 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
+//--------------------------------------------------------------------+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "common/tusb_common.h"
+
+void vApplicationMallocFailedHook(void) {
+ taskDISABLE_INTERRUPTS();
+ TU_ASSERT(false,);
+}
+
+void vApplicationStackOverflowHook(xTaskHandle pxTask, char *pcTaskName) {
+ (void) pxTask;
+ (void) pcTaskName;
+
+ taskDISABLE_INTERRUPTS();
+ TU_ASSERT(false,);
+}
+
+/* configSUPPORT_STATIC_ALLOCATION is set to 1, so the application must provide an
+ * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
+ * used by the Idle task. */
+void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer,
+ uint32_t *pulIdleTaskStackSize) {
+ /* If the buffers to be provided to the Idle task are declared inside this
+ * function then they must be declared static - otherwise they will be allocated on
+ * the stack and so not exists after this function exits. */
+ static StaticTask_t xIdleTaskTCB;
+ static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE];
+
+ /* Pass out a pointer to the StaticTask_t structure in which the Idle task's
+ state will be stored. */
+ *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
+
+ /* Pass out the array that will be used as the Idle task's stack. */
+ *ppxIdleTaskStackBuffer = uxIdleTaskStack;
+
+ /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
+ Note that, as the array is necessarily of type StackType_t,
+ configMINIMAL_STACK_SIZE is specified in words, not bytes. */
+ *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
+}
+
+/* configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
+ * application must provide an implementation of vApplicationGetTimerTaskMemory()
+ * to provide the memory that is used by the Timer service task. */
+void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer,
+ uint32_t *pulTimerTaskStackSize) {
+ /* If the buffers to be provided to the Timer task are declared inside this
+ * function then they must be declared static - otherwise they will be allocated on
+ * the stack and so not exists after this function exits. */
+ static StaticTask_t xTimerTaskTCB;
+ static StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH];
+
+ /* Pass out a pointer to the StaticTask_t structure in which the Timer
+ task's state will be stored. */
+ *ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
+
+ /* Pass out the array that will be used as the Timer task's stack. */
+ *ppxTimerTaskStackBuffer = uxTimerTaskStack;
+
+ /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
+ Note that, as the array is necessarily of type StackType_t,
+ configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */
+ *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
+}
+
+#if CFG_TUSB_MCU == OPT_MCU_RX63X | CFG_TUSB_MCU == OPT_MCU_RX65X
+#include "iodefine.h"
+void vApplicationSetupTimerInterrupt(void)
+{
+ /* Enable CMT0 */
+ SYSTEM.PRCR.WORD = (0xA5u<<8) | TU_BIT(1);
+ MSTP(CMT0) = 0;
+ SYSTEM.PRCR.WORD = (0xA5u<<8);
+
+ CMT0.CMCNT = 0;
+ CMT0.CMCOR = (unsigned short)(((configPERIPHERAL_CLOCK_HZ/configTICK_RATE_HZ)-1)/128);
+ CMT0.CMCR.WORD = TU_BIT(6) | 2;
+ IR(CMT0, CMI0) = 0;
+ IPR(CMT0, CMI0) = configKERNEL_INTERRUPT_PRIORITY;
+ IEN(CMT0, CMI0) = 1;
+ CMT.CMSTR0.BIT.STR0 = 1;
+}
+#endif
diff --git a/examples/host/cdc_msc_hid_freertos/src/hid_app.c b/examples/host/cdc_msc_hid_freertos/src/hid_app.c
new file mode 100644
index 000000000..9ea5c1be0
--- /dev/null
+++ b/examples/host/cdc_msc_hid_freertos/src/hid_app.c
@@ -0,0 +1,267 @@
+/*
+ * 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.
+ *
+ */
+
+#include "bsp/board_api.h"
+#include "tusb.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+// If your host terminal support ansi escape code such as TeraTerm
+// it can be use to simulate mouse cursor movement within terminal
+#define USE_ANSI_ESCAPE 0
+
+#define MAX_REPORT 4
+
+static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII };
+
+// Each HID instance can has multiple reports
+static struct {
+ uint8_t report_count;
+ tuh_hid_report_info_t report_info[MAX_REPORT];
+} hid_info[CFG_TUH_HID];
+
+static void process_kbd_report(hid_keyboard_report_t const *report);
+static void process_mouse_report(hid_mouse_report_t const *report);
+static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len);
+
+void hid_app_init(void) {
+ // nothing to do
+}
+
+//--------------------------------------------------------------------+
+// TinyUSB Callbacks
+//--------------------------------------------------------------------+
+
+// Invoked when device with hid interface is mounted
+// Report descriptor is also available for use. tuh_hid_parse_report_descriptor()
+// 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
+void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
+ printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
+
+ // Interface protocol (hid_interface_protocol_enum_t)
+ const char *protocol_str[] = { "None", "Keyboard", "Mouse" };
+ uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
+
+ printf("HID Interface Protocol = %s\r\n", protocol_str[itf_protocol]);
+
+ // By default host stack will use activate boot protocol on supported interface.
+ // Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser)
+ if (itf_protocol == HID_ITF_PROTOCOL_NONE) {
+ hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT,
+ desc_report, desc_len);
+ printf("HID has %u reports \r\n", hid_info[instance].report_count);
+ }
+
+ // request to receive report
+ // tuh_hid_report_received_cb() will be invoked when report is available
+ if (!tuh_hid_receive_report(dev_addr, instance)) {
+ printf("Error: cannot request to receive report\r\n");
+ }
+}
+
+// Invoked when device with hid interface is un-mounted
+void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
+ printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
+}
+
+// Invoked when received report from device via interrupt endpoint
+void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
+ uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
+
+ switch (itf_protocol) {
+ case HID_ITF_PROTOCOL_KEYBOARD:
+ TU_LOG2("HID receive boot keyboard report\r\n");
+ process_kbd_report((hid_keyboard_report_t const *) report);
+ break;
+
+ case HID_ITF_PROTOCOL_MOUSE:
+ TU_LOG2("HID receive boot mouse report\r\n");
+ process_mouse_report((hid_mouse_report_t const *) report);
+ break;
+
+ default:
+ // Generic report requires matching ReportID and contents with previous parsed report info
+ process_generic_report(dev_addr, instance, report, len);
+ break;
+ }
+
+ // continue to request to receive report
+ if (!tuh_hid_receive_report(dev_addr, instance)) {
+ printf("Error: cannot request to receive report\r\n");
+ }
+}
+
+//--------------------------------------------------------------------+
+// Keyboard
+//--------------------------------------------------------------------+
+
+// look up new key in previous keys
+static inline bool find_key_in_report(hid_keyboard_report_t const *report, uint8_t keycode) {
+ for (uint8_t i = 0; i < 6; i++) {
+ if (report->keycode[i] == keycode) return true;
+ }
+
+ return false;
+}
+
+static void process_kbd_report(hid_keyboard_report_t const *report) {
+ static hid_keyboard_report_t prev_report = { 0, 0, { 0 } }; // previous report to check key released
+
+ //------------- example code ignore control (non-printable) key affects -------------//
+ for (uint8_t i = 0; i < 6; i++) {
+ if (report->keycode[i]) {
+ if (find_key_in_report(&prev_report, report->keycode[i])) {
+ // exist in previous report means the current key is holding
+ } else {
+ // not existed in previous report means the current key is pressed
+ bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
+ uint8_t ch = keycode2ascii[report->keycode[i]][is_shift ? 1 : 0];
+ putchar(ch);
+ if (ch == '\r') putchar('\n'); // added new line for enter key
+
+ #ifndef __ICCARM__ // TODO IAR doesn't support stream control ?
+ fflush(stdout); // flush right away, else nanolib will wait for newline
+ #endif
+ }
+ }
+ // TODO example skips key released
+ }
+
+ prev_report = *report;
+}
+
+//--------------------------------------------------------------------+
+// Mouse
+//--------------------------------------------------------------------+
+
+void cursor_movement(int8_t x, int8_t y, int8_t wheel) {
+#if USE_ANSI_ESCAPE
+ // Move X using ansi escape
+ if ( x < 0) {
+ printf(ANSI_CURSOR_BACKWARD(%d), (-x)); // move left
+ }else if ( x > 0) {
+ printf(ANSI_CURSOR_FORWARD(%d), x); // move right
+ }
+
+ // Move Y using ansi escape
+ if ( y < 0) {
+ printf(ANSI_CURSOR_UP(%d), (-y)); // move up
+ }else if ( y > 0) {
+ printf(ANSI_CURSOR_DOWN(%d), y); // move down
+ }
+
+ // Scroll using ansi escape
+ if (wheel < 0) {
+ printf(ANSI_SCROLL_UP(%d), (-wheel)); // scroll up
+ }else if (wheel > 0) {
+ printf(ANSI_SCROLL_DOWN(%d), wheel); // scroll down
+ }
+
+ printf("\r\n");
+#else
+ printf("(%d %d %d)\r\n", x, y, wheel);
+#endif
+}
+
+static void process_mouse_report(hid_mouse_report_t const *report) {
+ static hid_mouse_report_t prev_report = { 0 };
+
+ //------------- button state -------------//
+ uint8_t button_changed_mask = report->buttons ^ prev_report.buttons;
+ if (button_changed_mask & report->buttons) {
+ printf(" %c%c%c ",
+ report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-',
+ report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-',
+ report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-');
+ }
+
+ //------------- cursor movement -------------//
+ cursor_movement(report->x, report->y, report->wheel);
+}
+
+//--------------------------------------------------------------------+
+// Generic Report
+//--------------------------------------------------------------------+
+static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
+ (void) dev_addr;
+
+ uint8_t const rpt_count = hid_info[instance].report_count;
+ tuh_hid_report_info_t *rpt_info_arr = hid_info[instance].report_info;
+ tuh_hid_report_info_t *rpt_info = NULL;
+
+ if (rpt_count == 1 && rpt_info_arr[0].report_id == 0) {
+ // Simple report without report ID as 1st byte
+ rpt_info = &rpt_info_arr[0];
+ } else {
+ // Composite report, 1st byte is report ID, data starts from 2nd byte
+ uint8_t const rpt_id = report[0];
+
+ // Find report id in the array
+ for (uint8_t i = 0; i < rpt_count; i++) {
+ if (rpt_id == rpt_info_arr[i].report_id) {
+ rpt_info = &rpt_info_arr[i];
+ break;
+ }
+ }
+
+ report++;
+ len--;
+ }
+
+ if (!rpt_info) {
+ printf("Couldn't find report info !\r\n");
+ return;
+ }
+
+ // For complete list of Usage Page & Usage checkout src/class/hid/hid.h. For examples:
+ // - Keyboard : Desktop, Keyboard
+ // - Mouse : Desktop, Mouse
+ // - Gamepad : Desktop, Gamepad
+ // - Consumer Control (Media Key) : Consumer, Consumer Control
+ // - System Control (Power key) : Desktop, System Control
+ // - Generic (vendor) : 0xFFxx, xx
+ if (rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP) {
+ switch (rpt_info->usage) {
+ case HID_USAGE_DESKTOP_KEYBOARD:
+ TU_LOG1("HID receive keyboard report\r\n");
+ // Assume keyboard follow boot report layout
+ process_kbd_report((hid_keyboard_report_t const *) report);
+ break;
+
+ case HID_USAGE_DESKTOP_MOUSE:
+ TU_LOG1("HID receive mouse report\r\n");
+ // Assume mouse follow boot report layout
+ process_mouse_report((hid_mouse_report_t const *) report);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
diff --git a/examples/host/cdc_msc_hid_freertos/src/main.c b/examples/host/cdc_msc_hid_freertos/src/main.c
new file mode 100644
index 000000000..069cbdc90
--- /dev/null
+++ b/examples/host/cdc_msc_hid_freertos/src/main.c
@@ -0,0 +1,177 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bsp/board_api.h"
+#include "tusb.h"
+
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+ // ESP-IDF need "freertos/" prefix in include path.
+ // CFG_TUSB_OS_INC_PATH should be defined accordingly.
+ #include "freertos/FreeRTOS.h"
+ #include "freertos/semphr.h"
+ #include "freertos/queue.h"
+ #include "freertos/task.h"
+ #include "freertos/timers.h"
+
+ #define USBH_STACK_SIZE 4096
+#else
+ #include "FreeRTOS.h"
+ #include "semphr.h"
+ #include "queue.h"
+ #include "task.h"
+ #include "timers.h"
+
+ // Increase stack size when debug log is enabled
+ #define USBH_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1)
+#endif
+
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTOTYPES
+//--------------------------------------------------------------------+
+/* 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 timer & task
+#if configSUPPORT_STATIC_ALLOCATION
+StaticTimer_t blinky_tmdef;
+
+StackType_t usb_host_stack[USBH_STACK_SIZE];
+StaticTask_t usb_host_taskdef;
+#endif
+
+TimerHandle_t blinky_tm;
+
+static void led_blinky_cb(TimerHandle_t xTimer);
+static void usb_host_task(void* param);
+
+extern void cdc_app_init(void);
+extern void hid_app_init(void);
+extern void msc_app_init(void);
+
+#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
+// API to read/rite MAX3421's register. Implemented by TinyUSB
+extern uint8_t tuh_max3421_reg_read(uint8_t rhport, uint8_t reg, bool in_isr);
+extern bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr);
+#endif
+
+/*------------- MAIN -------------*/
+int main(void) {
+ board_init();
+
+ printf("TinyUSB Host CDC MSC HID with FreeRTOS Example\r\n");
+
+ // Create soft timer for blinky, task for tinyusb stack
+#if configSUPPORT_STATIC_ALLOCATION
+ blinky_tm = xTimerCreateStatic(NULL, pdMS_TO_TICKS(BLINK_MOUNTED), true, NULL, led_blinky_cb, &blinky_tmdef);
+ xTaskCreateStatic(usb_host_task, "usbh", USBH_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_host_stack, &usb_host_taskdef);
+#else
+ blinky_tm = xTimerCreate(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb);
+ xTaskCreate(usb_host_task, "usbd", USBH_STACK_SIZE, NULL, configMAX_PRIORITIES-1, NULL);
+#endif
+
+ xTimerStart(blinky_tm, 0);
+
+ // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
+#if !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+ vTaskStartScheduler();
+#endif
+
+ return 0;
+}
+
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+void app_main(void) {
+ main();
+}
+#endif
+
+// USB Host task
+// This top level thread process all usb events and invoke callbacks
+static void usb_host_task(void *param) {
+ (void) param;
+
+ // init host stack on configured roothub port
+ tuh_init(BOARD_TUH_RHPORT);
+
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
+#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
+ // FeatherWing MAX3421E use MAX3421E's GPIO0 for VBUS enable
+ enum { IOPINS1_ADDR = 20u << 3, /* 0xA0 */ };
+ tuh_max3421_reg_write(BOARD_TUH_RHPORT, IOPINS1_ADDR, 0x01, false);
+#endif
+
+ cdc_app_init();
+ hid_app_init();
+ msc_app_init();
+
+ // RTOS forever loop
+ while (1) {
+ // put this thread to waiting state until there is new events
+ tuh_task();
+
+ // following code only run if tuh_task() process at least 1 event
+ }
+}
+
+//--------------------------------------------------------------------+
+// TinyUSB Callbacks
+//--------------------------------------------------------------------+
+
+void tuh_mount_cb(uint8_t dev_addr) {
+ // application set-up
+ printf("A device with address %d is mounted\r\n", dev_addr);
+}
+
+void tuh_umount_cb(uint8_t dev_addr) {
+ // application tear-down
+ printf("A device with address %d is unmounted \r\n", dev_addr);
+}
+
+//--------------------------------------------------------------------+
+// BLINKING TASK
+//--------------------------------------------------------------------+
+static void led_blinky_cb(TimerHandle_t xTimer) {
+ (void) xTimer;
+ static bool led_state = false;
+
+ board_led_write(led_state);
+ led_state = 1 - led_state; // toggle
+}
diff --git a/examples/host/cdc_msc_hid_freertos/src/msc_app.c b/examples/host/cdc_msc_hid_freertos/src/msc_app.c
new file mode 100644
index 000000000..ee02ba917
--- /dev/null
+++ b/examples/host/cdc_msc_hid_freertos/src/msc_app.c
@@ -0,0 +1,67 @@
+/*
+ * 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 "tusb.h"
+
+static scsi_inquiry_resp_t inquiry_resp;
+
+void msc_app_init(void) {
+ // nothing to do
+}
+
+bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const *cb_data) {
+ msc_cbw_t const *cbw = cb_data->cbw;
+ msc_csw_t const *csw = cb_data->csw;
+
+ if (csw->status != 0) {
+ printf("Inquiry failed\r\n");
+ return false;
+ }
+
+ // Print out Vendor ID, Product ID and Rev
+ printf("%.8s %.16s rev %.4s\r\n", inquiry_resp.vendor_id, inquiry_resp.product_id, inquiry_resp.product_rev);
+
+ // Get capacity of device
+ uint32_t const block_count = tuh_msc_get_block_count(dev_addr, cbw->lun);
+ uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun);
+
+ printf("Disk Size: %lu MB\r\n", block_count / ((1024 * 1024) / block_size));
+ printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size);
+
+ return true;
+}
+
+//------------- IMPLEMENTATION -------------//
+void tuh_msc_mount_cb(uint8_t dev_addr) {
+ printf("A MassStorage device is mounted\r\n");
+
+ uint8_t const lun = 0;
+ tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb, 0);
+}
+
+void tuh_msc_umount_cb(uint8_t dev_addr) {
+ (void) dev_addr;
+ printf("A MassStorage device is unmounted\r\n");
+}
diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h
new file mode 100644
index 000000000..35de5ee50
--- /dev/null
+++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#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_FREERTOS
+#endif
+
+// Espressif IDF requires "freertos/" prefix in include path
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
+#define CFG_TUSB_OS_INC_PATH freertos/
+#endif
+
+#ifndef CFG_TUSB_DEBUG
+#define CFG_TUSB_DEBUG 0
+#endif
+
+/* 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_TUH_MEM_SECTION
+#define CFG_TUH_MEM_SECTION
+#endif
+
+#ifndef CFG_TUH_MEM_ALIGN
+#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// Host Configuration
+//--------------------------------------------------------------------
+
+// Enable Host stack
+#define CFG_TUH_ENABLED 1
+
+#if CFG_TUSB_MCU == OPT_MCU_RP2040
+ // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller
+ // #define CFG_TUH_MAX3421 1 // use max3421 as host controller
+
+ // host roothub port is 1 if using either pio-usb or max3421
+ #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)
+ #define BOARD_TUH_RHPORT 1
+ #endif
+#endif
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUH_MAX_SPEED BOARD_TUH_MAX_SPEED
+
+//------------------------- Board Specific --------------------------
+
+// RHPort number used for host can be defined by board.mk, default to port 0
+#ifndef BOARD_TUH_RHPORT
+#define BOARD_TUH_RHPORT 0
+#endif
+
+// RHPort max operational speed can defined by board.mk
+#ifndef BOARD_TUH_MAX_SPEED
+#define BOARD_TUH_MAX_SPEED OPT_MODE_DEFAULT_SPEED
+#endif
+
+//--------------------------------------------------------------------
+// Driver Configuration
+//--------------------------------------------------------------------
+
+// Size of buffer to hold descriptors and other data used for enumeration
+#define CFG_TUH_ENUMERATION_BUFSIZE 256
+
+#define CFG_TUH_HUB 1 // number of supported hubs
+#define CFG_TUH_CDC 1 // CDC ACM
+#define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API
+#define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API
+#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API
+#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
+#define CFG_TUH_MSC 1
+#define CFG_TUH_VENDOR 0
+
+// max device support (excluding hub device): 1 hub typically has 4 ports
+#define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1)
+
+//------------- HID -------------//
+#define CFG_TUH_HID_EPIN_BUFSIZE 64
+#define CFG_TUH_HID_EPOUT_BUFSIZE 64
+
+//------------- CDC -------------//
+
+// Set Line Control state on enumeration/mounted:
+// DTR ( bit 0), RTS (bit 1)
+#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
+
+// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
+// bit rate = 115200, 1 stop bit, no parity, 8 bit data width
+#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */
diff --git a/examples/host/hid_controller/CMakeLists.txt b/examples/host/hid_controller/CMakeLists.txt
index 6153d399a..c1b500dd8 100644
--- a/examples/host/hid_controller/CMakeLists.txt
+++ b/examples/host/hid_controller/CMakeLists.txt
@@ -1,31 +1,33 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
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})
+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()
+
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
-
-# Configure compilation flags and libraries for the example... see the corresponding function
-# in hw/bsp/FAMILY/family.cmake for details.
-family_configure_host_example(${PROJECT})
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
-# For rp2040, un-comment to enable pico-pio-usb
-# family_add_pico_pio_usb(${PROJECT})
+# Configure compilation flags and libraries for the example without RTOS.
+# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
+family_configure_host_example(${PROJECT} noos)
diff --git a/examples/host/hid_controller/Makefile b/examples/host/hid_controller/Makefile
index 06dc56914..1377f1f90 100644
--- a/examples/host/hid_controller/Makefile
+++ b/examples/host/hid_controller/Makefile
@@ -1,5 +1,4 @@
-include ../../../tools/top.mk
-include ../../make.mk
+include ../../build_system/make/make.mk
INC += \
src \
@@ -12,17 +11,4 @@ EXAMPLE_SOURCE += \
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
-# TODO: suppress warning caused by host stack
-CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference
-
-# TinyUSB Host Stack source
-SRC_C += \
- src/class/cdc/cdc_host.c \
- src/class/hid/hid_host.c \
- src/class/msc/msc_host.c \
- src/host/hub.c \
- src/host/usbh.c \
- src/portable/ohci/ohci.c \
- src/portable/nxp/lpc17_40/hcd_lpc17_40.c
-
-include ../../rules.mk
+include ../../build_system/make/rules.mk
diff --git a/examples/host/hid_controller/only.txt b/examples/host/hid_controller/only.txt
index fa9c14857..fee10f9e2 100644
--- a/examples/host/hid_controller/only.txt
+++ b/examples/host/hid_controller/only.txt
@@ -1,11 +1,14 @@
+mcu:KINETIS_KL
mcu:LPC175X_6X
mcu:LPC177X_8X
mcu:LPC18XX
mcu:LPC40XX
mcu:LPC43XX
-mcu:MIMXRT
+mcu:MIMXRT1XXX
mcu:MIMXRT10XX
mcu:MIMXRT11XX
mcu:RP2040
mcu:MSP432E4
mcu:RX65X
+mcu:RAXXX
+mcu:MAX3421
diff --git a/examples/host/hid_controller/src/hid_app.c b/examples/host/hid_controller/src/hid_app.c
index 582e01959..bff830ca2 100644
--- a/examples/host/hid_controller/src/hid_app.c
+++ b/examples/host/hid_controller/src/hid_app.c
@@ -23,7 +23,7 @@
*
*/
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
/* From https://www.kernel.org/doc/html/latest/input/gamepad.html
@@ -91,9 +91,8 @@ typedef struct TU_ATTR_PACKED
uint8_t counter : 6; // +1 each report
};
- // comment out since not used by this example
- // uint8_t l2_trigger; // 0 released, 0xff fully pressed
- // uint8_t r2_trigger; // as above
+ uint8_t l2_trigger; // 0 released, 0xff fully pressed
+ uint8_t r2_trigger; // as above
// uint16_t timestamp;
// uint8_t battery;
@@ -105,15 +104,54 @@ typedef struct TU_ATTR_PACKED
} sony_ds4_report_t;
+typedef struct TU_ATTR_PACKED {
+ // First 16 bits set what data is pertinent in this structure (1 = set; 0 = not set)
+ uint8_t set_rumble : 1;
+ uint8_t set_led : 1;
+ uint8_t set_led_blink : 1;
+ uint8_t set_ext_write : 1;
+ uint8_t set_left_volume : 1;
+ uint8_t set_right_volume : 1;
+ uint8_t set_mic_volume : 1;
+ uint8_t set_speaker_volume : 1;
+ uint8_t set_flags2;
+
+ uint8_t reserved;
+
+ uint8_t motor_right;
+ uint8_t motor_left;
+
+ uint8_t lightbar_red;
+ uint8_t lightbar_green;
+ uint8_t lightbar_blue;
+ uint8_t lightbar_blink_on;
+ uint8_t lightbar_blink_off;
+
+ uint8_t ext_data[8];
+
+ uint8_t volume_left;
+ uint8_t volume_right;
+ uint8_t volume_mic;
+ uint8_t volume_speaker;
+
+ uint8_t other[9];
+} sony_ds4_output_report_t;
+
+static bool ds4_mounted = false;
+static uint8_t ds4_dev_addr = 0;
+static uint8_t ds4_instance = 0;
+static uint8_t motor_left = 0;
+static uint8_t motor_right = 0;
+
// check if device is Sony DualShock 4
static inline bool is_sony_ds4(uint8_t dev_addr)
{
uint16_t vid, pid;
tuh_vid_pid_get(dev_addr, &vid, &pid);
- return ( (vid == 0x054c && (pid == 0x09cc || pid == 0x05c4)) // Sony DualShock4
- || (vid == 0x0f0d && pid == 0x005e) // Hori FC4
- || (vid == 0x0f0d && pid == 0x00ee) // Hori PS4 Mini (PS4-099U)
+ return ( (vid == 0x054c && (pid == 0x09cc || pid == 0x05c4)) // Sony DualShock4
+ || (vid == 0x0f0d && pid == 0x005e) // Hori FC4
+ || (vid == 0x0f0d && pid == 0x00ee) // Hori PS4 Mini (PS4-099U)
|| (vid == 0x1f4f && pid == 0x1002) // ASW GG xrd controller
);
}
@@ -124,7 +162,23 @@ static inline bool is_sony_ds4(uint8_t dev_addr)
void hid_app_task(void)
{
- // nothing to do
+ if (ds4_mounted)
+ {
+ const uint32_t interval_ms = 200;
+ static uint32_t start_ms = 0;
+
+ uint32_t current_time_ms = board_millis();
+ if ( current_time_ms - start_ms >= interval_ms)
+ {
+ start_ms = current_time_ms;
+
+ sony_ds4_output_report_t output_report = {0};
+ output_report.set_rumble = 1;
+ output_report.motor_left = motor_left;
+ output_report.motor_right = motor_right;
+ tuh_hid_send_report(ds4_dev_addr, ds4_instance, 5, &output_report, sizeof(output_report));
+ }
+ }
}
//--------------------------------------------------------------------+
@@ -149,6 +203,14 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
// Sony DualShock 4 [CUH-ZCT2x]
if ( is_sony_ds4(dev_addr) )
{
+ if (!ds4_mounted)
+ {
+ ds4_dev_addr = dev_addr;
+ ds4_instance = instance;
+ motor_left = 0;
+ motor_right = 0;
+ ds4_mounted = true;
+ }
// request to receive report
// tuh_hid_report_received_cb() will be invoked when report is available
if ( !tuh_hid_receive_report(dev_addr, instance) )
@@ -162,7 +224,10 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
{
printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
-
+ if (ds4_mounted && ds4_dev_addr == dev_addr && ds4_instance == instance)
+ {
+ ds4_mounted = false;
+ }
}
// check if different than 2
@@ -180,8 +245,8 @@ bool diff_report(sony_ds4_report_t const* rpt1, sony_ds4_report_t const* rpt2)
result = diff_than_2(rpt1->x, rpt2->x) || diff_than_2(rpt1->y , rpt2->y ) ||
diff_than_2(rpt1->z, rpt2->z) || diff_than_2(rpt1->rz, rpt2->rz);
- // check the reset with mem compare
- result |= memcmp(&rpt1->rz + 1, &rpt2->rz + 1, sizeof(sony_ds4_report_t)-4);
+ // check the rest with mem compare
+ result |= memcmp(&rpt1->rz + 1, &rpt2->rz + 1, sizeof(sony_ds4_report_t)-6);
return result;
}
@@ -235,6 +300,10 @@ void process_sony_ds4(uint8_t const* report, uint16_t len)
printf("\r\n");
}
+ // The left and right triggers control the intensity of the left and right rumble motors
+ motor_left = ds4_report.l2_trigger;
+ motor_right = ds4_report.r2_trigger;
+
prev_report = ds4_report;
}
}
diff --git a/examples/host/hid_controller/src/main.c b/examples/host/hid_controller/src/main.c
index 299a3ff10..05a5ae176 100644
--- a/examples/host/hid_controller/src/main.c
+++ b/examples/host/hid_controller/src/main.c
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -32,7 +32,7 @@
#include <stdio.h>
#include <string.h>
-#include "bsp/board.h"
+#include "bsp/board_api.h"
#include "tusb.h"
//--------------------------------------------------------------------+
@@ -54,6 +54,10 @@ int main(void)
// init host stack on configured roothub port
tuh_init(BOARD_TUH_RHPORT);
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
while (1)
{
// tinyusb host task
@@ -68,8 +72,6 @@ int main(void)
hid_app_task();
#endif
}
-
- return 0;
}
//--------------------------------------------------------------------+
diff --git a/examples/host/hid_controller/src/tusb_config.h b/examples/host/hid_controller/src/tusb_config.h
index 475b9ca8f..3ac591d8f 100644
--- a/examples/host/hid_controller/src/tusb_config.h
+++ b/examples/host/hid_controller/src/tusb_config.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -30,22 +30,8 @@
extern "C" {
#endif
-//--------------------------------------------------------------------+
-// Board Specific Configuration
-//--------------------------------------------------------------------+
-
-// RHPort number used for host can be defined by board.mk, default to port 0
-#ifndef BOARD_TUH_RHPORT
-#define BOARD_TUH_RHPORT 0
-#endif
-
-// RHPort max operational speed can defined by board.mk
-#ifndef BOARD_TUH_MAX_SPEED
-#define BOARD_TUH_MAX_SPEED OPT_MODE_DEFAULT_SPEED
-#endif
-
//--------------------------------------------------------------------
-// COMMON CONFIGURATION
+// Common Configuration
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
@@ -61,12 +47,6 @@
#define CFG_TUSB_DEBUG 0
#endif
-// Enable Host stack
-#define CFG_TUH_ENABLED 1
-
-// Default is max speed that hardware controller could support with on-chip PHY
-#define CFG_TUH_MAX_SPEED BOARD_TUH_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.
@@ -74,16 +54,48 @@
* - 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
+#ifndef CFG_TUH_MEM_SECTION
+#define CFG_TUH_MEM_SECTION
+#endif
+
+#ifndef CFG_TUH_MEM_ALIGN
+#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// Host Configuration
+//--------------------------------------------------------------------
+
+// Enable Host stack
+#define CFG_TUH_ENABLED 1
+
+#if CFG_TUSB_MCU == OPT_MCU_RP2040
+ // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller
+ // #define CFG_TUH_MAX3421 1 // use max3421 as host controller
+
+ // host roothub port is 1 if using either pio-usb or max3421
+ #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)
+ #define BOARD_TUH_RHPORT 1
+ #endif
+#endif
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUH_MAX_SPEED BOARD_TUH_MAX_SPEED
+
+//------------------------- Board Specific --------------------------
+
+// RHPort number used for host can be defined by board.mk, default to port 0
+#ifndef BOARD_TUH_RHPORT
+#define BOARD_TUH_RHPORT 0
#endif
-#ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
+// RHPort max operational speed can defined by board.mk
+#ifndef BOARD_TUH_MAX_SPEED
+#define BOARD_TUH_MAX_SPEED OPT_MODE_DEFAULT_SPEED
#endif
//--------------------------------------------------------------------
-// CONFIGURATION
+// Driver Configuration
//--------------------------------------------------------------------
// Size of buffer to hold descriptors and other data used for enumeration
@@ -91,13 +103,12 @@
#define CFG_TUH_HUB 0
#define CFG_TUH_CDC 0
-#define CFG_TUH_HID 4 // typical keyboard + mouse device can have 3-4 HID interfaces
+#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
#define CFG_TUH_MSC 0
#define CFG_TUH_VENDOR 0
-// max device support (excluding hub device)
-// 1 hub typically has 4 ports
-#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1)
+// max device support (excluding hub device): 1 hub typically has 4 ports
+#define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1)
//------------- HID -------------//
diff --git a/examples/host/msc_file_explorer/CMakeLists.txt b/examples/host/msc_file_explorer/CMakeLists.txt
new file mode 100644
index 000000000..1a57c7466
--- /dev/null
+++ b/examples/host/msc_file_explorer/CMakeLists.txt
@@ -0,0 +1,47 @@
+cmake_minimum_required(VERSION 3.17)
+
+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()
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c
+ ${TOP}/lib/fatfs/source/ff.c
+ ${TOP}/lib/fatfs/source/ffsystem.c
+ ${TOP}/lib/fatfs/source/ffunicode.c
+ )
+
+# Suppress warnings on fatfs
+if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ set_source_files_properties(
+ ${TOP}/lib/fatfs/source/ff.c
+ PROPERTIES
+ COMPILE_FLAGS "-Wno-conversion -Wno-cast-qual"
+ )
+endif ()
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ ${TOP}/lib/fatfs/source
+ ${TOP}/lib/embedded-cli
+ )
+
+# Configure compilation flags and libraries for the example without RTOS.
+# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
+family_configure_host_example(${PROJECT} noos)
diff --git a/examples/host/msc_file_explorer/Makefile b/examples/host/msc_file_explorer/Makefile
new file mode 100644
index 000000000..c7d6a7cae
--- /dev/null
+++ b/examples/host/msc_file_explorer/Makefile
@@ -0,0 +1,27 @@
+include ../../build_system/make/make.mk
+
+FATFS_PATH = lib/fatfs/source
+
+INC += \
+ src \
+ $(TOP)/hw \
+ $(TOP)/$(FATFS_PATH) \
+ $(TOP)/lib/embedded-cli \
+
+# Example source
+EXAMPLE_SOURCE = \
+ src/main.c \
+ src/msc_app.c \
+
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
+
+# FatFS source
+SRC_C += \
+ $(FATFS_PATH)/ff.c \
+ $(FATFS_PATH)/ffsystem.c \
+ $(FATFS_PATH)/ffunicode.c \
+
+# suppress warning caused by fatfs
+CFLAGS += -Wno-error=cast-qual
+
+include ../../build_system/make/rules.mk
diff --git a/examples/host/msc_file_explorer/only.txt b/examples/host/msc_file_explorer/only.txt
new file mode 100644
index 000000000..fee10f9e2
--- /dev/null
+++ b/examples/host/msc_file_explorer/only.txt
@@ -0,0 +1,14 @@
+mcu:KINETIS_KL
+mcu:LPC175X_6X
+mcu:LPC177X_8X
+mcu:LPC18XX
+mcu:LPC40XX
+mcu:LPC43XX
+mcu:MIMXRT1XXX
+mcu:MIMXRT10XX
+mcu:MIMXRT11XX
+mcu:RP2040
+mcu:MSP432E4
+mcu:RX65X
+mcu:RAXXX
+mcu:MAX3421
diff --git a/examples/host/msc_file_explorer/src/main.c b/examples/host/msc_file_explorer/src/main.c
new file mode 100644
index 000000000..73f3e9eb5
--- /dev/null
+++ b/examples/host/msc_file_explorer/src/main.c
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ *
+ */
+
+/* Example to show how to navigate mass storage device with built-in command line.
+ * Type help for list of supported commands and syntax (mostly linux commands)
+
+ > help
+ * help
+ Print list of commands
+ * cat
+ Usage: cat [FILE]...
+ Concatenate FILE(s) to standard output..
+ * cd
+ Usage: cd [DIR]...
+ Change the current directory to DIR.
+ * cp
+ Usage: cp SOURCE DEST
+ Copy SOURCE to DEST.
+ * ls
+ Usage: ls [DIR]...
+ List information about the FILEs (the current directory by default).
+ * pwd
+ Usage: pwd
+ Print the name of the current working directory.
+ * mkdir
+ Usage: mkdir DIR...
+ Create the DIRECTORY(ies), if they do not already exist..
+ * mv
+ Usage: mv SOURCE DEST...
+ Rename SOURCE to DEST.
+ * rm
+ Usage: rm [FILE]...
+ Remove (unlink) the FILE(s).
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bsp/board_api.h"
+#include "tusb.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+void led_blinking_task(void);
+
+// from msc_app.c
+extern bool msc_app_init(void);
+extern void msc_app_task(void);
+
+/*------------- MAIN -------------*/
+int main(void)
+{
+ board_init();
+
+ printf("TinyUSB Host MassStorage Explorer Example\r\n");
+
+ // init host stack on configured roothub port
+ tuh_init(BOARD_TUH_RHPORT);
+
+ if (board_init_after_tusb) {
+ board_init_after_tusb();
+ }
+
+ msc_app_init();
+
+ while (1)
+ {
+ // tinyusb host task
+ tuh_task();
+
+ msc_app_task();
+ led_blinking_task();
+ }
+
+ return 0;
+}
+
+//--------------------------------------------------------------------+
+// TinyUSB Callbacks
+//--------------------------------------------------------------------+
+
+void tuh_mount_cb(uint8_t dev_addr)
+{
+ (void) dev_addr;
+}
+
+void tuh_umount_cb(uint8_t dev_addr)
+{
+ (void) dev_addr;
+}
+
+//--------------------------------------------------------------------+
+// Blinking Task
+//--------------------------------------------------------------------+
+void led_blinking_task(void)
+{
+ const uint32_t interval_ms = 1000;
+ static uint32_t start_ms = 0;
+
+ static bool led_state = false;
+
+ // Blink every interval ms
+ if ( board_millis() - start_ms < interval_ms) return; // not enough time
+ start_ms += interval_ms;
+
+ board_led_write(led_state);
+ led_state = 1 - led_state; // toggle
+}
diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c
new file mode 100644
index 000000000..ecea614a2
--- /dev/null
+++ b/examples/host/msc_file_explorer/src/msc_app.c
@@ -0,0 +1,643 @@
+/*
+ * 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 <ctype.h>
+#include "tusb.h"
+#include "bsp/board_api.h"
+
+#include "ff.h"
+#include "diskio.h"
+
+// lib/embedded-cli
+#define EMBEDDED_CLI_IMPL
+#include "embedded_cli.h"
+
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+//------------- embedded-cli -------------//
+#define CLI_BUFFER_SIZE 512
+#define CLI_RX_BUFFER_SIZE 16
+#define CLI_CMD_BUFFER_SIZE 64
+#define CLI_HISTORY_SIZE 32
+#define CLI_BINDING_COUNT 8
+
+static EmbeddedCli *_cli;
+static CLI_UINT cli_buffer[BYTES_TO_CLI_UINTS(CLI_BUFFER_SIZE)];
+
+//------------- Elm Chan FatFS -------------//
+static FATFS fatfs[CFG_TUH_DEVICE_MAX]; // for simplicity only support 1 LUN per device
+static volatile bool _disk_busy[CFG_TUH_DEVICE_MAX];
+
+static scsi_inquiry_resp_t inquiry_resp;
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+bool cli_init(void);
+
+bool msc_app_init(void)
+{
+ for(size_t i=0; i<CFG_TUH_DEVICE_MAX; i++) _disk_busy[i] = false;
+
+ // disable stdout buffered for echoing typing command
+ #ifndef __ICCARM__ // TODO IAR doesn't support stream control ?
+ setbuf(stdout, NULL);
+ #endif
+
+ cli_init();
+
+ return true;
+}
+
+void msc_app_task(void)
+{
+ if (!_cli) return;
+
+ int ch = board_getchar();
+ if ( ch > 0 )
+ {
+ while( ch > 0 )
+ {
+ embeddedCliReceiveChar(_cli, (char) ch);
+ ch = board_getchar();
+ }
+ embeddedCliProcess(_cli);
+ }
+}
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+
+bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
+{
+ msc_cbw_t const* cbw = cb_data->cbw;
+ msc_csw_t const* csw = cb_data->csw;
+
+ if (csw->status != 0)
+ {
+ printf("Inquiry failed\r\n");
+ return false;
+ }
+
+ // Print out Vendor ID, Product ID and Rev
+ printf("%.8s %.16s rev %.4s\r\n", inquiry_resp.vendor_id, inquiry_resp.product_id, inquiry_resp.product_rev);
+
+ // Get capacity of device
+ uint32_t const block_count = tuh_msc_get_block_count(dev_addr, cbw->lun);
+ uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun);
+
+ printf("Disk Size: %lu MB\r\n", block_count / ((1024*1024)/block_size));
+ // printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size);
+
+ // For simplicity: we only mount 1 LUN per device
+ uint8_t const drive_num = dev_addr-1;
+ char drive_path[3] = "0:";
+ drive_path[0] += drive_num;
+
+ if ( f_mount(&fatfs[drive_num], drive_path, 1) != FR_OK )
+ {
+ puts("mount failed");
+ }
+
+ // change to newly mounted drive
+ f_chdir(drive_path);
+
+ // print the drive label
+// char label[34];
+// if ( FR_OK == f_getlabel(drive_path, label, NULL) )
+// {
+// puts(label);
+// }
+
+ return true;
+}
+
+//------------- IMPLEMENTATION -------------//
+void tuh_msc_mount_cb(uint8_t dev_addr)
+{
+ printf("A MassStorage device is mounted\r\n");
+
+ uint8_t const lun = 0;
+ tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb, 0);
+}
+
+void tuh_msc_umount_cb(uint8_t dev_addr)
+{
+ printf("A MassStorage device is unmounted\r\n");
+
+ uint8_t const drive_num = dev_addr-1;
+ char drive_path[3] = "0:";
+ drive_path[0] += drive_num;
+
+ f_unmount(drive_path);
+
+// if ( phy_disk == f_get_current_drive() )
+// { // active drive is unplugged --> change to other drive
+// for(uint8_t i=0; i<CFG_TUH_DEVICE_MAX; i++)
+// {
+// if ( disk_is_ready(i) )
+// {
+// f_chdrive(i);
+// cli_init(); // refractor, rename
+// }
+// }
+// }
+}
+
+//--------------------------------------------------------------------+
+// DiskIO
+//--------------------------------------------------------------------+
+
+static void wait_for_disk_io(BYTE pdrv)
+{
+ while(_disk_busy[pdrv])
+ {
+ tuh_task();
+ }
+}
+
+static bool disk_io_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
+{
+ (void) dev_addr; (void) cb_data;
+ _disk_busy[dev_addr-1] = false;
+ return true;
+}
+
+DSTATUS disk_status (
+ BYTE pdrv /* Physical drive nmuber to identify the drive */
+)
+{
+ uint8_t dev_addr = pdrv + 1;
+ return tuh_msc_mounted(dev_addr) ? 0 : STA_NODISK;
+}
+
+DSTATUS disk_initialize (
+ BYTE pdrv /* Physical drive nmuber to identify the drive */
+)
+{
+ (void) pdrv;
+ return 0; // nothing to do
+}
+
+DRESULT disk_read (
+ BYTE pdrv, /* Physical drive nmuber to identify the drive */
+ BYTE *buff, /* Data buffer to store read data */
+ LBA_t sector, /* Start sector in LBA */
+ UINT count /* Number of sectors to read */
+)
+{
+ uint8_t const dev_addr = pdrv + 1;
+ uint8_t const lun = 0;
+
+ _disk_busy[pdrv] = true;
+ tuh_msc_read10(dev_addr, lun, buff, sector, (uint16_t) count, disk_io_complete, 0);
+ wait_for_disk_io(pdrv);
+
+ return RES_OK;
+}
+
+#if FF_FS_READONLY == 0
+
+DRESULT disk_write (
+ BYTE pdrv, /* Physical drive nmuber to identify the drive */
+ const BYTE *buff, /* Data to be written */
+ LBA_t sector, /* Start sector in LBA */
+ UINT count /* Number of sectors to write */
+)
+{
+ uint8_t const dev_addr = pdrv + 1;
+ uint8_t const lun = 0;
+
+ _disk_busy[pdrv] = true;
+ tuh_msc_write10(dev_addr, lun, buff, sector, (uint16_t) count, disk_io_complete, 0);
+ wait_for_disk_io(pdrv);
+
+ return RES_OK;
+}
+
+#endif
+
+DRESULT disk_ioctl (
+ BYTE pdrv, /* Physical drive nmuber (0..) */
+ BYTE cmd, /* Control code */
+ void *buff /* Buffer to send/receive control data */
+)
+{
+ uint8_t const dev_addr = pdrv + 1;
+ uint8_t const lun = 0;
+ switch ( cmd )
+ {
+ case CTRL_SYNC:
+ // nothing to do since we do blocking
+ return RES_OK;
+
+ case GET_SECTOR_COUNT:
+ *((DWORD*) buff) = (WORD) tuh_msc_get_block_count(dev_addr, lun);
+ return RES_OK;
+
+ case GET_SECTOR_SIZE:
+ *((WORD*) buff) = (WORD) tuh_msc_get_block_size(dev_addr, lun);
+ return RES_OK;
+
+ case GET_BLOCK_SIZE:
+ *((DWORD*) buff) = 1; // erase block size in units of sector size
+ return RES_OK;
+
+ default:
+ return RES_PARERR;
+ }
+
+ return RES_OK;
+}
+
+//--------------------------------------------------------------------+
+// CLI Commands
+//--------------------------------------------------------------------+
+
+void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_cp(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_pwd(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_mkdir(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_mv(EmbeddedCli *cli, char *args, void *context);
+void cli_cmd_rm(EmbeddedCli *cli, char *args, void *context);
+
+void cli_write_char(EmbeddedCli *cli, char c)
+{
+ (void) cli;
+ putchar((int) c);
+}
+
+void cli_cmd_unknown(EmbeddedCli *cli, CliCommand *command)
+{
+ (void) cli;
+ printf("%s: command not found\r\n", command->name);
+}
+
+bool cli_init(void)
+{
+ EmbeddedCliConfig *config = embeddedCliDefaultConfig();
+ config->cliBuffer = cli_buffer;
+ config->cliBufferSize = CLI_BUFFER_SIZE;
+ config->rxBufferSize = CLI_RX_BUFFER_SIZE;
+ config->cmdBufferSize = CLI_CMD_BUFFER_SIZE;
+ config->historyBufferSize = CLI_HISTORY_SIZE;
+ config->maxBindingCount = CLI_BINDING_COUNT;
+
+ TU_ASSERT(embeddedCliRequiredSize(config) <= CLI_BUFFER_SIZE);
+
+ _cli = embeddedCliNew(config);
+ TU_ASSERT(_cli != NULL);
+
+ _cli->writeChar = cli_write_char;
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "cat",
+ "Usage: cat [FILE]...\r\n\tConcatenate FILE(s) to standard output..",
+ true,
+ NULL,
+ cli_cmd_cat
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "cd",
+ "Usage: cd [DIR]...\r\n\tChange the current directory to DIR.",
+ true,
+ NULL,
+ cli_cmd_cd
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "cp",
+ "Usage: cp SOURCE DEST\r\n\tCopy SOURCE to DEST.",
+ true,
+ NULL,
+ cli_cmd_cp
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "ls",
+ "Usage: ls [DIR]...\r\n\tList information about the FILEs (the current directory by default).",
+ true,
+ NULL,
+ cli_cmd_ls
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "pwd",
+ "Usage: pwd\r\n\tPrint the name of the current working directory.",
+ true,
+ NULL,
+ cli_cmd_pwd
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "mkdir",
+ "Usage: mkdir DIR...\r\n\tCreate the DIRECTORY(ies), if they do not already exist..",
+ true,
+ NULL,
+ cli_cmd_mkdir
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "mv",
+ "Usage: mv SOURCE DEST...\r\n\tRename SOURCE to DEST.",
+ true,
+ NULL,
+ cli_cmd_mv
+ });
+
+ embeddedCliAddBinding(_cli, (CliCommandBinding) {
+ "rm",
+ "Usage: rm [FILE]...\r\n\tRemove (unlink) the FILE(s).",
+ true,
+ NULL,
+ cli_cmd_rm
+ });
+
+ return true;
+}
+
+void cli_cmd_cat(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+
+ // need at least 1 argument
+ if ( argc == 0 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ for(uint16_t i=0; i<argc; i++)
+ {
+ FIL fi;
+ const char* fpath = embeddedCliGetToken(args, i+1); // token count from 1
+
+ if ( FR_OK != f_open(&fi, fpath, FA_READ) )
+ {
+ printf("%s: No such file or directory\r\n", fpath);
+ }else
+ {
+ uint8_t buf[512];
+ UINT count = 0;
+ while ( (FR_OK == f_read(&fi, buf, sizeof(buf), &count)) && (count > 0) )
+ {
+ for(UINT c = 0; c < count; c++)
+ {
+ const uint8_t ch = buf[c];
+ if (isprint(ch) || iscntrl(ch))
+ {
+ putchar(ch);
+ }else
+ {
+ putchar('.');
+ }
+ }
+ }
+ }
+
+ f_close(&fi);
+ }
+}
+
+void cli_cmd_cd(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+
+ // only support 1 argument
+ if ( argc != 1 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ // default is current directory
+ const char* dpath = args;
+
+ if ( FR_OK != f_chdir(dpath) )
+ {
+ printf("%s: No such file or directory\r\n", dpath);
+ return;
+ }
+}
+
+void cli_cmd_cp(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+ if ( argc != 2 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ // default is current directory
+ const char* src = embeddedCliGetToken(args, 1);
+ const char* dst = embeddedCliGetToken(args, 2);
+
+ FIL f_src;
+ FIL f_dst;
+
+ if ( FR_OK != f_open(&f_src, src, FA_READ) )
+ {
+ printf("cannot stat '%s': No such file or directory\r\n", src);
+ return;
+ }
+
+ if ( FR_OK != f_open(&f_dst, dst, FA_WRITE | FA_CREATE_ALWAYS) )
+ {
+ printf("cannot create '%s'\r\n", dst);
+ return;
+ }else
+ {
+ uint8_t buf[512];
+ UINT rd_count = 0;
+ while ( (FR_OK == f_read(&f_src, buf, sizeof(buf), &rd_count)) && (rd_count > 0) )
+ {
+ UINT wr_count = 0;
+
+ if ( FR_OK != f_write(&f_dst, buf, rd_count, &wr_count) )
+ {
+ printf("cannot write to '%s'\r\n", dst);
+ break;
+ }
+ }
+ }
+
+ f_close(&f_src);
+ f_close(&f_dst);
+}
+
+void cli_cmd_ls(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+
+ // only support 1 argument
+ if ( argc > 1 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ // default is current directory
+ const char* dpath = ".";
+ if (argc) dpath = args;
+
+ DIR dir;
+ if ( FR_OK != f_opendir(&dir, dpath) )
+ {
+ printf("cannot access '%s': No such file or directory\r\n", dpath);
+ return;
+ }
+
+ FILINFO fno;
+ while( (f_readdir(&dir, &fno) == FR_OK) && (fno.fname[0] != 0) )
+ {
+ if ( fno.fname[0] != '.' ) // ignore . and .. entry
+ {
+ if ( fno.fattrib & AM_DIR )
+ {
+ // directory
+ printf("/%s\r\n", fno.fname);
+ }else
+ {
+ printf("%-40s", fno.fname);
+ if (fno.fsize < 1024)
+ {
+ printf("%lu B\r\n", fno.fsize);
+ }else
+ {
+ printf("%lu KB\r\n", fno.fsize / 1024);
+ }
+ }
+ }
+ }
+
+ f_closedir(&dir);
+}
+
+void cli_cmd_pwd(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+ uint16_t argc = embeddedCliGetTokenCount(args);
+
+ if (argc != 0)
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ char path[256];
+ if (FR_OK != f_getcwd(path, sizeof(path)))
+ {
+ printf("cannot get current working directory\r\n");
+ }
+
+ puts(path);
+}
+
+void cli_cmd_mkdir(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+
+ // only support 1 argument
+ if ( argc != 1 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ // default is current directory
+ const char* dpath = args;
+
+ if ( FR_OK != f_mkdir(dpath) )
+ {
+ printf("%s: cannot create this directory\r\n", dpath);
+ return;
+ }
+}
+
+void cli_cmd_mv(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+ if ( argc != 2 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ // default is current directory
+ const char* src = embeddedCliGetToken(args, 1);
+ const char* dst = embeddedCliGetToken(args, 2);
+
+ if ( FR_OK != f_rename(src, dst) )
+ {
+ printf("cannot mv %s to %s\r\n", src, dst);
+ return;
+ }
+}
+
+void cli_cmd_rm(EmbeddedCli *cli, char *args, void *context)
+{
+ (void) cli; (void) context;
+
+ uint16_t argc = embeddedCliGetTokenCount(args);
+
+ // need at least 1 argument
+ if ( argc == 0 )
+ {
+ printf("invalid arguments\r\n");
+ return;
+ }
+
+ for(uint16_t i=0; i<argc; i++)
+ {
+ const char* fpath = embeddedCliGetToken(args, i+1); // token count from 1
+
+ if ( FR_OK != f_unlink(fpath) )
+ {
+ printf("cannot remove '%s': No such file or directory\r\n", fpath);
+ }
+ }
+}
diff --git a/examples/host/msc_file_explorer/src/tusb_config.h b/examples/host/msc_file_explorer/src/tusb_config.h
new file mode 100644
index 000000000..c798b4383
--- /dev/null
+++ b/examples/host/msc_file_explorer/src/tusb_config.h
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#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
+
+/* 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_TUH_MEM_SECTION
+#define CFG_TUH_MEM_SECTION
+#endif
+
+#ifndef CFG_TUH_MEM_ALIGN
+#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// Host Configuration
+//--------------------------------------------------------------------
+
+// Enable Host stack
+#define CFG_TUH_ENABLED 1
+
+#if CFG_TUSB_MCU == OPT_MCU_RP2040
+ // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller
+ // #define CFG_TUH_MAX3421 1 // use max3421 as host controller
+
+ // host roothub port is 1 if using either pio-usb or max3421
+ #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)
+ #define BOARD_TUH_RHPORT 1
+ #endif
+#endif
+
+// Default is max speed that hardware controller could support with on-chip PHY
+#define CFG_TUH_MAX_SPEED BOARD_TUH_MAX_SPEED
+
+//------------------------- Board Specific --------------------------
+
+// RHPort number used for host can be defined by board.mk, default to port 0
+#ifndef BOARD_TUH_RHPORT
+#define BOARD_TUH_RHPORT 0
+#endif
+
+// RHPort max operational speed can defined by board.mk
+#ifndef BOARD_TUH_MAX_SPEED
+#define BOARD_TUH_MAX_SPEED OPT_MODE_DEFAULT_SPEED
+#endif
+
+//--------------------------------------------------------------------
+// Driver Configuration
+//--------------------------------------------------------------------
+
+// Size of buffer to hold descriptors and other data used for enumeration
+#define CFG_TUH_ENUMERATION_BUFSIZE 256
+
+#define CFG_TUH_HUB 1 // number of supported hubs
+#define CFG_TUH_MSC 1
+#define CFG_TUH_CDC 0
+#define CFG_TUH_HID 0 // typical keyboard + mouse device can have 3-4 HID interfaces
+#define CFG_TUH_VENDOR 0
+
+// max device support (excluding hub device): 1 hub typically has 4 ports
+#define CFG_TUH_DEVICE_MAX (3*CFG_TUH_HUB + 1)
+
+//------------- MSC -------------//
+#define CFG_TUH_MSC_MAXLUN 4 // typical for most card reader
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */
diff --git a/examples/typec/CMakeLists.txt b/examples/typec/CMakeLists.txt
new file mode 100644
index 000000000..c7641494e
--- /dev/null
+++ b/examples/typec/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.17)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/family_support.cmake)
+
+project(tinyusb_host_examples C CXX ASM)
+family_initialize_project(tinyusb_host_examples ${CMAKE_CURRENT_LIST_DIR})
+
+# family_add_subdirectory will filter what to actually add based on selected FAMILY
+family_add_subdirectory(power_delivery)
diff --git a/examples/typec/power_delivery/CMakeLists.txt b/examples/typec/power_delivery/CMakeLists.txt
new file mode 100644
index 000000000..012eff095
--- /dev/null
+++ b/examples/typec/power_delivery/CMakeLists.txt
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 3.17)
+
+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()
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ )
+
+# Example include
+target_include_directories(${PROJECT} 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(${PROJECT} noos)
diff --git a/examples/typec/power_delivery/Makefile b/examples/typec/power_delivery/Makefile
new file mode 100644
index 000000000..7fa475da5
--- /dev/null
+++ b/examples/typec/power_delivery/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/typec/power_delivery/only.txt b/examples/typec/power_delivery/only.txt
new file mode 100644
index 000000000..657aeaac5
--- /dev/null
+++ b/examples/typec/power_delivery/only.txt
@@ -0,0 +1 @@
+mcu:STM32G4
diff --git a/examples/typec/power_delivery/src/main.c b/examples/typec/power_delivery/src/main.c
new file mode 100644
index 000000000..489d01aa1
--- /dev/null
+++ b/examples/typec/power_delivery/src/main.c
@@ -0,0 +1,193 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bsp/board_api.h"
+#include "tusb.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTOTYPES
+//--------------------------------------------------------------------+
+
+// Voltage and current for selecting PDO
+// DANGEROUS: Please make sure your board can withstand the voltage and current
+// defined here. Otherwise, you may damage your board, smoke can come out
+#define VOLTAGE_MAX_MV 5000 // maximum voltage in mV
+#define CURRENT_MAX_MA 500 // maximum current in mA
+#define CURRENT_OPERATING_MA 100 // operating current in mA
+
+/* Blink pattern
+ * - 250 ms : button is not pressed
+ * - 1000 ms : button is pressed (and hold)
+ */
+enum {
+ BLINK_PRESSED = 250,
+ BLINK_UNPRESSED = 1000
+};
+
+static uint32_t blink_interval_ms = BLINK_UNPRESSED;
+
+void led_blinking_task(void);
+
+#define HELLO_STR "Hello from TinyUSB\r\n"
+
+int main(void)
+{
+ board_init();
+ board_led_write(true);
+
+ tuc_init(0, TUSB_TYPEC_PORT_SNK);
+
+ while (1) {
+ led_blinking_task();
+
+ // tinyusb typec task
+ tuc_task();
+ }
+}
+
+#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
+void app_main(void)
+{
+ main();
+}
+#endif
+
+//--------------------------------------------------------------------+
+// TypeC PD callbacks
+//--------------------------------------------------------------------+
+
+bool tuc_pd_data_received_cb(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end) {
+ switch (header->msg_type) {
+ case PD_DATA_SOURCE_CAP: {
+ printf("PD Source Capabilities\r\n");
+ // Examine source capability and select a suitable PDO (starting from 1 with safe5v)
+ uint8_t selected_pos = 1;
+
+ for(size_t i=0; i<header->n_data_obj; i++) {
+ TU_VERIFY(dobj < p_end);
+ uint32_t const pdo = tu_le32toh(tu_unaligned_read32(dobj));
+
+ switch ((pdo >> 30) & 0x03ul) {
+ case PD_PDO_TYPE_FIXED: {
+ pd_pdo_fixed_t const* fixed = (pd_pdo_fixed_t const*) &pdo;
+ uint32_t const voltage_mv = fixed->voltage_50mv*50;
+ uint32_t const current_ma = fixed->current_max_10ma*10;
+ printf("[Fixed] %lu mV %lu mA\r\n", voltage_mv, current_ma);
+
+ if (voltage_mv <= VOLTAGE_MAX_MV && current_ma >= CURRENT_MAX_MA) {
+ // Found a suitable PDO
+ selected_pos = i+1;
+ }
+
+ break;
+ }
+
+ case PD_PDO_TYPE_BATTERY:
+ break;
+
+ case PD_PDO_TYPE_VARIABLE:
+ break;
+
+ case PD_PDO_TYPE_APDO:
+ break;
+ }
+
+ dobj += 4;
+ }
+
+ //------------- Response with selected PDO -------------//
+ // Be careful and make sure your board can withstand the selected PDO
+ // voltage other than safe5v e.g 12v or 20v
+
+ printf("Selected PDO %u\r\n", selected_pos);
+
+ // Send request with selected PDO position as response to Source Cap
+ pd_rdo_fixed_variable_t rdo = {
+ .current_extremum_10ma = 50, // max 500mA
+ .current_operate_10ma = 30, // 300mA
+ .reserved = 0,
+ .epr_mode_capable = 0,
+ .unchunked_ext_msg_support = 0,
+ .no_usb_suspend = 0,
+ .usb_comm_capable = 1,
+ .capability_mismatch = 0,
+ .give_back_flag = 0, // exteremum is max
+ .object_position = selected_pos,
+ };
+ tuc_msg_request(rhport, &rdo);
+
+ break;
+ }
+
+ default: break;
+ }
+
+ return true;
+}
+
+bool tuc_pd_control_received_cb(uint8_t rhport, pd_header_t const* header) {
+ (void) rhport;
+ switch (header->msg_type) {
+ case PD_CTRL_ACCEPT:
+ printf("PD Request Accepted\r\n");
+ // preparing for power transition
+ break;
+
+ case PD_CTRL_REJECT:
+ printf("PD Request Rejected\r\n");
+ // try to negotiate further power
+ break;
+
+ case PD_CTRL_PS_READY:
+ printf("PD Power Ready\r\n");
+ // Source is ready to supply power
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// 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/typec/power_delivery/src/tusb_config.h b/examples/typec/power_delivery/src/tusb_config.h
new file mode 100644
index 000000000..f7cb3cc04
--- /dev/null
+++ b/examples/typec/power_delivery/src/tusb_config.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#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
+
+#define CFG_TUD_ENABLED 0
+#define CFG_TUH_ENABLED 0
+
+// Enable TYPEC stack
+#define CFG_TUC_ENABLED 1
+
+
+// special example that doesn't enable device or host stack
+// This can cause some TinyUSB API missing, this define hack to allow us to fill those API
+// to pass the compilation process
+#if CFG_TUD_ENABLED == 0
+#define tud_int_handler(x)
+#endif
+
+
+// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
+// #define CFG_TUSB_DEBUG 0
+
+/* 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
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */