summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2021-07-17 12:10:35 +0200
committerGitHub <[email protected]>2021-07-17 12:10:35 +0200
commitb194aa240bba9211e01dd9eaf4562e00a7215666 (patch)
treeb9ef8962f6fdac517e7fc8575526f6cdec8467c1
parent475742984f4d0f2b95c9c78dfff71814117feb90 (diff)
parent21bfd11683c4bb6e0996130bd1061a97d3049121 (diff)
Merge branch 'master' into dcd_same70
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md35
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.yml74
-rw-r--r--.github/workflows/build.yml2
-rw-r--r--.github/workflows/build_esp.yml4
-rw-r--r--.github/workflows/build_renesas.yml2
-rw-r--r--README.md5
-rw-r--r--docs/boards.md4
-rw-r--r--examples/device/CMakeLists.txt2
-rw-r--r--examples/device/audio_4_channel_mic/CMakeLists.txt2
-rw-r--r--examples/device/audio_test/CMakeLists.txt2
-rw-r--r--examples/device/board_test/CMakeLists.txt3
-rw-r--r--examples/device/cdc_dual_ports/CMakeLists.txt2
-rw-r--r--examples/device/cdc_msc/CMakeLists.txt2
-rw-r--r--examples/device/cdc_msc_freertos/CMakeLists.txt20
-rw-r--r--examples/device/cdc_msc_freertos/src/freertos_hook.c2
-rw-r--r--examples/device/dfu/CMakeLists.txt2
-rw-r--r--examples/device/dfu_runtime/CMakeLists.txt2
-rw-r--r--examples/device/dynamic_configuration/CMakeLists.txt2
-rw-r--r--examples/device/hid_composite/CMakeLists.txt2
-rw-r--r--examples/device/hid_composite/src/main.c32
-rw-r--r--examples/device/hid_composite_freertos/src/freertos_hook.c2
-rw-r--r--examples/device/hid_composite_freertos/src/main.c29
-rw-r--r--examples/device/hid_generic_inout/CMakeLists.txt2
-rw-r--r--examples/device/hid_multiple_interface/CMakeLists.txt2
-rw-r--r--examples/device/midi_test/CMakeLists.txt2
-rw-r--r--examples/device/msc_dual_lun/CMakeLists.txt2
-rw-r--r--examples/device/net_lwip_webserver/CMakeLists.txt2
-rw-r--r--examples/device/uac2_headset/.skip.MCU_LPC11UXX0
-rw-r--r--examples/device/uac2_headset/.skip.MCU_LPC13XX0
-rw-r--r--examples/device/uac2_headset/.skip.MCU_NUC1210
-rw-r--r--examples/device/uac2_headset/CMakeLists.txt2
-rw-r--r--examples/device/uac2_headset/src/main.c151
-rw-r--r--examples/device/uac2_headset/src/tusb_config.h48
-rw-r--r--examples/device/uac2_headset/src/usb_descriptors.c2
-rw-r--r--examples/device/uac2_headset/src/usb_descriptors.h59
-rw-r--r--examples/device/usbtmc/CMakeLists.txt2
-rw-r--r--examples/device/webusb_serial/CMakeLists.txt2
-rw-r--r--examples/host/CMakeLists.txt2
-rw-r--r--examples/host/cdc_msc_hid/CMakeLists.txt2
-rw-r--r--examples/host/cdc_msc_hid/src/hid_app.c162
-rw-r--r--examples/host/cdc_msc_hid/src/tusb_config.h4
-rw-r--r--hw/bsp/board.c59
-rw-r--r--hw/bsp/board.h9
-rw-r--r--hw/bsp/board_mcu.h4
-rw-r--r--hw/bsp/esp32s2/family.cmake3
-rw-r--r--hw/bsp/esp32s3/family.cmake3
-rw-r--r--hw/bsp/family_common.cmake57
-rw-r--r--hw/bsp/family_support.cmake71
-rw-r--r--hw/bsp/rp2040/family.cmake4
-rw-r--r--hw/bsp/rx/boards/gr_citrus/board.mk24
-rw-r--r--hw/bsp/rx/boards/gr_citrus/gr_citrus.c (renamed from hw/bsp/rx63n/boards/gr_citrus/gr_citrus.c)50
-rw-r--r--hw/bsp/rx/boards/gr_citrus/hwinit.c (renamed from hw/bsp/rx63n/boards/gr_citrus/hwinit.c)0
-rw-r--r--hw/bsp/rx/boards/gr_citrus/r5f5631fd.ld (renamed from hw/bsp/rx63n/boards/gr_citrus/r5f5631fd.ld)4
-rw-r--r--hw/bsp/rx/boards/rx65n_target/board.mk25
-rw-r--r--hw/bsp/rx/boards/rx65n_target/r5f565ne.ld168
-rw-r--r--hw/bsp/rx/boards/rx65n_target/rx65n_target.c320
-rw-r--r--hw/bsp/rx/family.mk32
-rw-r--r--hw/bsp/rx63n/boards/gr_citrus/board.mk61
-rw-r--r--hw/bsp/rx63n/family.mk1
-rw-r--r--hw/bsp/saml22/family.mk50
-rw-r--r--hw/bsp/saml2x/boards/atsaml21_xpro/board.h50
-rw-r--r--hw/bsp/saml2x/boards/atsaml21_xpro/board.mk12
-rw-r--r--hw/bsp/saml2x/boards/atsaml21_xpro/saml21j18b_flash.ld153
-rw-r--r--hw/bsp/saml2x/boards/saml22_feather/board.h (renamed from hw/bsp/saml22/boards/saml22_feather/board.h)0
-rw-r--r--hw/bsp/saml2x/boards/saml22_feather/board.mk (renamed from hw/bsp/saml22/boards/saml22_feather/board.mk)2
-rw-r--r--hw/bsp/saml2x/boards/saml22_feather/saml22_feather.ld (renamed from hw/bsp/saml22/boards/saml22_feather/saml22_feather.ld)0
-rw-r--r--hw/bsp/saml2x/boards/sensorwatch_m0/board.h (renamed from hw/bsp/saml22/boards/sensorwatch_m0/board.h)0
-rw-r--r--hw/bsp/saml2x/boards/sensorwatch_m0/board.mk (renamed from hw/bsp/saml22/boards/sensorwatch_m0/board.mk)2
-rw-r--r--hw/bsp/saml2x/boards/sensorwatch_m0/sensorwatch_m0.ld (renamed from hw/bsp/saml22/boards/sensorwatch_m0/sensorwatch_m0.ld)0
-rw-r--r--hw/bsp/saml2x/family.c (renamed from hw/bsp/saml22/family.c)16
-rw-r--r--hw/bsp/saml2x/family.mk48
m---------hw/mcu/microchip0
m---------hw/mcu/renesas/rx0
-rw-r--r--src/class/audio/audio.h29
-rw-r--r--src/class/audio/audio_device.c392
-rw-r--r--src/class/cdc/cdc_device.c10
-rw-r--r--src/class/cdc/cdc_host.c62
-rw-r--r--src/class/cdc/cdc_host.h10
-rw-r--r--src/class/dfu/dfu_device.c4
-rw-r--r--src/class/hid/hid_device.c28
-rw-r--r--src/class/hid/hid_host.c75
-rw-r--r--src/class/hid/hid_host.h17
-rw-r--r--src/class/midi/midi_device.c36
-rw-r--r--src/class/msc/msc_device.c20
-rw-r--r--src/class/msc/msc_host.c13
-rw-r--r--src/class/msc/msc_host.h20
-rw-r--r--src/common/tusb_common.h24
-rw-r--r--src/common/tusb_compiler.h16
-rw-r--r--src/common/tusb_fifo.c4
-rw-r--r--src/common/tusb_fifo.h4
-rw-r--r--src/common/tusb_verify.h2
-rw-r--r--src/device/usbd.c5
-rw-r--r--src/device/usbd.h5
-rw-r--r--src/device/usbd_control.c1
-rw-r--r--src/host/hub.c31
-rw-r--r--src/host/hub.h10
-rw-r--r--src/host/usbh.c86
-rw-r--r--src/host/usbh_classdriver.h10
-rw-r--r--src/host/usbh_control.c6
-rw-r--r--src/portable/microchip/samd/dcd_samd.c4
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c61
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c128
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c246
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c393
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.h63
-rw-r--r--src/portable/renesas/usba/dcd_usba.c37
-rw-r--r--src/tusb_option.h6
-rw-r--r--test/test/test_fifo.c24
108 files changed, 2491 insertions, 1297 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 3beef45d0..000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-name: Bug Report
-about: Create a report to help us improve
-title: 'Please provide all details at least for Setup/Describe/Reproduce'
-labels: Bug 🐞
-assignees: ''
-
----
-
-**Set Up**
-
-- **PC OS** e.g Ubuntu 20.04 / Windows 10 / macOS 10.15
-- **Board** e.g Feather nRF52840 Express (if custom specify your MCUs)
-- **TinyUSB version** relase version or git hash (preferrably running with master for lastest code)
-- **Firmware** e.g examples/device/cdc_msc
-
-**Describe The Bug**
-
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-
-Steps to reproduce the behavior:
-1. Go to '...'
-2. Click on '....'
-3. See error
-
-**Screenshots**
-
-If applicable, add screenshots, bus capture to help explain your problem.
-
-**Log**
-
-If applicable, provide the stack's log (uart/rtt/swo) where the issue occurred as attached txt file, best with comments to explain the actual events.
-Note: To enable logging, add `LOG=2` to to the make command if building with stock examples or set `CFG_TUSB_DEBUG=2` in your tusb_config.h. More information can be found at [example's readme](/docs/getting_started.md)
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 000000000..291b22079
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,74 @@
+name: Bug Report
+description: Report a problem with TinyUSB
+labels: 'Bug 🐞'
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Thanks for taking the time to fill out this bug report!
+ It's okay to leave some blank if it doesn't apply to your problem.
+
+ - type: dropdown
+ attributes:
+ label: Operating System
+ options:
+ - Linux
+ - MacOS
+ - RaspberryPi OS
+ - Windows 7
+ - Windows 10
+ - Windows 11
+ - Others
+ validations:
+ required: true
+
+ - type: input
+ attributes:
+ label: Board
+ placeholder: e.g Feather nRF52840 Express
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: Firmware
+ placeholder: |
+ e.g examples/device/cdc_msc.
+ If it is custom firmware, please provide links to your minimal sources or as attached files.
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: What happened ?
+ placeholder: A clear and concise description of what the bug is.
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: How to reproduce ?
+ placeholder: |
+ 1. Go to '...'
+ 2. Click on '....'
+ 3. See error
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: Debug Log
+ placeholder: |
+ TinyUSB debug log where the issue occurred as attached txt file, best with comments to explain the actual events.
+
+ Note: To enable logging, add `LOG=3` to to the make command if building with stock examples or set `CFG_TUSB_DEBUG=3` in your tusb_config.h.
+ More information can be found at [example's readme](https://github.com/hathach/tinyusb/blob/master/docs/getting_started.md)
+ validations:
+ required: false
+
+ - type: textarea
+ attributes:
+ label: Screenshots
+ description: If applicable, add screenshots to help explain your problem.
+ validations:
+ required: false
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 529a77bb1..fc5b92b68 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -49,7 +49,7 @@ jobs:
- 'samd11'
- 'samd21'
- 'samd51'
- - 'saml22'
+ - 'saml2x'
- 'stm32f0'
- 'stm32f4'
- 'stm32f7'
diff --git a/.github/workflows/build_esp.yml b/.github/workflows/build_esp.yml
index 08bb4f5d2..25f4e68f8 100644
--- a/.github/workflows/build_esp.yml
+++ b/.github/workflows/build_esp.yml
@@ -16,10 +16,10 @@ jobs:
board:
# Alphabetical order
# ESP32-S2
- - 'adafruit_metro_esp32s2'
- 'espressif_saola_1'
# ESP32-S3
- - 'espressif_addax_1'
+ # latest IDF does not define USB0 in linker
+ #- 'espressif_addax_1'
steps:
- name: Setup Python
diff --git a/.github/workflows/build_renesas.yml b/.github/workflows/build_renesas.yml
index 45e0c5fd5..ee9ba8289 100644
--- a/.github/workflows/build_renesas.yml
+++ b/.github/workflows/build_renesas.yml
@@ -15,7 +15,7 @@ jobs:
matrix:
family:
# Alphabetical order
- - 'rx63n'
+ - 'rx'
steps:
- name: Setup Python
uses: actions/setup-python@v2
diff --git a/README.md b/README.md
index bea6d0d49..bbe3e0184 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ The stack supports the following MCUs:
- **Dialog:** DA1469x
- **Espressif:** ESP32-S2, ESP32-S3
-- **MicroChip:** SAMD11, SAMD21, SAMD51, SAME5x, SAMG55
+- **MicroChip:** SAMD11, SAMD21, SAMD51, SAME5x, SAMG55, SAML21, SAML22
- **NordicSemi:** nRF52833, nRF52840
- **Nuvoton:** NUC120, NUC121/NUC125, NUC126, NUC505
- **NXP:**
@@ -40,7 +40,7 @@ The stack supports the following MCUs:
- Kinetis: KL25
- LPC Series: 11u, 13, 15, 17, 18, 40, 43, 51u, 54, 55
- **Raspberry Pi:** RP2040
-- **Renesas:** RX63N
+- **Renesas:** RX63N, RX65N
- **Silabs:** EFM32GG12
- **Sony:** CXD56
- **ST:** STM32 series: L0, F0, F1, F2, F3, F4, F7, H7 both FullSpeed and HighSpeed
@@ -106,6 +106,7 @@ TinyUSB is currently used by these other projects:
- [Espressif IDF](https://github.com/espressif/esp-idf)
- [MicroPython](https://github.com/micropython/micropython)
- [mynewt](https://mynewt.apache.org)
+- [openinput](https://github.com/openinput-fw/openinput)
- [Raspberry Pi Pico SDK](https://github.com/raspberrypi/pico-sdk)
- [TinyUF2 Bootloader](https://github.com/adafruit/tinyuf2)
- [TinyUSB Arduino Library](https://github.com/adafruit/Adafruit_TinyUSB_Arduino)
diff --git a/docs/boards.md b/docs/boards.md
index ebba1f841..324500bd1 100644
--- a/docs/boards.md
+++ b/docs/boards.md
@@ -47,8 +47,9 @@ This code base already had supported for a handful of following boards (sorted a
- [Microchip SAMG55 Xplained Pro](https://www.microchip.com/DevelopmentTools/ProductDetails/PartNO/ATSAMG55-XPRO)
-### MicroChip SAML22
+### MicroChip SAML2x
+- [SAML21 Xplaind Pro](https://www.microchip.com/DevelopmentTools/ProductDetails/ATSAML21-XPRO-B)
- [SAML22 Feather](https://github.com/joeycastillo/Feather-Projects/tree/main/SAML22%20Feather)
- [Sensor Watch](https://github.com/joeycastillo/Sensor-Watch)
@@ -126,6 +127,7 @@ This code base already had supported for a handful of following boards (sorted a
### Renesas RX
- [GR-CITRUS](https://www.renesas.com/us/en/products/gadget-renesas/boards/gr-citrus)
+- [Renesas RX65N Target Board](https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rx-32-bit-performance-efficiency-mcus/rtk5rx65n0c00000br-target-board-rx65n)
### Raspberry Pi RP2040
diff --git a/examples/device/CMakeLists.txt b/examples/device/CMakeLists.txt
index 4ed693cde..a0e4600f6 100644
--- a/examples/device/CMakeLists.txt
+++ b/examples/device/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/family_support.cmake)
project(tinyusb_device_examples)
family_initialize_project(tinyusb_device_examples ${CMAKE_CURRENT_LIST_DIR})
diff --git a/examples/device/audio_4_channel_mic/CMakeLists.txt b/examples/device/audio_4_channel_mic/CMakeLists.txt
index b653fc91f..f6e10e2ea 100644
--- a/examples/device/audio_4_channel_mic/CMakeLists.txt
+++ b/examples/device/audio_4_channel_mic/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/audio_test/CMakeLists.txt b/examples/device/audio_test/CMakeLists.txt
index fac0ca64f..cb321f9a8 100644
--- a/examples/device/audio_test/CMakeLists.txt
+++ b/examples/device/audio_test/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/board_test/CMakeLists.txt b/examples/device/board_test/CMakeLists.txt
index 8cd5b9ea4..37113578e 100644
--- a/examples/device/board_test/CMakeLists.txt
+++ b/examples/device/board_test/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# Check for -DFAMILY=
if(FAMILY MATCHES "^esp32s[2-3]")
@@ -12,7 +12,6 @@ if(FAMILY MATCHES "^esp32s[2-3]")
set(TOP "../../..")
get_filename_component(TOP "${TOP}" REALPATH)
- include(${TOP}/hw/bsp/${FAMILY}/family.cmake)
project(${PROJECT})
else()
diff --git a/examples/device/cdc_dual_ports/CMakeLists.txt b/examples/device/cdc_dual_ports/CMakeLists.txt
index 18367a893..abc4d91da 100644
--- a/examples/device/cdc_dual_ports/CMakeLists.txt
+++ b/examples/device/cdc_dual_ports/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/cdc_msc/CMakeLists.txt b/examples/device/cdc_msc/CMakeLists.txt
index 5da761a04..fa6e83b7e 100644
--- a/examples/device/cdc_msc/CMakeLists.txt
+++ b/examples/device/cdc_msc/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/cdc_msc_freertos/CMakeLists.txt b/examples/device/cdc_msc_freertos/CMakeLists.txt
index 1d04a8518..639dde99a 100644
--- a/examples/device/cdc_msc_freertos/CMakeLists.txt
+++ b/examples/device/cdc_msc_freertos/CMakeLists.txt
@@ -1,20 +1,22 @@
cmake_minimum_required(VERSION 3.5)
-# use BOARD-Directory name for project id
-get_filename_component(PROJECT ${CMAKE_CURRENT_SOURCE_DIR} NAME)
-set(PROJECT ${BOARD}-${PROJECT})
-
# 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)
-# Check for -DFAMILY=
-if(FAMILY MATCHES "^esp32s[2-3]")
- cmake_minimum_required(VERSION 3.5)
+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})
- include(${TOP}/hw/bsp/${FAMILY}/family.cmake)
- project(${PROJECT})
+project(${PROJECT})
+# 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}")
endif()
diff --git a/examples/device/cdc_msc_freertos/src/freertos_hook.c b/examples/device/cdc_msc_freertos/src/freertos_hook.c
index 273ad46e6..ab885947c 100644
--- a/examples/device/cdc_msc_freertos/src/freertos_hook.c
+++ b/examples/device/cdc_msc_freertos/src/freertos_hook.c
@@ -94,7 +94,7 @@ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, Stack
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
-#if CFG_TUSB_MCU == OPT_MCU_RX63X
+#if CFG_TUSB_MCU == OPT_MCU_RX63X | CFG_TUSB_MCU == OPT_MCU_RX65X
#include "iodefine.h"
void vApplicationSetupTimerInterrupt(void)
{
diff --git a/examples/device/dfu/CMakeLists.txt b/examples/device/dfu/CMakeLists.txt
index 18367a893..abc4d91da 100644
--- a/examples/device/dfu/CMakeLists.txt
+++ b/examples/device/dfu/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/dfu_runtime/CMakeLists.txt b/examples/device/dfu_runtime/CMakeLists.txt
index 18367a893..abc4d91da 100644
--- a/examples/device/dfu_runtime/CMakeLists.txt
+++ b/examples/device/dfu_runtime/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/dynamic_configuration/CMakeLists.txt b/examples/device/dynamic_configuration/CMakeLists.txt
index 5da761a04..fa6e83b7e 100644
--- a/examples/device/dynamic_configuration/CMakeLists.txt
+++ b/examples/device/dynamic_configuration/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/hid_composite/CMakeLists.txt b/examples/device/hid_composite/CMakeLists.txt
index 18367a893..abc4d91da 100644
--- a/examples/device/hid_composite/CMakeLists.txt
+++ b/examples/device/hid_composite/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/hid_composite/src/main.c b/examples/device/hid_composite/src/main.c
index 512f6f9d9..d2a8a28fa 100644
--- a/examples/device/hid_composite/src/main.c
+++ b/examples/device/hid_composite/src/main.c
@@ -255,12 +255,31 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
{
- // TODO set LED based on CAPLOCK, NUMLOCK etc...
(void) itf;
- (void) report_id;
- (void) report_type;
- (void) buffer;
- (void) bufsize;
+
+ if (report_type == HID_REPORT_TYPE_OUTPUT)
+ {
+ // Set keyboard LED e.g Capslock, Numlock etc...
+ if (report_id == REPORT_ID_KEYBOARD)
+ {
+ // bufsize should be (at least) 1
+ if ( bufsize < 1 ) return;
+
+ uint8_t const kbd_leds = buffer[0];
+
+ if (kbd_leds & KEYBOARD_LED_CAPSLOCK)
+ {
+ // Capslock On: disable blink, turn led on
+ blink_interval_ms = 0;
+ board_led_write(true);
+ }else
+ {
+ // Caplocks Off: back to normal blink
+ board_led_write(false);
+ blink_interval_ms = BLINK_MOUNTED;
+ }
+ }
+ }
}
//--------------------------------------------------------------------+
@@ -271,6 +290,9 @@ void led_blinking_task(void)
static uint32_t start_ms = 0;
static bool led_state = false;
+ // blink is disabled
+ if (!blink_interval_ms) return;
+
// Blink every interval ms
if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time
start_ms += blink_interval_ms;
diff --git a/examples/device/hid_composite_freertos/src/freertos_hook.c b/examples/device/hid_composite_freertos/src/freertos_hook.c
index 273ad46e6..ab885947c 100644
--- a/examples/device/hid_composite_freertos/src/freertos_hook.c
+++ b/examples/device/hid_composite_freertos/src/freertos_hook.c
@@ -94,7 +94,7 @@ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, Stack
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
-#if CFG_TUSB_MCU == OPT_MCU_RX63X
+#if CFG_TUSB_MCU == OPT_MCU_RX63X | CFG_TUSB_MCU == OPT_MCU_RX65X
#include "iodefine.h"
void vApplicationSetupTimerInterrupt(void)
{
diff --git a/examples/device/hid_composite_freertos/src/main.c b/examples/device/hid_composite_freertos/src/main.c
index 47f976427..a61710858 100644
--- a/examples/device/hid_composite_freertos/src/main.c
+++ b/examples/device/hid_composite_freertos/src/main.c
@@ -315,12 +315,31 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
{
- // TODO set LED based on CAPLOCK, NUMLOCK etc...
(void) itf;
- (void) report_id;
- (void) report_type;
- (void) buffer;
- (void) bufsize;
+
+ if (report_type == HID_REPORT_TYPE_OUTPUT)
+ {
+ // Set keyboard LED e.g Capslock, Numlock etc...
+ if (report_id == REPORT_ID_KEYBOARD)
+ {
+ // bufsize should be (at least) 1
+ if ( bufsize < 1 ) return;
+
+ uint8_t const kbd_leds = buffer[0];
+
+ if (kbd_leds & KEYBOARD_LED_CAPSLOCK)
+ {
+ // Capslock On: disable blink, turn led on
+ xTimerStop(blinky_tm, portMAX_DELAY);
+ board_led_write(true);
+ }else
+ {
+ // Caplocks Off: back to normal blink
+ board_led_write(false);
+ xTimerStart(blinky_tm, portMAX_DELAY);
+ }
+ }
+ }
}
//--------------------------------------------------------------------+
diff --git a/examples/device/hid_generic_inout/CMakeLists.txt b/examples/device/hid_generic_inout/CMakeLists.txt
index 18367a893..abc4d91da 100644
--- a/examples/device/hid_generic_inout/CMakeLists.txt
+++ b/examples/device/hid_generic_inout/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/hid_multiple_interface/CMakeLists.txt b/examples/device/hid_multiple_interface/CMakeLists.txt
index 18367a893..abc4d91da 100644
--- a/examples/device/hid_multiple_interface/CMakeLists.txt
+++ b/examples/device/hid_multiple_interface/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/midi_test/CMakeLists.txt b/examples/device/midi_test/CMakeLists.txt
index 18367a893..abc4d91da 100644
--- a/examples/device/midi_test/CMakeLists.txt
+++ b/examples/device/midi_test/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/msc_dual_lun/CMakeLists.txt b/examples/device/msc_dual_lun/CMakeLists.txt
index f60be8eda..9e834ae21 100644
--- a/examples/device/msc_dual_lun/CMakeLists.txt
+++ b/examples/device/msc_dual_lun/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/net_lwip_webserver/CMakeLists.txt b/examples/device/net_lwip_webserver/CMakeLists.txt
index f1f79b2d1..7500f6e9e 100644
--- a/examples/device/net_lwip_webserver/CMakeLists.txt
+++ b/examples/device/net_lwip_webserver/CMakeLists.txt
@@ -4,7 +4,7 @@ set(TOP "../../..")
get_filename_component(TOP "${TOP}" REALPATH)
if (EXISTS ${TOP}/lib/lwip/src)
- include(${TOP}/hw/bsp/${FAMILY}/family.cmake)
+ 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})
diff --git a/examples/device/uac2_headset/.skip.MCU_LPC11UXX b/examples/device/uac2_headset/.skip.MCU_LPC11UXX
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/device/uac2_headset/.skip.MCU_LPC11UXX
diff --git a/examples/device/uac2_headset/.skip.MCU_LPC13XX b/examples/device/uac2_headset/.skip.MCU_LPC13XX
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/device/uac2_headset/.skip.MCU_LPC13XX
diff --git a/examples/device/uac2_headset/.skip.MCU_NUC121 b/examples/device/uac2_headset/.skip.MCU_NUC121
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/examples/device/uac2_headset/.skip.MCU_NUC121
diff --git a/examples/device/uac2_headset/CMakeLists.txt b/examples/device/uac2_headset/CMakeLists.txt
index 18367a893..abc4d91da 100644
--- a/examples/device/uac2_headset/CMakeLists.txt
+++ b/examples/device/uac2_headset/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/uac2_headset/src/main.c b/examples/device/uac2_headset/src/main.c
index 1b6a770a3..ba27350b4 100644
--- a/examples/device/uac2_headset/src/main.c
+++ b/examples/device/uac2_headset/src/main.c
@@ -34,9 +34,11 @@
// MACRO CONSTANT TYPEDEF PROTOTYPES
//--------------------------------------------------------------------+
-#ifndef AUDIO_SAMPLE_RATE
-#define AUDIO_SAMPLE_RATE 48000
-#endif
+// List of supported sample rates
+const uint32_t sample_rates[] = {44100, 48000, 88200, 96000};
+uint32_t current_sample_rate = 44100;
+
+#define N_SAMPLE_RATES TU_ARRAY_SIZE(sample_rates)
/* Blink pattern
* - 25 ms : streaming data
@@ -76,11 +78,16 @@ int8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master chan
int16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
// Buffer for microphone data
-int16_t mic_buf[1000];
+int32_t mic_buf[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ / 4];
// Buffer for speaker data
-int16_t spk_buf[1000];
+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,
+ CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX};
+// Current resolution, update on format change
+uint8_t current_resolution;
void led_blinking_task(void);
void audio_task(void);
@@ -135,55 +142,35 @@ void tud_resume_cb(void)
blink_interval_ms = BLINK_MOUNTED;
}
-typedef struct TU_ATTR_PACKED
-{
- union
- {
- struct TU_ATTR_PACKED
- {
- uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
- uint8_t type : 2; ///< Request type tusb_request_type_t.
- uint8_t direction : 1; ///< Direction type. tusb_dir_t
- } bmRequestType_bit;
-
- uint8_t bmRequestType;
- };
-
- uint8_t bRequest; ///< Request type audio_cs_req_t
- uint8_t bChannelNumber;
- uint8_t bControlSelector;
- union
- {
- uint8_t bInterface;
- uint8_t bEndpoint;
- };
- uint8_t bEntityID;
- uint16_t wLength;
-} audio_control_request_t;
-
// 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);
- // Example supports only single frequency, same value will be used for current value and range
if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ)
{
if (request->bRequest == AUDIO_CS_REQ_CUR)
{
- TU_LOG2("Clock get current freq %u\r\n", AUDIO_SAMPLE_RATE);
+ TU_LOG1("Clock get current freq %u\r\n", current_sample_rate);
- audio_control_cur_4_t curf = { tu_htole32(AUDIO_SAMPLE_RATE) };
+ audio_control_cur_4_t curf = { 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(1) rangef =
+ audio_control_range_4_n_t(N_SAMPLE_RATES) rangef =
{
- .wNumSubRanges = tu_htole16(1),
- .subrange[0] = { tu_htole32(AUDIO_SAMPLE_RATE), tu_htole32(AUDIO_SAMPLE_RATE), 0}
+ .wNumSubRanges = tu_htole16(N_SAMPLE_RATES)
};
- TU_LOG2("Clock get freq range (%d, %d, %d)\r\n", (int)rangef.subrange[0].bMin, (int)rangef.subrange[0].bMax, (int)rangef.subrange[0].bRes);
+ 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 = sample_rates[i];
+ rangef.subrange[i].bMax = 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));
}
}
@@ -191,7 +178,7 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t
request->bRequest == AUDIO_CS_REQ_CUR)
{
audio_control_cur_1_t cur_valid = { .bCur = 1 };
- TU_LOG2("Clock get is valid %u\r\n", cur_valid.bCur);
+ 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",
@@ -199,6 +186,32 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t
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 = ((audio_control_cur_4_t *)buf)->bCur;
+
+ TU_LOG1("Clock set current freq: %d\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)
{
@@ -207,7 +220,7 @@ static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_req
if (request->bControlSelector == AUDIO_FU_CTRL_MUTE && request->bRequest == AUDIO_CS_REQ_CUR)
{
audio_control_cur_1_t mute1 = { .bCur = mute[request->bChannelNumber] };
- TU_LOG2("Get channel %u mute %d\r\n", request->bChannelNumber, mute1.bCur);
+ 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)
@@ -218,14 +231,14 @@ static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_req
.wNumSubRanges = tu_htole16(1),
.subrange[0] = { .bMin = tu_htole16(-VOLUME_CTRL_50_DB), tu_htole16(VOLUME_CTRL_0_DB), tu_htole16(256) }
};
- TU_LOG2("Get channel %u volume range (%d, %d, %u) dB\r\n", request->bChannelNumber,
+ 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_LOG2("Get channel %u volume %u dB\r\n", request->bChannelNumber, cur_vol.bCur);
+ 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));
}
}
@@ -249,7 +262,7 @@ static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_req
mute[request->bChannelNumber] = ((audio_control_cur_1_t *)buf)->bCur;
- TU_LOG2("Set channel %d Mute: %d\r\n", request->bChannelNumber, mute[request->bChannelNumber]);
+ TU_LOG1("Set channel %d Mute: %d\r\n", request->bChannelNumber, mute[request->bChannelNumber]);
return true;
}
@@ -259,7 +272,7 @@ static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_req
volume[request->bChannelNumber] = ((audio_control_cur_2_t const *)buf)->bCur;
- TU_LOG2("Set channel %d volume: %d dB\r\n", request->bChannelNumber, volume[request->bChannelNumber] / 256);
+ TU_LOG1("Set channel %d volume: %d dB\r\n", request->bChannelNumber, volume[request->bChannelNumber] / 256);
return true;
}
@@ -299,7 +312,8 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p
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);
@@ -329,6 +343,13 @@ bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_reque
if (ITF_NUM_AUDIO_STREAMING_SPK == itf && alt != 0)
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;
}
@@ -362,20 +383,40 @@ void audio_task(void)
{
// When new data arrived, copy data from speaker buffer, to microphone buffer
// and send it over
+ // Only support speaker & headphone both have the same resolution
+ // If one is 16bit another is 24bit be care of LOUD noise !
if (spk_data_size)
{
- int16_t *src = spk_buf;
- int16_t *limit = spk_buf + spk_data_size / 2;
- int16_t *dst = mic_buf;
- while (src < limit)
+ if (current_resolution == 16)
{
- // Combine two channels into one
- int32_t left = *src++;
- int32_t right = *src++;
- *dst++ = (int16_t)((left + right) / 2);
+ int16_t *src = (int16_t*)spk_buf;
+ int16_t *limit = (int16_t*)spk_buf + spk_data_size / 2;
+ int16_t *dst = (int16_t*)mic_buf;
+ while (src < limit)
+ {
+ // Combine two channels into one
+ int32_t left = *src++;
+ int32_t right = *src++;
+ *dst++ = (left >> 1) + (right >> 1);
+ }
+ tud_audio_write((uint8_t *)mic_buf, spk_data_size / 2);
+ spk_data_size = 0;
+ }
+ else if (current_resolution == 24)
+ {
+ int32_t *src = spk_buf;
+ int32_t *limit = spk_buf + spk_data_size / 4;
+ int32_t *dst = mic_buf;
+ while (src < limit)
+ {
+ // Combine two channels into one
+ int32_t left = *src++;
+ int32_t right = *src++;
+ *dst++ = ((left >> 1) + (right >> 1)) & 0xffffff00;
+ }
+ tud_audio_write((uint8_t *)mic_buf, spk_data_size / 2);
+ spk_data_size = 0;
}
- tud_audio_write((uint8_t *)mic_buf, spk_data_size / 2);
- spk_data_size = 0;
}
}
diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h
index 88f9efcff..d955a746d 100644
--- a/examples/device/uac2_headset/src/tusb_config.h
+++ b/examples/device/uac2_headset/src/tusb_config.h
@@ -93,33 +93,49 @@ extern "C" {
//--------------------------------------------------------------------
// AUDIO CLASS DRIVER CONFIGURATION
//--------------------------------------------------------------------
-#define CFG_TUD_AUDIO_IN_PATH (CFG_TUD_AUDIO)
-#define CFG_TUD_AUDIO_OUT_PATH (CFG_TUD_AUDIO)
-//#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN 220 // This equals TUD_AUDIO_HEADSET_STEREO_DESC_LEN, however, including it from usb_descriptors.h is not possible due to some strange include hassle
-#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN
+#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
-#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1
-#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2
-#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX 2
-#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX 2
-#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0
+#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
+#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1
+#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX 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_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
+
+// 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
// 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_EP_SZ_IN (CFG_TUD_AUDIO_IN_PATH * (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 n Channels
-#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN
-#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_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_2_EP_SZ_IN)*2
+#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
// 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_EP_OUT_SZ (CFG_TUD_AUDIO_OUT_PATH * ((48 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * (CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX) * (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX))) // N Samples (N kHz) x 2 Bytes/Sample x n Channels
-#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ CFG_TUD_AUDIO_EP_OUT_SZ*3
-#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX CFG_TUD_AUDIO_EP_OUT_SZ // Maximum EP IN size for all AS alternate settings used
+
+#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_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
// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1
+#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 2
// Size of control request buffer
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
diff --git a/examples/device/uac2_headset/src/usb_descriptors.c b/examples/device/uac2_headset/src/usb_descriptors.c
index cd749eb65..6a01f8938 100644
--- a/examples/device/uac2_headset/src/usb_descriptors.c
+++ b/examples/device/uac2_headset/src/usb_descriptors.c
@@ -93,7 +93,7 @@ uint8_t const desc_configuration[] =
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
// Interface number, string index, EP Out & EP In address, EP size
- TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, 2, 16, EPNUM_AUDIO, CFG_TUD_AUDIO_EP_OUT_SZ, EPNUM_AUDIO | 0x80, CFG_TUD_AUDIO_EP_SZ_IN)
+ TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, EPNUM_AUDIO, EPNUM_AUDIO | 0x80)
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
diff --git a/examples/device/uac2_headset/src/usb_descriptors.h b/examples/device/uac2_headset/src/usb_descriptors.h
index d9c5a63a7..d9510ea4f 100644
--- a/examples/device/uac2_headset/src/usb_descriptors.h
+++ b/examples/device/uac2_headset/src/usb_descriptors.h
@@ -55,21 +55,36 @@ enum
+ 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, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epoutsize, _epin, _epinsize) \
+#define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _epout, _epin) \
/* Standard Interface Association Descriptor (IAD) */\
TUD_AUDIO_DESC_IAD(/*_firstitfs*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ ITF_NUM_TOTAL, /*_stridx*/ 0x00),\
/* Standard AC Interface Descriptor(4.7.1) */\
@@ -77,13 +92,13 @@ enum
/* 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*/ 5, /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \
+ 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_GENERIC_SPEAKER, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
+ 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) */\
@@ -95,26 +110,46 @@ enum
/* 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*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+ 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(_nBytesPerSample, _nBitsUsedPerSample),\
+ 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*/ _epoutsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\
+ 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),\
+ /* 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*/ (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 1, Alternate 1 - alternate interface for data streaming */\
+ /* 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*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+ 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*/ (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(_nBytesPerSample, _nBitsUsedPerSample),\
+ 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*/ _epinsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\
+ 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),\
/* 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)\
+ 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/usbtmc/CMakeLists.txt b/examples/device/usbtmc/CMakeLists.txt
index 4306da8cb..c49603c26 100644
--- a/examples/device/usbtmc/CMakeLists.txt
+++ b/examples/device/usbtmc/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/device/webusb_serial/CMakeLists.txt b/examples/device/webusb_serial/CMakeLists.txt
index 18367a893..abc4d91da 100644
--- a/examples/device/webusb_serial/CMakeLists.txt
+++ b/examples/device/webusb_serial/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/host/CMakeLists.txt b/examples/host/CMakeLists.txt
index c70d11d5b..f185ac4f8 100644
--- a/examples/host/CMakeLists.txt
+++ b/examples/host/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/family_support.cmake)
project(tinyusb_host_examples)
family_initialize_project(tinyusb_host_examples ${CMAKE_CURRENT_LIST_DIR})
diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt
index ad0f412e2..0a99bc3a9 100644
--- a/examples/host/cdc_msc_hid/CMakeLists.txt
+++ b/examples/host/cdc_msc_hid/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+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})
diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c
index 23ab12404..420600f9a 100644
--- a/examples/host/cdc_msc_hid/src/hid_app.c
+++ b/examples/host/cdc_msc_hid/src/hid_app.c
@@ -30,7 +30,8 @@
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
-// If your host terminal support ansi escape code, it can be use to simulate mouse cursor
+// 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
@@ -38,11 +39,15 @@
static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII };
// Each HID instance can has multiple reports
-static uint8_t _report_count[CFG_TUH_HID];
-static tuh_hid_report_info_t _report_info_arr[CFG_TUH_HID][MAX_REPORT];
+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_task(void)
{
@@ -60,13 +65,19 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
{
printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
- // Interface protocol
- const char* protocol_str[] = { "None", "Keyboard", "Mouse" }; // hid_protocol_type_t
- uint8_t const interface_protocol = tuh_hid_interface_protocol(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]);
- // Parse report descriptor with built-in parser
- _report_count[instance] = tuh_hid_parse_report_descriptor(_report_info_arr[instance], MAX_REPORT, desc_report, desc_len);
- printf("HID has %u reports and interface protocol = %s\r\n", _report_count[instance], protocol_str[interface_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);
+ }
}
// Invoked when device with hid interface is un-mounted
@@ -78,59 +89,24 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t 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)
{
- (void) dev_addr;
-
- uint8_t const rpt_count = _report_count[instance];
- tuh_hid_report_info_t* rpt_info_arr = _report_info_arr[instance];
- 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 arrray
- 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--;
- }
+ uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
- if (!rpt_info)
+ switch (itf_protocol)
{
- printf("Couldn't find the report info for this report !\r\n");
- return;
- }
+ case HID_ITF_PROTOCOL_KEYBOARD:
+ TU_LOG2("HID receive boot keyboard report\r\n");
+ process_kbd_report( (hid_keyboard_report_t const*) report );
+ break;
- 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_ITF_PROTOCOL_MOUSE:
+ TU_LOG2("HID receive boot mouse report\r\n");
+ process_mouse_report( (hid_mouse_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;
- }
+ default:
+ // Generic report requires matching ReportID and contents with previous parsed report info
+ process_generic_report(dev_addr, instance, report, len);
+ break;
}
}
@@ -164,7 +140,7 @@ static void process_kbd_report(hid_keyboard_report_t const *report)
}else
{
// not existed in previous report means the current key is pressed
- bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
+ 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
@@ -235,3 +211,71 @@ static void process_mouse_report(hid_mouse_report_t const * report)
//------------- 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 arrray
+ 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 the report info for this report !\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/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h
index 8253964c0..b574acf9b 100644
--- a/examples/host/cdc_msc_hid/src/tusb_config.h
+++ b/examples/host/cdc_msc_hid/src/tusb_config.h
@@ -72,11 +72,11 @@
//--------------------------------------------------------------------
// Size of buffer to hold descriptors and other data used for enumeration
-#define CFG_TUH_ENUMERATION_BUFSZIE 256
+#define CFG_TUH_ENUMERATION_BUFSIZE 256
#define CFG_TUH_HUB 1
#define CFG_TUH_CDC 1
-#define CFG_TUH_HID 2
+#define CFG_TUH_HID 4
#define CFG_TUH_MSC 1
#define CFG_TUH_VENDOR 0
diff --git a/hw/bsp/board.c b/hw/bsp/board.c
index 383a02ef4..6a26f55b7 100644
--- a/hw/bsp/board.c
+++ b/hw/bsp/board.c
@@ -25,7 +25,60 @@
#include "board.h"
-#if defined(__MSP430__)
+#if 0
+#define LED_PHASE_MAX 8
+
+static struct
+{
+ uint32_t phase[LED_PHASE_MAX];
+ uint8_t phase_count;
+
+ bool led_state;
+ uint8_t current_phase;
+ uint32_t current_ms;
+}led_pattern;
+
+void board_led_pattern(uint32_t const phase_ms[], uint8_t count)
+{
+ memcpy(led_pattern.phase, phase_ms, 4*count);
+ led_pattern.phase_count = count;
+
+ // reset with 1st phase is on
+ led_pattern.current_ms = board_millis();
+ led_pattern.current_phase = 0;
+ led_pattern.led_state = true;
+ board_led_on();
+}
+
+void board_led_task(void)
+{
+ if ( led_pattern.phase_count == 0 ) return;
+
+ uint32_t const duration = led_pattern.phase[led_pattern.current_phase];
+
+ // return if not enough time
+ if (board_millis() - led_pattern.current_ms < duration) return;
+
+ led_pattern.led_state = !led_pattern.led_state;
+ board_led_write(led_pattern.led_state);
+
+ led_pattern.current_ms += duration;
+ led_pattern.current_phase++;
+
+ if (led_pattern.current_phase == led_pattern.phase_count)
+ {
+ led_pattern.current_phase = 0;
+ led_pattern.led_state = true;
+ board_led_on();
+ }
+}
+#endif
+
+//--------------------------------------------------------------------+
+// newlib read()/write() retarget
+//--------------------------------------------------------------------+
+
+#if defined(__MSP430__) || defined(__RX__)
#define sys_write write
#define sys_read read
#else
@@ -33,10 +86,6 @@
#define sys_read _read
#endif
-//--------------------------------------------------------------------+
-// newlib read()/write() retarget
-//--------------------------------------------------------------------+
-
#if defined(LOGGER_RTT)
// Logging with RTT
diff --git a/hw/bsp/board.h b/hw/bsp/board.h
index 7b77def50..782e0939c 100644
--- a/hw/bsp/board.h
+++ b/hw/bsp/board.h
@@ -54,6 +54,10 @@ void board_init(void);
// Turn LED on or off
void board_led_write(bool state);
+// Control led pattern using phase duration in ms.
+// For each phase, LED is toggle then repeated, board_led_task() is required to be called
+//void board_led_pattern(uint32_t const phase_ms[], uint8_t count);
+
// Get the current state of button
// a '1' means active (pressed), a '0' means inactive.
uint32_t board_button_read(void);
@@ -81,11 +85,12 @@ int board_uart_write(void const * buf, int len);
}
#elif CFG_TUSB_OS == OPT_OS_PICO
-#include "pico/time.h"
-static inline uint32_t board_millis(void)
+ #include "pico/time.h"
+ static inline uint32_t board_millis(void)
{
return to_ms_since_boot(get_absolute_time());
}
+
#elif CFG_TUSB_OS == OPT_OS_RTTHREAD
static inline uint32_t board_millis(void)
{
diff --git a/hw/bsp/board_mcu.h b/hw/bsp/board_mcu.h
index 1a659c410..9f6b489ea 100644
--- a/hw/bsp/board_mcu.h
+++ b/hw/bsp/board_mcu.h
@@ -54,7 +54,7 @@
#elif CFG_TUSB_MCU == OPT_MCU_SAMD11 || CFG_TUSB_MCU == OPT_MCU_SAMD21 || \
CFG_TUSB_MCU == OPT_MCU_SAMD51 || CFG_TUSB_MCU == OPT_MCU_SAME5X || \
- CFG_TUSB_MCU == OPT_MCU_SAML22
+ CFG_TUSB_MCU == OPT_MCU_SAML22 || CFG_TUSB_MCU == OPT_MCU_SAML21
#include "sam.h"
#elif CFG_TUSB_MCU == OPT_MCU_SAMG
@@ -127,7 +127,7 @@
#elif CFG_TUSB_MCU == OPT_MCU_EFM32GG || CFG_TUSB_MCU == OPT_MCU_EFM32GG11 || CFG_TUSB_MCU == OPT_MCU_EFM32GG12
#include "em_device.h"
-#elif CFG_TUSB_MCU == OPT_MCU_RX63X
+#elif CFG_TUSB_MCU == OPT_MCU_RX63X || CFG_TUSB_MCU == OPT_MCU_RX65X
// no header needed
#else
diff --git a/hw/bsp/esp32s2/family.cmake b/hw/bsp/esp32s2/family.cmake
index 9eb1627a1..f3d41d041 100644
--- a/hw/bsp/esp32s2/family.cmake
+++ b/hw/bsp/esp32s2/family.cmake
@@ -4,7 +4,4 @@ cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "src" "${TOP}/hw/bsp/esp32s2/boards" "${TOP}/hw/bsp/esp32s2/components")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(SUPPORTED_TARGETS esp32s2)
-
-# include basic family CMake functionality
set(FAMILY_MCUS ESP32S2)
-include(${CMAKE_CURRENT_LIST_DIR}/../family_common.cmake)
diff --git a/hw/bsp/esp32s3/family.cmake b/hw/bsp/esp32s3/family.cmake
index c99c3728b..511dd58bb 100644
--- a/hw/bsp/esp32s3/family.cmake
+++ b/hw/bsp/esp32s3/family.cmake
@@ -4,7 +4,4 @@ cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "src" "${TOP}/hw/bsp/esp32s3/boards" "${TOP}/hw/bsp/esp32s3/components")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(SUPPORTED_TARGETS esp32s3)
-
-# include basic family CMake functionality
set(FAMILY_MCUS ESP32S3)
-include(${CMAKE_CURRENT_LIST_DIR}/../family_common.cmake)
diff --git a/hw/bsp/family_common.cmake b/hw/bsp/family_common.cmake
deleted file mode 100644
index 2544c58c6..000000000
--- a/hw/bsp/family_common.cmake
+++ /dev/null
@@ -1,57 +0,0 @@
-if (NOT FAMILY_MCUS)
- set(FAMILY_MCUS ${FAMILY})
-endif()
-
-# save it in case of re-inclusion
-set(FAMILY_MCUS ${FAMILY_MCUS} CACHE INTERNAL "")
-
-function(family_filter RESULT DIR)
- get_filename_component(DIR ${DIR} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
- file(GLOB ONLYS "${DIR}/.only.MCU_*")
- if (ONLYS)
- foreach(MCU IN LISTS FAMILY_MCUS)
- if (EXISTS ${DIR}/.only.MCU_${MCU})
- set(${RESULT} 1 PARENT_SCOPE)
- return()
- endif()
- endforeach()
- else()
- foreach(MCU IN LISTS FAMILY_MCUS)
- if (EXISTS ${DIR}/.skip.MCU_${MCU})
- set(${RESULT} 0 PARENT_SCOPE)
- return()
- endif()
- endforeach()
- endif()
- set(${RESULT} 1 PARENT_SCOPE)
-endfunction()
-
-function(family_add_subdirectory DIR)
- family_filter(SHOULD_ADD "${DIR}")
- if (SHOULD_ADD)
- add_subdirectory(${DIR})
- endif()
-endfunction()
-
-function(family_get_project_name OUTPUT_NAME DIR)
- get_filename_component(SHORT_NAME ${DIR} NAME)
- set(${OUTPUT_NAME} ${TINYUSB_FAMILY_PROJECT_NAME_PREFIX}${SHORT_NAME} PARENT_SCOPE)
-endfunction()
-
-function(family_initialize_project PROJECT DIR)
- family_filter(ALLOWED "${DIR}")
- if (NOT ALLOWED)
- get_filename_component(SHORT_NAME ${DIR} NAME)
- message(FATAL_ERROR "${SHORT_NAME} is not supported on FAMILY=${FAMILY}")
- endif()
-endfunction()
-
-# configure an executable target to link to tinyusb in device mode, and add the board implementation
-function(family_configure_device_example TARGET)
- # default implentation is empty, the function should be redefined in the FAMILY/family.cmake
-endfunction()
-
-# configure an executable target to link to tinyusb in host mode, and add the board implementation
-function(family_configure_host_example TARGET)
- # default implentation is empty, the function should be redefined in the FAMILY/family.cmake
-endfunction()
diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake
new file mode 100644
index 000000000..af0e00b2d
--- /dev/null
+++ b/hw/bsp/family_support.cmake
@@ -0,0 +1,71 @@
+if (NOT TARGET _family_support_marker)
+ add_library(_family_support_marker INTERFACE)
+
+ if (NOT FAMILY)
+ message(FATAL_ERROR "You must set a FAMILY variable for the build (e.g. rp2040, eps32s2, esp32s3). You can do this via -DFAMILY=xxx on the camke command line")
+ endif()
+
+ if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/${FAMILY}/family.cmake)
+ message(FATAL_ERROR "Family '${FAMILY}' is not known/supported")
+ endif()
+
+ function(family_filter RESULT DIR)
+ get_filename_component(DIR ${DIR} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+ file(GLOB ONLYS "${DIR}/.only.MCU_*")
+ if (ONLYS)
+ foreach(MCU IN LISTS FAMILY_MCUS)
+ if (EXISTS ${DIR}/.only.MCU_${MCU})
+ set(${RESULT} 1 PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+ else()
+ foreach(MCU IN LISTS FAMILY_MCUS)
+ if (EXISTS ${DIR}/.skip.MCU_${MCU})
+ set(${RESULT} 0 PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+ endif()
+ set(${RESULT} 1 PARENT_SCOPE)
+ endfunction()
+
+ function(family_add_subdirectory DIR)
+ family_filter(SHOULD_ADD "${DIR}")
+ if (SHOULD_ADD)
+ add_subdirectory(${DIR})
+ endif()
+ endfunction()
+
+ function(family_get_project_name OUTPUT_NAME DIR)
+ get_filename_component(SHORT_NAME ${DIR} NAME)
+ set(${OUTPUT_NAME} ${TINYUSB_FAMILY_PROJECT_NAME_PREFIX}${SHORT_NAME} PARENT_SCOPE)
+ endfunction()
+
+ function(family_initialize_project PROJECT DIR)
+ family_filter(ALLOWED "${DIR}")
+ if (NOT ALLOWED)
+ get_filename_component(SHORT_NAME ${DIR} NAME)
+ message(FATAL_ERROR "${SHORT_NAME} is not supported on FAMILY=${FAMILY}")
+ endif()
+ endfunction()
+
+ # configure an executable target to link to tinyusb in device mode, and add the board implementation
+ function(family_configure_device_example TARGET)
+ # default implentation is empty, the function should be redefined in the FAMILY/family.cmake
+ endfunction()
+
+ # configure an executable target to link to tinyusb in host mode, and add the board implementation
+ function(family_configure_host_example TARGET)
+ # default implentation is empty, the function should be redefined in the FAMILY/family.cmake
+ endfunction()
+
+ include(${CMAKE_CURRENT_LIST_DIR}/${FAMILY}/family.cmake)
+
+ if (NOT FAMILY_MCUS)
+ set(FAMILY_MCUS ${FAMILY})
+ endif()
+
+ # save it in case of re-inclusion
+ set(FAMILY_MCUS ${FAMILY_MCUS} CACHE INTERNAL "")
+endif() \ No newline at end of file
diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake
index 752eb0cab..41960b6cd 100644
--- a/hw/bsp/rp2040/family.cmake
+++ b/hw/bsp/rp2040/family.cmake
@@ -3,7 +3,8 @@ if (NOT TARGET _rp2040_family_inclusion_marker)
add_library(_rp2040_family_inclusion_marker INTERFACE)
if (NOT BOARD)
- message(FATAL_ERROR "BOARD must be specified")
+ message("BOARD not specified, defaulting to pico_sdk")
+ set(BOARD pico_sdk)
endif()
# add the SDK in case we are standalone tinyusb example (noop if already present)
@@ -11,7 +12,6 @@ if (NOT TARGET _rp2040_family_inclusion_marker)
# include basic family CMake functionality
set(FAMILY_MCUS RP2040)
- include(${CMAKE_CURRENT_LIST_DIR}/../family_common.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
diff --git a/hw/bsp/rx/boards/gr_citrus/board.mk b/hw/bsp/rx/boards/gr_citrus/board.mk
new file mode 100644
index 000000000..0eba94610
--- /dev/null
+++ b/hw/bsp/rx/boards/gr_citrus/board.mk
@@ -0,0 +1,24 @@
+DEPS_SUBMODULES += hw/mcu/renesas/rx
+
+CFLAGS += \
+ -mcpu=rx610 \
+ -misa=v1 \
+ -DCFG_TUSB_MCU=OPT_MCU_RX63X
+
+MCU_DIR = hw/mcu/renesas/rx/rx63n
+
+# All source paths should be relative to the top level.
+LD_FILE = $(BOARD_PATH)/r5f5631fd.ld
+
+# For freeRTOS port source
+FREERTOS_PORT = RX600
+
+# For flash-jlink target
+JLINK_DEVICE = R5F5631F
+JLINK_IF = JTAG
+
+# For flash-pyocd target
+PYOCD_TARGET =
+
+# flash using jlink
+flash: flash-jlink
diff --git a/hw/bsp/rx63n/boards/gr_citrus/gr_citrus.c b/hw/bsp/rx/boards/gr_citrus/gr_citrus.c
index 6697012a7..caf5fd6fa 100644
--- a/hw/bsp/rx63n/boards/gr_citrus/gr_citrus.c
+++ b/hw/bsp/rx/boards/gr_citrus/gr_citrus.c
@@ -34,26 +34,22 @@
*
* The pads are [the back side of GR-CITRUS](https://www.slideshare.net/MinaoYamamoto/grcitrusrx631/2).
*
- * Connet the pins between GR-CITRUS and JLink as follows.
+ * Connect the pins between GR-CITRUS and JLink as follows.
*
- * | JTAG Function | GR-CITRUS pin name| JLink pin No.| note |
- * |:-------------:|:-----------------:|:------------:|:--------:|
- * | VTref | 3.3V | 1 | |
- * | TRST | 5 | 3 | |
- * | GND | GND | 4 | |
- * | TDI | 3 | 5 | |
- * | TMS | 2 | 7 | |
- * | TCK | 14 | 9 | short J4 |
- * | TDO | 9 | 13 | short J5 |
- * | nRES | RST | 15 | |
+ * | Function | GR-CITRUS pin | JLink pin No.| note |
+ * |:---------:|:-------------:|:------------:|:--------:|
+ * | VTref | 3.3V | 1 | |
+ * | TRST | 5 | 3 | |
+ * | GND | GND | 4 | |
+ * | TDI | 3 | 5 | |
+ * | TMS | 2 | 7 | |
+ * | TCK/FINEC | 14 | 9 | short J4 |
+ * | TDO | 9 | 13 | short J5 |
+ * | nRES | RST | 15 | |
*
* JLink firmware needs to update to V6.96 or newer version to avoid
* [a bug](https://forum.segger.com/index.php/Thread/7758-SOLVED-Bug-in-JLink-from-V6-88b-regarding-RX65N)
* regarding downloading.
- *
- * When using SEGGER RTT, `RX_NEWLIB=0` should be added to make command arguments.
- * The option is used to change the C runtime library to `optlib` from `newlib`.
- * RTT may not work with `newlib`.
*/
#include "../board.h"
@@ -253,3 +249,27 @@ uint32_t board_millis(void)
#else
uint32_t SystemCoreClock = 96000000;
#endif
+
+int close(int fd)
+{
+ (void)fd;
+ return -1;
+}
+int fstat(int fd, void *pstat)
+{
+ (void)fd;
+ (void)pstat;
+ return 0;
+}
+off_t lseek(int fd, off_t pos, int whence)
+{
+ (void)fd;
+ (void)pos;
+ (void)whence;
+ return 0;
+}
+int isatty(int fd)
+{
+ (void)fd;
+ return 1;
+}
diff --git a/hw/bsp/rx63n/boards/gr_citrus/hwinit.c b/hw/bsp/rx/boards/gr_citrus/hwinit.c
index 8245d7744..8245d7744 100644
--- a/hw/bsp/rx63n/boards/gr_citrus/hwinit.c
+++ b/hw/bsp/rx/boards/gr_citrus/hwinit.c
diff --git a/hw/bsp/rx63n/boards/gr_citrus/r5f5631fd.ld b/hw/bsp/rx/boards/gr_citrus/r5f5631fd.ld
index fa8142936..bb9c297c7 100644
--- a/hw/bsp/rx63n/boards/gr_citrus/r5f5631fd.ld
+++ b/hw/bsp/rx/boards/gr_citrus/r5f5631fd.ld
@@ -1,5 +1,5 @@
-__USTACK_SIZE = 0x00000200;
-__ISTACK_SIZE = 0x00000200;
+__USTACK_SIZE = 0x00000400;
+__ISTACK_SIZE = 0x00000400;
MEMORY
{
diff --git a/hw/bsp/rx/boards/rx65n_target/board.mk b/hw/bsp/rx/boards/rx65n_target/board.mk
new file mode 100644
index 000000000..fc76d79fa
--- /dev/null
+++ b/hw/bsp/rx/boards/rx65n_target/board.mk
@@ -0,0 +1,25 @@
+CFLAGS += \
+ -mcpu=rx64m \
+ -misa=v2 \
+ -DCFG_TUSB_MCU=OPT_MCU_RX65X \
+ -DIR_USB0_USBI0=IR_PERIB_INTB185 \
+ -DIER_USB0_USBI0=IER_PERIB_INTB185 \
+ -DIEN_USB0_USBI0=IEN_PERIB_INTB185
+
+MCU_DIR = hw/mcu/renesas/rx/rx65n
+
+# All source paths should be relative to the top level.
+LD_FILE = $(BOARD_PATH)/r5f565ne.ld
+
+# For freeRTOS port source
+FREERTOS_PORT = RX600
+
+# For flash-jlink target
+JLINK_DEVICE = R5F565NE
+JLINK_IF = JTAG
+
+# For flash-pyocd target
+PYOCD_TARGET =
+
+# flash using rfp-cli
+flash: flash-rfp
diff --git a/hw/bsp/rx/boards/rx65n_target/r5f565ne.ld b/hw/bsp/rx/boards/rx65n_target/r5f565ne.ld
new file mode 100644
index 000000000..8e5617f23
--- /dev/null
+++ b/hw/bsp/rx/boards/rx65n_target/r5f565ne.ld
@@ -0,0 +1,168 @@
+__USTACK_SIZE = 0x00000400;
+__ISTACK_SIZE = 0x00000400;
+
+MEMORY
+{
+ RAM : ORIGIN = 0x4, LENGTH = 0x3fffc
+ RAM2 : ORIGIN = 0x00800000, LENGTH = 0x60000
+ OFS : ORIGIN = 0xFE7F5D00, LENGTH = 128
+ ROM : ORIGIN = 0xFFE00000, LENGTH = 0x200000
+}
+SECTIONS
+{
+ .exvectors 0xFFFFFF80: AT(0xFFFFFF80)
+ {
+ "_exvectors_start" = .;
+ KEEP(*(.exvectors))
+ "_exvectors_end" = .;
+ } >ROM
+ .fvectors 0xFFFFFFFC: AT(0xFFFFFFFC)
+ {
+ KEEP(*(.fvectors))
+ } > ROM
+ .text 0xFFE00000: AT(0xFFE00000)
+ {
+ *(.text)
+ *(.text.*)
+ *(P)
+ KEEP(*(.text.*_isr))
+ etext = .;
+ } > ROM
+ .rvectors ALIGN(4):
+ {
+ _rvectors_start = .;
+ KEEP(*(.rvectors))
+ _rvectors_end = .;
+ } > ROM
+ .init :
+ {
+ KEEP(*(.init))
+ __preinit_array_start = .;
+ KEEP(*(.preinit_array))
+ __preinit_array_end = .;
+ __init_array_start = (. + 3) & ~ 3;
+ KEEP(*(.init_array))
+ KEEP(*(SORT(.init_array.*)))
+ __init_array_end = .;
+ __fini_array_start = .;
+ KEEP(*(.fini_array))
+ KEEP(*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+ } > ROM
+ .fini :
+ {
+ KEEP(*(.fini))
+ } > ROM
+ .got :
+ {
+ *(.got)
+ *(.got.plt)
+ } > ROM
+ .rodata :
+ {
+ *(.rodata)
+ *(.rodata.*)
+ *(C_1)
+ *(C_2)
+ *(C)
+ _erodata = .;
+ } > ROM
+ .eh_frame_hdr :
+ {
+ *(.eh_frame_hdr)
+ } > ROM
+ .eh_frame :
+ {
+ *(.eh_frame)
+ } > ROM
+ .jcr :
+ {
+ *(.jcr)
+ } > ROM
+ .tors :
+ {
+ __CTOR_LIST__ = .;
+ . = ALIGN(2);
+ ___ctors = .;
+ *(.ctors)
+ ___ctors_end = .;
+ __CTOR_END__ = .;
+ __DTOR_LIST__ = .;
+ ___dtors = .;
+ *(.dtors)
+ ___dtors_end = .;
+ __DTOR_END__ = .;
+ . = ALIGN(2);
+ _mdata = .;
+ } > ROM
+ .data : AT(_mdata)
+ {
+ _data = .;
+ *(.data)
+ *(.data.*)
+ *(D)
+ *(D_1)
+ *(D_2)
+ _edata = .;
+ } > RAM
+ .gcc_exc :
+ {
+ *(.gcc_exc)
+ } > RAM
+ .bss :
+ {
+ _bss = .;
+ *(.bss)
+ *(.bss.**)
+ *(COMMON)
+ *(B)
+ *(B_1)
+ *(B_2)
+ _ebss = .;
+ _end = .;
+ } > RAM
+ .ustack :
+ {
+ . = ALIGN(8);
+ . = . + __USTACK_SIZE;
+ PROVIDE(_ustack = .);
+ } > RAM
+ .istack :
+ {
+ . = ALIGN(8);
+ . = . + __ISTACK_SIZE;
+ PROVIDE(_istack = .);
+ } > RAM
+ .ofs1 0xFE7F5D00: AT(0xFE7F5D00)
+ {
+ KEEP(*(.ofs1))
+ } > OFS
+ .ofs2 0xFE7F5D10: AT(0xFE7F5D10)
+ {
+ KEEP(*(.ofs2))
+ } > OFS
+ .ofs3 0xFE7F5D20: AT(0xFE7F5D20)
+ {
+ KEEP(*(.ofs3))
+ } > OFS
+ .ofs4 0xFE7F5D40: AT(0xFE7F5D40)
+ {
+ KEEP(*(.ofs4))
+ } > OFS
+ .ofs5 0xFE7F5D48: AT(0xFE7F5D48)
+ {
+ KEEP(*(.ofs5))
+ } > OFS
+ .ofs6 0xFE7F5D50: AT(0xFE7F5D50)
+ {
+ KEEP(*(.ofs6))
+ } > OFS
+ .ofs7 0xFE7F5D64: AT(0xFE7F5D64)
+ {
+ KEEP(*(.ofs7))
+ } > OFS
+ .ofs8 0xFE7F5D70: AT(0xFE7F5D70)
+ {
+ KEEP(*(.ofs8))
+ } > OFS
+}
diff --git a/hw/bsp/rx/boards/rx65n_target/rx65n_target.c b/hw/bsp/rx/boards/rx65n_target/rx65n_target.c
new file mode 100644
index 000000000..20867455e
--- /dev/null
+++ b/hw/bsp/rx/boards/rx65n_target/rx65n_target.c
@@ -0,0 +1,320 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Koji Kitayama
+ *
+ * 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.
+ */
+
+/* How to connect JLink and RX65n Target and option board
+ * (For original comment https://github.com/hathach/tinyusb/pull/922#issuecomment-869786131)
+ *
+ * To enable JTAG, RX65N requires following connections on main board.
+ * - short EJ2 jumper header, to disable onboard E2L.
+ * - short EMLE(J1-2) and 3V3(J1-14 or J2-10), to enable In-Circuit Emulator.
+ *
+ * Note: For RX65N-Cloud-Kit, the option board's JTAG pins to some switches or floating.
+ * To use JLink with the option board, I think some further modifications will be necessary.
+ *
+ * | Function | RX65N pin | main board | option board | JLink connector |
+ * |:---------:|:----------:|:----------:|:------------:|:---------------:|
+ * | 3V3 | VCC | J1-14 | CN5-6 | 1 |
+ * | TRST | P34 | J1-16 | CN5-7 | 3 |
+ * | GND | VSS | J1-12 | CN5-5 | 4 |
+ * | TDI | P30 | J1-20 | CN5-10 | 5 |
+ * | TMS | P31 | J1-19 | USER_SW | 7 |
+ * | TCK/FINEC | P27 | J1-21 | N/A | 9 |
+ * | TDO | P26 | J1-22 | CN5-9 | 13 |
+ * | nRES | RES# | J1-10 | RESET_SW | 15 |
+ *
+ * JLink firmware needs to update to V6.96 or newer version to avoid
+ * [a bug](https://forum.segger.com/index.php/Thread/7758-SOLVED-Bug-in-JLink-from-V6-88b-regarding-RX65N)
+ * regarding downloading.
+ */
+
+#include "bsp/board.h"
+#include "iodefine.h"
+#include "interrupt_handlers.h"
+
+#define IRQ_PRIORITY_CMT0 5
+#define IRQ_PRIORITY_USBI0 6
+#define IRQ_PRIORITY_SCI5 5
+
+#define SYSTEM_PRCR_PRC1 (1<<1)
+#define SYSTEM_PRCR_PRKEY (0xA5u<<8)
+
+#define CMT_PCLK 60000000
+#define CMT_CMCR_CKS_DIV_128 2
+#define CMT_CMCR_CMIE (1<<6)
+#define MPC_PFS_ISEL (1<<6)
+
+#define SCI_PCLK 60000000
+#define SCI_SSR_FER (1<<4)
+#define SCI_SSR_ORER (1<<5)
+
+#define SCI_SCR_TEIE (1u<<2)
+#define SCI_SCR_RE (1u<<4)
+#define SCI_SCR_TE (1u<<5)
+#define SCI_SCR_RIE (1u<<6)
+#define SCI_SCR_TIE (1u<<7)
+#define INT_Excep_SCI5_TEI5 INT_Excep_ICU_GROUPBL0
+
+#define IRQ_USB0_USBI0 62
+#define SLIBR_USBI0 SLIBR185
+#define IPR_USB0_USBI0 IPR_PERIB_INTB185
+#define INT_Excep_USB0_USBI0 INT_Excep_PERIB_INTB185
+
+void HardwareSetup(void)
+{
+ FLASH.ROMCIV.WORD = 1;
+ while (FLASH.ROMCIV.WORD) ;
+ FLASH.ROMCE.WORD = 1;
+ while (!FLASH.ROMCE.WORD) ;
+
+ SYSTEM.PRCR.WORD = 0xA503u;
+ if (!SYSTEM.RSTSR1.BYTE) {
+ RTC.RCR4.BYTE = 0;
+ RTC.RCR3.BYTE = 12;
+ while (12 != RTC.RCR3.BYTE) ;
+ }
+ SYSTEM.SOSCCR.BYTE = 1;
+
+ if (SYSTEM.HOCOCR.BYTE) {
+ SYSTEM.HOCOCR.BYTE = 0;
+ while (!SYSTEM.OSCOVFSR.BIT.HCOVF) ;
+ }
+ SYSTEM.PLLCR.WORD = 0x1D10u; /* HOCO x 15 */
+ SYSTEM.PLLCR2.BYTE = 0;
+ while (!SYSTEM.OSCOVFSR.BIT.PLOVF) ;
+
+ SYSTEM.SCKCR.LONG = 0x21C11222u;
+ SYSTEM.SCKCR2.WORD = 0x0041u;
+ SYSTEM.ROMWT.BYTE = 0x02u;
+ while (0x02u != SYSTEM.ROMWT.BYTE) ;
+ SYSTEM.SCKCR3.WORD = 0x400u;
+ SYSTEM.PRCR.WORD = 0xA500u;
+}
+
+//--------------------------------------------------------------------+
+// SCI handling
+//--------------------------------------------------------------------+
+typedef struct {
+ uint8_t *buf;
+ uint32_t cnt;
+} sci_buf_t;
+static volatile sci_buf_t sci_buf[2];
+
+void INT_Excep_SCI5_TXI5(void)
+{
+ uint8_t *buf = sci_buf[0].buf;
+ uint32_t cnt = sci_buf[0].cnt;
+
+ if (!buf || !cnt) {
+ SCI5.SCR.BYTE &= ~(SCI_SCR_TEIE | SCI_SCR_TE | SCI_SCR_TIE);
+ return;
+ }
+ SCI5.TDR = *buf;
+ if (--cnt) {
+ ++buf;
+ } else {
+ buf = NULL;
+ SCI5.SCR.BIT.TIE = 0;
+ SCI5.SCR.BIT.TEIE = 1;
+ }
+ sci_buf[0].buf = buf;
+ sci_buf[0].cnt = cnt;
+}
+
+void INT_Excep_SCI5_TEI5(void)
+{
+ SCI5.SCR.BYTE &= ~(SCI_SCR_TEIE | SCI_SCR_TE | SCI_SCR_TIE);
+}
+
+void INT_Excep_SCI5_RXI5(void)
+{
+ uint8_t *buf = sci_buf[1].buf;
+ uint32_t cnt = sci_buf[1].cnt;
+
+ if (!buf || !cnt ||
+ (SCI5.SSR.BYTE & (SCI_SSR_FER | SCI_SSR_ORER))) {
+ sci_buf[1].buf = NULL;
+ SCI5.SSR.BYTE = 0;
+ SCI5.SCR.BYTE &= ~(SCI_SCR_RE | SCI_SCR_RIE);
+ return;
+ }
+ *buf = SCI5.RDR;
+ if (--cnt) {
+ ++buf;
+ } else {
+ buf = NULL;
+ SCI5.SCR.BYTE &= ~(SCI_SCR_RE | SCI_SCR_RIE);
+ }
+ sci_buf[1].buf = buf;
+ sci_buf[1].cnt = cnt;
+}
+
+//--------------------------------------------------------------------+
+// Forward USB interrupt events to TinyUSB IRQ Handler
+//--------------------------------------------------------------------+
+void INT_Excep_USB0_USBI0(void)
+{
+ tud_int_handler(0);
+}
+
+void board_init(void)
+{
+ /* setup software configurable interrupts */
+ ICU.SLIBR_USBI0.BYTE = IRQ_USB0_USBI0;
+ ICU.SLIPRCR.BYTE = 1;
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+ /* Enable CMT0 */
+ SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY | SYSTEM_PRCR_PRC1;
+ MSTP(CMT0) = 0;
+ SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY;
+ /* Setup 1ms tick timer */
+ CMT0.CMCNT = 0;
+ CMT0.CMCOR = CMT_PCLK / 1000 / 128;
+ CMT0.CMCR.WORD = CMT_CMCR_CMIE | CMT_CMCR_CKS_DIV_128;
+ IR(CMT0, CMI0) = 0;
+ IPR(CMT0, CMI0) = IRQ_PRIORITY_CMT0;
+ IEN(CMT0, CMI0) = 1;
+ CMT.CMSTR0.BIT.STR0 = 1;
+#endif
+
+ /* Unlock MPC registers */
+ MPC.PWPR.BIT.B0WI = 0;
+ MPC.PWPR.BIT.PFSWE = 1;
+ // SW PB1
+ PORTB.PMR.BIT.B1 = 0U;
+ PORTB.PDR.BIT.B1 = 0U;
+ // LED PD6
+ PORTD.PODR.BIT.B6 = 1U;
+ PORTD.ODR1.BIT.B4 = 1U;
+ PORTD.PMR.BIT.B6 = 0U;
+ PORTD.PDR.BIT.B6 = 1U;
+ /* UART TXD5 => PA4, RXD5 => PA3 */
+ PORTA.PMR.BIT.B4 = 1U;
+ PORTA.PCR.BIT.B4 = 1U;
+ MPC.PA4PFS.BYTE = 0b01010;
+ PORTA.PMR.BIT.B3 = 1U;
+ MPC.PA5PFS.BYTE = 0b01010;
+ /* USB VBUS -> P16 */
+ PORT1.PMR.BIT.B6 = 1U;
+ MPC.P16PFS.BYTE = MPC_PFS_ISEL | 0b10001;
+ /* Lock MPC registers */
+ MPC.PWPR.BIT.PFSWE = 0;
+ MPC.PWPR.BIT.B0WI = 1;
+
+ /* Enable SCI5 */
+ SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY | SYSTEM_PRCR_PRC1;
+ MSTP(SCI5) = 0;
+ SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY;
+ SCI5.SEMR.BIT.ABCS = 1;
+ SCI5.SEMR.BIT.BGDM = 1;
+ SCI5.BRR = (SCI_PCLK / (8 * 115200)) - 1;
+ IR(SCI5, RXI5) = 0;
+ IR(SCI5, TXI5) = 0;
+ IS(SCI5, TEI5) = 0;
+ IR(ICU, GROUPBL0) = 0;
+ IPR(SCI5, RXI5) = IRQ_PRIORITY_SCI5;
+ IPR(SCI5, TXI5) = IRQ_PRIORITY_SCI5;
+ IPR(ICU,GROUPBL0) = IRQ_PRIORITY_SCI5;
+ IEN(SCI5, RXI5) = 1;
+ IEN(SCI5, TXI5) = 1;
+ IEN(ICU,GROUPBL0) = 1;
+ EN(SCI5, TEI5) = 1;
+
+ /* setup USBI0 interrupt. */
+ IR(USB0, USBI0) = 0;
+ IPR(USB0, USBI0) = IRQ_PRIORITY_USBI0;
+}
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+
+void board_led_write(bool state)
+{
+ PORTD.PODR.BIT.B6 = state ? 0 : 1;
+}
+
+uint32_t board_button_read(void)
+{
+ return PORTB.PIDR.BIT.B1 ? 0 : 1;
+}
+
+int board_uart_read(uint8_t* buf, int len)
+{
+ sci_buf[1].buf = buf;
+ sci_buf[1].cnt = len;
+ SCI5.SCR.BYTE |= SCI_SCR_RE | SCI_SCR_RIE;
+ while (SCI5.SCR.BIT.RE) ;
+ return len - sci_buf[1].cnt;
+}
+
+int board_uart_write(void const *buf, int len)
+{
+ sci_buf[0].buf = (uint8_t*)buf;
+ sci_buf[0].cnt = len;
+ SCI5.SCR.BYTE |= SCI_SCR_TE | SCI_SCR_TIE;
+ while (SCI5.SCR.BIT.TE) ;
+ return len;
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+void INT_Excep_CMT0_CMI0(void)
+{
+ ++system_ticks;
+}
+
+uint32_t board_millis(void)
+{
+ return system_ticks;
+}
+#else
+uint32_t SystemCoreClock = 120000000;
+#endif
+
+int close(int fd)
+{
+ (void)fd;
+ return -1;
+}
+int fstat(int fd, void *pstat)
+{
+ (void)fd;
+ (void)pstat;
+ return 0;
+}
+off_t lseek(int fd, off_t pos, int whence)
+{
+ (void)fd;
+ (void)pos;
+ (void)whence;
+ return 0;
+}
+int isatty(int fd)
+{
+ (void)fd;
+ return 1;
+}
diff --git a/hw/bsp/rx/family.mk b/hw/bsp/rx/family.mk
new file mode 100644
index 000000000..5a8281718
--- /dev/null
+++ b/hw/bsp/rx/family.mk
@@ -0,0 +1,32 @@
+DEPS_SUBMODULES += hw/mcu/renesas/rx
+
+# Cross Compiler for RX
+CROSS_COMPILE = rx-elf-
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+CFLAGS += \
+ -nostartfiles \
+ -ffunction-sections \
+ -fdata-sections \
+ -fshort-enums \
+ -mlittle-endian-data \
+ -DSSIZE_MAX=__INT_MAX__
+
+SRC_C += \
+ src/portable/renesas/usba/dcd_usba.c \
+ $(MCU_DIR)/vects.c
+
+INC += \
+ $(TOP)/$(BOARD_PATH) \
+ $(TOP)/$(MCU_DIR)
+
+SRC_S += $(MCU_DIR)/start.S
+
+$(BUILD)/$(PROJECT).mot: $(BUILD)/$(PROJECT).elf
+ @echo CREATE $@
+ $(OBJCOPY) -O srec -I elf32-rx-be-ns $^ $@
+
+# flash using rfp-cli
+flash-rfp: $(BUILD)/$(PROJECT).mot
+ rfp-cli -device rx65x -tool e2l -if fine -fo id FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -auth id FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -auto $^
diff --git a/hw/bsp/rx63n/boards/gr_citrus/board.mk b/hw/bsp/rx63n/boards/gr_citrus/board.mk
deleted file mode 100644
index feab5b5e6..000000000
--- a/hw/bsp/rx63n/boards/gr_citrus/board.mk
+++ /dev/null
@@ -1,61 +0,0 @@
-DEPS_SUBMODULES += hw/mcu/renesas/rx
-
-CFLAGS += \
- -nostartfiles \
- -ffunction-sections \
- -fdata-sections \
- -fshort-enums \
- -mcpu=rx610 \
- -misa=v1 \
- -mlittle-endian-data \
- -DCFG_TUSB_MCU=OPT_MCU_RX63X
-
-# Cross Compiler for RX
-CROSS_COMPILE = rx-elf-
-
-RX_NEWLIB ?= 1
-
-ifeq ($(CMDEXE),1)
-OPTLIBINC="$(shell for /F "usebackq delims=" %%i in (`where rx-elf-gcc`) do echo %%~dpi..\rx-elf\optlibinc)"
-else
-OPTLIBINC=$(shell dirname `which rx-elf-gcc`)../rx-elf/optlibinc
-endif
-
-ifeq ($(RX_NEWLIB),1)
-CFLAGS += -DSSIZE_MAX=__INT_MAX__
-else
-# setup for optlib
-CFLAGS += -nostdinc \
- -isystem $(OPTLIBINC) \
- -DLWIP_NO_INTTYPES_H
-
-LIBS += -loptc -loptm
-endif
-
-MCU_DIR = hw/mcu/renesas/rx/rx63n
-
-# All source paths should be relative to the top level.
-LD_FILE = $(BOARD_PATH)/r5f5631fd.ld
-
-SRC_C += \
- src/portable/renesas/usba/dcd_usba.c \
- $(MCU_DIR)/vects.c
-
-INC += \
- $(TOP)/$(BOARD_PATH) \
- $(TOP)/$(MCU_DIR)
-
-SRC_S += $(MCU_DIR)/start.S
-
-# For freeRTOS port source
-FREERTOS_PORT = RX600
-
-# For flash-jlink target
-JLINK_DEVICE = R5F5631F
-JLINK_IF = JTAG
-
-# For flash-pyocd target
-PYOCD_TARGET =
-
-# flash using jlink
-flash: flash-jlink
diff --git a/hw/bsp/rx63n/family.mk b/hw/bsp/rx63n/family.mk
deleted file mode 100644
index d3c743ed1..000000000
--- a/hw/bsp/rx63n/family.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(TOP)/$(BOARD_PATH)/board.mk \ No newline at end of file
diff --git a/hw/bsp/saml22/family.mk b/hw/bsp/saml22/family.mk
deleted file mode 100644
index fbe4e66f8..000000000
--- a/hw/bsp/saml22/family.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-UF2_FAMILY_ID = 0x68ed2b88
-DEPS_SUBMODULES += hw/mcu/microchip
-
-include $(TOP)/$(BOARD_PATH)/board.mk
-
-CFLAGS += \
- -mthumb \
- -mabi=aapcs \
- -mcpu=cortex-m0plus \
- -nostdlib -nostartfiles \
- -DCONF_OSC32K_CALIB_ENABLE=0 \
- -DCFG_TUSB_MCU=OPT_MCU_SAML22
-
-SRC_C += \
- src/portable/microchip/samd/dcd_samd.c \
- hw/mcu/microchip/saml22/gcc/gcc/startup_saml22.c \
- hw/mcu/microchip/saml22/gcc/system_saml22.c \
- hw/mcu/microchip/saml22/hpl/gclk/hpl_gclk.c \
- hw/mcu/microchip/saml22/hpl/mclk/hpl_mclk.c \
- hw/mcu/microchip/saml22/hpl/pm/hpl_pm.c \
- hw/mcu/microchip/saml22/hpl/osc32kctrl/hpl_osc32kctrl.c \
- hw/mcu/microchip/saml22/hpl/oscctrl/hpl_oscctrl.c \
- hw/mcu/microchip/saml22/hal/src/hal_atomic.c
-
-INC += \
- $(TOP)/$(BOARD_PATH) \
- $(TOP)/hw/mcu/microchip/saml22/ \
- $(TOP)/hw/mcu/microchip/saml22/config \
- $(TOP)/hw/mcu/microchip/saml22/include \
- $(TOP)/hw/mcu/microchip/saml22/hal/include \
- $(TOP)/hw/mcu/microchip/saml22/hal/utils/include \
- $(TOP)/hw/mcu/microchip/saml22/hpl/port \
- $(TOP)/hw/mcu/microchip/saml22/hri \
- $(TOP)/hw/mcu/microchip/saml22/CMSIS/Core/Include
-
-# For TinyUSB port source
-VENDOR = microchip
-CHIP_FAMILY = samd
-
-# For freeRTOS port source
-FREERTOS_PORT = ARM_CM0
-
-# flash using bossac at least version 1.8
-# can be found in arduino15/packages/arduino/tools/bossac/
-# Add it to your PATH or change BOSSAC variable to match your installation
-BOSSAC = bossac
-
-flash-bossac: $(BUILD)/$(PROJECT).bin
- @:$(call check_defined, SERIAL, example: SERIAL=/dev/ttyACM0)
- $(BOSSAC) --port=$(SERIAL) -U -i --offset=0x2000 -e -w $^ -R
diff --git a/hw/bsp/saml2x/boards/atsaml21_xpro/board.h b/hw/bsp/saml2x/boards/atsaml21_xpro/board.h
new file mode 100644
index 000000000..a3e03997c
--- /dev/null
+++ b/hw/bsp/saml2x/boards/atsaml21_xpro/board.h
@@ -0,0 +1,50 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// LED
+#define LED_PIN (32 + 30) // PB30
+#define LED_STATE_ON 0
+
+// Button
+#define BUTTON_PIN (0 + 15) // PA15
+#define BUTTON_STATE_ACTIVE 0
+
+// UART
+#define UART_RX_PIN 4
+#define UART_TX_PIN 5
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* BOARD_H_ */
diff --git a/hw/bsp/saml2x/boards/atsaml21_xpro/board.mk b/hw/bsp/saml2x/boards/atsaml21_xpro/board.mk
new file mode 100644
index 000000000..81b4ecdcb
--- /dev/null
+++ b/hw/bsp/saml2x/boards/atsaml21_xpro/board.mk
@@ -0,0 +1,12 @@
+CFLAGS += -D__SAML21J18B__
+
+SAML_VARIANT = saml21
+
+# All source paths should be relative to the top level.
+LD_FILE = $(BOARD_PATH)/saml21j18b_flash.ld
+
+# For flash-jlink target
+JLINK_DEVICE = ATSAML21J18
+
+# flash using jlink
+flash: flash-jlink
diff --git a/hw/bsp/saml2x/boards/atsaml21_xpro/saml21j18b_flash.ld b/hw/bsp/saml2x/boards/atsaml21_xpro/saml21j18b_flash.ld
new file mode 100644
index 000000000..7f6b7fa99
--- /dev/null
+++ b/hw/bsp/saml2x/boards/atsaml21_xpro/saml21j18b_flash.ld
@@ -0,0 +1,153 @@
+/**
+ * \file
+ *
+ * \brief Linker script for running in internal FLASH on the SAML21J18B
+ *
+ * Copyright (c) 2016 Atmel Corporation,
+ * a wholly owned subsidiary of Microchip Technology Inc.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the Licence at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * \asf_license_stop
+ *
+ */
+
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+SEARCH_DIR(.)
+
+/* Memory Spaces Definitions */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
+ lpram (rwx) : ORIGIN = 0x30000000, LENGTH = 0x00002000
+}
+
+/* The stack size used by the application. NOTE: you need to adjust according to your application. */
+STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x2000;
+
+/* Section Definitions */
+SECTIONS
+{
+ .text :
+ {
+ . = ALIGN(4);
+ _sfixed = .;
+ KEEP(*(.vectors .vectors.*))
+ *(.text .text.* .gnu.linkonce.t.*)
+ *(.glue_7t) *(.glue_7)
+ *(.rodata .rodata* .gnu.linkonce.r.*)
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+
+ /* Support C constructors, and C destructors in both user code
+ and the C library. This also provides support for C++ code. */
+ . = ALIGN(4);
+ KEEP(*(.init))
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+
+ . = ALIGN(4);
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*crtend.o(.ctors))
+
+ . = ALIGN(4);
+ KEEP(*(.fini))
+
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*crtend.o(.dtors))
+
+ . = ALIGN(4);
+ _efixed = .; /* End of text section */
+ } > rom
+
+ /* .ARM.exidx is sorted, so has to go in its own output section. */
+ PROVIDE_HIDDEN (__exidx_start = .);
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } > rom
+ PROVIDE_HIDDEN (__exidx_end = .);
+
+ . = ALIGN(4);
+ _etext = .;
+
+ .relocate : AT (_etext)
+ {
+ . = ALIGN(4);
+ _srelocate = .;
+ *(.ramfunc .ramfunc.*);
+ *(.data .data.*);
+ . = ALIGN(4);
+ _erelocate = .;
+ } > ram
+
+ .lpram (NOLOAD):
+ {
+ . = ALIGN(8);
+ _slpram = .;
+ *(.lpram .lpram.*);
+ . = ALIGN(8);
+ _elpram = .;
+ } > lpram
+
+ /* .bss section which is used for uninitialized data */
+ .bss (NOLOAD) :
+ {
+ . = ALIGN(4);
+ _sbss = . ;
+ _szero = .;
+ *(.bss .bss.*)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = . ;
+ _ezero = .;
+ end = .;
+ } > ram
+
+ /* stack section */
+ .stack (NOLOAD):
+ {
+ . = ALIGN(8);
+ _sstack = .;
+ . = . + STACK_SIZE;
+ . = ALIGN(8);
+ _estack = .;
+ } > ram
+
+ . = ALIGN(4);
+ _end = . ;
+}
diff --git a/hw/bsp/saml22/boards/saml22_feather/board.h b/hw/bsp/saml2x/boards/saml22_feather/board.h
index 13a326000..13a326000 100644
--- a/hw/bsp/saml22/boards/saml22_feather/board.h
+++ b/hw/bsp/saml2x/boards/saml22_feather/board.h
diff --git a/hw/bsp/saml22/boards/saml22_feather/board.mk b/hw/bsp/saml2x/boards/saml22_feather/board.mk
index a6a773137..0605dca19 100644
--- a/hw/bsp/saml22/boards/saml22_feather/board.mk
+++ b/hw/bsp/saml2x/boards/saml22_feather/board.mk
@@ -1,5 +1,7 @@
CFLAGS += -D__SAML22J18A__
+SAML_VARIANT = saml22
+
# All source paths should be relative to the top level.
LD_FILE = $(BOARD_PATH)/$(BOARD).ld
diff --git a/hw/bsp/saml22/boards/saml22_feather/saml22_feather.ld b/hw/bsp/saml2x/boards/saml22_feather/saml22_feather.ld
index d1aaa44fc..d1aaa44fc 100644
--- a/hw/bsp/saml22/boards/saml22_feather/saml22_feather.ld
+++ b/hw/bsp/saml2x/boards/saml22_feather/saml22_feather.ld
diff --git a/hw/bsp/saml22/boards/sensorwatch_m0/board.h b/hw/bsp/saml2x/boards/sensorwatch_m0/board.h
index 7fc690ab2..7fc690ab2 100644
--- a/hw/bsp/saml22/boards/sensorwatch_m0/board.h
+++ b/hw/bsp/saml2x/boards/sensorwatch_m0/board.h
diff --git a/hw/bsp/saml22/boards/sensorwatch_m0/board.mk b/hw/bsp/saml2x/boards/sensorwatch_m0/board.mk
index a6a773137..0605dca19 100644
--- a/hw/bsp/saml22/boards/sensorwatch_m0/board.mk
+++ b/hw/bsp/saml2x/boards/sensorwatch_m0/board.mk
@@ -1,5 +1,7 @@
CFLAGS += -D__SAML22J18A__
+SAML_VARIANT = saml22
+
# All source paths should be relative to the top level.
LD_FILE = $(BOARD_PATH)/$(BOARD).ld
diff --git a/hw/bsp/saml22/boards/sensorwatch_m0/sensorwatch_m0.ld b/hw/bsp/saml2x/boards/sensorwatch_m0/sensorwatch_m0.ld
index d1aaa44fc..d1aaa44fc 100644
--- a/hw/bsp/saml22/boards/sensorwatch_m0/sensorwatch_m0.ld
+++ b/hw/bsp/saml2x/boards/sensorwatch_m0/sensorwatch_m0.ld
diff --git a/hw/bsp/saml22/family.c b/hw/bsp/saml2x/family.c
index fff11cbe5..470fde750 100644
--- a/hw/bsp/saml22/family.c
+++ b/hw/bsp/saml2x/family.c
@@ -108,13 +108,13 @@ void board_init(void)
gpio_set_pin_function(PIN_PA25, PINMUX_PA25G_USB_DP);
// Output 500hz PWM on PB23 (TCC0 WO[3]) so we can validate the GCLK1 clock speed
- hri_mclk_set_APBCMASK_TCC0_bit(MCLK);
- TCC0->PER.bit.PER = 48000000 / 1000;
- TCC0->CC[3].bit.CC = 48000000 / 2000;
- TCC0->CTRLA.bit.ENABLE = true;
-
- gpio_set_pin_function(PIN_PB23, PINMUX_PB23F_TCC0_WO3);
- hri_gclk_write_PCHCTRL_reg(GCLK, TCC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN);
+// hri_mclk_set_APBCMASK_TCC0_bit(MCLK);
+// TCC0->PER.bit.PER = 48000000 / 1000;
+// TCC0->CC[3].bit.CC = 48000000 / 2000;
+// TCC0->CTRLA.bit.ENABLE = true;
+//
+// gpio_set_pin_function(PIN_PB23, PINMUX_PB23F_TCC0_WO3);
+// hri_gclk_write_PCHCTRL_reg(GCLK, TCC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN);
}
//--------------------------------------------------------------------+
@@ -160,4 +160,4 @@ uint32_t board_millis(void)
void _init(void)
{
-} \ No newline at end of file
+}
diff --git a/hw/bsp/saml2x/family.mk b/hw/bsp/saml2x/family.mk
new file mode 100644
index 000000000..e0f6b2f77
--- /dev/null
+++ b/hw/bsp/saml2x/family.mk
@@ -0,0 +1,48 @@
+UF2_FAMILY_ID = 0x68ed2b88
+DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/microchip
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+MCU_DIR = hw/mcu/microchip/$(SAML_VARIANT)
+
+CFLAGS += \
+ -mthumb \
+ -mabi=aapcs \
+ -mcpu=cortex-m0plus \
+ -nostdlib -nostartfiles \
+ -DCONF_OSC32K_CALIB_ENABLE=0 \
+ -DCFG_TUSB_MCU=OPT_MCU_SAML22
+
+SRC_C += \
+ src/portable/microchip/samd/dcd_samd.c \
+ $(MCU_DIR)/gcc/gcc/startup_$(SAML_VARIANT).c \
+ $(MCU_DIR)/gcc/system_$(SAML_VARIANT).c \
+ $(MCU_DIR)/hpl/gclk/hpl_gclk.c \
+ $(MCU_DIR)/hpl/mclk/hpl_mclk.c \
+ $(MCU_DIR)/hpl/pm/hpl_pm.c \
+ $(MCU_DIR)/hpl/osc32kctrl/hpl_osc32kctrl.c \
+ $(MCU_DIR)/hpl/oscctrl/hpl_oscctrl.c \
+ $(MCU_DIR)/hal/src/hal_atomic.c
+
+INC += \
+ $(TOP)/$(BOARD_PATH) \
+ $(TOP)/$(MCU_DIR)/ \
+ $(TOP)/$(MCU_DIR)/config \
+ $(TOP)/$(MCU_DIR)/include \
+ $(TOP)/$(MCU_DIR)/hal/include \
+ $(TOP)/$(MCU_DIR)/hal/utils/include \
+ $(TOP)/$(MCU_DIR)/hpl/port \
+ $(TOP)/$(MCU_DIR)/hri \
+ $(TOP)/lib/CMSIS_5/CMSIS/Core/Include
+
+# For freeRTOS port source
+FREERTOS_PORT = ARM_CM0
+
+# flash using bossac at least version 1.8
+# can be found in arduino15/packages/arduino/tools/bossac/
+# Add it to your PATH or change BOSSAC variable to match your installation
+BOSSAC = bossac
+
+flash-bossac: $(BUILD)/$(PROJECT).bin
+ @:$(call check_defined, SERIAL, example: SERIAL=/dev/ttyACM0)
+ $(BOSSAC) --port=$(SERIAL) -U -i --offset=0x2000 -e -w $^ -R
diff --git a/hw/mcu/microchip b/hw/mcu/microchip
-Subproject f7087f04783c896627061fc151fa3527b73733c
+Subproject 58eb3763200ff51a998be5f537acf67299add22
diff --git a/hw/mcu/renesas/rx b/hw/mcu/renesas/rx
-Subproject 4a51dfe6ecdf936d2d89f223f069e24a2d10920
+Subproject 706b4e0cf485605c32351e2f90f569826799602
diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h
index 936f09104..f99061eae 100644
--- a/src/class/audio/audio.h
+++ b/src/class/audio/audio.h
@@ -489,7 +489,7 @@ typedef enum
AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT = (uint32_t) (1 << 2),
AUDIO_DATA_FORMAT_TYPE_I_ALAW = (uint32_t) (1 << 3),
AUDIO_DATA_FORMAT_TYPE_I_MULAW = (uint32_t) (1 << 4),
- AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x100000000,
+ AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x80000000,
} audio_data_format_type_I_t;
/// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification
@@ -823,6 +823,33 @@ typedef struct TU_ATTR_PACKED
uint16_t wLockDelay ; ///< Indicates the time it takes this endpoint to reliably lock its internal clock recovery circuitry. Units used depend on the value of the bLockDelayUnits field.
} audio_desc_cs_as_iso_data_ep_t;
+// 5.2.2 Control Request Layout
+typedef struct TU_ATTR_PACKED
+{
+ union
+ {
+ struct TU_ATTR_PACKED
+ {
+ uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
+ uint8_t type : 2; ///< Request type tusb_request_type_t.
+ uint8_t direction : 1; ///< Direction type. tusb_dir_t
+ } bmRequestType_bit;
+
+ uint8_t bmRequestType;
+ };
+
+ uint8_t bRequest; ///< Request type audio_cs_req_t
+ uint8_t bChannelNumber;
+ uint8_t bControlSelector;
+ union
+ {
+ uint8_t bInterface;
+ uint8_t bEndpoint;
+ };
+ uint8_t bEntityID;
+ uint16_t wLength;
+} audio_control_request_t;
+
//// 5.2.3 Control Request Parameter Block Layout
// 5.2.3.1 1-byte Control CUR Parameter Block
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index 8e4420ed0..404d28817 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -102,19 +102,19 @@
// EP IN software buffers and mutexes
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO
#endif
#endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO
#endif
#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO
#endif
@@ -126,32 +126,32 @@ osal_mutex_def_t ep_in_ff_mutex_wr_3;
// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0
-CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0
-CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX];
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0
-CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
#endif
#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
// EP OUT software buffers and mutexes
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO
#endif
#endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO
#endif
#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO
#endif
@@ -163,52 +163,52 @@ osal_mutex_def_t ep_out_ff_mutex_rd_3;
// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0
-CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX];
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0
-CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX];
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0
-CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
#endif
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
// Control buffers
-CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
#if CFG_TUD_AUDIO > 1
-CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
#endif
#if CFG_TUD_AUDIO > 2
-CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
#endif
// Active alternate setting of interfaces
-CFG_TUSB_MEM_ALIGN uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
+uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
-CFG_TUSB_MEM_ALIGN uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
+uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
-CFG_TUSB_MEM_ALIGN uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
+uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
#endif
// Software encoding/decoding support FIFOs
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ];
tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
#endif
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ];
tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
#endif
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ];
tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
@@ -218,21 +218,21 @@ osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ];
tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
#endif
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ];
tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
#endif
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ];
tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
@@ -294,7 +294,7 @@ typedef struct
// Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74)
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
- CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE];
+ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE];
#endif
// Decoding parameters - parameters are set when alternate AS interface is set by host
@@ -393,12 +393,12 @@ static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio);
#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf);
-#endif
static inline uint8_t tu_desc_subtype(void const* desc)
{
return ((uint8_t const*) desc)[2];
}
+#endif
bool tud_audio_n_mounted(uint8_t func_id)
{
@@ -643,7 +643,6 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u
// Determine amount of samples
uint8_t const n_ff_used = audio->n_ff_used_rx;
- uint16_t const nBytesToCopy = audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx;
uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used;
uint8_t cnt_ff;
@@ -662,14 +661,14 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u
info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin);
src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx];
dst_end = info.ptr_lin + info.len_lin;
- src = audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, info.ptr_lin, dst_end, src, n_ff_used);
+ src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_lin, dst_end, src, n_ff_used);
// Handle wrapped part of FIFO
info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap);
if (info.len_wrap != 0)
{
dst_end = info.ptr_wrap + info.len_wrap;
- audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, info.ptr_wrap, dst_end, src, n_ff_used);
+ audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_wrap, dst_end, src, n_ff_used);
}
tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
}
@@ -885,7 +884,7 @@ range [-1, +1)
* */
// Helper function
-static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, void * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used)
+static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, uint8_t * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used)
{
// Optimize for fast half word copies
typedef struct{
@@ -900,15 +899,15 @@ static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const
switch (nBytesToCopy)
{
case 1:
- while((uint8_t *)src < src_end)
+ while(src < src_end)
{
- *dst = *(uint8_t *)src++;
+ *dst = *src++;
dst += n_ff_used;
}
break;
case 2:
- while((uint8_t *)src < src_end)
+ while(src < src_end)
{
*(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src;
src += 2;
@@ -917,23 +916,23 @@ static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const
break;
case 3:
- while((uint8_t *)src < src_end)
+ while(src < src_end)
{
// memcpy(dst, src, 3);
// src = (uint8_t *)src + 3;
// dst += 3 * n_ff_used;
// TODO: Is there a faster way to copy 3 bytes?
- *dst++ = *(uint8_t *)src++;
- *dst++ = *(uint8_t *)src++;
- *dst++ = *(uint8_t *)src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
dst += 3 * (n_ff_used - 1);
}
break;
case 4:
- while((uint8_t *)src < src_end)
+ while(src < src_end)
{
*(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src;
src += 4;
@@ -993,8 +992,8 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
if (info.len_lin != 0)
{
info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); // Limit up to desired length
- src_end = info.ptr_lin + info.len_lin;
- dst = audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, info.ptr_lin, src_end, dst, n_ff_used);
+ src_end = (uint8_t *)info.ptr_lin + info.len_lin;
+ dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_lin, src_end, dst, n_ff_used);
// Limit up to desired length
info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap);
@@ -1002,8 +1001,8 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
// Handle wrapped part of FIFO
if (info.len_wrap != 0)
{
- src_end = info.ptr_wrap + info.len_wrap;
- audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, info.ptr_wrap, src_end, dst, n_ff_used);
+ src_end = (uint8_t *)info.ptr_wrap + info.len_wrap;
+ audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_wrap, src_end, dst, n_ff_used);
}
tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
@@ -1481,18 +1480,20 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
audio->ep_in_as_intf_num = 0;
usbd_edpt_close(rhport, audio->ep_in);
- // Invoke callback - can be used to stop data sampling
- if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
-
- audio->ep_in = 0; // Necessary?
-
- // Clear support FIFOs if used
-#if CFG_TUD_AUDIO_ENABLE_ENCODING
+ // Clear FIFOs, since data is no longer valid
+#if !CFG_TUD_AUDIO_ENABLE_ENCODING
+ tu_fifo_clear(&audio->ep_in_ff);
+#else
for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
{
tu_fifo_clear(&audio->tx_supp_ff[cnt]);
}
#endif
+
+ // Invoke callback - can be used to stop data sampling
+ if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
+
+ audio->ep_in = 0; // Necessary?
}
#endif
@@ -1502,16 +1503,22 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
{
audio->ep_out_as_intf_num = 0;
usbd_edpt_close(rhport, audio->ep_out);
- audio->ep_out = 0; // Necessary?
- // Clear support FIFOs if used
-#if CFG_TUD_AUDIO_ENABLE_DECODING
+ // Clear FIFOs, since data is no longer valid
+#if !CFG_TUD_AUDIO_ENABLE_DECODING
+ tu_fifo_clear(&audio->ep_out_ff);
+#else
for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
{
tu_fifo_clear(&audio->rx_supp_ff[cnt]);
}
#endif
+ // Invoke callback - can be used to stop data sampling
+ if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
+
+ audio->ep_out = 0; // Necessary?
+
// Close corresponding feedback EP
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
usbd_edpt_close(rhport, audio->ep_fb);
@@ -1605,9 +1612,17 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff );
#endif
#endif
+
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+ // In case of asynchronous EP, call Cb after ep_fb is set
+ if (!(((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.sync == 0x01 && audio->ep_fb == 0))
+ {
+ if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
+ }
+#else
// Invoke callback
if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
-
+#endif
// Prepare for incoming data
#if USE_LINEAR_BUFFER_RX
TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
@@ -1621,8 +1636,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
{
audio->ep_fb = ep_addr;
- // Invoke callback
- if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
+ // Invoke callback after ep_out is set
+ if (audio->ep_out != 0)
+ {
+ if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
+ }
}
#endif
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
@@ -1658,64 +1676,65 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const
switch (p_request->bmRequestType_bit.recipient)
{
- case TUSB_REQ_RCPT_INTERFACE: ; // The semicolon is there to enable a declaration right after the label
-
- uint8_t itf = TU_U16_LOW(p_request->wIndex);
- uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
-
- if (entityID != 0)
+ case TUSB_REQ_RCPT_INTERFACE:
{
- if (tud_audio_set_req_entity_cb)
+ uint8_t itf = TU_U16_LOW(p_request->wIndex);
+ uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+ if (entityID != 0)
{
- // Check if entity is present and get corresponding driver index
- TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
+ if (tud_audio_set_req_entity_cb)
+ {
+ // Check if entity is present and get corresponding driver index
+ TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
- // Invoke callback
- return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
+ // Invoke callback
+ return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
+ }
+ else
+ {
+ TU_LOG2(" No entity set request callback available!\r\n");
+ return false; // In case no callback function is present or request can not be conducted we stall it
+ }
}
else
{
- TU_LOG2(" No entity set request callback available!\r\n");
- return false; // In case no callback function is present or request can not be conducted we stall it
+ if (tud_audio_set_req_itf_cb)
+ {
+ // Find index of audio driver structure and verify interface really exists
+ TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+
+ // Invoke callback
+ return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
+ }
+ else
+ {
+ TU_LOG2(" No interface set request callback available!\r\n");
+ return false; // In case no callback function is present or request can not be conducted we stall it
+ }
}
}
- else
+ break;
+
+ case TUSB_REQ_RCPT_ENDPOINT:
{
- if (tud_audio_set_req_itf_cb)
+ uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+ if (tud_audio_set_req_ep_cb)
{
- // Find index of audio driver structure and verify interface really exists
- TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+ // Check if entity is present and get corresponding driver index
+ TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
// Invoke callback
- return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
+ return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
}
else
{
- TU_LOG2(" No interface set request callback available!\r\n");
- return false; // In case no callback function is present or request can not be conducted we stall it
+ TU_LOG2(" No EP set request callback available!\r\n");
+ return false; // In case no callback function is present or request can not be conducted we stall it
}
}
-
break;
-
- case TUSB_REQ_RCPT_ENDPOINT: ; // The semicolon is there to enable a declaration right after the label
-
- uint8_t ep = TU_U16_LOW(p_request->wIndex);
-
- if (tud_audio_set_req_ep_cb)
- {
- // Check if entity is present and get corresponding driver index
- TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
-
- // Invoke callback
- return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
- }
- else
- {
- TU_LOG2(" No EP set request callback available!\r\n");
- return false; // In case no callback function is present or request can not be conducted we stall it
- }
-
// Unknown/Unsupported recipient
default: TU_BREAKPOINT(); return false;
}
@@ -1754,73 +1773,75 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const
// Conduct checks which depend on the recipient
switch (p_request->bmRequestType_bit.recipient)
{
- case TUSB_REQ_RCPT_INTERFACE: ; // The semicolon is there to enable a declaration right after the label
-
- uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
-
- // Verify if entity is present
- if (entityID != 0)
+ case TUSB_REQ_RCPT_INTERFACE:
{
- // Find index of audio driver structure and verify entity really exists
- TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
+ uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
- // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
- if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
+ // Verify if entity is present
+ if (entityID != 0)
{
- if (tud_audio_get_req_entity_cb)
+ // Find index of audio driver structure and verify entity really exists
+ TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
+
+ // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
+ if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
{
- return tud_audio_get_req_entity_cb(rhport, p_request);
+ if (tud_audio_get_req_entity_cb)
+ {
+ return tud_audio_get_req_entity_cb(rhport, p_request);
+ }
+ else
+ {
+ TU_LOG2(" No entity get request callback available!\r\n");
+ return false; // Stall
+ }
}
- else
+ }
+ else
+ {
+ // Find index of audio driver structure and verify interface really exists
+ TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+
+ // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
+ if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
{
- TU_LOG2(" No entity get request callback available!\r\n");
- return false; // Stall
+ if (tud_audio_get_req_itf_cb)
+ {
+ return tud_audio_get_req_itf_cb(rhport, p_request);
+ }
+ else
+ {
+ TU_LOG2(" No interface get request callback available!\r\n");
+ return false; // Stall
+ }
}
}
}
- else
+ break;
+
+ case TUSB_REQ_RCPT_ENDPOINT:
{
- // Find index of audio driver structure and verify interface really exists
- TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+ uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+ // Find index of audio driver structure and verify EP really exists
+ TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
{
- if (tud_audio_get_req_itf_cb)
+ if (tud_audio_get_req_ep_cb)
{
- return tud_audio_get_req_itf_cb(rhport, p_request);
+ return tud_audio_get_req_ep_cb(rhport, p_request);
}
else
{
- TU_LOG2(" No interface get request callback available!\r\n");
- return false; // Stall
+ TU_LOG2(" No EP get request callback available!\r\n");
+ return false; // Stall
}
}
}
break;
- case TUSB_REQ_RCPT_ENDPOINT: ; // The semicolon is there to enable a declaration right after the label
-
- uint8_t ep = TU_U16_LOW(p_request->wIndex);
-
- // Find index of audio driver structure and verify EP really exists
- TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
-
- // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
- if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
- {
- if (tud_audio_get_req_ep_cb)
- {
- return tud_audio_get_req_ep_cb(rhport, p_request);
- }
- else
- {
- TU_LOG2(" No EP get request callback available!\r\n");
- return false; // Stall
- }
- }
- break;
-
// Unknown/Unsupported recipient
default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
}
@@ -1913,8 +1934,12 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
{
if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport));
- // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent
- return audiod_fb_send(rhport, &_audiod_fct[func_id]);
+ // Schedule a transmit with the new value if EP is not busy
+ if (!usbd_edpt_busy(rhport, _audiod_fct[func_id].ep_fb))
+ {
+ // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent
+ return audiod_fb_send(rhport, &_audiod_fct[func_id]);
+ }
}
#endif
#endif
@@ -1935,29 +1960,31 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req
// Conduct checks which depend on the recipient
switch (p_request->bmRequestType_bit.recipient)
{
- case TUSB_REQ_RCPT_INTERFACE: ; // The semicolon is there to enable a declaration right after the label
-
- uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
-
- // Verify if entity is present
- if (entityID != 0)
- {
- // Find index of audio driver structure and verify entity really exists
- TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
- }
- else
+ case TUSB_REQ_RCPT_INTERFACE:
{
- // Find index of audio driver structure and verify interface really exists
- TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+ uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+ // Verify if entity is present
+ if (entityID != 0)
+ {
+ // Find index of audio driver structure and verify entity really exists
+ TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
+ }
+ else
+ {
+ // Find index of audio driver structure and verify interface really exists
+ TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+ }
}
break;
- case TUSB_REQ_RCPT_ENDPOINT: ; // The semicolon is there to enable a declaration right after the label
-
- uint8_t ep = TU_U16_LOW(p_request->wIndex);
+ case TUSB_REQ_RCPT_ENDPOINT:
+ {
+ uint8_t ep = TU_U16_LOW(p_request->wIndex);
- // Find index of audio driver structure and verify EP really exists
- TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
+ // Find index of audio driver structure and verify EP really exists
+ TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
+ }
break;
// Unknown/Unsupported recipient
@@ -1992,15 +2019,17 @@ static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio
while (p_desc < p_desc_end)
{
// We assume the number of alternate settings is increasing thus we return the index of alternate setting zero!
- if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf)
+ if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0)
{
- *idxItf = tmp;
- *pp_desc_int = p_desc;
- return true;
+ if (((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf)
+ {
+ *idxItf = tmp;
+ *pp_desc_int = p_desc;
+ return true;
+ }
+ // Increase index, bytes read, and pointer
+ tmp++;
}
-
- // Increase index, bytes read, and pointer
- tmp++;
p_desc = tu_desc_next(p_desc);
}
}
@@ -2137,10 +2166,10 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const *
if (as_itf == audio->ep_in_as_intf_num)
{
audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels;
- audio->format_type_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType;
+ audio->format_type_tx = (audio_format_type_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType);
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
- audio->format_type_I_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats;
+ audio->format_type_I_tx = (audio_data_format_type_I_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats);
#endif
}
#endif
@@ -2202,22 +2231,19 @@ bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
// Format the feedback value
- if (_audiod_fct[func_id].rhport == 0)
- {
- uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].fb_val;
+#if !TUD_OPT_HIGH_SPEED
+ uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].fb_val;
- // For FS format is 10.14
- *(fb++) = (feedback >> 2) & 0xFF;
- *(fb++) = (feedback >> 10) & 0xFF;
- *(fb++) = (feedback >> 18) & 0xFF;
- // 4th byte is needed to work correctly with MS Windows
- *fb = 0;
- }
- else
- {
- // For HS format is 16.16 as originally demanded
- _audiod_fct[func_id].fb_val = feedback;
- }
+ // For FS format is 10.14
+ *(fb++) = (feedback >> 2) & 0xFF;
+ *(fb++) = (feedback >> 10) & 0xFF;
+ *(fb++) = (feedback >> 18) & 0xFF;
+ // 4th byte is needed to work correctly with MS Windows
+ *fb = 0;
+#else
+ // For HS format is 16.16 as originally demanded
+ _audiod_fct[func_id].fb_val = feedback;
+#endif
// Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
if (!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb))
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c
index a926081cc..68080c61d 100644
--- a/src/class/cdc/cdc_device.c
+++ b/src/class/cdc/cdc_device.c
@@ -273,9 +273,6 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass &&
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass, 0);
- // Note: 0xFF can be used with RNDIS
- TU_VERIFY(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA), 0);
-
// Find available interface
cdcd_interface_t * p_cdc = NULL;
for(uint8_t cdc_id=0; cdc_id<CFG_TUD_CDC; cdc_id++)
@@ -303,10 +300,11 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
{
- // notification endpoint if any
- TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 );
+ // notification endpoint
+ tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
- p_cdc->ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
+ TU_ASSERT( usbd_edpt_open(rhport, desc_ep), 0 );
+ p_cdc->ep_notif = desc_ep->bEndpointAddress;
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index 33f1a8ad3..fc7100e81 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -149,29 +149,27 @@ void cdch_init(void)
tu_memclr(cdch_data, sizeof(cdch_data_t)*CFG_TUSB_HOST_DEVICE_MAX);
}
-bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
+uint16_t cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
{
- // Only support ACM
- TU_VERIFY( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass);
+ (void) max_len;
- // Only support AT commands, no protocol and vendor specific commands.
- TU_VERIFY(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
- 0xff == itf_desc->bInterfaceProtocol);
+ // Only support ACM subclass
+ // Protocol 0xFF can be RNDIS device for windows XP
+ TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass &&
+ CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass &&
+ 0xFF != itf_desc->bInterfaceProtocol, 0);
- uint8_t const * p_desc;
- cdch_data_t * p_cdc;
-
- p_desc = tu_desc_next(itf_desc);
- p_cdc = get_itf(dev_addr);
+ cdch_data_t * p_cdc = get_itf(dev_addr);
- p_cdc->itf_num = itf_desc->bInterfaceNumber;
- p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; // TODO 0xff is consider as rndis candidate, other is virtual Com
+ p_cdc->itf_num = itf_desc->bInterfaceNumber;
+ p_cdc->itf_protocol = itf_desc->bInterfaceProtocol;
//------------- Communication Interface -------------//
- (*p_length) = sizeof(tusb_desc_interface_t);
+ uint16_t drv_len = tu_desc_len(itf_desc);
+ uint8_t const * p_desc = tu_desc_next(itf_desc);
// Communication Functional Descriptors
- while( TUSB_DESC_CS_INTERFACE == p_desc[DESC_OFFSET_TYPE] )
+ while( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len )
{
if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) )
{
@@ -179,52 +177,52 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it
p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities;
}
- (*p_length) += p_desc[DESC_OFFSET_LEN];
+ drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
}
- if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE])
+ if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
{
// notification endpoint
- tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) p_desc;
+ tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
- TU_ASSERT( usbh_edpt_open(rhport, dev_addr, ep_desc) );
- p_cdc->ep_notif = ep_desc->bEndpointAddress;
+ TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep), 0 );
+ p_cdc->ep_notif = desc_ep->bEndpointAddress;
- (*p_length) += p_desc[DESC_OFFSET_LEN];
+ drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
}
//------------- Data Interface (if any) -------------//
- if ( (TUSB_DESC_INTERFACE == p_desc[DESC_OFFSET_TYPE]) &&
+ if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
(TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
{
- (*p_length) += p_desc[DESC_OFFSET_LEN];
+ // next to endpoint descriptor
+ drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
// data endpoints expected to be in pairs
for(uint32_t i=0; i<2; i++)
{
- tusb_desc_endpoint_t const *ep_desc = (tusb_desc_endpoint_t const *) p_desc;
- TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType);
- TU_ASSERT(TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
+ tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
+ TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer, 0);
- TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc));
+ TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep), 0);
- if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
+ if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN )
{
- p_cdc->ep_in = ep_desc->bEndpointAddress;
+ p_cdc->ep_in = desc_ep->bEndpointAddress;
}else
{
- p_cdc->ep_out = ep_desc->bEndpointAddress;
+ p_cdc->ep_out = desc_ep->bEndpointAddress;
}
- (*p_length) += p_desc[DESC_OFFSET_LEN];
+ drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next( p_desc );
}
}
- return true;
+ return drv_len;
}
bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num)
diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h
index 6ff392709..edcd258a8 100644
--- a/src/class/cdc/cdc_host.h
+++ b/src/class/cdc/cdc_host.h
@@ -121,11 +121,11 @@ void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_i
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
-void cdch_init(void);
-bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length);
-bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num);
-bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
-void cdch_close(uint8_t dev_addr);
+void cdch_init (void);
+uint16_t cdch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
+bool cdch_set_config (uint8_t dev_addr, uint8_t itf_num);
+bool cdch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+void cdch_close (uint8_t dev_addr);
#ifdef __cplusplus
}
diff --git a/src/class/dfu/dfu_device.c b/src/class/dfu/dfu_device.c
index 81045ff7b..c696d70a2 100644
--- a/src/class/dfu/dfu_device.c
+++ b/src/class/dfu/dfu_device.c
@@ -247,7 +247,7 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_reque
static uint16_t dfu_req_upload(uint8_t rhport, tusb_control_request_t const * request, uint16_t block_num, uint16_t wLength)
{
- TU_VERIFY( wLength <= CFG_TUD_DFU_TRANSFER_BUFFER_SIZE);
+ TU_VERIFY( wLength <= CFG_TUD_DFU_TRANSFER_BUFFER_SIZE, 0);
uint16_t retval = tud_dfu_req_upload_data_cb(block_num, (uint8_t *)_dfu_state_ctx.transfer_buf, wLength);
tud_control_xfer(rhport, request, _dfu_state_ctx.transfer_buf, retval);
return retval;
@@ -276,6 +276,7 @@ static void dfu_req_dnload_setup(uint8_t rhport, tusb_control_request_t const *
// if they wish, there still will be the internal control buffer copy to this buffer
// but this mode would provide zero copy from the class driver to the application
+ TU_VERIFY( request->wLength <= CFG_TUD_DFU_TRANSFER_BUFFER_SIZE, );
// setup for data phase
tud_control_xfer(rhport, request, _dfu_state_ctx.transfer_buf, request->wLength);
}
@@ -283,6 +284,7 @@ static void dfu_req_dnload_setup(uint8_t rhport, tusb_control_request_t const *
static void dfu_req_dnload_reply(uint8_t rhport, tusb_control_request_t const * request)
{
(void) rhport;
+ TU_VERIFY( request->wLength <= CFG_TUD_DFU_TRANSFER_BUFFER_SIZE, );
tud_dfu_req_dnload_data_cb(request->wValue, (uint8_t *)_dfu_state_ctx.transfer_buf, request->wLength);
_dfu_state_ctx.blk_transfer_in_proc = false;
}
diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c
index e44f282c4..a10e3a5e3 100644
--- a/src/class/hid/hid_device.c
+++ b/src/class/hid/hid_device.c
@@ -280,7 +280,21 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
uint8_t const report_type = tu_u16_high(request->wValue);
uint8_t const report_id = tu_u16_low(request->wValue);
- uint16_t xferlen = tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, p_hid->epin_buf, request->wLength);
+ uint8_t* report_buf = p_hid->epin_buf;
+ uint16_t req_len = request->wLength;
+
+ uint16_t xferlen = 0;
+
+ // If host request a specific Report ID, add ID to as 1 byte of response
+ if ( (report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1) )
+ {
+ *report_buf++ = report_id;
+ req_len--;
+
+ xferlen++;
+ }
+
+ xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len);
TU_ASSERT( xferlen > 0 );
tud_control_xfer(rhport, request, p_hid->epin_buf, xferlen);
@@ -298,7 +312,17 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
uint8_t const report_type = tu_u16_high(request->wValue);
uint8_t const report_id = tu_u16_low(request->wValue);
- tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, p_hid->epout_buf, request->wLength);
+ uint8_t const* report_buf = p_hid->epout_buf;
+ uint16_t report_len = request->wLength;
+
+ // If host request a specific Report ID, extract report ID in buffer before invoking callback
+ if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) )
+ {
+ report_buf++;
+ report_len--;
+ }
+
+ tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len);
}
break;
diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c
index cde5e23a5..40b6f5631 100644
--- a/src/class/hid/hid_host.c
+++ b/src/class/hid/hid_host.c
@@ -37,16 +37,6 @@
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
-/*
- "KEYBOARD" : in_len=8 , out_len=1, usage_page=0x01, usage=0x06 # Generic Desktop, Keyboard
- "MOUSE" : in_len=4 , out_len=0, usage_page=0x01, usage=0x02 # Generic Desktop, Mouse
- "CONSUMER" : in_len=2 , out_len=0, usage_page=0x0C, usage=0x01 # Consumer, Consumer Control
- "SYS_CONTROL" : in_len=1 , out_len=0, usage_page=0x01, usage=0x80 # Generic Desktop, Sys Control
- "GAMEPAD" : in_len=6 , out_len=0, usage_page=0x01, usage=0x05 # Generic Desktop, Game Pad
- "DIGITIZER" : in_len=5 , out_len=0, usage_page=0x0D, usage=0x02 # Digitizers, Pen
- "XAC_COMPATIBLE_GAMEPAD" : in_len=3 , out_len=0, usage_page=0x01, usage=0x05 # Generic Desktop, Game Pad
- "RAW" : in_len=64, out_len=0, usage_page=0xFFAF, usage=0xAF # Vendor 0xFFAF "Adafruit", 0xAF
- */
typedef struct
{
uint8_t itf_num;
@@ -108,7 +98,7 @@ uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance)
return hid_itf->itf_protocol;
}
-bool tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance)
+uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance)
{
hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
return hid_itf->protocol_mode;
@@ -253,33 +243,37 @@ void hidh_close(uint8_t dev_addr)
// Enumeration
//--------------------------------------------------------------------+
-static bool config_get_protocol (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+static bool config_set_protocol (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
static bool config_get_report_desc (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
static bool config_get_report_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
-bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t *p_length)
+uint16_t hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
{
- TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass);
+ (void) max_len;
+
+ TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0);
+ uint16_t drv_len = sizeof(tusb_desc_interface_t);
uint8_t const *p_desc = (uint8_t const *) desc_itf;
//------------- HID descriptor -------------//
p_desc = tu_desc_next(p_desc);
tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc;
- TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType);
+ TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType, 0);
// not enough interface, try to increase CFG_TUH_HID
// TODO multiple devices
hidh_device_t* hid_dev = get_dev(dev_addr);
- TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID);
+ TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID, 0);
//------------- Endpoint Descriptor -------------//
+ drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
- TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
+ TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType, 0);
// TODO also open endpoint OUT
- TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep) );
+ TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep), 0 );
hidh_interface_t* hid_itf = get_instance(dev_addr, hid_dev->inst_count);
hid_dev->inst_count++;
@@ -292,12 +286,13 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
hid_itf->report_desc_type = desc_hid->bReportType;
hid_itf->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength);
- hid_itf->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode
+ // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config
+ hid_itf->protocol_mode = HID_PROTOCOL_BOOT;
if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) hid_itf->itf_protocol = desc_itf->bInterfaceProtocol;
- *p_length = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
+ drv_len += desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
- return true;
+ return drv_len;
}
bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
@@ -324,43 +319,49 @@ bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
.wLength = 0
};
- TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? config_get_protocol : config_get_report_desc) );
+ TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? config_set_protocol : config_get_report_desc) );
return true;
}
-static bool config_get_protocol(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+// Force device to work in BOOT protocol
+static bool config_set_protocol(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
{
- // Stall is a valid response for SET_IDLE GET_PROTOCOL, therefore we could ignore its result
+ // Stall is a valid response for SET_IDLE, therefore we could ignore its result
(void) result;
uint8_t const itf_num = (uint8_t) request->wIndex;
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
- TU_LOG2("HID Get Protocol\r\n");
+ TU_LOG2("HID Set Protocol\r\n");
+ hid_itf->protocol_mode = HID_PROTOCOL_BOOT;
tusb_control_request_t const new_request =
{
.bmRequestType_bit =
{
.recipient = TUSB_REQ_RCPT_INTERFACE,
.type = TUSB_REQ_TYPE_CLASS,
- .direction = TUSB_DIR_IN
+ .direction = TUSB_DIR_OUT
},
- .bRequest = HID_REQ_CONTROL_GET_PROTOCOL,
- .wValue = 0,
+ .bRequest = HID_REQ_CONTROL_SET_PROTOCOL,
+ .wValue = HID_PROTOCOL_BOOT,
.wIndex = hid_itf->itf_num,
- .wLength = 1
+ .wLength = 0
};
- TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, &hid_itf->protocol_mode, config_get_report_desc) );
- return false;
+ TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, config_get_report_desc) );
+ return true;
}
static bool config_get_report_desc(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
{
- // Stall is a valid response for SET_IDLE GET_PROTOCOL, therefore we could ignore its result
- (void) result;
+ // We can be here after SET_IDLE or SET_PROTOCOL (boot device)
+ // Trigger assert if result is not successful with set protocol
+ if ( request->bRequest != HID_REQ_CONTROL_SET_IDLE )
+ {
+ TU_ASSERT(result == XFER_RESULT_SUCCESS);
+ }
uint8_t const itf_num = (uint8_t) request->wIndex;
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
@@ -368,7 +369,7 @@ static bool config_get_report_desc(uint8_t dev_addr, tusb_control_request_t cons
// Get Report Descriptor
// using usbh enumeration buffer since report descriptor can be very long
- TU_ASSERT( hid_itf->report_desc_len <= CFG_TUH_ENUMERATION_BUFSZIE );
+ TU_ASSERT( hid_itf->report_desc_len <= CFG_TUH_ENUMERATION_BUFSIZE );
TU_LOG2("HID Get Report Descriptor\r\n");
tusb_control_request_t const new_request =
@@ -452,9 +453,9 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr,
uint8_t const data8 = desc_report[0];
- TU_LOG2("tag = %d, type = %d, size = %d, data = ", tag, type, size);
- for(uint32_t i=0; i<size; i++) TU_LOG2("%02X ", desc_report[i]);
- TU_LOG2("\r\n");
+ TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size);
+ for(uint32_t i=0; i<size; i++) TU_LOG(3, "%02X ", desc_report[i]);
+ TU_LOG(3, "\r\n");
switch(type)
{
diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h
index 2e4cce600..ef203123d 100644
--- a/src/class/hid/hid_host.h
+++ b/src/class/hid/hid_host.h
@@ -66,9 +66,10 @@ bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance);
// Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values
uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance);
-// Get current active protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
-// Note: as HID spec, device will be initialized in Report mode
-bool tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance);
+// Get current protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
+// Note: Device will be initialized in Boot protocol for simplicity.
+// Application can use set_protocol() to switch back to Report protocol.
+uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance);
// Set protocol to HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
// This function is only supported by Boot interface (tuh_n_hid_interface_protocol() != NONE)
@@ -118,11 +119,11 @@ TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t ins
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
-void hidh_init(void);
-bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t *p_length);
-bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num);
-bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
-void hidh_close(uint8_t dev_addr);
+void hidh_init (void);
+uint16_t hidh_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
+bool hidh_set_config (uint8_t dev_addr, uint8_t itf_num);
+bool hidh_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+void hidh_close (uint8_t dev_addr);
#ifdef __cplusplus
}
diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c
index 953ca26e6..c39e03976 100644
--- a/src/class/midi/midi_device.c
+++ b/src/class/midi/midi_device.c
@@ -197,9 +197,11 @@ uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, ui
bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4])
{
- midid_interface_t* p_midi = &_midid_itf[itf];
- uint32_t num_read = tu_fifo_read_n(&p_midi->rx_ff, packet, 4);
- _prep_out_transaction(p_midi);
+ midid_interface_t* midi = &_midid_itf[itf];
+ TU_VERIFY(midi->ep_out);
+
+ uint32_t const num_read = tu_fifo_read_n(&midi->rx_ff, packet, 4);
+ _prep_out_transaction(midi);
return (num_read == 4);
}
@@ -234,19 +236,19 @@ static uint32_t write_flush(midid_interface_t* midi)
uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize)
{
midid_interface_t* midi = &_midid_itf[itf];
- TU_VERIFY(midi->itf_num, 0);
+ TU_VERIFY(midi->ep_in, 0);
midid_stream_t* stream = &midi->stream_write;
- uint32_t total_written = 0;
uint32_t i = 0;
- while ( i < bufsize )
+ while ( (i < bufsize) && (tu_fifo_remaining(&midi->tx_ff) >= 4) )
{
uint8_t const data = buffer[i];
+ i++;
if ( stream->index == 0 )
{
- // new event packet
+ //------------- New event packet -------------//
uint8_t const msg = data >> 4;
@@ -308,9 +310,9 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
}
else
{
- // On-going (buffering) packet
+ //------------- On-going (buffering) packet -------------//
- TU_ASSERT(stream->index < 4, total_written);
+ TU_ASSERT(stream->index < 4, i);
stream->buffer[stream->index] = data;
stream->index++;
@@ -333,27 +335,20 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
// complete current event packet, reset stream
stream->index = stream->total = 0;
- // fifo overflow, here we assume FIFO is multiple of 4 and didn't check remaining before writing
- if ( count != 4 ) break;
-
- // updated written if succeeded
- total_written = i;
+ // FIFO overflown, since we already check fifo remaining. It is probably race condition
+ TU_ASSERT(count == 4, i);
}
-
- i++;
}
write_flush(midi);
- return total_written;
+ return i;
}
bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4])
{
midid_interface_t* midi = &_midid_itf[itf];
- if (midi->itf_num == 0) {
- return 0;
- }
+ TU_VERIFY(midi->ep_in);
if (tu_fifo_remaining(&midi->tx_ff) < 4) return false;
@@ -435,6 +430,7 @@ uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint
}
p_midi->itf_num = desc_midi->bInterfaceNumber;
+ (void) p_midi->itf_num;
// next descriptor
drv_len += tu_desc_len(p_desc);
diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c
index 7f13b4891..014e8b69e 100644
--- a/src/class/msc/msc_device.c
+++ b/src/class/msc/msc_device.c
@@ -37,6 +37,10 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
+
+// Can be selectively disabled to reduce logging when troubleshooting other driver
+#define MSC_DEBUG 2
+
enum
{
MSC_STAGE_CMD = 0,
@@ -99,7 +103,7 @@ static inline uint16_t rdwr10_get_blockcount(uint8_t const command[])
//--------------------------------------------------------------------+
#if CFG_TUSB_DEBUG >= 2
-static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] =
+TU_ATTR_UNUSED static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] =
{
{ .key = SCSI_CMD_TEST_UNIT_READY , .data = "Test Unit Ready" },
{ .key = SCSI_CMD_INQUIRY , .data = "Inquiry" },
@@ -114,7 +118,7 @@ static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] =
{ .key = SCSI_CMD_WRITE_10 , .data = "Write10" }
};
-static tu_lookup_table_t const _msc_scsi_cmd_table =
+TU_ATTR_UNUSED static tu_lookup_table_t const _msc_scsi_cmd_table =
{
.count = TU_ARRAY_SIZE(_msc_scsi_cmd_lookup),
.items = _msc_scsi_cmd_lookup
@@ -232,8 +236,8 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
TU_ASSERT( event == XFER_RESULT_SUCCESS &&
xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE );
- TU_LOG2(" SCSI Command: %s\r\n", tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
- // TU_LOG2_MEM(p_cbw, xferred_bytes, 2);
+ TU_LOG(MSC_DEBUG, " SCSI Command: %s\r\n", tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
+ // TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2);
p_csw->signature = MSC_CSW_SIGNATURE;
p_csw->tag = p_cbw->tag;
@@ -305,8 +309,8 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
break;
case MSC_STAGE_DATA:
- TU_LOG2(" SCSI Data\r\n");
- //TU_LOG2_MEM(_mscd_buf, xferred_bytes, 2);
+ TU_LOG(MSC_DEBUG, " SCSI Data\r\n");
+ //TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2);
// OUT transfer, invoke callback if needed
if ( !tu_bit_test(p_cbw->dir, 7) )
@@ -402,8 +406,8 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
// Wait for the Status phase to complete
if( (ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t)) )
{
- TU_LOG2(" SCSI Status: %u\r\n", p_csw->status);
- // TU_LOG2_MEM(p_csw, xferred_bytes, 2);
+ TU_LOG(MSC_DEBUG, " SCSI Status: %u\r\n", p_csw->status);
+ // TU_LOG_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2);
// Invoke complete callback if defined
// Note: There is racing issue with samd51 + qspi flash testing with arduino
diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c
index 7f98ef9b1..2c027deff 100644
--- a/src/class/msc/msc_host.c
+++ b/src/class/msc/msc_host.c
@@ -360,18 +360,22 @@ static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* c
static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
-bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t *p_length)
+uint16_t msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
{
TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass &&
MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol);
+ // msc driver length is fixed
+ uint16_t const drv_len = sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
+ TU_ASSERT(drv_len <= max_len, 0);
+
msch_interface_t* p_msc = get_itf(dev_addr);
tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(desc_itf);
for(uint32_t i=0; i<2; i++)
{
- TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
- TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc));
+ TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer, 0);
+ TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc), 0);
if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
{
@@ -385,9 +389,8 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
}
p_msc->itf_num = desc_itf->bInterfaceNumber;
- (*p_length) += sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
- return true;
+ return drv_len;
}
bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)
diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h
index ce4fe64dc..9e4217ba5 100644
--- a/src/class/msc/msc_host.h
+++ b/src/class/msc/msc_host.h
@@ -41,13 +41,6 @@
#define CFG_TUH_MSC_MAXLUN 4
#endif
-
-/** \addtogroup ClassDriver_MSC
- * @{
- * \defgroup MSC_Host Host
- * The interface API includes status checking function, data transferring function and callback functions
- * @{ */
-
typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
//--------------------------------------------------------------------+
@@ -113,17 +106,14 @@ TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr);
// Internal Class Driver API
//--------------------------------------------------------------------+
-void msch_init(void);
-bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t *p_length);
-bool msch_set_config(uint8_t dev_addr, uint8_t itf_num);
-bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
-void msch_close(uint8_t dev_addr);
+void msch_init (void);
+uint16_t msch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
+bool msch_set_config (uint8_t dev_addr, uint8_t itf_num);
+bool msch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+void msch_close (uint8_t dev_addr);
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_MSC_HOST_H_ */
-
-/// @}
-/// @}
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h
index 889ad7b25..c8a66a879 100644
--- a/src/common/tusb_common.h
+++ b/src/common/tusb_common.h
@@ -123,7 +123,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4k (uint32_t value) { retur
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); }
//------------- Mathematics -------------//
-TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_abs(int32_t value) { return (uint32_t)((value < 0) ? (-value) : value); }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return (v + d -1)/d; }
/// inclusive range checking TODO remove
TU_ATTR_ALWAYS_INLINE static inline bool tu_within(uint32_t lower, uint32_t value, uint32_t upper)
@@ -305,11 +305,11 @@ void tu_print_var(uint8_t const* buf, uint32_t bufsize)
}
// Log with Level
-#define TU_LOG(n, ...) TU_LOG##n(__VA_ARGS__)
-#define TU_LOG_MEM(n, ...) TU_LOG##n##_MEM(__VA_ARGS__)
-#define TU_LOG_VAR(n, ...) TU_LOG##n##_VAR(__VA_ARGS__)
-#define TU_LOG_INT(n, ...) TU_LOG##n##_INT(__VA_ARGS__)
-#define TU_LOG_HEX(n, ...) TU_LOG##n##_HEX(__VA_ARGS__)
+#define TU_LOG(n, ...) TU_XSTRCAT(TU_LOG, n)(__VA_ARGS__)
+#define TU_LOG_MEM(n, ...) TU_XSTRCAT3(TU_LOG, n, _MEM)(__VA_ARGS__)
+#define TU_LOG_VAR(n, ...) TU_XSTRCAT3(TU_LOG, n, _VAR)(__VA_ARGS__)
+#define TU_LOG_INT(n, ...) TU_XSTRCAT3(TU_LOG, n, _INT)(__VA_ARGS__)
+#define TU_LOG_HEX(n, ...) TU_XSTRCAT3(TU_LOG, n, _HEX)(__VA_ARGS__)
#define TU_LOG_LOCATION() tu_printf("%s: %d:\r\n", __PRETTY_FUNCTION__, __LINE__)
#define TU_LOG_FAILED() tu_printf("%s: %d: Failed\r\n", __PRETTY_FUNCTION__, __LINE__)
@@ -317,8 +317,8 @@ void tu_print_var(uint8_t const* buf, uint32_t bufsize)
#define TU_LOG1 tu_printf
#define TU_LOG1_MEM tu_print_mem
#define TU_LOG1_VAR(_x) tu_print_var((uint8_t const*)(_x), sizeof(*(_x)))
-#define TU_LOG1_INT(_x) tu_printf(#_x " = %ld\n", (uint32_t) (_x) )
-#define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\n", (uint32_t) (_x) )
+#define TU_LOG1_INT(_x) tu_printf(#_x " = %ld\r\n", (uint32_t) (_x) )
+#define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\r\n", (uint32_t) (_x) )
// Log Level 2: Warn
#if CFG_TUSB_DEBUG >= 2
@@ -373,6 +373,14 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3
#endif
// TODO replace all TU_LOGn with TU_LOG(n)
+
+#define TU_LOG0(...)
+#define TU_LOG0_MEM(...)
+#define TU_LOG0_VAR(...)
+#define TU_LOG0_INT(...)
+#define TU_LOG0_HEX(...)
+
+
#ifndef TU_LOG1
#define TU_LOG1(...)
#define TU_LOG1_MEM(...)
diff --git a/src/common/tusb_compiler.h b/src/common/tusb_compiler.h
index 679060b20..0dd9ba016 100644
--- a/src/common/tusb_compiler.h
+++ b/src/common/tusb_compiler.h
@@ -32,10 +32,14 @@
#ifndef _TUSB_COMPILER_H_
#define _TUSB_COMPILER_H_
-#define TU_STRING(x) #x ///< stringify without expand
-#define TU_XSTRING(x) TU_STRING(x) ///< expand then stringify
-#define TU_STRCAT(a, b) a##b ///< concat without expand
-#define TU_XSTRCAT(a, b) TU_STRCAT(a, b) ///< expand then concat
+#define TU_STRING(x) #x ///< stringify without expand
+#define TU_XSTRING(x) TU_STRING(x) ///< expand then stringify
+
+#define TU_STRCAT(a, b) a##b ///< concat without expand
+#define TU_STRCAT3(a, b, c) a##b##c ///< concat without expand
+
+#define TU_XSTRCAT(a, b) TU_STRCAT(a, b) ///< expand then concat
+#define TU_XSTRCAT3(a, b, c) TU_STRCAT3(a, b, c) ///< expand then concat 3 tokens
#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
#define _TU_COUNTER_ __COUNTER__
@@ -83,6 +87,10 @@
#define TU_BSWAP16(u16) (__builtin_bswap16(u16))
#define TU_BSWAP32(u32) (__builtin_bswap32(u32))
+ // List of obsolete callback function that is renamed and should not be defined.
+ // Put it here since only gcc support this pragma
+ #pragma GCC poison tud_vendor_control_request_cb
+
#elif defined(__TI_COMPILER_VERSION__)
#define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes)))
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c
index 1eb886aa1..73217cf75 100644
--- a/src/common/tusb_fifo.c
+++ b/src/common/tusb_fifo.c
@@ -325,7 +325,7 @@ static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
// We are exploiting the wrap around to the correct index
// TODO warning: assuming signed overflow does not occur when assuming that (X + c) < X is always false [-Wstrict-overflow]
- if ((p > p + offset) || (p + offset > f->max_pointer_idx))
+ if ((p > (uint16_t)(p + offset)) || ((uint16_t)(p + offset) > f->max_pointer_idx))
{
p = (p + offset) + f->non_used_index_space;
}
@@ -342,7 +342,7 @@ static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
// We limit the index space of p such that a correct wrap around happens
// Check for a wrap around or if we are in unused index space - This has to be checked first!!
// We are exploiting the wrap around to the correct index
- if ((p < p - offset) || (p - offset > f->max_pointer_idx))
+ if ((p < (uint16_t)(p - offset)) || ((uint16_t)(p - offset) > f->max_pointer_idx))
{
p = (p - offset) - f->non_used_index_space;
}
diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h
index cf299269d..18db289a1 100644
--- a/src/common/tusb_fifo.h
+++ b/src/common/tusb_fifo.h
@@ -86,8 +86,8 @@ typedef struct
.depth = _depth, \
.item_size = sizeof(_type), \
.overwritable = _overwritable, \
- .max_pointer_idx = 2*(_depth)-1, \
.non_used_index_space = UINT16_MAX - (2*(_depth)-1), \
+ .max_pointer_idx = 2*(_depth)-1, \
}
#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \
@@ -120,9 +120,9 @@ bool tu_fifo_peek (tu_fifo_t* f, void * p_buffer);
uint16_t tu_fifo_peek_n (tu_fifo_t* f, void * p_buffer, uint16_t n);
uint16_t tu_fifo_count (tu_fifo_t* f);
+uint16_t tu_fifo_remaining (tu_fifo_t* f);
bool tu_fifo_empty (tu_fifo_t* f);
bool tu_fifo_full (tu_fifo_t* f);
-uint16_t tu_fifo_remaining (tu_fifo_t* f);
bool tu_fifo_overflowed (tu_fifo_t* f);
void tu_fifo_correct_read_pointer (tu_fifo_t* f);
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
index 542809899..56ba8bcd1 100644
--- a/src/common/tusb_verify.h
+++ b/src/common/tusb_verify.h
@@ -75,7 +75,7 @@
#if CFG_TUSB_DEBUG
#include <stdio.h>
#define _MESS_ERR(_err) tu_printf("%s %d: failed, error = %s\r\n", __func__, __LINE__, tusb_strerr[_err])
- #define _MESS_FAILED() tu_printf("%s %d: assert failed\r\n", __func__, __LINE__)
+ #define _MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__)
#else
#define _MESS_ERR(_err) do {} while (0)
#define _MESS_FAILED() do {} while (0)
diff --git a/src/device/usbd.c b/src/device/usbd.c
index 2935defd0..af4fd58c4 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -1243,7 +1243,7 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
- TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
+ TU_LOG2(" Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes);
// Attempt to transfer on a busy endpoint, sound like an race condition !
TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0);
@@ -1254,14 +1254,13 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
if ( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) )
{
- TU_LOG2("OK\r\n");
return true;
}else
{
// DCD error, mark endpoint as ready to allow next transfer
_usbd_dev.ep_status[epnum][dir].busy = false;
_usbd_dev.ep_status[epnum][dir].claimed = 0;
- TU_LOG2("failed\r\n");
+ TU_LOG2("FAILED\r\n");
TU_BREAKPOINT();
return false;
}
diff --git a/src/device/usbd.h b/src/device/usbd.h
index 0a0f0bf00..2de6a5cfd 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -542,6 +542,11 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\
TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_interval*/ 1)\
+// Calculate wMaxPacketSize of Endpoints
+#define TUD_AUDIO_EP_SIZE(_maxFrequency, _nBytesPerSample, _nChannels) \
+ ((((_maxFrequency + ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 7999 : 999)) / ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 8000 : 1000)) + 1) * _nBytesPerSample * _nChannels)
+
+
//------------- TUD_USBTMC/USB488 -------------//
#define TUD_USBTMC_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC)
#define TUD_USBTMC_APP_SUBCLASS 0x03u
diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c
index 724c652e6..7a8244699 100644
--- a/src/device/usbd_control.c
+++ b/src/device/usbd_control.c
@@ -186,6 +186,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result
{
TU_VERIFY(_ctrl_xfer.buffer);
memcpy(_ctrl_xfer.buffer, _usbd_ctrl_buf, xferred_bytes);
+ TU_LOG_MEM(2, _usbd_ctrl_buf, xferred_bytes, 2);
}
_ctrl_xfer.total_xferred += xferred_bytes;
diff --git a/src/host/hub.c b/src/host/hub.c
index b2761184d..2ead5bed1 100644
--- a/src/host/hub.c
+++ b/src/host/hub.c
@@ -144,29 +144,32 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_con
//--------------------------------------------------------------------+
void hub_init(void)
{
- tu_memclr(hub_data, CFG_TUSB_HOST_DEVICE_MAX*sizeof( hub_interface_t));
+ tu_memclr(hub_data, CFG_TUSB_HOST_DEVICE_MAX*sizeof(hub_interface_t));
}
-bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
+uint16_t hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
{
- // not support multiple TT yet
- if ( itf_desc->bInterfaceProtocol > 1 ) return false;
+ // hub driver does not support multiple TT yet
+ TU_VERIFY(TUSB_CLASS_HUB == itf_desc->bInterfaceClass &&
+ 0 == itf_desc->bInterfaceSubClass &&
+ 1 <= itf_desc->bInterfaceProtocol, 0);
- //------------- Open Interrupt Status Pipe -------------//
- tusb_desc_endpoint_t const *ep_desc;
- ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
+ // msc driver length is fixed
+ uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t);
+ TU_ASSERT(drv_len <= max_len, 0);
- TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType);
- TU_ASSERT(TUSB_XFER_INTERRUPT == ep_desc->bmAttributes.xfer);
+ //------------- Interrupt Status endpoint -------------//
+ tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
+
+ TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType &&
+ TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0);
- TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc));
+ TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep));
hub_data[dev_addr-1].itf_num = itf_desc->bInterfaceNumber;
- hub_data[dev_addr-1].ep_in = ep_desc->bEndpointAddress;
-
- (*p_length) = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t);
+ hub_data[dev_addr-1].ep_in = desc_ep->bEndpointAddress;
- return true;
+ return drv_len;
}
void hub_close(uint8_t dev_addr)
diff --git a/src/host/hub.h b/src/host/hub.h
index a5111b8e7..c9ffe4985 100644
--- a/src/host/hub.h
+++ b/src/host/hub.h
@@ -181,11 +181,11 @@ bool hub_status_pipe_queue(uint8_t dev_addr);
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
-void hub_init(void);
-bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length);
-bool hub_set_config(uint8_t dev_addr, uint8_t itf_num);
-bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
-void hub_close(uint8_t dev_addr);
+void hub_init (void);
+uint16_t hub_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
+bool hub_set_config (uint8_t dev_addr, uint8_t itf_num);
+bool hub_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+void hub_close (uint8_t dev_addr);
#ifdef __cplusplus
}
diff --git a/src/host/usbh.c b/src/host/usbh.c
index 59246a663..93621c42a 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -130,7 +130,7 @@ CFG_TUSB_MEM_SECTION usbh_device_t _usbh_devices[CFG_TUSB_HOST_DEVICE_MAX+1];
OSAL_QUEUE_DEF(OPT_MODE_HOST, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t);
static osal_queue_t _usbh_q;
-CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSZIE];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
//------------- Helper Function Prototypes -------------//
static bool enum_new_device(hcd_event_t* event);
@@ -795,6 +795,8 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r
return false;
}
+ TU_ASSERT(tu_desc_type(_usbh_ctrl_buf) == TUSB_DESC_DEVICE);
+
// Reset device again before Set Address
TU_LOG2("Port reset \r\n");
@@ -907,7 +909,7 @@ static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_r
// Use offsetof to avoid pointer to the odd/misaligned address
memcpy(&total_len, (uint8_t*) desc_config + offsetof(tusb_desc_configuration_t, wTotalLength), 2);
- TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSZIE);
+ TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE);
// Get full configuration descriptor
TU_LOG2("Get Configuration Descriptor\r\n");
@@ -938,7 +940,7 @@ static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request
// Parse configuration & set up drivers
// Driver open aren't allowed to make any usb transfer yet
- parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf);
+ TU_ASSERT( parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf) );
TU_LOG2("Set Configuration = %d\r\n", CONFIG_NUM);
tusb_control_request_t const new_request =
@@ -982,55 +984,61 @@ static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t co
static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg)
{
usbh_device_t* dev = &_usbh_devices[dev_addr];
- uint8_t const* p_desc = (uint8_t const*) desc_cfg;
- p_desc = tu_desc_next(p_desc);
+
+ uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
+ uint8_t const* p_desc = tu_desc_next(desc_cfg);
// parse each interfaces
- while( p_desc < _usbh_ctrl_buf + desc_cfg->wTotalLength )
+ while( p_desc < desc_end )
{
- // skip until we see interface descriptor
- if ( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) )
+ // TODO Do we need to use IAD
+ // tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL;
+
+ // Class will always starts with Interface Association (if any) and then Interface descriptor
+ if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
{
- p_desc = tu_desc_next(p_desc); // skip the descriptor, increase by the descriptor's length
- }else
+ // desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc;
+ p_desc = tu_desc_next(p_desc);
+ }
+
+ TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) );
+
+ tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
+ uint16_t const remaining_len = desc_end-p_desc;
+
+ // Check if class is supported TODO drop class_code
+ uint8_t drv_id;
+ for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
{
- tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
+ if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break;
+ }
- // Check if class is supported
- uint8_t drv_id;
- for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
- {
- if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break;
- }
+ if( drv_id >= USBH_CLASS_DRIVER_COUNT )
+ {
+ // skip unsupported class
+ p_desc = tu_desc_next(p_desc);
+ }
+ else
+ {
+ usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
- if( drv_id >= USBH_CLASS_DRIVER_COUNT )
+ // Interface number must not be used already TODO alternate interface
+ TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff );
+ dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id;
+
+ if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0)
{
- // skip unsupported class
+ // TODO Attach hub to Hub is not currently supported
+ // skip this interface
p_desc = tu_desc_next(p_desc);
}
else
{
- usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
-
- // Interface number must not be used already TODO alternate interface
- TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff );
- dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id;
+ TU_LOG2("%s open\r\n", driver->name);
- if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0)
- {
- // TODO Attach hub to Hub is not currently supported
- // skip this interface
- p_desc = tu_desc_next(p_desc);
- }
- else
- {
- TU_LOG2("%s open\r\n", driver->name);
-
- uint16_t itf_len = 0;
- TU_ASSERT( driver->open(dev->rhport, dev_addr, desc_itf, &itf_len) );
- TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) );
- p_desc += itf_len;
- }
+ uint16_t const itf_len = driver->open(dev->rhport, dev_addr, desc_itf, remaining_len);
+ TU_ASSERT( sizeof(tusb_desc_interface_t) <= itf_len && itf_len <= remaining_len);
+ p_desc += itf_len;
}
}
}
diff --git a/src/host/usbh_classdriver.h b/src/host/usbh_classdriver.h
index 07480fe8e..0736fefa1 100644
--- a/src/host/usbh_classdriver.h
+++ b/src/host/usbh_classdriver.h
@@ -45,11 +45,11 @@ typedef struct {
uint8_t class_code;
- void (* const init )(void);
- bool (* const open )(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t* outlen);
- bool (* const set_config )(uint8_t dev_addr, uint8_t itf_num);
- bool (* const xfer_cb )(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
- void (* const close )(uint8_t dev_addr);
+ void (* const init )(void);
+ uint16_t (* const open )(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+ bool (* const set_config )(uint8_t dev_addr, uint8_t itf_num);
+ bool (* const xfer_cb )(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+ void (* const close )(uint8_t dev_addr);
} usbh_class_driver_t;
// Call by class driver to tell USBH that it has complete the enumeration
diff --git a/src/host/usbh_control.c b/src/host/usbh_control.c
index 4dbf8592a..0bdb66fb5 100644
--- a/src/host/usbh_control.c
+++ b/src/host/usbh_control.c
@@ -50,7 +50,7 @@ typedef struct
static usbh_control_xfer_t _ctrl_xfer;
//CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN
-//static uint8_t _tuh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSZIE];
+//static uint8_t _tuh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
@@ -68,7 +68,7 @@ bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request,
_ctrl_xfer.stage = STAGE_SETUP;
_ctrl_xfer.complete_cb = complete_cb;
- TU_LOG2("Control Setup: ");
+ TU_LOG2("Control Setup (addr = %u): ", dev_addr);
TU_LOG2_VAR(request);
TU_LOG2("\r\n");
@@ -119,7 +119,7 @@ bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t resu
if (request->wLength)
{
- TU_LOG2("Control data:\r\n");
+ TU_LOG2("Control data (addr = %u):\r\n", dev_addr);
TU_LOG2_MEM(_ctrl_xfer.buffer, request->wLength, 2);
}
diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c
index 13e56453d..577bd0e05 100644
--- a/src/portable/microchip/samd/dcd_samd.c
+++ b/src/portable/microchip/samd/dcd_samd.c
@@ -29,7 +29,7 @@
#if TUSB_OPT_DEVICE_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_SAMD11 || CFG_TUSB_MCU == OPT_MCU_SAMD21 || \
CFG_TUSB_MCU == OPT_MCU_SAMD51 || CFG_TUSB_MCU == OPT_MCU_SAME5X || \
- CFG_TUSB_MCU == OPT_MCU_SAML22)
+ CFG_TUSB_MCU == OPT_MCU_SAML22 || CFG_TUSB_MCU == OPT_MCU_SAML21)
#include "sam.h"
#include "device/dcd.h"
@@ -125,7 +125,7 @@ void dcd_int_disable(uint8_t rhport)
}
#elif CFG_TUSB_MCU == OPT_MCU_SAMD11 || CFG_TUSB_MCU == OPT_MCU_SAMD21 || \
- CFG_TUSB_MCU == OPT_MCU_SAML22
+ CFG_TUSB_MCU == OPT_MCU_SAML22 || CFG_TUSB_MCU == OPT_MCU_SAML21
void dcd_int_enable(uint8_t rhport)
{
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index 977ec6cdb..5f4fe08ad 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -108,13 +108,21 @@ static inline uint32_t NVIC_GetEnableIRQ(IRQn_Type IRQn)
}
#endif
+// check if we are in ISR
+TU_ATTR_ALWAYS_INLINE static inline bool is_in_isr(void)
+{
+ return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) ? true : false;
+}
+
// helper to start DMA
+// TODO use Cortex M4 LDREX and STREX command (atomic) to have better mutex access to EasyDMA
+// since current implementation does not 100% guarded against race condition
static void edpt_dma_start(volatile uint32_t* reg_startep)
{
// Only one dma can be active
if ( _dcd.dma_pending )
{
- if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk)
+ if (is_in_isr())
{
// Called within ISR, use usbd task to defer later
usbd_defer_func( (osal_task_func_t) edpt_dma_start, (void*) reg_startep, true );
@@ -159,6 +167,17 @@ static void edpt_dma_end(void)
_dcd.dma_pending = 0;
}
+// helper to set TASKS_EP0STATUS / TASKS_EP0RCVOUT since they also need EasyDMA
+// However TASKS_EP0STATUS doesn't trigger any DMA transfer and got ENDED event subsequently
+// Therefore dma_running state will be corrected right away
+void start_ep0_task(volatile uint32_t* reg_task)
+{
+ edpt_dma_start(reg_task);
+
+ // correct the dma_running++ in dma start
+ if (_dcd.dma_pending) _dcd.dma_pending--;
+}
+
// helper getting td
static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir)
{
@@ -407,21 +426,18 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
if ( control_status )
{
- // Status Phase also requires Easy DMA has to be available as well !!!!
- // However TASKS_EP0STATUS doesn't trigger any DMA transfer and got ENDED event subsequently
- // Therefore dma_running state will be corrected right away
- edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS);
- if (_dcd.dma_pending) _dcd.dma_pending--; // correct the dma_running++ in dma start
+ // Status Phase also requires EasyDMA has to be available as well !!!!
+ start_ep0_task(&NRF_USBD->TASKS_EP0STATUS);
// The nRF doesn't interrupt on status transmit so we queue up a success response.
- dcd_event_xfer_complete(0, ep_addr, 0, XFER_RESULT_SUCCESS, false);
+ dcd_event_xfer_complete(0, ep_addr, 0, XFER_RESULT_SUCCESS, is_in_isr());
}
else if ( dir == TUSB_DIR_OUT )
{
if ( epnum == 0 )
{
- // Accept next Control Out packet
- NRF_USBD->TASKS_EP0RCVOUT = 1;
+ // Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
+ start_ep0_task(&NRF_USBD->TASKS_EP0RCVOUT);
}else
{
if ( xfer->data_received )
@@ -581,12 +597,6 @@ void dcd_int_handler(uint8_t rhport)
}
}
- if ( int_status & EDPT_END_ALL_MASK )
- {
- // DMA complete move data from SRAM -> Endpoint
- edpt_dma_end();
- }
-
// Setup tokens are specific to the Control endpoint.
if ( int_status & USBD_INTEN_EP0SETUP_Msk )
{
@@ -607,6 +617,12 @@ void dcd_int_handler(uint8_t rhport)
}
}
+ if ( int_status & EDPT_END_ALL_MASK )
+ {
+ // DMA complete move data from SRAM -> Endpoint
+ edpt_dma_end();
+ }
+
//--------------------------------------------------------------------+
/* Control/Bulk/Interrupt (CBI) Transfer
*
@@ -655,8 +671,15 @@ void dcd_int_handler(uint8_t rhport)
{
if ( epnum == 0 )
{
- // Accept next Control Out packet
- NRF_USBD->TASKS_EP0RCVOUT = 1;
+ // Accept next Control Out packet. TASKS_EP0RCVOUT also require EasyDMA
+ if ( _dcd.dma_pending )
+ {
+ // use usbd task to defer later
+ usbd_defer_func( (osal_task_func_t) start_ep0_task, (void*) &NRF_USBD->TASKS_EP0RCVOUT, true );
+ }else
+ {
+ start_ep0_task(&NRF_USBD->TASKS_EP0RCVOUT);
+ }
}else
{
// nRF auto accept next Bulk/Interrupt OUT packet
@@ -764,7 +787,7 @@ static bool hfclk_running(void)
#ifdef SOFTDEVICE_PRESENT
if ( is_sd_enabled() )
{
- uint32_t is_running;
+ uint32_t is_running = 0;
(void) sd_clock_hfclk_is_running(&is_running);
return (is_running ? true : false);
}
@@ -973,7 +996,7 @@ void tusb_hal_nrf_power_event (uint32_t event)
hfclk_disable();
- dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) ? true : false);
+ dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, is_in_isr());
}
break;
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index 0048270a6..f78a932f1 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -64,67 +64,48 @@ static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr)
static void _hw_endpoint_alloc(struct hw_endpoint *ep)
{
- uint16_t size = tu_min16(64, ep->wMaxPacketSize);
+ // size must be multiple of 64
+ uint16_t size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
- // Assumes single buffered for now
- ep->hw_data_buf = next_buffer_ptr;
- next_buffer_ptr += size;
- // Bits 0-5 are ignored by the controller so make sure these are 0
- if ((uintptr_t)next_buffer_ptr & 0b111111u)
- {
- // Round up to the next 64
- uint32_t fixptr = (uintptr_t)next_buffer_ptr;
- fixptr &= ~0b111111u;
- fixptr += 64;
- pico_info("Rounding non 64 byte boundary buffer up from %x to %x\n", (uintptr_t)next_buffer_ptr, fixptr);
- next_buffer_ptr = (uint8_t*)fixptr;
- }
- assert(((uintptr_t)next_buffer_ptr & 0b111111u) == 0);
- uint dpram_offset = hw_data_offset(ep->hw_data_buf);
- assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
+ // double buffered for Control and Bulk endpoint
+ if ( ep->transfer_type == TUSB_XFER_CONTROL || ep->transfer_type == TUSB_XFER_BULK)
+ {
+ size *= 2u;
+ }
+
+ ep->hw_data_buf = next_buffer_ptr;
+ next_buffer_ptr += size;
+
+ assert(((uintptr_t )next_buffer_ptr & 0b111111u) == 0);
+ uint dpram_offset = hw_data_offset(ep->hw_data_buf);
+ assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
- pico_info("Alloced %d bytes at offset 0x%x (0x%p) for ep %d %s\n",
- size,
- dpram_offset,
- ep->hw_data_buf,
- ep->num,
- ep_dir_string[ep->in]);
+ pico_info("Alloced %d bytes at offset 0x%x (0x%p) for ep %d %s\n",
+ size,
+ dpram_offset,
+ ep->hw_data_buf,
+ tu_edpt_number(ep->ep_addr),
+ ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
- // Fill in endpoint control register with buffer offset
- uint32_t reg = EP_CTRL_ENABLE_BITS
- | EP_CTRL_INTERRUPT_PER_BUFFER
- | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB)
- | dpram_offset;
+ // Fill in endpoint control register with buffer offset
+ uint32_t const reg = EP_CTRL_ENABLE_BITS | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
- *ep->endpoint_control = reg;
+ *ep->endpoint_control = reg;
}
static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
{
const uint8_t num = tu_edpt_number(ep_addr);
const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+
ep->ep_addr = ep_addr;
+
// For device, IN is a tx transfer and OUT is an rx transfer
ep->rx = (dir == TUSB_DIR_OUT);
+
// Response to a setup packet on EP0 starts with pid of 1
ep->next_pid = num == 0 ? 1u : 0u;
- // Add some checks around the max packet size
- if (transfer_type == TUSB_XFER_ISOCHRONOUS)
- {
- if (wMaxPacketSize > USB_MAX_ISO_PACKET_SIZE)
- {
- panic("Isochronous wMaxPacketSize %d too large", wMaxPacketSize);
- }
- }
- else
- {
- if (wMaxPacketSize > USB_MAX_PACKET_SIZE)
- {
- panic("Isochronous wMaxPacketSize %d too large", wMaxPacketSize);
- }
- }
-
ep->wMaxPacketSize = wMaxPacketSize;
ep->transfer_type = transfer_type;
@@ -164,6 +145,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t
// Now if it hasn't already been done
//alloc a buffer and fill in endpoint control register
+ // TODO device may change configuration (dynamic), should clear and reallocate
if(!(ep->configured))
{
_hw_endpoint_alloc(ep);
@@ -198,10 +180,10 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t b
_hw_endpoint_init(ep, ep_addr, wMaxPacketSize, bmAttributes);
}
-static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool start)
+static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
- _hw_endpoint_xfer(ep, buffer, total_bytes, start);
+ hw_endpoint_xfer_start(ep, buffer, total_bytes);
}
static void hw_handle_buff_status(void)
@@ -213,19 +195,16 @@ static void hw_handle_buff_status(void)
{
if (remaining_buffers & bit)
{
- uint __unused which = (usb_hw->buf_cpu_should_handle & bit) ? 1 : 0;
- // Should be single buffered
- assert(which == 0);
// clear this in advance
usb_hw_clear->buf_status = bit;
// IN transfer for even i, OUT transfer for odd i
struct hw_endpoint *ep = hw_endpoint_get_by_num(i >> 1u, !(i & 1u));
// Continue xfer
- bool done = _hw_endpoint_xfer_continue(ep);
+ bool done = hw_endpoint_xfer_continue(ep);
if (done)
{
// Notify
- dcd_event_xfer_complete(0, ep->ep_addr, ep->len, XFER_RESULT_SUCCESS, true);
+ dcd_event_xfer_complete(0, ep->ep_addr, ep->xferred_len, XFER_RESULT_SUCCESS, true);
hw_endpoint_reset_transfer(ep);
}
remaining_buffers &= ~bit;
@@ -251,7 +230,7 @@ static void ep0_0len_status(void)
{
// Send 0len complete response on EP0 IN
reset_ep0();
- hw_endpoint_xfer(0x80, NULL, 0, true);
+ hw_endpoint_xfer(0x80, NULL, 0);
}
static void _hw_endpoint_stall(struct hw_endpoint *ep)
@@ -339,10 +318,7 @@ static void dcd_rp2040_irq(void)
#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
// Only run enumeration walk-around if pull up is enabled
- if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS )
- {
- rp2040_usb_device_enumeration_fix();
- }
+ if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) rp2040_usb_device_enumeration_fix();
#endif
}
@@ -402,9 +378,9 @@ void dcd_init (uint8_t rhport)
// EP0 always exists so init it now
// EP0 OUT
- hw_endpoint_init(0x0, 64, 0);
+ hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
// EP0 IN
- hw_endpoint_init(0x80, 64, 0);
+ hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
// Initializes the USB peripheral for device mode and enables it.
// Don't need to enable the pull up here. Force VBUS
@@ -470,23 +446,22 @@ void dcd_connect(uint8_t rhport)
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
{
- pico_trace("dcd_edpt0_status_complete %d\n", rhport);
- assert(rhport == 0);
+ (void) rhport;
- if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
- request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
- request->bRequest == TUSB_REQ_SET_ADDRESS)
- {
- pico_trace("Set HW address %d\n", assigned_address);
- usb_hw->dev_addr_ctrl = (uint8_t) request->wValue;
- }
+ if ( request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
+ request->bRequest == TUSB_REQ_SET_ADDRESS )
+ {
+ pico_trace("Set HW address %d\n", request->wValue);
+ usb_hw->dev_addr_ctrl = (uint8_t) request->wValue;
+ }
- reset_ep0();
+ reset_ep0();
}
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
{
- pico_info("dcd_edpt_open %d %02x\n", rhport, desc_edpt->bEndpointAddress);
+ pico_info("dcd_edpt_open %02x\n", desc_edpt->bEndpointAddress);
assert(rhport == 0);
hw_endpoint_init(desc_edpt->bEndpointAddress, desc_edpt->wMaxPacketSize.size, desc_edpt->bmAttributes.xfer);
return true;
@@ -495,21 +470,20 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
assert(rhport == 0);
- // True means start new xfer
- hw_endpoint_xfer(ep_addr, buffer, total_bytes, true);
+ hw_endpoint_xfer(ep_addr, buffer, total_bytes);
return true;
}
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
{
- pico_trace("dcd_edpt_stall %d %02x\n", rhport, ep_addr);
+ pico_trace("dcd_edpt_stall %02x\n", ep_addr);
assert(rhport == 0);
hw_endpoint_stall(ep_addr);
}
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
{
- pico_trace("dcd_edpt_clear_stall %d %02x\n", rhport, ep_addr);
+ pico_trace("dcd_edpt_clear_stall %02x\n", ep_addr);
assert(rhport == 0);
hw_endpoint_clear_stall(ep_addr);
}
@@ -517,9 +491,11 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
{
- // usbd.c says: In progress transfers on this EP may be delivered after this call
- pico_trace("dcd_edpt_close %d %02x\n", rhport, ep_addr);
+ (void) rhport;
+ (void) ep_addr;
+ // usbd.c says: In progress transfers on this EP may be delivered after this call
+ pico_trace("dcd_edpt_close %02x\n", ep_addr);
}
void dcd_int_handler(uint8_t rhport)
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index b575c6afc..40a0805c6 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -52,46 +53,30 @@
static_assert(PICO_USB_HOST_INTERRUPT_ENDPOINTS <= USB_MAX_ENDPOINTS, "");
// Host mode uses one shared endpoint register for non-interrupt endpoint
-struct hw_endpoint eps[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS];
-#define epx (eps[0])
+static struct hw_endpoint ep_pool[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS];
+#define epx (ep_pool[0])
-#define usb_hw_set hw_set_alias(usb_hw)
+#define usb_hw_set hw_set_alias(usb_hw)
#define usb_hw_clear hw_clear_alias(usb_hw)
-// Used for hcd pipe busy.
-// todo still a bit wasteful
-// top bit set if valid
-uint8_t dev_ep_map[CFG_TUSB_HOST_DEVICE_MAX][1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS][2];
-
// Flags we set by default in sie_ctrl (we add other bits on top)
-static uint32_t sie_ctrl_base = USB_SIE_CTRL_SOF_EN_BITS |
- USB_SIE_CTRL_KEEP_ALIVE_EN_BITS |
- USB_SIE_CTRL_PULLDOWN_EN_BITS |
- USB_SIE_CTRL_EP0_INT_1BUF_BITS;
+enum {
+ SIE_CTRL_BASE = USB_SIE_CTRL_SOF_EN_BITS | USB_SIE_CTRL_KEEP_ALIVE_EN_BITS |
+ USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS
+};
static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr)
{
- uint8_t num = tu_edpt_number(ep_addr);
- if (num == 0) {
- return &epx;
- }
- uint8_t in = (ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0;
- uint mapping = dev_ep_map[dev_addr-1][num][in];
- pico_trace("Get dev addr %d ep %d = %d\n", dev_addr, ep_addr, mapping);
- return mapping >= 128 ? eps + (mapping & 0x7fu) : NULL;
-}
+ uint8_t num = tu_edpt_number(ep_addr);
+ if ( num == 0 ) return &epx;
-static void set_dev_ep(uint8_t dev_addr, uint8_t ep_addr, struct hw_endpoint *ep)
-{
- uint8_t num = tu_edpt_number(ep_addr);
- uint8_t in = (ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0;
- uint32_t index = ep - eps;
- hard_assert(index < TU_ARRAY_SIZE(eps));
- // todo revisit why dev_addr can be 0 here
- if (dev_addr) {
- dev_ep_map[dev_addr-1][num][in] = 128u | index;
- }
- pico_trace("Set dev addr %d ep %d = %d\n", dev_addr, ep_addr, index);
+ for ( uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++ )
+ {
+ struct hw_endpoint *ep = &ep_pool[i];
+ if ( ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr) ) return ep;
+ }
+
+ return NULL;
}
static inline uint8_t dev_speed(void)
@@ -111,15 +96,15 @@ static void hw_xfer_complete(struct hw_endpoint *ep, xfer_result_t xfer_result)
// Mark transfer as done before we tell the tinyusb stack
uint8_t dev_addr = ep->dev_addr;
uint8_t ep_addr = ep->ep_addr;
- uint total_len = ep->total_len;
+ uint xferred_len = ep->xferred_len;
hw_endpoint_reset_transfer(ep);
- hcd_event_xfer_complete(dev_addr, ep_addr, total_len, xfer_result, true);
+ hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true);
}
static void _handle_buff_status_bit(uint bit, struct hw_endpoint *ep)
{
usb_hw_clear->buf_status = bit;
- bool done = _hw_endpoint_xfer_continue(ep);
+ bool done = hw_endpoint_xfer_continue(ep);
if (done)
{
hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
@@ -137,6 +122,17 @@ static void hw_handle_buff_status(void)
{
remaining_buffers &= ~bit;
struct hw_endpoint *ep = &epx;
+
+ uint32_t ep_ctrl = *ep->endpoint_control;
+ if (ep_ctrl & EP_CTRL_DOUBLE_BUFFERED_BITS)
+ {
+ TU_LOG(3, "Double Buffered: ");
+ }else
+ {
+ TU_LOG(3, "Single Buffered: ");
+ }
+ TU_LOG_HEX(3, ep_ctrl);
+
_handle_buff_status_bit(bit, ep);
}
@@ -153,7 +149,7 @@ static void hw_handle_buff_status(void)
if (remaining_buffers & bit)
{
remaining_buffers &= ~bit;
- _handle_buff_status_bit(bit, &eps[i]);
+ _handle_buff_status_bit(bit, &ep_pool[i]);
}
}
@@ -165,19 +161,19 @@ static void hw_handle_buff_status(void)
static void hw_trans_complete(void)
{
- struct hw_endpoint *ep = &epx;
- assert(ep->active);
+ struct hw_endpoint *ep = &epx;
+ assert(ep->active);
- if (ep->sent_setup)
- {
- pico_trace("Sent setup packet\n");
- hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
- }
- else
- {
- // Don't care. Will handle this in buff status
- return;
- }
+ if (usb_hw->sie_ctrl & USB_SIE_CTRL_SEND_SETUP_BITS)
+ {
+ pico_trace("Sent setup packet\n");
+ hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
+ }
+ else
+ {
+ // Don't care. Will handle this in buff status
+ return;
+ }
}
static void hcd_rp2040_irq(void)
@@ -202,20 +198,22 @@ static void hcd_rp2040_irq(void)
usb_hw_clear->sie_status = USB_SIE_STATUS_SPEED_BITS;
}
- if (status & USB_INTS_TRANS_COMPLETE_BITS)
- {
- handled |= USB_INTS_TRANS_COMPLETE_BITS;
- usb_hw_clear->sie_status = USB_SIE_STATUS_TRANS_COMPLETE_BITS;
- hw_trans_complete();
- }
-
if (status & USB_INTS_BUFF_STATUS_BITS)
{
handled |= USB_INTS_BUFF_STATUS_BITS;
+ TU_LOG(2, "Buffer complete\n");
// print_bufctrl32(*epx.buffer_control);
hw_handle_buff_status();
}
+ if (status & USB_INTS_TRANS_COMPLETE_BITS)
+ {
+ handled |= USB_INTS_TRANS_COMPLETE_BITS;
+ usb_hw_clear->sie_status = USB_SIE_STATUS_TRANS_COMPLETE_BITS;
+ TU_LOG(2, "Transfer complete\n");
+ hw_trans_complete();
+ }
+
if (status & USB_INTS_STALL_BITS)
{
// We have rx'd a stall from the device
@@ -234,7 +232,7 @@ static void hcd_rp2040_irq(void)
if (status & USB_INTS_ERROR_DATA_SEQ_BITS)
{
usb_hw_clear->sie_status = USB_SIE_STATUS_DATA_SEQ_ERROR_BITS;
- // print_bufctrl32(*epx.buffer_control);
+ print_bufctrl32(*epx.buffer_control);
panic("Data Seq Error \n");
}
@@ -247,9 +245,9 @@ static void hcd_rp2040_irq(void)
static struct hw_endpoint *_next_free_interrupt_ep(void)
{
struct hw_endpoint *ep = NULL;
- for (uint i = 1; i < TU_ARRAY_SIZE(eps); i++)
+ for (uint i = 1; i < TU_ARRAY_SIZE(ep_pool); i++)
{
- ep = &eps[i];
+ ep = &ep_pool[i];
if (!ep->configured)
{
// Will be configured by _hw_endpoint_init / _hw_endpoint_allocate
@@ -263,6 +261,7 @@ static struct hw_endpoint *_next_free_interrupt_ep(void)
static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
{
struct hw_endpoint *ep = NULL;
+
if (transfer_type == TUSB_XFER_INTERRUPT)
{
ep = _next_free_interrupt_ep();
@@ -270,11 +269,11 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
assert(ep);
ep->buffer_control = &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl;
ep->endpoint_control = &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl;
- // 0x180 for epx
- // 0x1c0 for intep0
- // 0x200 for intep1
+ // 0 for epx (double buffered): TODO increase to 1024 for ISO
+ // 2x64 for intep0
+ // 3x64 for intep1
// etc
- ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 1)];
+ ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 2)];
}
else
{
@@ -283,6 +282,7 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
ep->endpoint_control = &usbh_dpram->epx_ctrl;
ep->hw_data_buf = &usbh_dpram->epx_data[0];
}
+
return ep;
}
@@ -303,7 +303,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
ep->rx = (dir == TUSB_DIR_IN);
// Response to a setup packet on EP0 starts with pid of 1
- ep->next_pid = num == 0 ? 1u : 0u;
+ ep->next_pid = (num == 0 ? 1u : 0u);
ep->wMaxPacketSize = wMaxPacketSize;
ep->transfer_type = transfer_type;
@@ -332,6 +332,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
// preamble
uint32_t reg = dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB);
// Assert the interrupt endpoint is IN_TO_HOST
+ // TODO Interrupt can also be OUT
assert(dir == TUSB_DIR_IN);
if (need_pre(dev_addr))
@@ -345,24 +346,9 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
// If it's an interrupt endpoint we need to set up the buffer control
// register
-
}
}
-static void hw_endpoint_init(uint8_t dev_addr, const tusb_desc_endpoint_t *ep_desc)
-{
- // Allocated differently based on if it's an interrupt endpoint or not
- struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
- _hw_endpoint_init(ep,
- dev_addr,
- ep_desc->bEndpointAddress,
- ep_desc->wMaxPacketSize.size,
- ep_desc->bmAttributes.xfer,
- ep_desc->bInterval);
- // Map this struct to ep@device address
- set_dev_ep(dev_addr, ep_desc->bEndpointAddress, ep);
-}
-
//--------------------------------------------------------------------+
// HCD API
//--------------------------------------------------------------------+
@@ -377,11 +363,11 @@ bool hcd_init(uint8_t rhport)
irq_set_exclusive_handler(USBCTRL_IRQ, hcd_rp2040_irq);
// clear epx and interrupt eps
- memset(&eps, 0, sizeof(eps));
+ memset(&ep_pool, 0, sizeof(ep_pool));
// Enable in host mode with SOF / Keep alive on
usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS;
- usb_hw->sie_ctrl = sie_ctrl_base;
+ usb_hw->sie_ctrl = SIE_CTRL_BASE;
usb_hw->inte = USB_INTE_BUFF_STATUS_BITS |
USB_INTE_HOST_CONN_DIS_BITS |
USB_INTE_HOST_RESUME_BITS |
@@ -409,7 +395,6 @@ bool hcd_port_connect_status(uint8_t rhport)
tusb_speed_t hcd_port_speed_get(uint8_t rhport)
{
- pico_trace("hcd_port_speed_get\n");
assert(rhport == 0);
// TODO: Should enumval this register
switch (dev_speed())
@@ -420,15 +405,25 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport)
return TUSB_SPEED_FULL;
default:
panic("Invalid speed\n");
+ return TUSB_SPEED_INVALID;
}
}
// Close all opened endpoint belong to this device
void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
{
+ (void) rhport;
+ (void) dev_addr;
+
pico_trace("hcd_device_close %d\n", dev_addr);
}
+uint32_t hcd_frame_number(uint8_t rhport)
+{
+ (void) rhport;
+ return usb_hw->sof_rd;
+}
+
void hcd_int_enable(uint8_t rhport)
{
assert(rhport == 0);
@@ -442,36 +437,70 @@ void hcd_int_disable(uint8_t rhport)
irq_set_enabled(USBCTRL_IRQ, false);
}
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void) rhport;
+
+ pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress);
+
+ // Allocated differently based on if it's an interrupt endpoint or not
+ struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
+
+ _hw_endpoint_init(ep,
+ dev_addr,
+ ep_desc->bEndpointAddress,
+ ep_desc->wMaxPacketSize.size,
+ ep_desc->bmAttributes.xfer,
+ ep_desc->bInterval);
+
+ return true;
+}
+
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
{
- pico_info("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen);
+ (void) rhport;
+
+ pico_trace("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen);
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr);
+
// Get appropriate ep. Either EPX or interrupt endpoint
struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
assert(ep);
- if (ep_addr != ep->ep_addr)
+ // Control endpoint can change direction 0x00 <-> 0x80
+ if ( ep_addr != ep->ep_addr )
{
- // Direction has flipped so re init it but with same properties
- // TODO treat IN and OUT as invidual endpoints
- _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0);
- }
+ assert(ep_num == 0);
- // True indicates this is the start of the transfer
- _hw_endpoint_xfer(ep, buffer, buflen, true);
+ // Direction has flipped on endpoint control so re init it but with same properties
+ _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0);
+ }
// If a normal transfer (non-interrupt) then initiate using
// sie ctrl registers. Otherwise interrupt ep registers should
// already be configured
if (ep == &epx) {
+ hw_endpoint_xfer_start(ep, buffer, buflen);
+
// That has set up buffer control, endpoint control etc
// for host we have to initiate the transfer
- usb_hw->dev_addr_ctrl = dev_addr | (tu_edpt_number(ep_addr) << USB_ADDR_ENDP_ENDPOINT_LSB);
- uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | sie_ctrl_base;
- flags |= ep->rx ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS;
+ usb_hw->dev_addr_ctrl = dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB);
+
+ uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | SIE_CTRL_BASE |
+ (ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS);
// Set pre if we are a low speed device on full speed hub
flags |= need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0;
+
usb_hw->sie_ctrl = flags;
+ }else
+ {
+ hw_endpoint_xfer_start(ep, buffer, buflen);
}
return true;
@@ -479,42 +508,34 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
{
- pico_info("hcd_setup_send dev_addr %d\n", dev_addr);
-
+ (void) rhport;
+
// Copy data into setup packet buffer
memcpy((void*)&usbh_dpram->setup_packet[0], setup_packet, 8);
// Configure EP0 struct with setup info for the trans complete
struct hw_endpoint *ep = _hw_endpoint_allocate(0);
+
// EP0 out
_hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0);
assert(ep->configured);
- ep->total_len = 8;
- ep->transfer_size = 8;
- ep->active = true;
- ep->sent_setup = true;
+
+ ep->remaining_len = 8;
+ ep->active = true;
// Set device address
usb_hw->dev_addr_ctrl = dev_addr;
+
// Set pre if we are a low speed device on full speed hub
- uint32_t flags = sie_ctrl_base | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS;
- flags |= need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0;
- usb_hw->sie_ctrl = flags;
- return true;
-}
+ uint32_t const flags = SIE_CTRL_BASE | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS |
+ (need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0);
-uint32_t hcd_frame_number(uint8_t rhport)
-{
- return usb_hw->sof_rd;
-}
+ usb_hw->sie_ctrl = flags;
-bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
-{
- pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress);
- hw_endpoint_init(dev_addr, ep_desc);
return true;
}
+
//bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
//{
// // EPX is shared, so multiple device addresses and endpoint addresses share that
@@ -531,6 +552,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
{
+ (void) dev_addr;
+ (void) ep_addr;
+
panic("hcd_clear_stall");
return true;
}
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index 31381e6c2..dc12e6d82 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -43,42 +44,38 @@ static inline void _hw_endpoint_lock_update(struct hw_endpoint *ep, int delta) {
// sense to have worker and IRQ on same core, however I think using critsec is about equivalent.
}
-#if TUSB_OPT_HOST_ENABLED
-static inline void _hw_endpoint_update_last_buf(struct hw_endpoint *ep)
-{
- ep->last_buf = (ep->len + ep->transfer_size == ep->total_len);
-}
-#endif
+static void _hw_endpoint_xfer_sync(struct hw_endpoint *ep);
+static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep);
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
void rp2040_usb_init(void)
{
- // Reset usb controller
- reset_block(RESETS_RESET_USBCTRL_BITS);
- unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
+ // Reset usb controller
+ reset_block(RESETS_RESET_USBCTRL_BITS);
+ unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
- // Clear any previous state just in case
- memset(usb_hw, 0, sizeof(*usb_hw));
- memset(usb_dpram, 0, sizeof(*usb_dpram));
+ // Clear any previous state just in case
+ memset(usb_hw, 0, sizeof(*usb_hw));
+ memset(usb_dpram, 0, sizeof(*usb_dpram));
- // Mux the controller to the onboard usb phy
- usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
+ // Mux the controller to the onboard usb phy
+ usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
- // Force VBUS detect so the device thinks it is plugged into a host
- // TODO support VBUs detect
- usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
+ // Force VBUS detect so the device thinks it is plugged into a host
+ // TODO support VBUs detect
+ usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
}
void hw_endpoint_reset_transfer(struct hw_endpoint *ep)
{
- ep->stalled = false;
- ep->active = false;
-#if TUSB_OPT_HOST_ENABLED
- ep->sent_setup = false;
-#endif
- ep->total_len = 0;
- ep->len = 0;
- ep->transfer_size = 0;
- ep->user_buf = 0;
+ ep->stalled = false;
+ ep->active = false;
+ ep->remaining_len = 0;
+ ep->xferred_len = 0;
+ ep->user_buf = 0;
}
void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask) {
@@ -111,215 +108,223 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m
*ep->buffer_control = value;
}
-void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
+// prepare buffer, return buffer control
+static uint32_t prepare_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
{
- // Prepare buffer control register value
- uint32_t val = ep->transfer_size | USB_BUF_CTRL_AVAIL;
+ uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize);
+ ep->remaining_len -= buflen;
- if (!ep->rx)
- {
- // Copy data from user buffer to hw buffer
- memcpy(ep->hw_data_buf, &ep->user_buf[ep->len], ep->transfer_size);
- // Mark as full
- val |= USB_BUF_CTRL_FULL;
- }
+ uint32_t buf_ctrl = buflen | USB_BUF_CTRL_AVAIL;
- // PID
- val |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
+ // PID
+ buf_ctrl |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
+ ep->next_pid ^= 1u;
-#if TUSB_OPT_DEVICE_ENABLED
- ep->next_pid ^= 1u;
+ if ( !ep->rx )
+ {
+ // Copy data from user buffer to hw buffer
+ memcpy(ep->hw_data_buf + buf_id*64, ep->user_buf, buflen);
+ ep->user_buf += buflen;
-#else
- // For Host (also device but since we dictate the endpoint size, following scenario does not occur)
- // Next PID depends on the number of packet in case wMaxPacketSize < 64 (e.g Interrupt Endpoint 8, or 12)
- // Special case with control status stage where PID is always DATA1
- if ( ep->transfer_size == 0 )
- {
- // ZLP also toggle data
- ep->next_pid ^= 1u;
- }else
- {
- uint32_t packet_count = 1 + ((ep->transfer_size - 1) / ep->wMaxPacketSize);
-
- if ( packet_count & 0x01 )
- {
- ep->next_pid ^= 1u;
- }
- }
-#endif
+ // Mark as full
+ buf_ctrl |= USB_BUF_CTRL_FULL;
+ }
+ // Is this the last buffer? Only really matters for host mode. Will trigger
+ // the trans complete irq but also stop it polling. We only really care about
+ // trans complete for setup packets being sent
+ if (ep->remaining_len == 0)
+ {
+ buf_ctrl |= USB_BUF_CTRL_LAST;
+ }
-#if TUSB_OPT_HOST_ENABLED
- // Is this the last buffer? Only really matters for host mode. Will trigger
- // the trans complete irq but also stop it polling. We only really care about
- // trans complete for setup packets being sent
- if (ep->last_buf)
- {
- pico_trace("Last buf (%d bytes left)\n", ep->transfer_size);
- val |= USB_BUF_CTRL_LAST;
- }
-#endif
+ if (buf_id) buf_ctrl = buf_ctrl << 16;
- // Finally, write to buffer_control which will trigger the transfer
- // the next time the controller polls this dpram address
- _hw_endpoint_buffer_control_set_value32(ep, val);
- pico_trace("buffer control (0x%p) <- 0x%x\n", ep->buffer_control, val);
- //print_bufctrl16(val);
+ return buf_ctrl;
}
-
-void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len)
+// Prepare buffer control register value
+static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep)
{
- _hw_endpoint_lock_update(ep, 1);
- pico_trace("Start transfer of total len %d on ep %d %s\n", total_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
- if (ep->active)
- {
- // TODO: Is this acceptable for interrupt packets?
- pico_warn("WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
+ uint32_t ep_ctrl = *ep->endpoint_control;
- hw_endpoint_reset_transfer(ep);
- }
+ // always compute and start with buffer 0
+ uint32_t buf_ctrl = prepare_ep_buffer(ep, 0) | USB_BUF_CTRL_SEL;
- // Fill in info now that we're kicking off the hw
- ep->total_len = total_len;
- ep->len = 0;
+ // For now: skip double buffered for Device mode, OUT endpoint since
+ // host could send < 64 bytes and cause short packet on buffer0
+ // NOTE this could happen to Host mode IN endpoint
+ bool const force_single = !(usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) && !tu_edpt_dir(ep->ep_addr);
- // Limit by packet size but not less 64 (i.e low speed 8 bytes EP0)
- ep->transfer_size = tu_min16(total_len, tu_max16(64, ep->wMaxPacketSize));
+ if(ep->remaining_len && !force_single)
+ {
+ // Use buffer 1 (double buffered) if there is still data
+ // TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt)
- ep->active = true;
- ep->user_buf = buffer;
-#if TUSB_OPT_HOST_ENABLED
- // Recalculate if this is the last buffer
- _hw_endpoint_update_last_buf(ep);
- ep->buf_sel = 0;
-#endif
+ buf_ctrl |= prepare_ep_buffer(ep, 1);
- _hw_endpoint_start_next_buffer(ep);
- _hw_endpoint_lock_update(ep, -1);
+ // Set endpoint control double buffered bit if needed
+ ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER;
+ ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER;
+ }else
+ {
+ // Single buffered since 1 is enough
+ ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
+ ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
+ }
+
+ *ep->endpoint_control = ep_ctrl;
+
+ TU_LOG(3, "Prepare Buffer Control:\r\n");
+ print_bufctrl32(buf_ctrl);
+
+ // Finally, write to buffer_control which will trigger the transfer
+ // the next time the controller polls this dpram address
+ _hw_endpoint_buffer_control_set_value32(ep, buf_ctrl);
}
-void _hw_endpoint_xfer_sync(struct hw_endpoint *ep)
+void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len)
{
- // Update hw endpoint struct with info from hardware
- // after a buff status interrupt
+ _hw_endpoint_lock_update(ep, 1);
- uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
+ if ( ep->active )
+ {
+ // TODO: Is this acceptable for interrupt packets?
+ TU_LOG(1, "WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr),
+ ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
-#if TUSB_OPT_HOST_ENABLED
- // RP2040-E4
- // tag::host_buf_sel_fix[]
- // TODO need changes to support double buffering
- if (ep->buf_sel == 1)
- {
- // Host can erroneously write status to top half of buf_ctrl register
- buf_ctrl = buf_ctrl >> 16;
+ hw_endpoint_reset_transfer(ep);
+ }
- // update buf1 -> buf0 to prevent panic with "already available"
- *ep->buffer_control = buf_ctrl;
- }
- // Flip buf sel for host
- ep->buf_sel ^= 1u;
- // end::host_buf_sel_fix[]
-#endif
+ // Fill in info now that we're kicking off the hw
+ ep->remaining_len = total_len;
+ ep->xferred_len = 0;
+ ep->active = true;
+ ep->user_buf = buffer;
+
+ _hw_endpoint_start_next_buffer(ep);
+ _hw_endpoint_lock_update(ep, -1);
+}
+
+// sync endpoint buffer and return transferred bytes
+static uint16_t sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id)
+{
+ uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
+ if (buf_id) buf_ctrl = buf_ctrl >> 16;
- // Get tranferred bytes after adjusted buf sel
- uint16_t const transferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
+ uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
- // We are continuing a transfer here. If we are TX, we have successfullly
+ if ( !ep->rx )
+ {
+ // We are continuing a transfer here. If we are TX, we have successfully
// sent some data can increase the length we have sent
- if (!ep->rx)
- {
- assert(!(buf_ctrl & USB_BUF_CTRL_FULL));
- pico_trace("tx %d bytes (buf_ctrl 0x%08x)\n", transferred_bytes, buf_ctrl);
- ep->len += transferred_bytes;
- }
- else
- {
- // If we are OUT we have recieved some data, so can increase the length
- // we have recieved AFTER we have copied it to the user buffer at the appropriate
- // offset
- pico_trace("rx %d bytes (buf_ctrl 0x%08x)\n", transferred_bytes, buf_ctrl);
- assert(buf_ctrl & USB_BUF_CTRL_FULL);
- memcpy(&ep->user_buf[ep->len], ep->hw_data_buf, transferred_bytes);
- ep->len += transferred_bytes;
- }
+ assert(!(buf_ctrl & USB_BUF_CTRL_FULL));
- // Sometimes the host will send less data than we expect...
- // If this is a short out transfer update the total length of the transfer
- // to be the current length
- if ((ep->rx) && (transferred_bytes < ep->wMaxPacketSize))
- {
- pico_trace("Short rx transfer\n");
- // Reduce total length as this is last packet
- ep->total_len = ep->len;
- }
+ ep->xferred_len += xferred_bytes;
+ }else
+ {
+ // If we have received some data, so can increase the length
+ // we have received AFTER we have copied it to the user buffer at the appropriate offset
+ assert(buf_ctrl & USB_BUF_CTRL_FULL);
+
+ memcpy(ep->user_buf, ep->hw_data_buf + buf_id*64, xferred_bytes);
+ ep->xferred_len += xferred_bytes;
+ ep->user_buf += xferred_bytes;
+ }
+
+ // Short packet
+ if (xferred_bytes < ep->wMaxPacketSize)
+ {
+ pico_trace("Short rx transfer on buffer %d with %u bytes\n", buf_id, xferred_bytes);
+ // Reduce total length as this is last packet
+ ep->remaining_len = 0;
+ }
+
+ return xferred_bytes;
}
-// Returns true if transfer is complete
-bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep)
+static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep)
{
- _hw_endpoint_lock_update(ep, 1);
- // Part way through a transfer
- if (!ep->active)
- {
- panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string);
- }
+ // Update hw endpoint struct with info from hardware
+ // after a buff status interrupt
- // Update EP struct from hardware state
- _hw_endpoint_xfer_sync(ep);
-
- // Now we have synced our state with the hardware. Is there more data to transfer?
- // Limit by packet size but not less 64 (i.e low speed 8 bytes EP0)
- uint16_t remaining_bytes = ep->total_len - ep->len;
- ep->transfer_size = tu_min16(remaining_bytes, tu_max16(64, ep->wMaxPacketSize));
-#if TUSB_OPT_HOST_ENABLED
- _hw_endpoint_update_last_buf(ep);
-#endif
+ uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
+ TU_LOG(3, "_hw_endpoint_xfer_sync:\r\n");
+ print_bufctrl32(buf_ctrl);
- // Can happen because of programmer error so check for it
- if (ep->len > ep->total_len)
- {
- panic("Transferred more data than expected");
- }
+ // always sync buffer 0
+ uint16_t buf0_bytes = sync_ep_buffer(ep, 0);
- // If we are done then notify tinyusb
- if (ep->len == ep->total_len)
+ // sync buffer 1 if double buffered
+ if ( (*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS )
+ {
+ if (buf0_bytes == ep->wMaxPacketSize)
{
- pico_trace("Completed transfer of %d bytes on ep %d %s\n",
- ep->len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
- // Notify caller we are done so it can notify the tinyusb stack
- _hw_endpoint_lock_update(ep, -1);
- return true;
- }
- else
+ // sync buffer 1 if not short packet
+ sync_ep_buffer(ep, 1);
+ }else
{
- _hw_endpoint_start_next_buffer(ep);
- }
+ // short packet on buffer 0
+ // TODO couldn't figure out how to handle this case which happen with net_lwip_webserver example
+ // At this time (currently trigger per 2 buffer), the buffer1 is probably filled with data from
+ // the next transfer (not current one). For now we disable double buffered for device OUT
+ // NOTE this could happen to Host IN
+#if 0
+ uint8_t const ep_num = tu_edpt_number(ep->ep_addr);
+ uint8_t const dir = (uint8_t) tu_edpt_dir(ep->ep_addr);
+ uint8_t const ep_id = 2*ep_num + (dir ? 0 : 1);
- _hw_endpoint_lock_update(ep, -1);
- // More work to do
- return false;
+ // abort queued transfer on buffer 1
+ usb_hw->abort |= TU_BIT(ep_id);
+
+ while ( !(usb_hw->abort_done & TU_BIT(ep_id)) ) {}
+
+ uint32_t ep_ctrl = *ep->endpoint_control;
+ ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
+ ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
+
+ _hw_endpoint_buffer_control_set_value32(ep, 0);
+
+ usb_hw->abort &= ~TU_BIT(ep_id);
+
+ TU_LOG(3, "----SHORT PACKET buffer0 on EP %02X:\r\n", ep->ep_addr);
+ print_bufctrl32(buf_ctrl);
+#endif
+ }
+ }
}
-void _hw_endpoint_xfer(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len, bool start)
+// Returns true if transfer is complete
+bool hw_endpoint_xfer_continue(struct hw_endpoint *ep)
{
- // Trace
- pico_trace("hw_endpoint_xfer ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
- pico_trace(" total_len %d, start=%d\n", total_len, start);
+ _hw_endpoint_lock_update(ep, 1);
+ // Part way through a transfer
+ if (!ep->active)
+ {
+ panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string);
+ }
- assert(ep->configured);
+ // Update EP struct from hardware state
+ _hw_endpoint_xfer_sync(ep);
+ // Now we have synced our state with the hardware. Is there more data to transfer?
+ // If we are done then notify tinyusb
+ if (ep->remaining_len == 0)
+ {
+ pico_trace("Completed transfer of %d bytes on ep %d %s\n",
+ ep->xferred_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
+ // Notify caller we are done so it can notify the tinyusb stack
+ _hw_endpoint_lock_update(ep, -1);
+ return true;
+ }
+ else
+ {
+ _hw_endpoint_start_next_buffer(ep);
+ }
- if (start)
- {
- _hw_endpoint_xfer_start(ep, buffer, total_len);
- }
- else
- {
- _hw_endpoint_xfer_continue(ep);
- }
+ _hw_endpoint_lock_update(ep, -1);
+ // More work to do
+ return false;
}
#endif
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h
index 33f3ecd41..514152cd9 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.h
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h
@@ -17,23 +17,8 @@
#endif
-#if false && !defined(NDEBUG)
-#define pico_trace(format,args...) printf(format, ## args)
-#else
-#define pico_trace(format,...) ((void)0)
-#endif
-
-#if false && !defined(NDEBUG)
-#define pico_info(format,args...) printf(format, ## args)
-#else
-#define pico_info(format,...) ((void)0)
-#endif
-
-#if false && !defined(NDEBUG)
-#define pico_warn(format,args...) printf(format, ## args)
-#else
-#define pico_warn(format,...) ((void)0)
-#endif
+#define pico_info(...) TU_LOG(2, __VA_ARGS__)
+#define pico_trace(...) TU_LOG(3, __VA_ARGS__)
// Hardware information per endpoint
struct hw_endpoint
@@ -50,6 +35,7 @@ struct hw_endpoint
// Endpoint control register
io_rw_32 *endpoint_control;
+
// Buffer control register
io_rw_32 *buffer_control;
@@ -61,27 +47,22 @@ struct hw_endpoint
// Current transfer information
bool active;
- uint16_t total_len;
- uint16_t len;
- // Amount of data with the hardware
- uint16_t transfer_size;
+ uint16_t remaining_len;
+ uint16_t xferred_len;
+
// User buffer in main memory
uint8_t *user_buf;
// Data needed from EP descriptor
uint16_t wMaxPacketSize;
+
// Interrupt, bulk, etc
uint8_t transfer_type;
#if TUSB_OPT_HOST_ENABLED
- // Only needed for host mode
- bool last_buf;
- // RP2040-E4: HOST BUG. Host will incorrect write status to top half of buffer
- // control register when doing transfers > 1 packet
- uint8_t buf_sel;
// Only needed for host
uint8_t dev_addr;
- bool sent_setup;
+
// If interrupt endpoint
uint8_t interrupt_num;
#endif
@@ -89,12 +70,10 @@ struct hw_endpoint
void rp2040_usb_init(void);
+void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len);
+bool hw_endpoint_xfer_continue(struct hw_endpoint *ep);
void hw_endpoint_reset_transfer(struct hw_endpoint *ep);
-void _hw_endpoint_xfer(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len, bool start);
-void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep);
-void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len);
-void _hw_endpoint_xfer_sync(struct hw_endpoint *ep);
-bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep);
+
void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask);
static inline uint32_t _hw_endpoint_buffer_control_get_value32(struct hw_endpoint *ep) {
return *ep->buffer_control;
@@ -134,14 +113,15 @@ typedef union TU_ATTR_PACKED
TU_VERIFY_STATIC(sizeof(rp2040_buffer_control_t) == 2, "size is not correct");
-static inline void print_bufctrl16(uint32_t __unused u16)
+#if CFG_TUSB_DEBUG >= 3
+static inline void print_bufctrl16(uint32_t u16)
{
- rp2040_buffer_control_t __unused bufctrl = {
+ rp2040_buffer_control_t bufctrl = {
.u16 = u16
};
- TU_LOG(2, "len = %u, available = %u, stall = %u, reset = %u, toggle = %u, last = %u, full = %u\r\n",
- bufctrl.xfer_len, bufctrl.available, bufctrl.stall, bufctrl.reset_bufsel, bufctrl.data_toggle, bufctrl.last_buf, bufctrl.full);
+ TU_LOG(3, "len = %u, available = %u, full = %u, last = %u, stall = %u, reset = %u, toggle = %u\r\n",
+ bufctrl.xfer_len, bufctrl.available, bufctrl.full, bufctrl.last_buf, bufctrl.stall, bufctrl.reset_bufsel, bufctrl.data_toggle);
}
static inline void print_bufctrl32(uint32_t u32)
@@ -149,12 +129,19 @@ static inline void print_bufctrl32(uint32_t u32)
uint16_t u16;
u16 = u32 >> 16;
- TU_LOG(2, "Buffer Control 1 0x%x: ", u16);
+ TU_LOG(3, " Buffer Control 1 0x%x: ", u16);
print_bufctrl16(u16);
u16 = u32 & 0x0000ffff;
- TU_LOG(2, "Buffer Control 0 0x%x: ", u16);
+ TU_LOG(3, " Buffer Control 0 0x%x: ", u16);
print_bufctrl16(u16);
}
+#else
+
+#define print_bufctrl16(u16)
+#define print_bufctrl32(u32)
+
+#endif
+
#endif
diff --git a/src/portable/renesas/usba/dcd_usba.c b/src/portable/renesas/usba/dcd_usba.c
index 06ea1a3f9..338d5b0e6 100644
--- a/src/portable/renesas/usba/dcd_usba.c
+++ b/src/portable/renesas/usba/dcd_usba.c
@@ -26,8 +26,8 @@
#include "tusb_option.h"
-#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X )
-
+#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_RX63X || \
+ CFG_TUSB_MCU == OPT_MCU_RX65X)
#include "device/dcd.h"
#include "iodefine.h"
@@ -63,7 +63,10 @@
#define USB_IS0_CTSQ_SETUP (1u)
#define USB_IS0_DVSQ_DEF (1u<<4)
#define USB_IS0_DVSQ_ADDR (2u<<4)
-#define USB_IS0_DVSQ_SUSP (4u<<4)
+#define USB_IS0_DVSQ_SUSP0 (4u<<4)
+#define USB_IS0_DVSQ_SUSP1 (5u<<4)
+#define USB_IS0_DVSQ_SUSP2 (6u<<4)
+#define USB_IS0_DVSQ_SUSP3 (7u<<4)
#define USB_PIPECTR_PID_NAK (0u)
#define USB_PIPECTR_PID_BUF (1u)
@@ -125,6 +128,7 @@ typedef struct
{
pipe_state_t pipe[9];
uint8_t ep[2][16]; /* a lookup table for a pipe index from an endpoint address */
+ uint8_t suspended;
} dcd_data_t;
//--------------------------------------------------------------------+
@@ -517,7 +521,8 @@ void dcd_init(uint8_t rhport)
/* Setup default control pipe */
USB0.DCPMAXP.BIT.MXPS = 64;
- USB0.INTENB0.WORD = USB_IS0_VBINT | USB_IS0_BRDY | USB_IS0_BEMP | USB_IS0_DVST | USB_IS0_CTRT;
+ USB0.INTENB0.WORD = USB_IS0_VBINT | USB_IS0_BRDY | USB_IS0_BEMP |
+ USB_IS0_DVST | USB_IS0_CTRT | USB_IS0_SOFR | USB_IS0_RESM;
USB0.BEMPENB.WORD = 1;
USB0.BRDYENB.WORD = 1;
@@ -547,7 +552,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
void dcd_remote_wakeup(uint8_t rhport)
{
(void)rhport;
- /* TODO */
+ USB0.DVSTCTR0.BIT.WKUP = 1;
}
void dcd_connect(uint8_t rhport)
@@ -689,6 +694,22 @@ void dcd_int_handler(uint8_t rhport)
dcd_disconnect(rhport);
}
}
+ if (is0 & USB_IS0_RESM) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+ _dcd.suspended = 0;
+ }
+ if (is0 & USB_IS0_SOFR) {
+ if (_dcd.suspended) {
+ /* When USB host resumes caused by `dcd_remote_wakeup()`,
+ * RESM interrupt does not rise.
+ * Therefore we need to manually send resume event.
+ * Of course, when USB host resumes on its own,
+ * RESM interrupt rise properly, then this statements are ignored. */
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+ _dcd.suspended = 0;
+ }
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ }
if (is0 & USB_IS0_DVST) {
switch (is0 & USB_IS0_DVSQ) {
case USB_IS0_DVSQ_DEF:
@@ -697,6 +718,12 @@ void dcd_int_handler(uint8_t rhport)
case USB_IS0_DVSQ_ADDR:
process_set_address(rhport);
break;
+ case USB_IS0_DVSQ_SUSP0:
+ case USB_IS0_DVSQ_SUSP1:
+ case USB_IS0_DVSQ_SUSP2:
+ case USB_IS0_DVSQ_SUSP3:
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+ _dcd.suspended = 1;
default:
break;
}
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 9b0ea4358..13d11fdfe 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -64,7 +64,6 @@
#define OPT_MCU_SAML21 206 ///< MicroChip SAML21
#define OPT_MCU_SAMX7X 207 ///< MicroChip SAME70, S70, V70, V71 family
-
// STM32
#define OPT_MCU_STM32F0 300 ///< ST STM32F0
#define OPT_MCU_STM32F1 301 ///< ST STM32F1
@@ -115,6 +114,7 @@
// Renesas RX
#define OPT_MCU_RX63X 1400 ///< Renesas RX63N/631
+#define OPT_MCU_RX65X 1401 ///< Renesas RX65N/RX651
// Mind Motion
#define OPT_MCU_MM32F327X 1500 ///< Mind Motion MM32F327
@@ -280,8 +280,8 @@
#error there is no benefit enable hub with max device is 1. Please disable hub or increase CFG_TUSB_HOST_DEVICE_MAX
#endif
- #ifndef CFG_TUH_ENUMERATION_BUFSZIE
- #define CFG_TUH_ENUMERATION_BUFSZIE 256
+ #ifndef CFG_TUH_ENUMERATION_BUFSIZE
+ #define CFG_TUH_ENUMERATION_BUFSIZE 256
#endif
//------------- CLASS -------------//
diff --git a/test/test/test_fifo.c b/test/test/test_fifo.c
index f9bfc5f03..0a5f4d3b9 100644
--- a/test/test/test_fifo.c
+++ b/test/test/test_fifo.c
@@ -292,3 +292,27 @@ void test_full(void)
// write info
}
+
+void test_rd_idx_wrap()
+{
+ tu_fifo_t ff10;
+ uint8_t buf[10];
+ uint8_t dst[10];
+
+ tu_fifo_config(&ff10, buf, 10, 1, 1);
+
+ uint16_t n;
+
+ ff10.wr_idx = 6;
+ ff10.rd_idx = 15;
+
+ n = tu_fifo_read_n(&ff10, dst, 4);
+ TEST_ASSERT_EQUAL(n, 4);
+ TEST_ASSERT_EQUAL(ff10.rd_idx, 0);
+ n = tu_fifo_read_n(&ff10, dst, 4);
+ TEST_ASSERT_EQUAL(n, 4);
+ TEST_ASSERT_EQUAL(ff10.rd_idx, 4);
+ n = tu_fifo_read_n(&ff10, dst, 4);
+ TEST_ASSERT_EQUAL(n, 2);
+ TEST_ASSERT_EQUAL(ff10.rd_idx, 6);
+} \ No newline at end of file