diff --git a/.codespell/ignore-words.txt b/.codespell/ignore-words.txt
index 5c89bae1c..2513691cb 100644
--- a/.codespell/ignore-words.txt
+++ b/.codespell/ignore-words.txt
@@ -1,6 +1,7 @@
synopsys
sie
tre
+thre
hsi
fro
dout
diff --git a/.github/workflows/build_aarch64.yml b/.github/workflows/build_aarch64.yml
index cc8ddb070..6ac7ad015 100644
--- a/.github/workflows/build_aarch64.yml
+++ b/.github/workflows/build_aarch64.yml
@@ -1,6 +1,7 @@
name: Build AArch64
on:
+ workflow_dispatch:
push:
paths:
- 'src/**'
@@ -69,7 +70,7 @@ jobs:
run: echo >> $GITHUB_PATH `echo ~/cache/toolchain/*/bin`
- name: Get Dependencies
- run: python3 tools/get_family_deps.py ${{ matrix.family }}
+ run: python3 tools/get_deps.py ${{ matrix.family }}
- name: Build
run: python3 tools/build_family.py ${{ matrix.family }}
diff --git a/.github/workflows/build_arm.yml b/.github/workflows/build_arm.yml
index b60d12a98..3a2daab08 100644
--- a/.github/workflows/build_arm.yml
+++ b/.github/workflows/build_arm.yml
@@ -1,6 +1,7 @@
name: Build ARM
on:
+ workflow_dispatch:
push:
paths:
- 'src/**'
@@ -33,14 +34,12 @@ jobs:
family:
# Alphabetical order
- 'broadcom_32bit'
- - 'imxrt'
- - 'kinetis_k32 kinetis_kl'
- - 'lpc11 lpc13 lpc15 lpc17 lpc18'
+ - 'kinetis_k32l kinetis_kl'
+ - 'lpc11 lpc13 lpc15 lpc17'
- 'lpc51 lpc54 lpc55'
- 'mm32 msp432e4'
- 'nrf'
- 'ra'
- - 'rp2040'
- 'samd11 samd21'
- 'samd51 same5x'
- 'saml2x'
@@ -77,7 +76,7 @@ jobs:
echo >> $GITHUB_ENV PICO_SDK_PATH=~/pico-sdk
- name: Get Dependencies
- run: python3 tools/get_family_deps.py ${{ matrix.family }}
+ run: python3 tools/get_deps.py ${{ matrix.family }}
- name: Build
run: python3 tools/build_family.py ${{ matrix.family }}
@@ -91,24 +90,11 @@ jobs:
find ${ex} -name *.map -print -quit | xargs -I % sh -c 'echo "::group::%"; linkermap -v %; echo "::endgroup::"'
done
- # Upload binaries for rp2040/stm32l412nucleo hardware test with self-hosted
-
- - name: Prepare rp2040 Artifacts
- if: contains(matrix.family, 'rp2040') && github.repository_owner == 'hathach'
- run: find examples/ -name "*.elf" -exec mv {} . \;
-
+ # Upload binaries for hardware test with self-hosted
- name: Prepare stm32l412nucleo Artifacts
if: contains(matrix.family, 'stm32l4')
run: find examples/ -path "*stm32l412nucleo/*.elf" -exec mv {} . \;
- - name: Upload Artifacts for rp2040
- if: contains(matrix.family,'rp2040') && github.repository_owner == 'hathach'
- uses: actions/upload-artifact@v3
- with:
- name: rp2040
- path: |
- *.elf
-
- name: Upload Artifacts for stm32l412nucleo
if: contains(matrix.family, 'stm32l4') && github.repository_owner == 'hathach'
uses: actions/upload-artifact@v3
@@ -117,67 +103,6 @@ jobs:
path: |
*.elf
- # ---------------------------------------
- # Hardware in the loop (HIL)
- # Current self-hosted instance is running on an RPI4 with
- # - pico + pico-probe connected via USB
- # - pico-probe is /dev/ttyACM0
- # ---------------------------------------
- hw-rp2040-test:
- # run only with hathach's commit due to limited resource on RPI4
- if: github.repository_owner == 'hathach'
- needs: build-arm
- runs-on: [self-hosted, Linux, ARM64, rp2040]
-
- steps:
- - name: Clean workspace
- run: |
- echo "Cleaning up previous run"
- rm -rf "${{ github.workspace }}"
- mkdir -p "${{ github.workspace }}"
-
- - name: Download rp2040 Artifacts
- uses: actions/download-artifact@v3
- with:
- name: rp2040
-
- - name: Create flash.sh
- run: |
- #echo > flash.sh 'cmdout=$(openocd -f "interface/picoprobe.cfg" -f "target/rp2040.cfg" -c "program $1 reset exit")'
- echo > flash.sh 'pyocd flash -t rp2040 $1'
- echo >> flash.sh 'if (( $? )) ; then echo $cmdout ; fi'
- chmod +x flash.sh
-
- - name: Test cdc_dual_ports
- run: |
- ./flash.sh cdc_dual_ports.elf
- while (! ([ -e /dev/ttyACM1 ] && [ -e /dev/ttyACM2 ])) && [ $SECONDS -le 10 ]; do :; done
- test -e /dev/ttyACM1 && echo "ttyACM1 exists"
- test -e /dev/ttyACM2 && echo "ttyACM2 exists"
-
- - name: Test cdc_msc
- run: |
- ./flash.sh cdc_msc.elf
- readme='/media/pi/TinyUSB MSC/README.TXT'
- while (! ([ -e /dev/ttyACM1 ] && [ -f "$readme" ])) && [ $SECONDS -le 10 ]; do :; done
- test -e /dev/ttyACM1 && echo "ttyACM1 exists"
- test -f "$readme" && echo "$readme exists"
- cat "$readme"
-
- - name: Test dfu
- run: |
- ./flash.sh dfu.elf
- while (! (dfu-util -l | grep "Found DFU")) && [ $SECONDS -le 10 ]; do :; done
- dfu-util -d cafe -a 0 -U dfu0
- dfu-util -d cafe -a 1 -U dfu1
- grep "TinyUSB DFU! - Partition 0" dfu0
- grep "TinyUSB DFU! - Partition 1" dfu1
-
- - name: Test dfu_runtime
- run: |
- ./flash.sh dfu_runtime.elf
- while (! (dfu-util -l | grep "Found Runtime")) && [ $SECONDS -le 10 ]; do :; done
-
# ---------------------------------------
# Hardware in the loop (HIL)
# Current self-hosted instance is running on an EPYC 7232 server hosted by HiFiPhile user
diff --git a/.github/workflows/build_esp.yml b/.github/workflows/build_esp.yml
index 0a6815ea2..29585cb36 100644
--- a/.github/workflows/build_esp.yml
+++ b/.github/workflows/build_esp.yml
@@ -1,6 +1,7 @@
name: Build ESP
on:
+ workflow_dispatch:
push:
paths:
- 'src/**'
diff --git a/.github/workflows/build_iar.yml b/.github/workflows/build_iar.yml
index a5d24892f..3da5ed40f 100644
--- a/.github/workflows/build_iar.yml
+++ b/.github/workflows/build_iar.yml
@@ -1,6 +1,7 @@
name: Build IAR
on:
+ workflow_dispatch:
push:
paths:
- 'src/**'
@@ -43,7 +44,7 @@ jobs:
uses: actions/checkout@v3
- name: Get Dependencies
- run: python3 tools/get_family_deps.py ${{ matrix.family }}
+ run: python3 tools/get_deps.py ${{ matrix.family }}
- name: Build
run: python3 tools/build_family.py ${{ matrix.family }} CC=iccarm
diff --git a/.github/workflows/build_msp430.yml b/.github/workflows/build_msp430.yml
index 7cb60dceb..c62056940 100644
--- a/.github/workflows/build_msp430.yml
+++ b/.github/workflows/build_msp430.yml
@@ -1,6 +1,7 @@
name: Build MSP430
on:
+ workflow_dispatch:
push:
paths:
- 'src/**'
@@ -67,7 +68,7 @@ jobs:
run: echo >> $GITHUB_PATH `echo ~/cache/toolchain/*/bin`
- name: Get Dependencies
- run: python3 tools/get_family_deps.py ${{ matrix.family }}
+ run: python3 tools/get_deps.py ${{ matrix.family }}
- name: Build
run: python3 tools/build_family.py ${{ matrix.family }}
diff --git a/.github/workflows/build_renesas.yml b/.github/workflows/build_renesas.yml
index ffdeedb71..66b98a71b 100644
--- a/.github/workflows/build_renesas.yml
+++ b/.github/workflows/build_renesas.yml
@@ -1,6 +1,7 @@
name: Build Renesas
on:
+ workflow_dispatch:
push:
paths:
- 'src/**'
@@ -67,7 +68,7 @@ jobs:
run: echo >> $GITHUB_PATH `echo ~/cache/toolchain/*/bin`
- name: Get Dependencies
- run: python3 tools/get_family_deps.py ${{ matrix.family }}
+ run: python3 tools/get_deps.py ${{ matrix.family }}
- name: Build
run: python3 tools/build_family.py ${{ matrix.family }}
diff --git a/.github/workflows/build_riscv.yml b/.github/workflows/build_riscv.yml
index 87c7b522e..8ec549072 100644
--- a/.github/workflows/build_riscv.yml
+++ b/.github/workflows/build_riscv.yml
@@ -1,6 +1,7 @@
name: Build RISC-V
on:
+ workflow_dispatch:
push:
paths:
- 'src/**'
@@ -68,7 +69,7 @@ jobs:
run: echo >> $GITHUB_PATH `echo ~/cache/toolchain/*/bin`
- name: Get Dependencies
- run: python3 tools/get_family_deps.py ${{ matrix.family }}
+ run: python3 tools/get_deps.py ${{ matrix.family }}
- name: Build
run: python3 tools/build_family.py ${{ matrix.family }}
diff --git a/.github/workflows/build_win_mac.yml b/.github/workflows/build_win_mac.yml
index 4b743a686..45fc62f78 100644
--- a/.github/workflows/build_win_mac.yml
+++ b/.github/workflows/build_win_mac.yml
@@ -1,6 +1,7 @@
name: Build Windows/MacOS
on:
+ workflow_dispatch:
push:
paths:
- 'src/**'
diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml
index 7314fd9e6..4c4b12a6b 100644
--- a/.github/workflows/cifuzz.yml
+++ b/.github/workflows/cifuzz.yml
@@ -1,5 +1,6 @@
name: CIFuzz
on:
+ workflow_dispatch:
pull_request:
branches:
- master
diff --git a/.github/workflows/cmake_arm.yml b/.github/workflows/cmake_arm.yml
new file mode 100644
index 000000000..ccca0c9be
--- /dev/null
+++ b/.github/workflows/cmake_arm.yml
@@ -0,0 +1,149 @@
+name: CMake ARM
+
+on:
+ workflow_dispatch:
+ push:
+ paths:
+ - 'src/**'
+ - 'examples/**'
+ - 'lib/**'
+ - 'hw/**'
+ - '.github/workflows/cmake_arm.yml'
+ pull_request:
+ branches: [ master ]
+ paths:
+ - 'src/**'
+ - 'examples/**'
+ - 'lib/**'
+ - 'hw/**'
+ - '.github/workflows/cmake_arm.yml'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
+ cancel-in-progress: true
+
+jobs:
+ # ---------------------------------------
+ # Build ARM family
+ # ---------------------------------------
+ build-arm:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ family:
+ # Alphabetical order
+ - 'lpc18'
+ - 'mcx'
+ - 'imxrt'
+ - 'rp2040'
+ steps:
+ - name: Setup Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
+
+ - name: Install ARM GCC
+ uses: carlosperate/arm-none-eabi-gcc-action@v1
+ with:
+ release: '11.2-2022.02'
+
+ - name: Install Ninja
+ run: sudo apt install -y ninja-build
+
+ - name: Checkout TinyUSB
+ uses: actions/checkout@v3
+
+ - name: Checkout pico-sdk for rp2040
+ if: matrix.family == 'rp2040'
+ uses: actions/checkout@v3
+ with:
+ repository: raspberrypi/pico-sdk
+ ref: develop
+ path: pico-sdk
+
+ - name: Get Dependencies
+ run: python3 tools/get_deps.py ${{ matrix.family }}
+
+ - name: Build
+ run: python tools/build_cmake.py ${{ matrix.family }}
+ env:
+ # for rp2040, there is no harm if defined for other families
+ PICO_SDK_PATH: ${{ github.workspace }}/pico-sdk
+
+ # Upload binaries for hardware test with self-hosted
+ - name: Prepare rp2040 Artifacts
+ if: contains(matrix.family, 'rp2040') && github.repository_owner == 'hathach'
+ working-directory: ${{github.workspace}}/cmake-build-ci-raspberry_pi_pico
+ run: |
+ find device/ -name "*.elf" -exec mv {} ../ \;
+ # find host/ -name "*.elf" -exec mv {} ../ \;
+ # find dual/ -name "*.elf" -exec mv {} ../ \;
+
+ - name: Upload Artifacts for rp2040
+ if: contains(matrix.family,'rp2040') && github.repository_owner == 'hathach'
+ uses: actions/upload-artifact@v3
+ with:
+ name: rp2040
+ path: |
+ *.elf
+
+ # ---------------------------------------
+ # Hardware in the loop (HIL)
+ # Current self-hosted instance is running on an RPI4 with
+ # - pico + pico-probe connected via USB
+ # - pico-probe is /dev/ttyACM0
+ # ---------------------------------------
+ hw-rp2040-test:
+ # run only with hathach's commit due to limited resource on RPI4
+ if: github.repository_owner == 'hathach'
+ needs: build-arm
+ runs-on: [self-hosted, Linux, ARM64, rp2040]
+
+ steps:
+ - name: Clean workspace
+ run: |
+ echo "Cleaning up previous run"
+ rm -rf "${{ github.workspace }}"
+ mkdir -p "${{ github.workspace }}"
+
+ - name: Download rp2040 Artifacts
+ uses: actions/download-artifact@v3
+ with:
+ name: rp2040
+
+ - name: Create flash.sh
+ run: |
+ echo > flash.sh 'cmdout=$(openocd -f "interface/cmsis-dap.cfg" -f "target/rp2040.cfg" -c "adapter speed 5000" -c "program $1 reset exit")'
+ echo >> flash.sh 'if (( $? )) ; then echo $cmdout ; fi'
+ chmod +x flash.sh
+
+ - name: Test cdc_dual_ports
+ run: |
+ ./flash.sh cdc_dual_ports.elf
+ while (! ([ -e /dev/ttyACM1 ] && [ -e /dev/ttyACM2 ])) && [ $SECONDS -le 10 ]; do :; done
+ test -e /dev/ttyACM1 && echo "ttyACM1 exists"
+ test -e /dev/ttyACM2 && echo "ttyACM2 exists"
+
+ - name: Test cdc_msc
+ run: |
+ ./flash.sh cdc_msc.elf
+ readme='/media/pi/TinyUSB MSC/README.TXT'
+ while (! ([ -e /dev/ttyACM1 ] && [ -f "$readme" ])) && [ $SECONDS -le 10 ]; do :; done
+ test -e /dev/ttyACM1 && echo "ttyACM1 exists"
+ test -f "$readme" && echo "$readme exists"
+ cat "$readme"
+
+ - name: Test dfu
+ run: |
+ ./flash.sh dfu.elf
+ while (! (dfu-util -l | grep "Found DFU")) && [ $SECONDS -le 10 ]; do :; done
+ dfu-util -d cafe -a 0 -U dfu0
+ dfu-util -d cafe -a 1 -U dfu1
+ grep "TinyUSB DFU! - Partition 0" dfu0
+ grep "TinyUSB DFU! - Partition 1" dfu1
+
+ - name: Test dfu_runtime
+ run: |
+ ./flash.sh dfu_runtime.elf
+ while (! (dfu-util -l | grep "Found Runtime")) && [ $SECONDS -le 10 ]; do :; done
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index ab416bc52..f984954d9 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -1,6 +1,7 @@
name: pre-commit
on:
+ workflow_dispatch:
push:
pull_request:
branches: [ master ]
diff --git a/.github/workflows/trigger.yml b/.github/workflows/trigger.yml
index 86c699dac..33e3db859 100644
--- a/.github/workflows/trigger.yml
+++ b/.github/workflows/trigger.yml
@@ -1,6 +1,7 @@
name: Trigger Repos
on:
+ workflow_dispatch:
push:
branches: master
release:
diff --git a/.idea/cmake.xml b/.idea/cmake.xml
index 291da5371..a80ebed3c 100644
--- a/.idea/cmake.xml
+++ b/.idea/cmake.xml
@@ -2,6 +2,11 @@
+
+
+
+
+
@@ -22,7 +27,11 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/cdc_msc.xml b/.idea/runConfigurations/cdc_msc.xml
deleted file mode 100644
index fbeb4ae05..000000000
--- a/.idea/runConfigurations/cdc_msc.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/hid_composite.xml b/.idea/runConfigurations/hid_composite.xml
deleted file mode 100644
index b9f1d1a72..000000000
--- a/.idea/runConfigurations/hid_composite.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/msc_dual_lun.xml b/.idea/runConfigurations/msc_dual_lun.xml
deleted file mode 100644
index 6e0d74f5b..000000000
--- a/.idea/runConfigurations/msc_dual_lun.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/rp2040.xml b/.idea/runConfigurations/rp2040.xml
new file mode 100644
index 000000000..227a5e2bc
--- /dev/null
+++ b/.idea/runConfigurations/rp2040.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/rt1010_jlink.xml b/.idea/runConfigurations/rt1010_jlink.xml
new file mode 100644
index 000000000..70cfeea53
--- /dev/null
+++ b/.idea/runConfigurations/rt1010_jlink.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/rt1060_jlink.xml b/.idea/runConfigurations/rt1060_jlink.xml
new file mode 100644
index 000000000..eabadaf59
--- /dev/null
+++ b/.idea/runConfigurations/rt1060_jlink.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/tinyusb_examples.xml b/.idea/runConfigurations/tinyusb_examples.xml
deleted file mode 100644
index 60e586bbc..000000000
--- a/.idea/runConfigurations/tinyusb_examples.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index f05d025e7..94a25f7f4 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -1,65 +1,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 6fb98afb8..4071ec326 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -8,8 +8,16 @@ repos:
hooks:
- id: check-yaml
- id: trailing-whitespace
+ exclude: |
+ (?x)^(
+ hw/bsp/mcx/sdk/
+ )
- id: end-of-file-fixer
- exclude: ^.idea/
+ exclude: |
+ (?x)^(
+ .idea/|
+ hw/bsp/mcx/sdk/
+ )
- id: forbid-submodules
- repo: https://github.com/codespell-project/codespell
@@ -17,7 +25,11 @@ repos:
hooks:
- id: codespell
args: [-w]
- exclude: ^lib/
+ exclude: |
+ (?x)^(
+ lib/|
+ hw/bsp/mcx/sdk/
+ )
- repo: local
hooks:
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index 1421b397a..e26b1f475 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -4,11 +4,18 @@
version: 2
+# Set the version of Python and other tools you might need
+build:
+ os: ubuntu-22.04
+ tools:
+ python: "3.11"
+
+# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
+# Optionally declare the Python requirements required to build your docs
python:
- version: 3.8
install:
- requirements: docs/requirements.txt
diff --git a/docs/contributing/porting.rst b/docs/contributing/porting.rst
index 710af51c3..f81d98782 100644
--- a/docs/contributing/porting.rst
+++ b/docs/contributing/porting.rst
@@ -62,9 +62,9 @@ Feel free to skip this until you want to verify your demo code is running. To im
OS Abstraction Layer (OSAL)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The OS Abstraction Layer is responsible for providing basic data structures for TinyUSB that may allow for concurrency when used with an RTOS. Without an RTOS it simply handles concurrency issues between the main code and interrupts.
+The OS Abstraction Layer is responsible for providing basic data structures for TinyUSB that may allow for concurrency when used with an RTOS. Without an RTOS it simply handles concurrency issues between the main code and interrupts. The code is almost entirely agnostic of MCU and lives in ``src/osal``.
-The code is almost entirely agnostic of MCU and lives in ``src/osal``.
+In RTOS configurations, tud_task()/tuh_task() blocks behind a synchronization structure when the event queue is empty, so that the scheduler may give the CPU to a different task. To take advantage of the library's capability to yield the CPU when there are no actionable USB device events, ensure that the `CFG_TUSB_OS` symbol is defined, e.g `OPT_OS_FREERTOS` enables the FreeRTOS scheduler to schedule other threads than that which calls `tud_task()/tuh_task()`.
Device API
^^^^^^^^^^
diff --git a/docs/info/changelog.rst b/docs/info/changelog.rst
index ca715cb58..c6c02d181 100644
--- a/docs/info/changelog.rst
+++ b/docs/info/changelog.rst
@@ -93,7 +93,7 @@ Controller Driver (DCD & HCD)
- CFG_TUD_ENABLED/CFG_TUH_ENABLED, CFG_TUD_MAX_SPEED/CFG_TUH_MAX_SPEED can be used to replace CFG_TUSB_RHPORT0_MODE/CFG_TUSB_RHPORT1_MODE
- tud_init(rphort), tuh_init(rhport) can be used to init stack on specified roothub port (controller) instead of tusb_init(void)
-- Add dcd/hcd port specific defines TUP_ (stand for tinyusb port-specific)
+- Add dcd/hcd port specific defines `TUP_` (stand for tinyusb port-specific)
- [dwc2]
- Update to support stm32 h72x, h73x with only 1 otg controller
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 15022e147..ad5c89922 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,4 +1,4 @@
-sphinx~=3.0
+sphinx>=5.0
furo>=2020.12.30.b24
sphinx-autodoc-typehints>=1.10
-jinja2==3.0.3
+jinja2>=3.0.3
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index d91d8ca62..91c9fb098 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,9 +1,9 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
#set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include(${CMAKE_CURRENT_SOURCE_DIR}/../hw/bsp/family_support.cmake)
-project(tinyusb_examples)
+project(tinyusb_examples C CXX ASM)
add_subdirectory(device)
add_subdirectory(dual)
diff --git a/examples/device/CMakeLists.txt b/examples/device/CMakeLists.txt
index 5520209e0..5b077a5e1 100644
--- a/examples/device/CMakeLists.txt
+++ b/examples/device/CMakeLists.txt
@@ -1,8 +1,8 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/family_support.cmake)
-project(tinyusb_device_examples)
+project(tinyusb_device_examples C CXX ASM)
family_initialize_project(tinyusb_device_examples ${CMAKE_CURRENT_LIST_DIR})
# family_add_subdirectory will filter what to actually add based on selected FAMILY
diff --git a/examples/device/audio_4_channel_mic/CMakeLists.txt b/examples/device/audio_4_channel_mic/CMakeLists.txt
index f6e10e2ea..87b7d07d4 100644
--- a/examples/device/audio_4_channel_mic/CMakeLists.txt
+++ b/examples/device/audio_4_channel_mic/CMakeLists.txt
@@ -1,27 +1,32 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
+
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
-)
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
-)
+ )
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
diff --git a/examples/device/audio_test/CMakeLists.txt b/examples/device/audio_test/CMakeLists.txt
index f6e10e2ea..87b7d07d4 100644
--- a/examples/device/audio_test/CMakeLists.txt
+++ b/examples/device/audio_test/CMakeLists.txt
@@ -1,27 +1,32 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
+
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
-)
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
-)
+ )
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
diff --git a/examples/device/audio_test_multi_rate/CMakeLists.txt b/examples/device/audio_test_multi_rate/CMakeLists.txt
index f6e10e2ea..87b7d07d4 100644
--- a/examples/device/audio_test_multi_rate/CMakeLists.txt
+++ b/examples/device/audio_test_multi_rate/CMakeLists.txt
@@ -1,27 +1,32 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
+
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
-)
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
-)
+ )
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
diff --git a/examples/device/board_test/CMakeLists.txt b/examples/device/board_test/CMakeLists.txt
index 4435bd523..4ab8d5a65 100644
--- a/examples/device/board_test/CMakeLists.txt
+++ b/examples/device/board_test/CMakeLists.txt
@@ -1,30 +1,32 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
-# Other family such as rp2040
-if(NOT FAMILY STREQUAL "espressif")
- add_executable(${PROJECT})
-
- # Example source
- target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- )
-
- # Example include
- target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
-
- # Configure compilation flags and libraries for the example... see the corresponding function
- # in hw/bsp/FAMILY/family.cmake for details.
- family_configure_device_example(${PROJECT})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
endif()
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
+
+# Configure compilation flags and libraries for the example... see the corresponding function
+# in hw/bsp/FAMILY/family.cmake for details.
+family_configure_device_example(${PROJECT})
diff --git a/examples/device/cdc_dual_ports/CMakeLists.txt b/examples/device/cdc_dual_ports/CMakeLists.txt
index acaa54198..87b7d07d4 100644
--- a/examples/device/cdc_dual_ports/CMakeLists.txt
+++ b/examples/device/cdc_dual_ports/CMakeLists.txt
@@ -1,27 +1,32 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
+
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
diff --git a/examples/device/cdc_msc/CMakeLists.txt b/examples/device/cdc_msc/CMakeLists.txt
index 8e4db9d29..4ec172f17 100644
--- a/examples/device/cdc_msc/CMakeLists.txt
+++ b/examples/device/cdc_msc/CMakeLists.txt
@@ -1,28 +1,34 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
+
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
diff --git a/examples/device/cdc_msc_freertos/CMakeLists.txt b/examples/device/cdc_msc_freertos/CMakeLists.txt
index 714e5333b..319ad0356 100644
--- a/examples/device/cdc_msc_freertos/CMakeLists.txt
+++ b/examples/device/cdc_msc_freertos/CMakeLists.txt
@@ -1,16 +1,38 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
-# Check for -DFAMILY=
-if(NOT FAMILY STREQUAL "espressif")
- message(FATAL_ERROR "Invalid FAMILY specified: ${FAMILY}")
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
endif()
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/freertos_hook.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
+
+# Configure compilation flags and libraries for the example... see the corresponding function
+# in hw/bsp/FAMILY/family.cmake for details.
+family_configure_device_example(${PROJECT})
+
+# Add FreeRTOS for this example
+family_add_freertos(${PROJECT})
diff --git a/examples/device/cdc_msc_freertos/src/CMakeLists.txt b/examples/device/cdc_msc_freertos/src/CMakeLists.txt
index b77a68c8d..fee264363 100644
--- a/examples/device/cdc_msc_freertos/src/CMakeLists.txt
+++ b/examples/device/cdc_msc_freertos/src/CMakeLists.txt
@@ -1,3 +1,4 @@
+# This file is for ESP-IDF only
idf_component_register(SRCS "main.c" "usb_descriptors.c" "msc_disk.c"
INCLUDE_DIRS "."
REQUIRES boards tinyusb_src)
diff --git a/examples/device/dfu/CMakeLists.txt b/examples/device/dfu/CMakeLists.txt
index acaa54198..eb4c198d6 100644
--- a/examples/device/dfu/CMakeLists.txt
+++ b/examples/device/dfu/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
add_executable(${PROJECT})
diff --git a/examples/device/dfu_runtime/CMakeLists.txt b/examples/device/dfu_runtime/CMakeLists.txt
index acaa54198..eb4c198d6 100644
--- a/examples/device/dfu_runtime/CMakeLists.txt
+++ b/examples/device/dfu_runtime/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
add_executable(${PROJECT})
diff --git a/examples/device/dynamic_configuration/CMakeLists.txt b/examples/device/dynamic_configuration/CMakeLists.txt
index 8e4db9d29..046a32257 100644
--- a/examples/device/dynamic_configuration/CMakeLists.txt
+++ b/examples/device/dynamic_configuration/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
add_executable(${PROJECT})
diff --git a/examples/device/dynamic_configuration/src/usb_descriptors.c b/examples/device/dynamic_configuration/src/usb_descriptors.c
index 0590bd679..71348abef 100644
--- a/examples/device/dynamic_configuration/src/usb_descriptors.c
+++ b/examples/device/dynamic_configuration/src/usb_descriptors.c
@@ -183,7 +183,7 @@ uint8_t const desc_configuration_0[] =
};
-uint8_t const desc_configuraiton_1[] =
+uint8_t const desc_configuration_1[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_1_NUM_TOTAL, 0, CONFIG_1_TOTAL_LEN, 0x00, 100),
@@ -199,7 +199,7 @@ uint8_t const desc_configuraiton_1[] =
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
- return mode ? desc_configuraiton_1 : desc_configuration_0;
+ return mode ? desc_configuration_1 : desc_configuration_0;
}
//--------------------------------------------------------------------+
diff --git a/examples/device/hid_boot_interface/CMakeLists.txt b/examples/device/hid_boot_interface/CMakeLists.txt
index acaa54198..eb4c198d6 100644
--- a/examples/device/hid_boot_interface/CMakeLists.txt
+++ b/examples/device/hid_boot_interface/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
add_executable(${PROJECT})
diff --git a/examples/device/hid_composite/CMakeLists.txt b/examples/device/hid_composite/CMakeLists.txt
index acaa54198..eb4c198d6 100644
--- a/examples/device/hid_composite/CMakeLists.txt
+++ b/examples/device/hid_composite/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
add_executable(${PROJECT})
diff --git a/examples/device/hid_composite_freertos/CMakeLists.txt b/examples/device/hid_composite_freertos/CMakeLists.txt
index 714e5333b..211904cf9 100644
--- a/examples/device/hid_composite_freertos/CMakeLists.txt
+++ b/examples/device/hid_composite_freertos/CMakeLists.txt
@@ -1,16 +1,37 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
-# Check for -DFAMILY=
-if(NOT FAMILY STREQUAL "espressif")
- message(FATAL_ERROR "Invalid FAMILY specified: ${FAMILY}")
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
endif()
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/freertos_hook.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
+
+# Configure compilation flags and libraries for the example... see the corresponding function
+# in hw/bsp/FAMILY/family.cmake for details.
+family_configure_device_example(${PROJECT})
+
+# Add FreeRTOS for this example
+family_add_freertos(${PROJECT})
diff --git a/examples/device/hid_generic_inout/CMakeLists.txt b/examples/device/hid_generic_inout/CMakeLists.txt
index acaa54198..eb4c198d6 100644
--- a/examples/device/hid_generic_inout/CMakeLists.txt
+++ b/examples/device/hid_generic_inout/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
add_executable(${PROJECT})
diff --git a/examples/device/hid_multiple_interface/CMakeLists.txt b/examples/device/hid_multiple_interface/CMakeLists.txt
index acaa54198..eb4c198d6 100644
--- a/examples/device/hid_multiple_interface/CMakeLists.txt
+++ b/examples/device/hid_multiple_interface/CMakeLists.txt
@@ -1,14 +1,18 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
add_executable(${PROJECT})
diff --git a/examples/device/midi_test/CMakeLists.txt b/examples/device/midi_test/CMakeLists.txt
index acaa54198..5b1a5547d 100644
--- a/examples/device/midi_test/CMakeLists.txt
+++ b/examples/device/midi_test/CMakeLists.txt
@@ -1,17 +1,20 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
add_executable(${PROJECT})
-
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
diff --git a/examples/device/msc_dual_lun/CMakeLists.txt b/examples/device/msc_dual_lun/CMakeLists.txt
index 9188ab06c..dc8d5512c 100644
--- a/examples/device/msc_dual_lun/CMakeLists.txt
+++ b/examples/device/msc_dual_lun/CMakeLists.txt
@@ -1,28 +1,33 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
+
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk_dual.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk_dual.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
diff --git a/examples/device/net_lwip_webserver/CMakeLists.txt b/examples/device/net_lwip_webserver/CMakeLists.txt
index 5f1e37931..5225f7c42 100644
--- a/examples/device/net_lwip_webserver/CMakeLists.txt
+++ b/examples/device/net_lwip_webserver/CMakeLists.txt
@@ -1,83 +1,89 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
-set(TOP "../../..")
-get_filename_component(TOP "${TOP}" REALPATH)
+include(${CMAKE_CURRENT_LIST_DIR}/../../../hw/bsp/family_support.cmake)
-if (EXISTS ${TOP}/lib/lwip/src)
- include(${TOP}/hw/bsp/family_support.cmake)
-
- # gets PROJECT name for the example (e.g. -)
- family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-
- project(${PROJECT})
-
- # Checks this example is valid for the family and initializes the project
- family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
-
- add_executable(${PROJECT})
-
- # Example source
- target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
- )
-
- # Example include
- target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- ${TOP}/lib/lwip/src/include
- ${TOP}/lib/lwip/src/include/ipv4
- ${TOP}/lib/lwip/src/include/lwip/apps
- ${TOP}/lib/networking
- )
-
- target_sources(${PROJECT} PUBLIC
- ${TOP}/lib/lwip/src/core/altcp.c
- ${TOP}/lib/lwip/src/core/altcp_alloc.c
- ${TOP}/lib/lwip/src/core/altcp_tcp.c
- ${TOP}/lib/lwip/src/core/def.c
- ${TOP}/lib/lwip/src/core/dns.c
- ${TOP}/lib/lwip/src/core/inet_chksum.c
- ${TOP}/lib/lwip/src/core/init.c
- ${TOP}/lib/lwip/src/core/ip.c
- ${TOP}/lib/lwip/src/core/mem.c
- ${TOP}/lib/lwip/src/core/memp.c
- ${TOP}/lib/lwip/src/core/netif.c
- ${TOP}/lib/lwip/src/core/pbuf.c
- ${TOP}/lib/lwip/src/core/raw.c
- ${TOP}/lib/lwip/src/core/stats.c
- ${TOP}/lib/lwip/src/core/sys.c
- ${TOP}/lib/lwip/src/core/tcp.c
- ${TOP}/lib/lwip/src/core/tcp_in.c
- ${TOP}/lib/lwip/src/core/tcp_out.c
- ${TOP}/lib/lwip/src/core/timeouts.c
- ${TOP}/lib/lwip/src/core/udp.c
- ${TOP}/lib/lwip/src/core/ipv4/autoip.c
- ${TOP}/lib/lwip/src/core/ipv4/dhcp.c
- ${TOP}/lib/lwip/src/core/ipv4/etharp.c
- ${TOP}/lib/lwip/src/core/ipv4/icmp.c
- ${TOP}/lib/lwip/src/core/ipv4/igmp.c
- ${TOP}/lib/lwip/src/core/ipv4/ip4.c
- ${TOP}/lib/lwip/src/core/ipv4/ip4_addr.c
- ${TOP}/lib/lwip/src/core/ipv4/ip4_frag.c
- ${TOP}/lib/lwip/src/netif/ethernet.c
- ${TOP}/lib/lwip/src/netif/slipif.c
- ${TOP}/lib/lwip/src/apps/http/httpd.c
- ${TOP}/lib/lwip/src/apps/http/fs.c
- ${TOP}/lib/networking/dhserver.c
- ${TOP}/lib/networking/dnserver.c
- ${TOP}/lib/networking/rndis_reports.c
- )
-
- # due to warnings from other net source, we need to prevent error from some of the warnings options
- target_compile_options(${PROJECT} PUBLIC
- -Wno-error=null-dereference
- -Wno-error=conversion
- -Wno-error=sign-conversion
- -Wno-error=sign-compare
- )
-
- # Configure compilation flags and libraries for the example... see the corresponding function
- # in hw/bsp/FAMILY/family.cmake for details.
- family_configure_device_example(${PROJECT})
+set(LWIP ${TOP}/lib/lwip)
+if (NOT EXISTS ${LWIP}/src)
+ MESSAGE(WARNING "lib/lwip submodule not found, please run 'python tools/get_deps.py lib/lwip' to fetch it")
+ return()
endif()
+
+# gets PROJECT name for the example (e.g. -)
+family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
+
+project(${PROJECT} C CXX ASM)
+
+# Checks this example is valid for the family and initializes the project
+family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_LIST_DIR}/src/main.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/usb_descriptors.c
+ )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+ ${CMAKE_CURRENT_LIST_DIR}/src
+ ${LWIP}/src/include
+ ${LWIP}/src/include/ipv4
+ ${LWIP}/src/include/lwip/apps
+ ${TOP}/lib/networking
+ )
+
+# lib/networking sources
+target_sources(${PROJECT} PUBLIC
+ ${TOP}/lib/networking/dhserver.c
+ ${TOP}/lib/networking/dnserver.c
+ ${TOP}/lib/networking/rndis_reports.c
+ )
+
+# lwip sources
+target_sources(${PROJECT} PUBLIC
+ ${LWIP}/src/core/altcp.c
+ ${LWIP}/src/core/altcp_alloc.c
+ ${LWIP}/src/core/altcp_tcp.c
+ ${LWIP}/src/core/def.c
+ ${LWIP}/src/core/dns.c
+ ${LWIP}/src/core/inet_chksum.c
+ ${LWIP}/src/core/init.c
+ ${LWIP}/src/core/ip.c
+ ${LWIP}/src/core/mem.c
+ ${LWIP}/src/core/memp.c
+ ${LWIP}/src/core/netif.c
+ ${LWIP}/src/core/pbuf.c
+ ${LWIP}/src/core/raw.c
+ ${LWIP}/src/core/stats.c
+ ${LWIP}/src/core/sys.c
+ ${LWIP}/src/core/tcp.c
+ ${LWIP}/src/core/tcp_in.c
+ ${LWIP}/src/core/tcp_out.c
+ ${LWIP}/src/core/timeouts.c
+ ${LWIP}/src/core/udp.c
+ ${LWIP}/src/core/ipv4/autoip.c
+ ${LWIP}/src/core/ipv4/dhcp.c
+ ${LWIP}/src/core/ipv4/etharp.c
+ ${LWIP}/src/core/ipv4/icmp.c
+ ${LWIP}/src/core/ipv4/igmp.c
+ ${LWIP}/src/core/ipv4/ip4.c
+ ${LWIP}/src/core/ipv4/ip4_addr.c
+ ${LWIP}/src/core/ipv4/ip4_frag.c
+ ${LWIP}/src/netif/ethernet.c
+ ${LWIP}/src/netif/slipif.c
+ ${LWIP}/src/apps/http/httpd.c
+ ${LWIP}/src/apps/http/fs.c
+ )
+
+# due to warnings from other net source, we need to prevent error from some of the warnings options
+target_compile_options(${PROJECT} PUBLIC
+ -Wno-error=null-dereference
+ -Wno-error=conversion
+ -Wno-error=sign-conversion
+ -Wno-error=sign-compare
+ )
+
+# Configure compilation flags and libraries for the example... see the corresponding function
+# in hw/bsp/FAMILY/family.cmake for details.
+family_configure_device_example(${PROJECT})
diff --git a/examples/device/uac2_headset/CMakeLists.txt b/examples/device/uac2_headset/CMakeLists.txt
index acaa54198..d142e9c04 100644
--- a/examples/device/uac2_headset/CMakeLists.txt
+++ b/examples/device/uac2_headset/CMakeLists.txt
@@ -1,15 +1,20 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
+
add_executable(${PROJECT})
# Example source
diff --git a/examples/device/usbtmc/CMakeLists.txt b/examples/device/usbtmc/CMakeLists.txt
index b4678dc5e..a6b22ab36 100644
--- a/examples/device/usbtmc/CMakeLists.txt
+++ b/examples/device/usbtmc/CMakeLists.txt
@@ -1,15 +1,20 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
+
add_executable(${PROJECT})
# Example source
diff --git a/examples/device/video_capture/CMakeLists.txt b/examples/device/video_capture/CMakeLists.txt
index f1ef247e1..e0bd975c4 100644
--- a/examples/device/video_capture/CMakeLists.txt
+++ b/examples/device/video_capture/CMakeLists.txt
@@ -1,15 +1,20 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
+
add_executable(${PROJECT})
if (FORCE_READONLY)
diff --git a/examples/device/webusb_serial/CMakeLists.txt b/examples/device/webusb_serial/CMakeLists.txt
index acaa54198..d142e9c04 100644
--- a/examples/device/webusb_serial/CMakeLists.txt
+++ b/examples/device/webusb_serial/CMakeLists.txt
@@ -1,15 +1,20 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+# Espressif has its own cmake build system
+if(FAMILY STREQUAL "espressif")
+ return()
+endif()
+
add_executable(${PROJECT})
# Example source
diff --git a/examples/dual/CMakeLists.txt b/examples/dual/CMakeLists.txt
index d2f9a42f0..15081cf26 100644
--- a/examples/dual/CMakeLists.txt
+++ b/examples/dual/CMakeLists.txt
@@ -1,12 +1,13 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/family_support.cmake)
-project(tinyusb_dual_examples)
+project(tinyusb_dual_examples C CXX ASM)
family_initialize_project(tinyusb_dual_examples ${CMAKE_CURRENT_LIST_DIR})
+
if (FAMILY STREQUAL "rp2040" AND NOT TARGET tinyusb_pico_pio_usb)
- message("Skipping dual host/device mode examples as Pico-PIO-USB is not available")
-else()
- # family_add_subdirectory will filter what to actually add based on selected FAMILY
- family_add_subdirectory(host_hid_to_device_cdc)
-endif()
+ message("Skipping dual host/device mode examples as Pico-PIO-USB is not available")
+else ()
+ # family_add_subdirectory will filter what to actually add based on selected FAMILY
+ family_add_subdirectory(host_hid_to_device_cdc)
+endif ()
diff --git a/examples/dual/host_hid_to_device_cdc/CMakeLists.txt b/examples/dual/host_hid_to_device_cdc/CMakeLists.txt
index 724d1e119..c6d19a720 100644
--- a/examples/dual/host_hid_to_device_cdc/CMakeLists.txt
+++ b/examples/dual/host_hid_to_device_cdc/CMakeLists.txt
@@ -1,11 +1,11 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
@@ -14,14 +14,14 @@ add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
@@ -29,12 +29,12 @@ family_configure_dual_usb_example(${PROJECT})
# due to warnings from Pico-PIO-USB
target_compile_options(${PROJECT} PUBLIC
- -Wno-error=shadow
- -Wno-error=cast-align
- -Wno-error=cast-qual
- -Wno-error=redundant-decls
- -Wno-error=sign-conversion
- -Wno-error=conversion
- -Wno-error=sign-compare
- -Wno-error=unused-function
- )
+ -Wno-error=shadow
+ -Wno-error=cast-align
+ -Wno-error=cast-qual
+ -Wno-error=redundant-decls
+ -Wno-error=sign-conversion
+ -Wno-error=conversion
+ -Wno-error=sign-compare
+ -Wno-error=unused-function
+ )
diff --git a/examples/dual/host_hid_to_device_cdc/src/tusb_config.h b/examples/dual/host_hid_to_device_cdc/src/tusb_config.h
index 2185cd1f1..8133ed418 100644
--- a/examples/dual/host_hid_to_device_cdc/src/tusb_config.h
+++ b/examples/dual/host_hid_to_device_cdc/src/tusb_config.h
@@ -84,10 +84,6 @@
#define CFG_TUH_RPI_PIO_USB 1
#endif
-
-// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
-// #define CFG_TUSB_DEBUG 0
-
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
@@ -133,7 +129,7 @@
#endif
#ifndef CFG_TUH_MEM_ALIGN
-#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
+#define CFG_TUH_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
#define CFG_TUH_HUB 1
diff --git a/examples/host/CMakeLists.txt b/examples/host/CMakeLists.txt
index 758973ab2..bedd2220b 100644
--- a/examples/host/CMakeLists.txt
+++ b/examples/host/CMakeLists.txt
@@ -1,8 +1,8 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/family_support.cmake)
-project(tinyusb_host_examples)
+project(tinyusb_host_examples C CXX ASM)
family_initialize_project(tinyusb_host_examples ${CMAKE_CURRENT_LIST_DIR})
# family_add_subdirectory will filter what to actually add based on selected FAMILY
diff --git a/examples/host/bare_api/CMakeLists.txt b/examples/host/bare_api/CMakeLists.txt
index 616edd4ac..b6d8c9c89 100644
--- a/examples/host/bare_api/CMakeLists.txt
+++ b/examples/host/bare_api/CMakeLists.txt
@@ -1,11 +1,11 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt
index d7d1a54d7..68b52e274 100644
--- a/examples/host/cdc_msc_hid/CMakeLists.txt
+++ b/examples/host/cdc_msc_hid/CMakeLists.txt
@@ -1,11 +1,11 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
@@ -14,16 +14,16 @@ add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c
index ed53c502d..87e110ab2 100644
--- a/examples/host/cdc_msc_hid/src/hid_app.c
+++ b/examples/host/cdc_msc_hid/src/hid_app.c
@@ -263,7 +263,7 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c
if (!rpt_info)
{
- printf("Couldn't find the report info for this report !\r\n");
+ printf("Couldn't find report info !\r\n");
return;
}
diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h
index 1152e4910..abb75f068 100644
--- a/examples/host/cdc_msc_hid/src/tusb_config.h
+++ b/examples/host/cdc_msc_hid/src/tusb_config.h
@@ -96,7 +96,9 @@
#define CFG_TUH_ENUMERATION_BUFSIZE 256
#define CFG_TUH_HUB 1 // number of supported hubs
-#define CFG_TUH_CDC 1
+#define CFG_TUH_CDC 1 // CDC ACM
+#define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API
+#define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
#define CFG_TUH_MSC 1
#define CFG_TUH_VENDOR 0
diff --git a/examples/host/hid_controller/CMakeLists.txt b/examples/host/hid_controller/CMakeLists.txt
index ac3070b82..e27f83c53 100644
--- a/examples/host/hid_controller/CMakeLists.txt
+++ b/examples/host/hid_controller/CMakeLists.txt
@@ -1,11 +1,11 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
@@ -14,14 +14,14 @@ add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
diff --git a/examples/host/msc_file_explorer/CMakeLists.txt b/examples/host/msc_file_explorer/CMakeLists.txt
index 7955b3078..2d5600059 100644
--- a/examples/host/msc_file_explorer/CMakeLists.txt
+++ b/examples/host/msc_file_explorer/CMakeLists.txt
@@ -1,11 +1,11 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.17)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example (e.g. -)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
-project(${PROJECT})
+project(${PROJECT} C CXX ASM)
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
@@ -14,19 +14,19 @@ add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
- ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c
- ${TOP}/lib/fatfs/source/ff.c
- ${TOP}/lib/fatfs/source/ffsystem.c
- ${TOP}/lib/fatfs/source/ffunicode.c
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c
+ ${TOP}/lib/fatfs/source/ff.c
+ ${TOP}/lib/fatfs/source/ffsystem.c
+ ${TOP}/lib/fatfs/source/ffunicode.c
+ )
# Example include
target_include_directories(${PROJECT} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- ${TOP}/lib/fatfs/source
- ${TOP}/lib/embedded-cli
- )
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ ${TOP}/lib/fatfs/source
+ ${TOP}/lib/embedded-cli
+ )
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
diff --git a/examples/make.mk b/examples/make.mk
index 2ce6fb398..28ebc62da 100644
--- a/examples/make.mk
+++ b/examples/make.mk
@@ -2,6 +2,8 @@
# Common make definition for all examples
# ---------------------------------------
+TOOLCHAIN ?= gcc
+
#-------------- TOP and CURRENT_PATH ------------
# Set TOP to be the path to get from the current directory (where make was
@@ -75,6 +77,7 @@ else
endif
#-------------- Cross Compiler ------------
+
# Can be set by board, default to ARM GCC
CROSS_COMPILE ?= arm-none-eabi-
diff --git a/examples/rules.mk b/examples/rules.mk
index c125408df..f6422092a 100644
--- a/examples/rules.mk
+++ b/examples/rules.mk
@@ -72,6 +72,11 @@ endif
LDFLAGS += $(CFLAGS) -Wl,-Map=$@.map -Wl,-cref -Wl,-gc-sections
+# Some toolchain such as renesas rx does not support --print-memory-usage flags
+ifneq ($(FAMILY),rx)
+LDFLAGS += -Wl,--print-memory-usage
+endif
+
ifdef LD_FILE
LDFLAGS += -Wl,-T,$(TOP)/$(LD_FILE)
endif
@@ -81,7 +86,7 @@ LDFLAGS += -Wl,-T,$(TOP)/$(GCC_LD_FILE)
endif
ifneq ($(SKIP_NANOLIB), 1)
-LDFLAGS += -specs=nosys.specs -specs=nano.specs
+LDFLAGS += --specs=nosys.specs --specs=nano.specs
endif
ASFLAGS += $(CFLAGS)
@@ -222,14 +227,19 @@ endif
# Jlink Interface
JLINK_IF ?= swd
+# Jlink script
+define jlink_script
+halt
+loadfile $^
+r
+go
+exit
+endef
+export jlink_script
+
# Flash using jlink
flash-jlink: $(BUILD)/$(PROJECT).hex
- @echo halt > $(BUILD)/$(BOARD).jlink
- @echo r > $(BUILD)/$(BOARD).jlink
- @echo loadfile $^ >> $(BUILD)/$(BOARD).jlink
- @echo r >> $(BUILD)/$(BOARD).jlink
- @echo go >> $(BUILD)/$(BOARD).jlink
- @echo exit >> $(BUILD)/$(BOARD).jlink
+ @echo "$$jlink_script" > $(BUILD)/$(BOARD).jlink
$(JLINKEXE) -device $(JLINK_DEVICE) -if $(JLINK_IF) -JTAGConf -1,-1 -speed auto -CommandFile $(BUILD)/$(BOARD).jlink
# Flash STM32 MCU using stlink with STM32 Cube Programmer CLI
diff --git a/hw/bsp/board.c b/hw/bsp/board.c
index e715bdf2e..66ffcb199 100644
--- a/hw/bsp/board.c
+++ b/hw/bsp/board.c
@@ -25,55 +25,6 @@
#include "board.h"
-#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
//--------------------------------------------------------------------+
diff --git a/hw/bsp/board_mcu.h b/hw/bsp/board_mcu.h
index 6d40aa0d1..edae4c645 100644
--- a/hw/bsp/board_mcu.h
+++ b/hw/bsp/board_mcu.h
@@ -44,7 +44,7 @@
TU_CHECK_MCU(OPT_MCU_LPC40XX, OPT_MCU_LPC43XX)
#include "chip.h"
-#elif TU_CHECK_MCU(OPT_MCU_LPC51UXX, OPT_MCU_LPC54XXX, OPT_MCU_LPC55XX)
+#elif TU_CHECK_MCU(OPT_MCU_LPC51UXX, OPT_MCU_LPC54XXX, OPT_MCU_LPC55XX, OPT_MCU_MCXN9)
#include "fsl_device_registers.h"
#elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32)
diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake
index 08bb20bc3..69290ceec 100644
--- a/hw/bsp/family_support.cmake
+++ b/hw/bsp/family_support.cmake
@@ -1,142 +1,272 @@
-if (NOT TARGET _family_support_marker)
- add_library(_family_support_marker INTERFACE)
+include_guard()
- 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 cmake command line")
- endif()
+include(CMakePrintHelpers)
- if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/${FAMILY}/family.cmake)
- message(FATAL_ERROR "Family '${FAMILY}' is not known/supported")
- endif()
+# TOP is path to root directory
+set(TOP "${CMAKE_CURRENT_LIST_DIR}/../..")
- function(family_filter RESULT DIR)
- get_filename_component(DIR ${DIR} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+# Default to gcc
+if (NOT DEFINED TOOLCHAIN)
+ set(TOOLCHAIN gcc)
+endif ()
- if (EXISTS "${DIR}/only.txt")
- file(READ "${DIR}/only.txt" ONLYS)
- # Replace newlines with semicolon so that it is treated as a list by CMake
- string(REPLACE "\n" ";" ONLYS_LINES ${ONLYS})
- # For each mcu
- foreach(MCU IN LISTS FAMILY_MCUS)
- # For each line in only.txt
- foreach(_line ${ONLYS_LINES})
- # If mcu:xxx exists for this mcu then include
- if (${_line} STREQUAL "mcu:${MCU}")
- set(${RESULT} 1 PARENT_SCOPE)
- return()
- endif()
- endforeach()
- endforeach()
+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 cmake command line")
+endif ()
- # Didn't find it in only file so don't build
- set(${RESULT} 0 PARENT_SCOPE)
-
- elseif (EXISTS "${DIR}/skip.txt")
- file(READ "${DIR}/skip.txt" SKIPS)
- # Replace newlines with semicolon so that it is treated as a list by CMake
- string(REPLACE "\n" ";" SKIPS_LINES ${SKIPS})
- # For each mcu
- foreach(MCU IN LISTS FAMILY_MCUS)
- # For each line in only.txt
- foreach(_line ${SKIPS_LINES})
- # If mcu:xxx exists for this mcu then skip
- if (${_line} STREQUAL "mcu:${MCU}")
- set(${RESULT} 0 PARENT_SCOPE)
- return()
- endif()
- endforeach()
- endforeach()
-
- # Didn't find in skip file so build
- set(${RESULT} 1 PARENT_SCOPE)
-
- else()
-
- # Didn't find skip or only file so build
- set(${RESULT} 1 PARENT_SCOPE)
-
- endif()
-
- 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()
-
- function(family_add_default_example_warnings TARGET)
- target_compile_options(${TARGET} PUBLIC
- -Wall
- -Wextra
- -Werror
- -Wfatal-errors
- -Wdouble-promotion
- -Wfloat-equal
- -Wshadow
- -Wwrite-strings
- -Wsign-compare
- -Wmissing-format-attribute
- -Wunreachable-code
- -Wcast-align
- -Wcast-qual
- -Wnull-dereference
- -Wuninitialized
- -Wunused
- -Wredundant-decls
- #-Wstrict-prototypes
- #-Werror-implicit-function-declaration
- #-Wundef
- )
-
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
- # GCC 10
- if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0)
- target_compile_options(${TARGET} PUBLIC -Wconversion)
- endif()
-
- # GCC 8
- if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0)
- target_compile_options(${TARGET} PUBLIC -Wcast-function-type -Wstrict-overflow)
- endif()
-
- # GCC 6
- if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.0)
- target_compile_options(${TARGET} PUBLIC -Wno-strict-aliasing)
- endif()
- 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 implementation 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 implementation 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 "")
+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})
+
+ if (EXISTS "${DIR}/only.txt")
+ file(READ "${DIR}/only.txt" ONLYS)
+ # Replace newlines with semicolon so that it is treated as a list by CMake
+ string(REPLACE "\n" ";" ONLYS_LINES ${ONLYS})
+
+ # For each mcu
+ foreach(MCU IN LISTS FAMILY_MCUS)
+ # For each line in only.txt
+ foreach(_line ${ONLYS_LINES})
+ # If mcu:xxx exists for this mcu or board:xxx then include
+ if (${_line} STREQUAL "mcu:${MCU}" OR ${_line} STREQUAL "board:${BOARD}")
+ set(${RESULT} 1 PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+ endforeach()
+
+ # Didn't find it in only file so don't build
+ set(${RESULT} 0 PARENT_SCOPE)
+
+ elseif (EXISTS "${DIR}/skip.txt")
+ file(READ "${DIR}/skip.txt" SKIPS)
+ # Replace newlines with semicolon so that it is treated as a list by CMake
+ string(REPLACE "\n" ";" SKIPS_LINES ${SKIPS})
+
+ # For each mcu
+ foreach(MCU IN LISTS FAMILY_MCUS)
+ # For each line in only.txt
+ foreach(_line ${SKIPS_LINES})
+ # If mcu:xxx exists for this mcu then skip
+ if (${_line} STREQUAL "mcu:${MCU}")
+ set(${RESULT} 0 PARENT_SCOPE)
+ return()
+ endif()
+ endforeach()
+ endforeach()
+
+ # Didn't find in skip file so build
+ set(${RESULT} 1 PARENT_SCOPE)
+ else()
+
+ # Didn't find skip or only file so build
+ set(${RESULT} 1 PARENT_SCOPE)
+ endif()
+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)
+ # set output suffix to .elf (skip espressif)
+ if(NOT FAMILY STREQUAL "espressif")
+ set(CMAKE_EXECUTABLE_SUFFIX .elf PARENT_SCOPE)
+ endif()
+
+ 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()
+
+
+function(family_add_default_example_warnings TARGET)
+ target_compile_options(${TARGET} PUBLIC
+ -Wall
+ -Wextra
+ -Werror
+ -Wfatal-errors
+ -Wdouble-promotion
+ -Wfloat-equal
+ -Wshadow
+ -Wwrite-strings
+ -Wsign-compare
+ -Wmissing-format-attribute
+ -Wunreachable-code
+ -Wcast-align
+ -Wcast-qual
+ -Wnull-dereference
+ -Wuninitialized
+ -Wunused
+ -Wredundant-decls
+ #-Wstrict-prototypes
+ #-Werror-implicit-function-declaration
+ #-Wundef
+ )
+
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0)
+ target_link_options(${TARGET} PUBLIC "LINKER:--no-warn-rwx-segments")
+ endif()
+
+ # GCC 10
+ if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0)
+ target_compile_options(${TARGET} PUBLIC -Wconversion)
+ endif()
+
+ # GCC 8
+ if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0)
+ target_compile_options(${TARGET} PUBLIC -Wcast-function-type -Wstrict-overflow)
+ endif()
+
+ # GCC 6
+ if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.0)
+ target_compile_options(${TARGET} PUBLIC -Wno-strict-aliasing)
+ endif()
+ endif()
+endfunction()
+
+
+function(family_configure_common TARGET)
+ # run size after build
+ add_custom_command(TARGET ${TARGET} POST_BUILD
+ COMMAND ${CMAKE_SIZE} $
+ )
+
+ # Generate map file
+ target_link_options(${TARGET} PUBLIC
+ # link map
+ "LINKER:-Map=$.map"
+ )
+endfunction()
+
+
+# Add bin/hex output
+function(family_add_bin_hex TARGET)
+ add_custom_command(TARGET ${TARGET} POST_BUILD
+ COMMAND ${CMAKE_OBJCOPY} -Obinary $ $/${TARGET}.bin
+ COMMAND ${CMAKE_OBJCOPY} -Oihex $ $/${TARGET}.hex
+ VERBATIM)
+endfunction()
+
+
+# Add flash jlink target
+function(family_flash_jlink TARGET)
+ if (NOT DEFINED JLINKEXE)
+ set(JLINKEXE JLinkExe)
+ endif ()
+
+ file(GENERATE
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}.jlink
+ CONTENT "halt
+loadfile $
+r
+go
+exit"
+ )
+
+ add_custom_target(${TARGET}-jlink
+ DEPENDS ${TARGET}
+ COMMAND ${JLINKEXE} -device ${JLINK_DEVICE} -if swd -JTAGConf -1,-1 -speed auto -CommandFile ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}.jlink
+ )
+endfunction()
+
+
+# Add flash pycod target
+function(family_flash_pyocd TARGET)
+ if (NOT DEFINED PYOC)
+ set(PYOCD pyocd)
+ endif ()
+
+ add_custom_target(${TARGET}-pyocd
+ DEPENDS ${TARGET}
+ COMMAND ${PYOCD} flash -t ${PYOCD_TARGET} $
+ )
+endfunction()
+
+
+# Add flash using NXP's LinkServer (redserver)
+# https://www.nxp.com/design/software/development-software/mcuxpresso-software-and-tools-/linkserver-for-microcontrollers:LINKERSERVER
+function(family_flash_nxplink TARGET)
+ if (NOT DEFINED LINKSERVER)
+ set(LINKSERVER LinkServer)
+ endif ()
+
+ # LinkServer has a bug that can only execute with full path otherwise it throws:
+ # realpath error: No such file or directory
+ execute_process(COMMAND which ${LINKSERVER} OUTPUT_VARIABLE LINKSERVER_PATH OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ add_custom_target(${TARGET}-nxplink
+ DEPENDS ${TARGET}
+ COMMAND ${LINKSERVER_PATH} flash ${NXPLINK_DEVICE} load $
+ )
+endfunction()
+
+
+# configure an executable target to link to tinyusb in device mode, and add the board implementation
+function(family_configure_device_example TARGET)
+ # default implementation 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 implementation is empty, the function should be redefined in the FAMILY/family.cmake
+endfunction()
+
+
+# Add freeRTOS support to example, can be overridden by FAMILY/family.cmake
+function(family_add_freertos TARGET)
+ # freeros config
+ if (NOT TARGET freertos_config)
+ add_library(freertos_config INTERFACE)
+ target_include_directories(freertos_config SYSTEM INTERFACE
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/${FAMILY}/FreeRTOSConfig
+ )
+ endif()
+
+ # freertos kernel should be generic as freertos_config however, CMAKE complains with missing variable
+ # such as CMAKE_C_COMPILE_OBJECT
+ if (NOT TARGET freertos_kernel)
+ add_subdirectory(${TOP}/lib/FreeRTOS-Kernel ${CMAKE_BINARY_DIR}/lib/freertos_kernel)
+ endif ()
+
+ # Add FreeRTOS option to tinyusb_config
+ target_compile_definitions(${TARGET}-tinyusb_config INTERFACE
+ CFG_TUSB_OS=OPT_OS_FREERTOS
+ )
+ # link tinyusb with freeRTOS kernel
+ target_link_libraries(${TARGET}-tinyusb PUBLIC
+ freertos_kernel
+ )
+ target_link_libraries(${TARGET} PUBLIC
+ freertos_kernel
+ )
+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 "")
diff --git a/hw/bsp/imxrt/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/imxrt/FreeRTOSConfig/FreeRTOSConfig.h
new file mode 100644
index 000000000..c1928fbcd
--- /dev/null
+++ b/hw/bsp/imxrt/FreeRTOSConfig/FreeRTOSConfig.h
@@ -0,0 +1,166 @@
+/*
+ * FreeRTOS Kernel V10.0.0
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. If you wish to use our Amazon
+ * FreeRTOS name, please do so in a fair use way that does not cause confusion.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://www.FreeRTOS.org
+ * http://aws.amazon.com/freertos
+ *
+ * 1 tab == 4 spaces!
+ */
+
+
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+/*-----------------------------------------------------------
+ * Application specific definitions.
+ *
+ * These definitions should be adjusted for your particular hardware and
+ * application requirements.
+ *
+ * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
+ * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
+ *
+ * See http://www.freertos.org/a00110.html.
+ *----------------------------------------------------------*/
+
+// skip if included from IAR assembler
+#ifndef __IASMARM__
+// FIXME cause redundant-decls warnings
+extern uint32_t SystemCoreClock;
+#endif
+
+/* Cortex M23/M33 port configuration. */
+#define configENABLE_MPU 0
+#define configENABLE_FPU 1
+#define configENABLE_TRUSTZONE 0
+#define configMINIMAL_SECURE_STACK_SIZE (1024)
+
+#define configUSE_PREEMPTION 1
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
+#define configCPU_CLOCK_HZ SystemCoreClock
+#define configTICK_RATE_HZ ( 1000 )
+#define configMAX_PRIORITIES ( 5 )
+#define configMINIMAL_STACK_SIZE ( 128 )
+#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 )
+#define configMAX_TASK_NAME_LEN 16
+#define configUSE_16_BIT_TICKS 0
+#define configIDLE_SHOULD_YIELD 1
+#define configUSE_MUTEXES 1
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configQUEUE_REGISTRY_SIZE 2
+#define configUSE_QUEUE_SETS 0
+#define configUSE_TIME_SLICING 0
+#define configUSE_NEWLIB_REENTRANT 0
+#define configENABLE_BACKWARD_COMPATIBILITY 1
+#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
+
+#define configSUPPORT_STATIC_ALLOCATION 0
+#define configSUPPORT_DYNAMIC_ALLOCATION 1
+
+/* Hook function related definitions. */
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning
+#define configCHECK_FOR_STACK_OVERFLOW 2
+
+/* Run time and task stats gathering related definitions. */
+#define configGENERATE_RUN_TIME_STATS 0
+#define configRECORD_STACK_HIGH_ADDRESS 1
+#define configUSE_TRACE_FACILITY 1 // legacy trace
+#define configUSE_STATS_FORMATTING_FUNCTIONS 0
+
+/* Co-routine definitions. */
+#define configUSE_CO_ROUTINES 0
+#define configMAX_CO_ROUTINE_PRIORITIES 2
+
+/* Software timer related definitions. */
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2)
+#define configTIMER_QUEUE_LENGTH 32
+#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
+
+/* Optional functions - most linkers will remove unused functions anyway. */
+#define INCLUDE_vTaskPrioritySet 0
+#define INCLUDE_uxTaskPriorityGet 0
+#define INCLUDE_vTaskDelete 0
+#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY
+#define INCLUDE_xResumeFromISR 0
+#define INCLUDE_vTaskDelayUntil 1
+#define INCLUDE_vTaskDelay 1
+#define INCLUDE_xTaskGetSchedulerState 0
+#define INCLUDE_xTaskGetCurrentTaskHandle 1
+#define INCLUDE_uxTaskGetStackHighWaterMark 0
+#define INCLUDE_xTaskGetIdleTaskHandle 0
+#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
+#define INCLUDE_pcTaskGetTaskName 0
+#define INCLUDE_eTaskGetState 0
+#define INCLUDE_xEventGroupSetBitFromISR 0
+#define INCLUDE_xTimerPendFunctionCall 0
+
+/* Define to trap errors during development. */
+// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7
+#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
+ #define configASSERT(_exp) \
+ do {\
+ if ( !(_exp) ) { \
+ volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
+ if ( (*ARM_CM_DHCSR) & 1UL ) { /* Only halt mcu if debugger is attached */ \
+ taskDISABLE_INTERRUPTS(); \
+ __asm("BKPT #0\n"); \
+ }\
+ }\
+ } while(0)
+#else
+ #define configASSERT( x )
+#endif
+
+/* FreeRTOS hooks to NVIC vectors */
+#define xPortPendSVHandler PendSV_Handler
+#define xPortSysTickHandler SysTick_Handler
+#define vPortSVCHandler SVC_Handler
+
+//--------------------------------------------------------------------+
+// Interrupt nesting behavior configuration.
+//--------------------------------------------------------------------+
+
+// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header
+#define configPRIO_BITS 4
+
+/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<
+#include "teensy40_flexspi_nor_config.h"
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
diff --git a/hw/bsp/imxrt/boards/teensy_41/board.cmake b/hw/bsp/imxrt/boards/teensy_41/board.cmake
new file mode 100644
index 000000000..0fd8d528e
--- /dev/null
+++ b/hw/bsp/imxrt/boards/teensy_41/board.cmake
@@ -0,0 +1,21 @@
+set(MCU_VARIANT MIMXRT1062)
+
+set(JLINK_DEVICE MIMXRT1062xxx6A)
+set(PYOCD_TARGET mimxrt1060)
+set(NXPLINK_DEVICE MIMXRT1062xxxxA:EVK-MIMXRT1060)
+
+function(update_board TARGET)
+ target_sources(${TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/teensy41_flexspi_nor_config.c
+ )
+ target_compile_definitions(${TARGET} PUBLIC
+ CPU_MIMXRT1062DVL6A
+ BOARD_TUD_RHPORT=0
+ BOARD_TUH_RHPORT=1
+ )
+endfunction()
+
+# flash by using teensy_loader_cli https://github.com/PaulStoffregen/teensy_loader_cli
+# Make sure it is in your PATH
+# flash: $(BUILD)/$(PROJECT).hex
+# teensy_loader_cli --mcu=imxrt1062 -v -w $<
diff --git a/hw/bsp/imxrt/boards/teensy_41/teensy41_flexspi_nor_config.c b/hw/bsp/imxrt/boards/teensy_41/teensy41_flexspi_nor_config.c
index 2d2bf8f09..f40c72cf7 100644
--- a/hw/bsp/imxrt/boards/teensy_41/teensy41_flexspi_nor_config.c
+++ b/hw/bsp/imxrt/boards/teensy_41/teensy41_flexspi_nor_config.c
@@ -5,7 +5,7 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include
+#include "teensy41_flexspi_nor_config.h"
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
diff --git a/hw/bsp/imxrt/family.c b/hw/bsp/imxrt/family.c
index 5eb672c24..46adabf0a 100644
--- a/hw/bsp/imxrt/family.c
+++ b/hw/bsp/imxrt/family.c
@@ -47,12 +47,28 @@
#endif
// needed by fsl_flexspi_nor_boot
+TU_ATTR_USED
const uint8_t dcd_data[] = { 0x00 };
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
+static void init_usb_phy(USBPHY_Type* usb_phy) {
+ // Enable PHY support for Low speed device + LS via FS Hub
+ usb_phy->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK | USBPHY_CTRL_SET_ENUTMILEVEL3_MASK;
+
+ // Enable all power for normal operation
+ // TODO may not be needed since it is called within CLOCK_EnableUsbhs0PhyPllClock()
+ usb_phy->PWD = 0;
+
+ // TX Timing
+ uint32_t phytx = usb_phy->TX;
+ phytx &= ~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK);
+ phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06);
+ usb_phy->TX = phytx;
+}
+
void board_init(void)
{
// make sure the dcache is on.
@@ -70,6 +86,7 @@ void board_init(void)
#if CFG_TUSB_OS == OPT_OS_NONE
// 1ms tick timer
SysTick_Config(SystemCoreClock / 1000);
+
#elif CFG_TUSB_OS == OPT_OS_FREERTOS
// If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
NVIC_SetPriority(USB_OTG1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
@@ -114,54 +131,29 @@ void board_init(void)
freq = CLOCK_GetOscFreq() / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
}
- LPUART_Init(UART_PORT, &uart_config, freq);
+ if ( kStatus_Success != LPUART_Init(UART_PORT, &uart_config, freq) ) {
+ // failed to init uart, probably baudrate is not supported
+ // TU_BREAKPOINT();
+ }
- //------------- USB0 -------------//
+ //------------- USB -------------//
+ // Note: RT105x RT106x and later have dual USB controllers.
// Clock
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
- USBPHY_Type* usb_phy;
-
- // RT105x RT106x have dual USB controller.
#ifdef USBPHY1
- usb_phy = USBPHY1;
+ init_usb_phy(USBPHY1);
#else
- usb_phy = USBPHY;
+ init_usb_phy(USBPHY);
#endif
- // Enable PHY support for Low speed device + LS via FS Hub
- usb_phy->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK | USBPHY_CTRL_SET_ENUTMILEVEL3_MASK;
-
- // Enable all power for normal operation
- usb_phy->PWD = 0;
-
- // TX Timing
- uint32_t phytx = usb_phy->TX;
- phytx &= ~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK);
- phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06);
- usb_phy->TX = phytx;
-
- // RT105x RT106x have dual USB controller.
#ifdef USBPHY2
// USB1
CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U);
-
- usb_phy = USBPHY2;
-
- // Enable PHY support for Low speed device + LS via FS Hub
- usb_phy->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK | USBPHY_CTRL_SET_ENUTMILEVEL3_MASK;
-
- // Enable all power for normal operation
- usb_phy->PWD = 0;
-
- // TX Timing
- phytx = usb_phy->TX;
- phytx &= ~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK);
- phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06);
- usb_phy->TX = phytx;
+ init_usb_phy(USBPHY2);
#endif
}
@@ -207,8 +199,28 @@ uint32_t board_button_read(void)
int board_uart_read(uint8_t* buf, int len)
{
- LPUART_ReadBlocking(UART_PORT, buf, len);
- return len;
+ int count = 0;
+
+ while( count < len )
+ {
+ uint8_t const rx_count = LPUART_GetRxFifoCount(UART_PORT);
+ if (!rx_count)
+ {
+ // clear all error flag if any
+ uint32_t status_flags = LPUART_GetStatusFlags(UART_PORT);
+ status_flags &= (kLPUART_RxOverrunFlag | kLPUART_ParityErrorFlag | kLPUART_FramingErrorFlag | kLPUART_NoiseErrorFlag);
+ LPUART_ClearStatusFlags(UART_PORT, status_flags);
+ break;
+ }
+
+ for(int i=0; iDHCSR */ \
+ if ( (*ARM_CM_DHCSR) & 1UL ) { /* Only halt mcu if debugger is attached */ \
+ taskDISABLE_INTERRUPTS(); \
+ __asm("BKPT #0\n"); \
+ }\
+ }\
+ } while(0)
+#else
+ #define configASSERT( x )
+#endif
+
+/* FreeRTOS hooks to NVIC vectors */
+#define xPortPendSVHandler PendSV_Handler
+#define xPortSysTickHandler SysTick_Handler
+#define vPortSVCHandler SVC_Handler
+
+//--------------------------------------------------------------------+
+// Interrupt nesting behavior configuration.
+//--------------------------------------------------------------------+
+
+// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header
+#define configPRIO_BITS 3
+
+/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<>,$,$>${CMAKE_EXECUTABLE_SUFFIX}.map"
+ # nanolib
+ --specs=nosys.specs
+ --specs=nano.specs
+ )
+ else ()
+ # TODO support IAR
+ endif ()
+endif () # BOARD_TARGET
+
+
+#------------------------------------
+# Functions
+#------------------------------------
+function(family_configure_example TARGET)
+ family_configure_common(${TARGET})
+
+ #---------- Port Specific ----------
+ # These files are built for each example since it depends on example's tusb_config.h
+ target_sources(${TARGET} PUBLIC
+ # TinyUSB Port
+ ${TOP}/src/portable/chipidea/ci_hs/dcd_ci_hs.c
+ ${TOP}/src/portable/chipidea/ci_hs/hcd_ci_hs.c
+ ${TOP}/src/portable/ehci/ehci.c
+ # BSP
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
+ )
+ target_include_directories(${TARGET} PUBLIC
+ # family, hw, board
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
+ )
+
+ #---------- TinyUSB ----------
+ # tinyusb target is built for each example since it depends on example's tusb_config.h
+ set(TINYUSB_TARGET_PREFIX ${TARGET}-)
+ add_library(${TARGET}-tinyusb_config INTERFACE)
+
+ target_include_directories(${TARGET}-tinyusb_config INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
+ target_compile_definitions(${TARGET}-tinyusb_config INTERFACE
+ CFG_TUSB_MCU=OPT_MCU_LPC18XX
+ )
+
+ # tinyusb's CMakeList.txt
+ add_subdirectory(${TOP}/src ${CMAKE_CURRENT_BINARY_DIR}/tinyusb)
+
+ # Link dependencies
+ target_link_libraries(${TARGET} PUBLIC ${BOARD_TARGET} ${TARGET}-tinyusb)
+
+ # group target (not yet supported by clion)
+ set_target_properties(${TARGET}-tinyusb ${TARGET}-tinyusb_config
+ PROPERTIES FOLDER ${TARGET}_sub
+ )
+
+ #---------- Flash ----------
+ family_flash_jlink(${TARGET})
+endfunction()
+
+
+function(family_configure_device_example TARGET)
+ family_configure_example(${TARGET})
+endfunction()
+
+function(family_configure_host_example TARGET)
+ family_configure_example(${TARGET})
+endfunction()
+
+function(family_configure_dual_usb_example TARGET)
+ family_configure_example(${TARGET})
+endfunction()
diff --git a/hw/bsp/lpc51/family.mk b/hw/bsp/lpc51/family.mk
index 8a64f0945..bfca2f6b1 100644
--- a/hw/bsp/lpc51/family.mk
+++ b/hw/bsp/lpc51/family.mk
@@ -1,5 +1,5 @@
SDK_DIR = hw/mcu/nxp/mcux-sdk
-DEPS_SUBMODULES += $(SDK_DIR)
+DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5
MCU_DIR = $(SDK_DIR)/devices/$(MCU)
include $(TOP)/$(BOARD_PATH)/board.mk
@@ -29,7 +29,7 @@ SRC_C += \
$(SDK_DIR)/drivers/flexcomm/fsl_usart.c
INC += \
- $(TOP)/$(MCU_DIR)/../../CMSIS/Include \
+ $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
$(TOP)/$(MCU_DIR) \
$(TOP)/$(MCU_DIR)/drivers \
$(TOP)/$(SDK_DIR)/drivers/common \
diff --git a/hw/bsp/lpc54/family.mk b/hw/bsp/lpc54/family.mk
index 0ec59f9bf..f52b9b5eb 100644
--- a/hw/bsp/lpc54/family.mk
+++ b/hw/bsp/lpc54/family.mk
@@ -1,5 +1,5 @@
SDK_DIR = hw/mcu/nxp/mcux-sdk
-DEPS_SUBMODULES += $(SDK_DIR)
+DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5
include $(TOP)/$(BOARD_PATH)/board.mk
@@ -40,7 +40,7 @@ SRC_C += \
INC += \
$(TOP)/$(BOARD_PATH) \
- $(TOP)/$(MCU_DIR)/../../CMSIS/Include \
+ $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
$(TOP)/$(MCU_DIR) \
$(TOP)/$(MCU_DIR)/drivers \
$(TOP)/$(SDK_DIR)/drivers/common \
diff --git a/hw/bsp/lpc55/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/lpc55/FreeRTOSConfig/FreeRTOSConfig.h
new file mode 100644
index 000000000..421106f08
--- /dev/null
+++ b/hw/bsp/lpc55/FreeRTOSConfig/FreeRTOSConfig.h
@@ -0,0 +1,166 @@
+/*
+ * FreeRTOS Kernel V10.0.0
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. If you wish to use our Amazon
+ * FreeRTOS name, please do so in a fair use way that does not cause confusion.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://www.FreeRTOS.org
+ * http://aws.amazon.com/freertos
+ *
+ * 1 tab == 4 spaces!
+ */
+
+
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+/*-----------------------------------------------------------
+ * Application specific definitions.
+ *
+ * These definitions should be adjusted for your particular hardware and
+ * application requirements.
+ *
+ * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
+ * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
+ *
+ * See http://www.freertos.org/a00110.html.
+ *----------------------------------------------------------*/
+
+// IAR assembler have limited preprocessor support and it only need following macros:
+#ifndef __IASMARM__
+// FIXME cause redundant-decls warnings
+extern uint32_t SystemCoreClock;
+#endif
+
+/* Cortex M23/M33 port configuration. */
+#define configENABLE_MPU 0
+#define configENABLE_FPU 1
+#define configENABLE_TRUSTZONE 0
+#define configMINIMAL_SECURE_STACK_SIZE (1024)
+
+#define configUSE_PREEMPTION 1
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
+#define configCPU_CLOCK_HZ SystemCoreClock
+#define configTICK_RATE_HZ ( 1000 )
+#define configMAX_PRIORITIES ( 5 )
+#define configMINIMAL_STACK_SIZE ( 128 )
+#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 )
+#define configMAX_TASK_NAME_LEN 16
+#define configUSE_16_BIT_TICKS 0
+#define configIDLE_SHOULD_YIELD 1
+#define configUSE_MUTEXES 1
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configQUEUE_REGISTRY_SIZE 2
+#define configUSE_QUEUE_SETS 0
+#define configUSE_TIME_SLICING 0
+#define configUSE_NEWLIB_REENTRANT 0
+#define configENABLE_BACKWARD_COMPATIBILITY 1
+#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
+
+#define configSUPPORT_STATIC_ALLOCATION 0
+#define configSUPPORT_DYNAMIC_ALLOCATION 1
+
+/* Hook function related definitions. */
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning
+#define configCHECK_FOR_STACK_OVERFLOW 2
+
+/* Run time and task stats gathering related definitions. */
+#define configGENERATE_RUN_TIME_STATS 0
+#define configRECORD_STACK_HIGH_ADDRESS 1
+#define configUSE_TRACE_FACILITY 1 // legacy trace
+#define configUSE_STATS_FORMATTING_FUNCTIONS 0
+
+/* Co-routine definitions. */
+#define configUSE_CO_ROUTINES 0
+#define configMAX_CO_ROUTINE_PRIORITIES 2
+
+/* Software timer related definitions. */
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2)
+#define configTIMER_QUEUE_LENGTH 32
+#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
+
+/* Optional functions - most linkers will remove unused functions anyway. */
+#define INCLUDE_vTaskPrioritySet 0
+#define INCLUDE_uxTaskPriorityGet 0
+#define INCLUDE_vTaskDelete 0
+#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY
+#define INCLUDE_xResumeFromISR 0
+#define INCLUDE_vTaskDelayUntil 1
+#define INCLUDE_vTaskDelay 1
+#define INCLUDE_xTaskGetSchedulerState 0
+#define INCLUDE_xTaskGetCurrentTaskHandle 1
+#define INCLUDE_uxTaskGetStackHighWaterMark 0
+#define INCLUDE_xTaskGetIdleTaskHandle 0
+#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
+#define INCLUDE_pcTaskGetTaskName 0
+#define INCLUDE_eTaskGetState 0
+#define INCLUDE_xEventGroupSetBitFromISR 0
+#define INCLUDE_xTimerPendFunctionCall 0
+
+/* Define to trap errors during development. */
+// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7
+#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
+ #define configASSERT(_exp) \
+ do {\
+ if ( !(_exp) ) { \
+ volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
+ if ( (*ARM_CM_DHCSR) & 1UL ) { /* Only halt mcu if debugger is attached */ \
+ taskDISABLE_INTERRUPTS(); \
+ __asm("BKPT #0\n"); \
+ }\
+ }\
+ } while(0)
+#else
+ #define configASSERT( x )
+#endif
+
+/* FreeRTOS hooks to NVIC vectors */
+#define xPortPendSVHandler PendSV_Handler
+#define xPortSysTickHandler SysTick_Handler
+#define vPortSVCHandler SVC_Handler
+
+//--------------------------------------------------------------------+
+// Interrupt nesting behavior configuration.
+//--------------------------------------------------------------------+
+
+// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header
+#define configPRIO_BITS 3
+
+/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<DHCSR */ \
+ if ( (*ARM_CM_DHCSR) & 1UL ) { /* Only halt mcu if debugger is attached */ \
+ taskDISABLE_INTERRUPTS(); \
+ __asm("BKPT #0\n"); \
+ }\
+ }\
+ } while(0)
+#else
+ #define configASSERT( x )
+#endif
+
+/* FreeRTOS hooks to NVIC vectors */
+#define xPortPendSVHandler PendSV_Handler
+#define xPortSysTickHandler SysTick_Handler
+#define vPortSVCHandler SVC_Handler
+
+//--------------------------------------------------------------------+
+// Interrupt nesting behavior configuration.
+//--------------------------------------------------------------------+
+
+// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header
+#define configPRIO_BITS 3
+
+/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<FRO192M_CTRL |= ANACTRL_FRO192M_CTRL_USBCLKADJ_MASK;
+ CLOCK_SetClkDiv(kCLOCK_DivUsb0Clk, 1, false);
+ CLOCK_AttachClk(kFRO_HF_to_USB0_CLK);
+
+ /*According to reference manual, device mode setting has to be set by access usb host register */
+ CLOCK_EnableClock(kCLOCK_Usbhsl0); // enable usb0 host clock
+ USBFSH->PORTMODE |= USBFSH_PORTMODE_DEV_ENABLE_MASK;
+ CLOCK_DisableClock(kCLOCK_Usbhsl0); // disable usb0 host clock
+
+ /* enable USB Device clock */
+ CLOCK_EnableUsbfs0DeviceClock(kCLOCK_UsbfsSrcFro, CLOCK_GetFreq(kCLOCK_FroHf));
+#endif
+
+#if PORT_SUPPORT_DEVICE(1)
+ // Port1 is High Speed
+
+ // Power
+ SPC0->ACTIVE_VDELAY = 0x0500;
+ /* Change the power DCDC to 1.8v (By default, DCDC is 1.8V), CORELDO to 1.1v (By default, CORELDO is 1.0V) */
+ SPC0->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_CORELDO_VDD_DS_MASK;
+ SPC0->ACTIVE_CFG |= SPC_ACTIVE_CFG_DCDC_VDD_LVL(0x3) | SPC_ACTIVE_CFG_CORELDO_VDD_LVL(0x3) |
+ SPC_ACTIVE_CFG_SYSLDO_VDD_DS_MASK | SPC_ACTIVE_CFG_DCDC_VDD_DS(0x2u);
+ /* Wait until it is done */
+ while (SPC0->SC & SPC_SC_BUSY_MASK) {}
+ if (0u == (SCG0->LDOCSR & SCG_LDOCSR_LDOEN_MASK)) {
+ SCG0->TRIM_LOCK = 0x5a5a0001U;
+ SCG0->LDOCSR |= SCG_LDOCSR_LDOEN_MASK;
+ /* wait LDO ready */
+ while (0U == (SCG0->LDOCSR & SCG_LDOCSR_VOUT_OK_MASK));
+ }
+ SYSCON->AHBCLKCTRLSET[2] |= SYSCON_AHBCLKCTRL2_USB_HS_MASK | SYSCON_AHBCLKCTRL2_USB_HS_PHY_MASK;
+ SCG0->SOSCCFG &= ~(SCG_SOSCCFG_RANGE_MASK | SCG_SOSCCFG_EREFS_MASK);
+ /* xtal = 20 ~ 30MHz */
+ SCG0->SOSCCFG = (1U << SCG_SOSCCFG_RANGE_SHIFT) | (1U << SCG_SOSCCFG_EREFS_SHIFT);
+ SCG0->SOSCCSR |= SCG_SOSCCSR_SOSCEN_MASK;
+ while (1) {
+ if (SCG0->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK) {
+ break;
+ }
+ }
+
+ // Clock
+ SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK | SYSCON_CLOCK_CTRL_CLKIN_ENA_FM_USBH_LPT_MASK;
+ CLOCK_EnableClock(kCLOCK_UsbHs);
+ CLOCK_EnableClock(kCLOCK_UsbHsPhy);
+ CLOCK_EnableUsbhsPhyPllClock(kCLOCK_Usbphy480M, 24000000U);
+ CLOCK_EnableUsbhsClock();
+
+ // USB PHY
+#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT)))
+ USBPHY->TRIM_OVERRIDE_EN = 0x001fU; /* override IFR value */
+#endif
+
+ // Enable PHY support for Low speed device + LS via FS Hub
+ USBPHY->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK | USBPHY_CTRL_SET_ENUTMILEVEL3_MASK;
+
+ // Enable all power for normal operation
+ USBPHY->PWD = 0;
+
+ // TX Timing
+ uint32_t phytx = USBPHY->TX;
+ phytx &= ~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK);
+ phytx |= USBPHY_TX_D_CAL(0x04) | USBPHY_TX_TXCAL45DP(0x07) | USBPHY_TX_TXCAL45DM(0x07);
+ //phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06);
+ USBPHY->TX = phytx;
+#endif
+}
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+
+void board_led_write(bool state)
+{
+ GPIO_PinWrite(LED_GPIO, LED_PIN, state ? LED_STATE_ON : (1-LED_STATE_ON));
+
+#ifdef NEOPIXEL_PIN
+ if (state) {
+ sctpix_setPixel(NEOPIXEL_CH, 0, 0x100000);
+ sctpix_setPixel(NEOPIXEL_CH, 1, 0x101010);
+ } else {
+ sctpix_setPixel(NEOPIXEL_CH, 0, 0x001000);
+ sctpix_setPixel(NEOPIXEL_CH, 1, 0x000010);
+ }
+ sctpix_show();
+#endif
+}
+
+uint32_t board_button_read(void)
+{
+#ifdef BUTTON_GPIO
+ return BUTTON_STATE_ACTIVE == GPIO_PinRead(BUTTON_GPIO, BUTTON_PIN);
+#endif
+}
+
+int board_uart_read(uint8_t* buf, int len)
+{
+ (void) buf; (void) len;
+ return 0;
+}
+
+int board_uart_write(void const * buf, int len)
+{
+#ifdef UART_DEV
+ LPUART_WriteBlocking(UART_DEV, (uint8_t const *) buf, len);
+ return len;
+#else
+ (void) buf; (void) len;
+ return 0;
+#endif
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+void SysTick_Handler(void)
+{
+ system_ticks++;
+}
+
+uint32_t board_millis(void)
+{
+ return system_ticks;
+}
+#endif
diff --git a/hw/bsp/mcx/family.cmake b/hw/bsp/mcx/family.cmake
new file mode 100644
index 000000000..d5a17f584
--- /dev/null
+++ b/hw/bsp/mcx/family.cmake
@@ -0,0 +1,134 @@
+include_guard()
+
+if (NOT BOARD)
+ message(FATAL_ERROR "BOARD not specified")
+endif ()
+
+set(SDK_DIR ${TOP}/hw/mcu/nxp/mcux-sdk)
+set(CMSIS_DIR ${TOP}/lib/CMSIS_5)
+
+# enable LTO
+set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
+
+# toolchain set up
+set(CMAKE_SYSTEM_PROCESSOR cortex-m33 CACHE INTERNAL "System Processor")
+set(CMAKE_TOOLCHAIN_FILE ${TOP}/tools/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
+
+set(FAMILY_MCUS LPC55XX CACHE INTERNAL "")
+
+# include board specific
+include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
+
+
+#------------------------------------
+# BOARD_TARGET
+#------------------------------------
+# only need to be built ONCE for all examples
+set(BOARD_TARGET board_${BOARD})
+if (NOT TARGET ${BOARD_TARGET})
+ add_library(${BOARD_TARGET} STATIC
+ # external driver
+ #lib/sct_neopixel/sct_neopixel.c
+
+ # driver
+ ${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_gpio.c
+ ${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_common_arm.c
+ ${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_lpuart.c
+ ${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_lpflexcomm.c
+ # mcu
+ ${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_clock.c
+ ${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_reset.c
+ ${SDK_DIR}/devices/${MCU_VARIANT}/system_${MCU_CORE}.c
+ )
+# target_compile_definitions(${BOARD_TARGET} PUBLIC
+# )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ # driver
+ # mcu
+ ${CMSIS_DIR}/CMSIS/Core/Include
+ ${SDK_DIR}/devices/${MCU_VARIANT}
+ ${SDK_DIR}/devices/${MCU_VARIANT}/drivers
+ )
+ update_board(${BOARD_TARGET})
+
+ if (TOOLCHAIN STREQUAL "gcc")
+ target_sources(${BOARD_TARGET} PUBLIC
+ ${SDK_DIR}/devices/${MCU_VARIANT}/gcc/startup_${MCU_CORE}.S
+ )
+ cmake_print_variables(CMAKE_CURRENT_BINARY_DIR)
+ target_link_options(${BOARD_TARGET} PUBLIC
+ # linker file
+ "LINKER:--script=${SDK_DIR}/devices/${MCU_VARIANT}/gcc/${MCU_CORE}_flash.ld"
+ # nanolib
+ --specs=nosys.specs
+ --specs=nano.specs
+ )
+ else ()
+ # TODO support IAR
+ endif ()
+endif () # BOARD_TARGET
+
+
+#------------------------------------
+# Functions
+#------------------------------------
+function(family_configure_example TARGET)
+ family_configure_common(${TARGET})
+
+ #---------- Port Specific ----------
+ # These files are built for each example since it depends on example's tusb_config.h
+ target_sources(${TARGET} PUBLIC
+ # TinyUSB Port
+ ${TOP}/src/portable/chipidea/ci_hs/dcd_ci_hs.c
+ # BSP
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
+ )
+ target_include_directories(${TARGET} PUBLIC
+ # family, hw, board
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
+ )
+
+ #---------- TinyUSB ----------
+ # tinyusb target is built for each example since it depends on example's tusb_config.h
+ set(TINYUSB_TARGET_PREFIX ${TARGET}-)
+ add_library(${TARGET}-tinyusb_config INTERFACE)
+
+ target_include_directories(${TARGET}-tinyusb_config INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
+ target_compile_definitions(${TARGET}-tinyusb_config INTERFACE
+ CFG_TUSB_MCU=OPT_MCU_MCXN9
+ )
+
+ # tinyusb's CMakeList.txt
+ add_subdirectory(${TOP}/src ${CMAKE_CURRENT_BINARY_DIR}/tinyusb)
+
+ # Link dependencies
+ target_link_libraries(${TARGET} PUBLIC ${BOARD_TARGET} ${TARGET}-tinyusb)
+
+ # group target (not yet supported by clion)
+ set_target_properties(${TARGET}-tinyusb ${TARGET}-tinyusb_config
+ PROPERTIES FOLDER ${TARGET}_sub
+ )
+
+ #---------- Flash ----------
+ family_flash_jlink(${TARGET})
+ #family_flash_nxplink(${TARGET})
+ #family_flash_pyocd(${TARGET})
+endfunction()
+
+
+function(family_configure_device_example TARGET)
+ family_configure_example(${TARGET})
+endfunction()
+
+function(family_configure_host_example TARGET)
+ family_configure_example(${TARGET})
+endfunction()
+
+function(family_configure_dual_usb_example TARGET)
+ family_configure_example(${TARGET})
+endfunction()
diff --git a/hw/bsp/mcx/family.mk b/hw/bsp/mcx/family.mk
new file mode 100644
index 000000000..2cd4c2448
--- /dev/null
+++ b/hw/bsp/mcx/family.mk
@@ -0,0 +1,48 @@
+UF2_FAMILY_ID = 0x2abc77ec
+SDK_DIR = hw/mcu/nxp/mcux-sdk
+
+DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+CPU_CORE ?= cortex-m33
+include $(TOP)/tools/make/cpu/$(CPU_CORE).mk
+
+# Default to Highspeed PORT1
+PORT ?= 1
+
+CFLAGS += \
+ -flto \
+ -DCFG_TUSB_MCU=OPT_MCU_MCXN9 \
+ -DBOARD_TUD_RHPORT=$(PORT) \
+
+ifeq ($(PORT), 1)
+ $(info "PORT1 High Speed")
+ CFLAGS += -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
+else
+ $(info "PORT0 Full Speed")
+endif
+
+# mcu driver cause following warnings
+CFLAGS += -Wno-error=unused-parameter -Wno-error=old-style-declaration
+
+# All source paths should be relative to the top level.
+LD_FILE ?= $(SDK_DIR)/devices/$(MCU_VARIANT)/gcc/$(MCU_CORE)_flash.ld
+
+SRC_C += \
+ src/portable/chipidea/ci_hs/dcd_ci_hs.c \
+ $(SDK_DIR)/devices/$(MCU_VARIANT)/system_$(MCU_CORE).c \
+ $(SDK_DIR)/devices/$(MCU_VARIANT)/drivers/fsl_clock.c \
+ $(SDK_DIR)/devices/$(MCU_VARIANT)/drivers/fsl_reset.c \
+ $(SDK_DIR)/devices/$(MCU_VARIANT)/drivers/fsl_gpio.c \
+ $(SDK_DIR)/devices/$(MCU_VARIANT)/drivers/fsl_common_arm.c \
+ $(SDK_DIR)/devices/$(MCU_VARIANT)/drivers/fsl_lpflexcomm.c \
+ $(SDK_DIR)/devices/$(MCU_VARIANT)/drivers/fsl_lpuart.c \
+
+INC += \
+ $(TOP)/$(BOARD_PATH) \
+ $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
+ $(TOP)/$(SDK_DIR)/devices/$(MCU_VARIANT) \
+ $(TOP)/$(SDK_DIR)/devices/$(MCU_VARIANT)/drivers \
+
+SRC_S += $(SDK_DIR)/devices/$(MCU_VARIANT)/gcc/startup_$(MCU_CORE).S
diff --git a/hw/bsp/nrf/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/nrf/FreeRTOSConfig/FreeRTOSConfig.h
new file mode 100644
index 000000000..421106f08
--- /dev/null
+++ b/hw/bsp/nrf/FreeRTOSConfig/FreeRTOSConfig.h
@@ -0,0 +1,166 @@
+/*
+ * FreeRTOS Kernel V10.0.0
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. If you wish to use our Amazon
+ * FreeRTOS name, please do so in a fair use way that does not cause confusion.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://www.FreeRTOS.org
+ * http://aws.amazon.com/freertos
+ *
+ * 1 tab == 4 spaces!
+ */
+
+
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+/*-----------------------------------------------------------
+ * Application specific definitions.
+ *
+ * These definitions should be adjusted for your particular hardware and
+ * application requirements.
+ *
+ * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
+ * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
+ *
+ * See http://www.freertos.org/a00110.html.
+ *----------------------------------------------------------*/
+
+// IAR assembler have limited preprocessor support and it only need following macros:
+#ifndef __IASMARM__
+// FIXME cause redundant-decls warnings
+extern uint32_t SystemCoreClock;
+#endif
+
+/* Cortex M23/M33 port configuration. */
+#define configENABLE_MPU 0
+#define configENABLE_FPU 1
+#define configENABLE_TRUSTZONE 0
+#define configMINIMAL_SECURE_STACK_SIZE (1024)
+
+#define configUSE_PREEMPTION 1
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
+#define configCPU_CLOCK_HZ SystemCoreClock
+#define configTICK_RATE_HZ ( 1000 )
+#define configMAX_PRIORITIES ( 5 )
+#define configMINIMAL_STACK_SIZE ( 128 )
+#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 )
+#define configMAX_TASK_NAME_LEN 16
+#define configUSE_16_BIT_TICKS 0
+#define configIDLE_SHOULD_YIELD 1
+#define configUSE_MUTEXES 1
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configQUEUE_REGISTRY_SIZE 2
+#define configUSE_QUEUE_SETS 0
+#define configUSE_TIME_SLICING 0
+#define configUSE_NEWLIB_REENTRANT 0
+#define configENABLE_BACKWARD_COMPATIBILITY 1
+#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
+
+#define configSUPPORT_STATIC_ALLOCATION 0
+#define configSUPPORT_DYNAMIC_ALLOCATION 1
+
+/* Hook function related definitions. */
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning
+#define configCHECK_FOR_STACK_OVERFLOW 2
+
+/* Run time and task stats gathering related definitions. */
+#define configGENERATE_RUN_TIME_STATS 0
+#define configRECORD_STACK_HIGH_ADDRESS 1
+#define configUSE_TRACE_FACILITY 1 // legacy trace
+#define configUSE_STATS_FORMATTING_FUNCTIONS 0
+
+/* Co-routine definitions. */
+#define configUSE_CO_ROUTINES 0
+#define configMAX_CO_ROUTINE_PRIORITIES 2
+
+/* Software timer related definitions. */
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2)
+#define configTIMER_QUEUE_LENGTH 32
+#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
+
+/* Optional functions - most linkers will remove unused functions anyway. */
+#define INCLUDE_vTaskPrioritySet 0
+#define INCLUDE_uxTaskPriorityGet 0
+#define INCLUDE_vTaskDelete 0
+#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY
+#define INCLUDE_xResumeFromISR 0
+#define INCLUDE_vTaskDelayUntil 1
+#define INCLUDE_vTaskDelay 1
+#define INCLUDE_xTaskGetSchedulerState 0
+#define INCLUDE_xTaskGetCurrentTaskHandle 1
+#define INCLUDE_uxTaskGetStackHighWaterMark 0
+#define INCLUDE_xTaskGetIdleTaskHandle 0
+#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
+#define INCLUDE_pcTaskGetTaskName 0
+#define INCLUDE_eTaskGetState 0
+#define INCLUDE_xEventGroupSetBitFromISR 0
+#define INCLUDE_xTimerPendFunctionCall 0
+
+/* Define to trap errors during development. */
+// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7
+#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
+ #define configASSERT(_exp) \
+ do {\
+ if ( !(_exp) ) { \
+ volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
+ if ( (*ARM_CM_DHCSR) & 1UL ) { /* Only halt mcu if debugger is attached */ \
+ taskDISABLE_INTERRUPTS(); \
+ __asm("BKPT #0\n"); \
+ }\
+ }\
+ } while(0)
+#else
+ #define configASSERT( x )
+#endif
+
+/* FreeRTOS hooks to NVIC vectors */
+#define xPortPendSVHandler PendSV_Handler
+#define xPortSysTickHandler SysTick_Handler
+#define vPortSVCHandler SVC_Handler
+
+//--------------------------------------------------------------------+
+// Interrupt nesting behavior configuration.
+//--------------------------------------------------------------------+
+
+// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header
+#define configPRIO_BITS 3
+
+/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1< RAM
-
- .fs_data :
- {
- PROVIDE(__start_fs_data = .);
- KEEP(*(.fs_data))
- PROVIDE(__stop_fs_data = .);
- } > RAM
-} INSERT AFTER .data;
-
-INCLUDE "nrf52_common.ld"
diff --git a/hw/bsp/nrf/boards/arduino_nano33_ble/arduino_nano33_ble.ld b/hw/bsp/nrf/boards/arduino_nano33_ble/arduino_nano33_ble.ld
index f609f743f..b7cac1019 100755
--- a/hw/bsp/nrf/boards/arduino_nano33_ble/arduino_nano33_ble.ld
+++ b/hw/bsp/nrf/boards/arduino_nano33_ble/arduino_nano33_ble.ld
@@ -29,4 +29,4 @@ SECTIONS
} > RAM
} INSERT AFTER .data;
-INCLUDE "nrf52_common.ld"
+INCLUDE "nrf_common.ld"
diff --git a/hw/bsp/nrf/boards/circuitplayground_bluefruit/board.mk b/hw/bsp/nrf/boards/circuitplayground_bluefruit/board.mk
index f31899eb7..b80807963 100644
--- a/hw/bsp/nrf/boards/circuitplayground_bluefruit/board.mk
+++ b/hw/bsp/nrf/boards/circuitplayground_bluefruit/board.mk
@@ -1,6 +1,9 @@
MCU_VARIANT = nrf52840
CFLAGS += -DNRF52840_XXAA
+# All source paths should be relative to the top level.
+LD_FILE = hw/bsp/nrf/linker/nrf52840_s140_v6.ld
+
$(BUILD)/$(PROJECT).zip: $(BUILD)/$(PROJECT).hex
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --sd-req 0xFFFE --application $^ $@
diff --git a/hw/bsp/nrf/boards/circuitplayground_bluefruit/nrf52840_s140_v6.ld b/hw/bsp/nrf/boards/circuitplayground_bluefruit/nrf52840_s140_v6.ld
deleted file mode 100755
index 71c55bb81..000000000
--- a/hw/bsp/nrf/boards/circuitplayground_bluefruit/nrf52840_s140_v6.ld
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Linker script to configure memory regions. */
-
-SEARCH_DIR(.)
-GROUP(-lgcc -lc -lnosys)
-
-MEMORY
-{
- FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0xED000 - 0x26000
-
- /* SRAM required by S132 depend on
- * - Attribute Table Size
- * - Vendor UUID count
- * - Max ATT MTU
- * - Concurrent connection peripheral + central + secure links
- * - Event Len, HVN queue, Write CMD queue
- */
- RAM (rwx) : ORIGIN = 0x20003400, LENGTH = 0x20040000 - 0x20003400
-}
-
-SECTIONS
-{
- . = ALIGN(4);
- .svc_data :
- {
- PROVIDE(__start_svc_data = .);
- KEEP(*(.svc_data))
- PROVIDE(__stop_svc_data = .);
- } > RAM
-
- .fs_data :
- {
- PROVIDE(__start_fs_data = .);
- KEEP(*(.fs_data))
- PROVIDE(__stop_fs_data = .);
- } > RAM
-} INSERT AFTER .data;
-
-INCLUDE "nrf52_common.ld"
diff --git a/hw/bsp/nrf/boards/feather_nrf52840_express/board.mk b/hw/bsp/nrf/boards/feather_nrf52840_express/board.mk
index f31899eb7..b80807963 100644
--- a/hw/bsp/nrf/boards/feather_nrf52840_express/board.mk
+++ b/hw/bsp/nrf/boards/feather_nrf52840_express/board.mk
@@ -1,6 +1,9 @@
MCU_VARIANT = nrf52840
CFLAGS += -DNRF52840_XXAA
+# All source paths should be relative to the top level.
+LD_FILE = hw/bsp/nrf/linker/nrf52840_s140_v6.ld
+
$(BUILD)/$(PROJECT).zip: $(BUILD)/$(PROJECT).hex
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --sd-req 0xFFFE --application $^ $@
diff --git a/hw/bsp/nrf/boards/feather_nrf52840_express/nrf52840_s140_v6.ld b/hw/bsp/nrf/boards/feather_nrf52840_express/nrf52840_s140_v6.ld
deleted file mode 100644
index 71c55bb81..000000000
--- a/hw/bsp/nrf/boards/feather_nrf52840_express/nrf52840_s140_v6.ld
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Linker script to configure memory regions. */
-
-SEARCH_DIR(.)
-GROUP(-lgcc -lc -lnosys)
-
-MEMORY
-{
- FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0xED000 - 0x26000
-
- /* SRAM required by S132 depend on
- * - Attribute Table Size
- * - Vendor UUID count
- * - Max ATT MTU
- * - Concurrent connection peripheral + central + secure links
- * - Event Len, HVN queue, Write CMD queue
- */
- RAM (rwx) : ORIGIN = 0x20003400, LENGTH = 0x20040000 - 0x20003400
-}
-
-SECTIONS
-{
- . = ALIGN(4);
- .svc_data :
- {
- PROVIDE(__start_svc_data = .);
- KEEP(*(.svc_data))
- PROVIDE(__stop_svc_data = .);
- } > RAM
-
- .fs_data :
- {
- PROVIDE(__start_fs_data = .);
- KEEP(*(.fs_data))
- PROVIDE(__stop_fs_data = .);
- } > RAM
-} INSERT AFTER .data;
-
-INCLUDE "nrf52_common.ld"
diff --git a/hw/bsp/nrf/boards/feather_nrf52840_sense/board.mk b/hw/bsp/nrf/boards/feather_nrf52840_sense/board.mk
index f31899eb7..b80807963 100644
--- a/hw/bsp/nrf/boards/feather_nrf52840_sense/board.mk
+++ b/hw/bsp/nrf/boards/feather_nrf52840_sense/board.mk
@@ -1,6 +1,9 @@
MCU_VARIANT = nrf52840
CFLAGS += -DNRF52840_XXAA
+# All source paths should be relative to the top level.
+LD_FILE = hw/bsp/nrf/linker/nrf52840_s140_v6.ld
+
$(BUILD)/$(PROJECT).zip: $(BUILD)/$(PROJECT).hex
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --sd-req 0xFFFE --application $^ $@
diff --git a/hw/bsp/nrf/boards/itsybitsy_nrf52840/board.mk b/hw/bsp/nrf/boards/itsybitsy_nrf52840/board.mk
index f31899eb7..b80807963 100644
--- a/hw/bsp/nrf/boards/itsybitsy_nrf52840/board.mk
+++ b/hw/bsp/nrf/boards/itsybitsy_nrf52840/board.mk
@@ -1,6 +1,9 @@
MCU_VARIANT = nrf52840
CFLAGS += -DNRF52840_XXAA
+# All source paths should be relative to the top level.
+LD_FILE = hw/bsp/nrf/linker/nrf52840_s140_v6.ld
+
$(BUILD)/$(PROJECT).zip: $(BUILD)/$(PROJECT).hex
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --sd-req 0xFFFE --application $^ $@
diff --git a/hw/bsp/nrf/boards/itsybitsy_nrf52840/nrf52840_s140_v6.ld b/hw/bsp/nrf/boards/itsybitsy_nrf52840/nrf52840_s140_v6.ld
deleted file mode 100644
index 71c55bb81..000000000
--- a/hw/bsp/nrf/boards/itsybitsy_nrf52840/nrf52840_s140_v6.ld
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Linker script to configure memory regions. */
-
-SEARCH_DIR(.)
-GROUP(-lgcc -lc -lnosys)
-
-MEMORY
-{
- FLASH (rx) : ORIGIN = 0x26000, LENGTH = 0xED000 - 0x26000
-
- /* SRAM required by S132 depend on
- * - Attribute Table Size
- * - Vendor UUID count
- * - Max ATT MTU
- * - Concurrent connection peripheral + central + secure links
- * - Event Len, HVN queue, Write CMD queue
- */
- RAM (rwx) : ORIGIN = 0x20003400, LENGTH = 0x20040000 - 0x20003400
-}
-
-SECTIONS
-{
- . = ALIGN(4);
- .svc_data :
- {
- PROVIDE(__start_svc_data = .);
- KEEP(*(.svc_data))
- PROVIDE(__stop_svc_data = .);
- } > RAM
-
- .fs_data :
- {
- PROVIDE(__start_fs_data = .);
- KEEP(*(.fs_data))
- PROVIDE(__stop_fs_data = .);
- } > RAM
-} INSERT AFTER .data;
-
-INCLUDE "nrf52_common.ld"
diff --git a/hw/bsp/nrf/boards/pca10056/board.cmake b/hw/bsp/nrf/boards/pca10056/board.cmake
new file mode 100644
index 000000000..cc8ef2fcb
--- /dev/null
+++ b/hw/bsp/nrf/boards/pca10056/board.cmake
@@ -0,0 +1,8 @@
+set(MCU_VARIANT nrf52840)
+set(LD_FILE_gcc ${NRFX_DIR}/mdk/nrf52840_xxaa.ld)
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC
+ NRF52840_XXAA
+ )
+endfunction()
diff --git a/hw/bsp/nrf/boards/pca10095/board.cmake b/hw/bsp/nrf/boards/pca10095/board.cmake
new file mode 100644
index 000000000..e90d76e91
--- /dev/null
+++ b/hw/bsp/nrf/boards/pca10095/board.cmake
@@ -0,0 +1,12 @@
+set(MCU_VARIANT nrf5340_application)
+set(LD_FILE_gcc ${NRFX_DIR}/mdk/nrf5340_xxaa_application.ld)
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC
+ NRF5340_XXAA
+ NRF5340_XXAA_APPLICATION
+ )
+ target_sources(${TARGET} PUBLIC
+ ${NRFX_DIR}/drivers/src/nrfx_usbreg.c
+ )
+endfunction()
diff --git a/hw/bsp/nrf/boards/pca10095/board.h b/hw/bsp/nrf/boards/pca10095/board.h
new file mode 100644
index 000000000..fd3c63d6a
--- /dev/null
+++ b/hw/bsp/nrf/boards/pca10095/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 28
+#define LED_STATE_ON 0
+
+// Button
+#define BUTTON_PIN 23
+#define BUTTON_STATE_ACTIVE 0
+
+// UART
+#define UART_RX_PIN 32
+#define UART_TX_PIN 33
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* BOARD_H_ */
diff --git a/hw/bsp/nrf/boards/pca10095/board.mk b/hw/bsp/nrf/boards/pca10095/board.mk
new file mode 100644
index 000000000..9c4edbafc
--- /dev/null
+++ b/hw/bsp/nrf/boards/pca10095/board.mk
@@ -0,0 +1,14 @@
+CPU_CORE = cortex-m33
+MCU_VARIANT = nrf5340_application
+CFLAGS += -DNRF5340_XXAA -DNRF5340_XXAA_APPLICATION
+
+LD_FILE = hw/mcu/nordic/nrfx/mdk/nrf5340_xxaa_application.ld
+
+SRC_C += hw/mcu/nordic/nrfx/drivers/src/nrfx_usbreg.c
+
+# caused by void SystemStoreFICRNS() (without void) in system_nrf5340_application.c
+CFLAGS += -Wno-error=strict-prototypes
+
+# flash using jlink
+JLINK_DEVICE = nrf5340_xxaa_app
+flash: flash-jlink
diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c
index 02cec31ef..157b2bf21 100644
--- a/hw/bsp/nrf/family.c
+++ b/hw/bsp/nrf/family.c
@@ -28,9 +28,9 @@
#include "board.h"
#include "nrfx.h"
-#include "nrfx/hal/nrf_gpio.h"
-#include "nrfx/drivers/include/nrfx_power.h"
-#include "nrfx/drivers/include/nrfx_uarte.h"
+#include "hal/nrf_gpio.h"
+#include "drivers/include/nrfx_power.h"
+#include "drivers/include/nrfx_uarte.h"
#ifdef SOFTDEVICE_PRESENT
#include "nrf_sdm.h"
@@ -49,6 +49,23 @@ void USBD_IRQHandler(void)
/* MACRO TYPEDEF CONSTANT ENUM
*------------------------------------------------------------------*/
+// Value is chosen to be as same as NRFX_POWER_USB_EVT_* in nrfx_power.h
+enum {
+ USB_EVT_DETECTED = 0,
+ USB_EVT_REMOVED = 1,
+ USB_EVT_READY = 2
+};
+
+#ifdef NRF5340_XXAA
+ #define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_LFRC
+ #define VBUSDETECT_Msk USBREG_USBREGSTATUS_VBUSDETECT_Msk
+ #define OUTPUTRDY_Msk USBREG_USBREGSTATUS_OUTPUTRDY_Msk
+#else
+ #define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_RC
+ #define VBUSDETECT_Msk POWER_USBREGSTATUS_VBUSDETECT_Msk
+ #define OUTPUTRDY_Msk POWER_USBREGSTATUS_OUTPUTRDY_Msk
+#endif
+
static nrfx_uarte_t _uart_id = NRFX_UARTE_INSTANCE(0);
// tinyusb function that handles power event (detected, ready, removed)
@@ -68,7 +85,7 @@ void board_init(void)
NRF_CLOCK->TASKS_LFCLKSTOP = 1UL;
// Use Internal OSC to compatible with all boards
- NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_RC;
+ NRF_CLOCK->LFCLKSRC = LFCLK_SRC_RC;
NRF_CLOCK->TASKS_LFCLKSTART = 1UL;
// LED
@@ -123,21 +140,26 @@ void board_init(void)
#endif
{
// Power module init
- const nrfx_power_config_t pwr_cfg = { 0 };
+ const nrfx_power_config_t pwr_cfg = {0};
nrfx_power_init(&pwr_cfg);
// Register tusb function as USB power handler
// cause cast-function-type warning
- const nrfx_power_usbevt_config_t config = { .handler = power_event_handler };
+ const nrfx_power_usbevt_config_t config = {.handler = power_event_handler};
nrfx_power_usbevt_init(&config);
-
nrfx_power_usbevt_enable();
+ // USB power may already be ready at this time -> no event generated
+ // We need to invoke the handler based on the status initially
+ #ifdef NRF5340_XXAA
+ usb_reg = NRF_USBREGULATOR->USBREGSTATUS;
+ #else
usb_reg = NRF_POWER->USBREGSTATUS;
+ #endif
}
- if ( usb_reg & POWER_USBREGSTATUS_VBUSDETECT_Msk ) tusb_hal_nrf_power_event(NRFX_POWER_USB_EVT_DETECTED);
- if ( usb_reg & POWER_USBREGSTATUS_OUTPUTRDY_Msk ) tusb_hal_nrf_power_event(NRFX_POWER_USB_EVT_READY);
+ if ( usb_reg & VBUSDETECT_Msk ) tusb_hal_nrf_power_event(USB_EVT_DETECTED);
+ if ( usb_reg & OUTPUTRDY_Msk ) tusb_hal_nrf_power_event(USB_EVT_READY);
#endif
}
diff --git a/hw/bsp/nrf/family.cmake b/hw/bsp/nrf/family.cmake
new file mode 100644
index 000000000..71067c8ae
--- /dev/null
+++ b/hw/bsp/nrf/family.cmake
@@ -0,0 +1,139 @@
+include_guard()
+
+if (NOT BOARD)
+ message(FATAL_ERROR "BOARD not specified")
+endif ()
+
+set(NRFX_DIR ${TOP}/hw/mcu/nordic/nrfx)
+set(CMSIS_DIR ${TOP}/lib/CMSIS_5)
+
+# include board specific
+include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
+
+# enable LTO
+set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
+
+# toolchain set up
+if (MCU_VARIANT STREQUAL "nrf5340_application")
+ set(CMAKE_SYSTEM_PROCESSOR cortex-m33 CACHE INTERNAL "System Processor")
+ set(JLINK_DEVICE nrf5340_xxaa_app)
+else ()
+ set(CMAKE_SYSTEM_PROCESSOR cortex-m4 CACHE INTERNAL "System Processor")
+ set(JLINK_DEVICE ${MCU_VARIANT}_xxaa)
+endif ()
+
+set(CMAKE_TOOLCHAIN_FILE ${TOP}/tools/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
+
+set(FAMILY_MCUS NRF5X CACHE INTERNAL "")
+
+
+#------------------------------------
+# BOARD_TARGET
+#------------------------------------
+# only need to be built ONCE for all examples
+set(BOARD_TARGET board_${BOARD})
+if (NOT TARGET ${BOARD_TARGET})
+ add_library(${BOARD_TARGET} STATIC
+ # driver
+ ${NRFX_DIR}/drivers/src/nrfx_power.c
+ ${NRFX_DIR}/drivers/src/nrfx_uarte.c
+ # mcu
+ ${NRFX_DIR}/mdk/system_${MCU_VARIANT}.c
+ )
+ target_compile_definitions(${BOARD_TARGET} PUBLIC
+ CONFIG_GPIO_AS_PINRESET
+ )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${CMAKE_CURRENT_LIST_DIR}
+ ${NRFX_DIR}
+ ${NRFX_DIR}/mdk
+ ${NRFX_DIR}/hal
+ ${NRFX_DIR}/drivers/include
+ ${NRFX_DIR}/drivers/src
+ ${CMSIS_DIR}/CMSIS/Core/Include
+ )
+ update_board(${BOARD_TARGET})
+
+ if (NOT DEFINED LD_FILE_${TOOLCHAIN})
+ set(LD_FILE_gcc ${NRFX_DIR}/mdk/${MCU_VARIANT}_xxaa.ld)
+ endif ()
+
+ if (TOOLCHAIN STREQUAL "gcc")
+ target_sources(${BOARD_TARGET} PUBLIC
+ ${NRFX_DIR}/mdk/gcc_startup_${MCU_VARIANT}.S
+ )
+ target_link_options(${BOARD_TARGET} PUBLIC
+ # linker file
+ "LINKER:--script=${LD_FILE_gcc}"
+ -L${NRFX_DIR}/mdk
+ # nanolib
+ --specs=nosys.specs
+ --specs=nano.specs
+ )
+ else ()
+ # TODO support IAR
+ endif ()
+endif () # BOARD_TARGET
+
+
+#------------------------------------
+# Functions
+#------------------------------------
+function(family_configure_example TARGET)
+ family_configure_common(${TARGET})
+
+ #---------- Port Specific ----------
+ # These files are built for each example since it depends on example's tusb_config.h
+ target_sources(${TARGET} PUBLIC
+ # TinyUSB Port
+ ${TOP}/src/portable/nordic/nrf5x/dcd_nrf5x.c
+ # BSP
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
+ )
+ target_include_directories(${TARGET} PUBLIC
+ # family, hw, board
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
+ )
+
+ #---------- TinyUSB ----------
+ # tinyusb target is built for each example since it depends on example's tusb_config.h
+ set(TINYUSB_TARGET_PREFIX ${TARGET}-)
+ add_library(${TARGET}-tinyusb_config INTERFACE)
+
+ target_include_directories(${TARGET}-tinyusb_config INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ )
+ target_compile_definitions(${TARGET}-tinyusb_config INTERFACE
+ CFG_TUSB_MCU=OPT_MCU_NRF5X
+ )
+
+ # tinyusb's CMakeList.txt
+ add_subdirectory(${TOP}/src ${CMAKE_CURRENT_BINARY_DIR}/tinyusb)
+
+ # Link dependencies
+ target_link_libraries(${TARGET} PUBLIC ${BOARD_TARGET} ${TARGET}-tinyusb)
+
+ # group target (not yet supported by clion)
+ set_target_properties(${TARGET}-tinyusb ${TARGET}-tinyusb_config
+ PROPERTIES FOLDER ${TARGET}_sub
+ )
+
+ #---------- Flash ----------
+ family_flash_jlink(${TARGET})
+endfunction()
+
+
+function(family_configure_device_example TARGET)
+ family_configure_example(${TARGET})
+endfunction()
+
+function(family_configure_host_example TARGET)
+ family_configure_example(${TARGET})
+endfunction()
+
+function(family_configure_dual_usb_example TARGET)
+ family_configure_example(${TARGET})
+endfunction()
diff --git a/hw/bsp/nrf/family.mk b/hw/bsp/nrf/family.mk
index 4102c8187..6d067e1c2 100644
--- a/hw/bsp/nrf/family.mk
+++ b/hw/bsp/nrf/family.mk
@@ -3,21 +3,17 @@ DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/nordic/nrfx
include $(TOP)/$(BOARD_PATH)/board.mk
+# nRF52 is cortex-m4, nRF53 is cortex-m33
+CPU_CORE ?= cortex-m4
+include $(TOP)/tools/make/cpu/$(CPU_CORE).mk
+
CFLAGS += \
-flto \
- -mthumb \
- -mabi=aapcs \
- -mcpu=cortex-m4 \
- -mfloat-abi=hard \
- -mfpu=fpv4-sp-d16 \
-DCFG_TUSB_MCU=OPT_MCU_NRF5X \
-DCONFIG_GPIO_AS_PINRESET
# suppress warning caused by vendor mcu driver
-CFLAGS += -Wno-error=undef -Wno-error=unused-parameter -Wno-error=cast-align -Wno-error=cast-qual
-
-# All source paths should be relative to the top level.
-LD_FILE ?= hw/bsp/nrf/boards/$(BOARD)/nrf52840_s140_v6.ld
+CFLAGS += -Wno-error=undef -Wno-error=unused-parameter -Wno-error=cast-align -Wno-error=cast-qual -Wno-error=redundant-decls
LDFLAGS += -L$(TOP)/hw/mcu/nordic/nrfx/mdk
@@ -30,7 +26,6 @@ SRC_C += \
INC += \
$(TOP)/$(BOARD_PATH) \
$(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
- $(TOP)/hw/mcu/nordic \
$(TOP)/hw/mcu/nordic/nrfx \
$(TOP)/hw/mcu/nordic/nrfx/mdk \
$(TOP)/hw/mcu/nordic/nrfx/hal \
@@ -41,8 +36,5 @@ SRC_S += hw/mcu/nordic/nrfx/mdk/gcc_startup_$(MCU_VARIANT).S
ASFLAGS += -D__HEAP_SIZE=0
-# For freeRTOS port source
-FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/ARM_CM4F
-
# For flash-jlink target
-JLINK_DEVICE = $(MCU_VARIANT)_xxaa
+JLINK_DEVICE ?= $(MCU_VARIANT)_xxaa
diff --git a/hw/bsp/nrf/boards/feather_nrf52840_sense/nrf52840_s140_v6.ld b/hw/bsp/nrf/linker/nrf52840_s140_v6.ld
similarity index 96%
rename from hw/bsp/nrf/boards/feather_nrf52840_sense/nrf52840_s140_v6.ld
rename to hw/bsp/nrf/linker/nrf52840_s140_v6.ld
index 71c55bb81..e27fa1c91 100644
--- a/hw/bsp/nrf/boards/feather_nrf52840_sense/nrf52840_s140_v6.ld
+++ b/hw/bsp/nrf/linker/nrf52840_s140_v6.ld
@@ -35,4 +35,4 @@ SECTIONS
} > RAM
} INSERT AFTER .data;
-INCLUDE "nrf52_common.ld"
+INCLUDE "nrf_common.ld"
diff --git a/hw/bsp/nrf/nrfx_config.h b/hw/bsp/nrf/nrfx_config.h
new file mode 100644
index 000000000..696a3fb04
--- /dev/null
+++ b/hw/bsp/nrf/nrfx_config.h
@@ -0,0 +1,46 @@
+#ifndef NRFX_CONFIG_H__
+#define NRFX_CONFIG_H__
+
+#define NRFX_POWER_ENABLED 1
+#define NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY 7
+
+#define NRFX_CLOCK_ENABLED 0
+
+#define NRFX_UARTE_ENABLED 1
+#define NRFX_UARTE0_ENABLED 1
+
+#define NRFX_UARTE1_ENABLED 0
+#define NRFX_UARTE2_ENABLED 0
+#define NRFX_UARTE3_ENABLED 0
+
+#define NRFX_PRS_ENABLED 0
+#define NRFX_USBREG_ENABLED 1
+
+#if defined(NRF51)
+#include
+#elif defined(NRF52805_XXAA)
+#include
+#elif defined(NRF52810_XXAA)
+#include
+#elif defined(NRF52811_XXAA)
+#include
+#elif defined(NRF52820_XXAA)
+#include
+#elif defined(NRF52832_XXAA) || defined (NRF52832_XXAB)
+#include
+#elif defined(NRF52833_XXAA)
+#include
+#elif defined(NRF52840_XXAA)
+#include
+#elif defined(NRF5340_XXAA_APPLICATION)
+#include
+#elif defined(NRF5340_XXAA_NETWORK)
+ #include
+#elif defined(NRF9120_XXAA) || defined(NRF9160_XXAA)
+ #include
+#else
+ #error "Unknown device."
+#endif
+
+
+#endif // NRFX_CONFIG_H__
diff --git a/hw/mcu/nordic/nrfx_glue.h b/hw/bsp/nrf/nrfx_glue.h
similarity index 100%
rename from hw/mcu/nordic/nrfx_glue.h
rename to hw/bsp/nrf/nrfx_glue.h
diff --git a/hw/mcu/nordic/nrfx_log.h b/hw/bsp/nrf/nrfx_log.h
similarity index 100%
rename from hw/mcu/nordic/nrfx_log.h
rename to hw/bsp/nrf/nrfx_log.h
diff --git a/hw/bsp/rp2040/family.c b/hw/bsp/rp2040/family.c
index 920869585..3aa989c0e 100644
--- a/hw/bsp/rp2040/family.c
+++ b/hw/bsp/rp2040/family.c
@@ -125,10 +125,10 @@ void board_init(void)
// Set the system clock to a multiple of 120mhz for bitbanging USB with pico-usb
set_sys_clock_khz(120000, true);
-#ifdef PIO_USB_VBUSEN_PIN
+#ifdef PICO_DEFAULT_PIO_USB_VBUSEN_PIN
gpio_init(PICO_DEFAULT_PIO_USB_VBUSEN_PIN);
gpio_set_dir(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, GPIO_OUT);
- gpio_put(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, PIO_USB_VBUSEN_STATE);
+ gpio_put(PICO_DEFAULT_PIO_USB_VBUSEN_PIN, PICO_DEFAULT_PIO_USB_VBUSEN_STATE);
#endif
// rp2040 use pico-pio-usb for host tuh_configure() can be used to passed pio configuration to the host stack
diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake
index 5d80ab66e..28637e3ee 100644
--- a/hw/bsp/rp2040/family.cmake
+++ b/hw/bsp/rp2040/family.cmake
@@ -16,8 +16,8 @@ if (NOT TARGET _rp2040_family_inclusion_marker)
include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
# TOP is absolute path to root directory of TinyUSB git repo
- set(TOP "${CMAKE_CURRENT_LIST_DIR}/../../..")
- get_filename_component(TOP "${TOP}" REALPATH)
+ #set(TOP "${CMAKE_CURRENT_LIST_DIR}/../../..")
+ #get_filename_component(TOP "${TOP}" REALPATH)
if (NOT PICO_TINYUSB_PATH)
set(PICO_TINYUSB_PATH ${TOP})
@@ -330,4 +330,8 @@ if (NOT TARGET _rp2040_family_inclusion_marker)
COMPILE_FLAGS "-Wno-cast-qual")
endif()
endfunction()
+
+ # rp2040 does not support freeRTOS example yet
+ function(family_add_freertos TARGET)
+ endfunction()
endif()
diff --git a/hw/bsp/saml2x/family.mk b/hw/bsp/saml2x/family.mk
index 91c2cfa61..62e5f8f4a 100644
--- a/hw/bsp/saml2x/family.mk
+++ b/hw/bsp/saml2x/family.mk
@@ -32,7 +32,7 @@ SRC_C += \
INC += \
$(TOP)/$(BOARD_PATH) \
- $(TOP)/$(MCU_DIR)/ \
+ $(TOP)/$(MCU_DIR) \
$(TOP)/$(MCU_DIR)/config \
$(TOP)/$(MCU_DIR)/include \
$(TOP)/$(MCU_DIR)/hal/include \
diff --git a/hw/mcu/nordic/nrfx_config.h b/hw/mcu/nordic/nrfx_config.h
deleted file mode 100644
index 6a974ba70..000000000
--- a/hw/mcu/nordic/nrfx_config.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef NRFX_CONFIG_H__
-#define NRFX_CONFIG_H__
-
-#define NRFX_POWER_ENABLED 1
-#define NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY 7
-
-#define NRFX_CLOCK_ENABLED 0
-
-#define NRFX_UARTE_ENABLED 1
-#define NRFX_UARTE0_ENABLED 1
-
-#define NRFX_UARTE1_ENABLED 0
-#define NRFX_UARTE2_ENABLED 0
-#define NRFX_UARTE3_ENABLED 0
-
-#define NRFX_PRS_ENABLED 0
-
-#endif // NRFX_CONFIG_H__
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 000000000..396737ed5
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,98 @@
+# TODO more docs and example on how to use this file
+# Usage: requires target tinyusb_config which expose tusb_config.h file
+# TINYUSB_TARGET_PREFIX and TINYUSB_TARGET_SUFFIX can be used to change the name of the target
+
+cmake_minimum_required(VERSION 3.17)
+
+# Add tinyusb to a target, if user don't want to compile tinyusb as a library
+function(add_tinyusb TARGET)
+ target_sources(${TARGET} PRIVATE
+ # common
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/tusb.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/common/tusb_fifo.c
+ # device
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/device/usbd.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/device/usbd_control.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/audio/audio_device.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/cdc/cdc_device.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/dfu/dfu_device.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/dfu/dfu_rt_device.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/hid/hid_device.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/midi/midi_device.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/msc/msc_device.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/net/ecm_rndis_device.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/net/ncm_device.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/usbtmc/usbtmc_device.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/vendor/vendor_device.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/video/video_device.c
+ # host
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/host/usbh.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/host/hub.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/cdc/cdc_host.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/hid/hid_host.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/msc/msc_host.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/vendor/vendor_host.c
+ )
+ target_include_directories(${TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ # TODO for net driver, should be removed/changed
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../lib/networking
+ )
+
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(${TARGET} PRIVATE
+ -Wall
+ -Wextra
+ -Werror
+ -Wfatal-errors
+ -Wdouble-promotion
+ -Wstrict-prototypes
+ -Wstrict-overflow
+ -Werror-implicit-function-declaration
+ -Wfloat-equal
+ -Wundef
+ -Wshadow
+ -Wwrite-strings
+ -Wsign-compare
+ -Wmissing-format-attribute
+ -Wunreachable-code
+ -Wcast-align
+ -Wcast-function-type
+ -Wcast-qual
+ -Wnull-dereference
+ -Wuninitialized
+ -Wunused
+ -Wreturn-type
+ -Wredundant-decls
+ )
+ endif ()
+endfunction()
+
+#------------------------------------
+# TinyUSB as library target
+#------------------------------------
+set(TINYUSB_TARGET "tinyusb")
+set(TINYUSB_CONFIG_TARGET "tinyusb_config")
+
+if (DEFINED TINYUSB_TARGET_PREFIX)
+ set(TINYUSB_TARGET "${TINYUSB_TARGET_PREFIX}${TINYUSB_TARGET}")
+ set(TINYUSB_CONFIG_TARGET "${TINYUSB_TARGET_PREFIX}${TINYUSB_CONFIG_TARGET}")
+endif ()
+
+if (DEFINED TINYUSB_TARGET_SUFFIX)
+ set(TINYUSB_TARGET "${TINYUSB_TARGET}${TINYUSB_TARGET_SUFFIX}")
+ set(TINYUSB_CONFIG_TARGET "${TINYUSB_CONFIG_TARGET}${TINYUSB_TARGET_SUFFIX}")
+endif ()
+
+add_library(${TINYUSB_TARGET} STATIC)
+add_tinyusb(${TINYUSB_TARGET})
+
+# Check if tinyusb_config target is defined
+if (NOT TARGET ${TINYUSB_CONFIG_TARGET})
+ message(FATAL_ERROR "${TINYUSB_CONFIG_TARGET} target is not defined")
+endif()
+
+# Link with tinyusb_config target
+target_link_libraries(${TINYUSB_TARGET} PUBLIC
+ ${TINYUSB_CONFIG_TARGET}
+ )
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c
index a82ef1d62..5adce521d 100644
--- a/src/class/cdc/cdc_device.c
+++ b/src/class/cdc/cdc_device.c
@@ -53,7 +53,7 @@ typedef struct
/*------------- From this point, data is not cleared by bus reset -------------*/
char wanted_char;
- cdc_line_coding_t line_coding;
+ TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding;
// FIFO
tu_fifo_t rx_ff;
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index c0cc41adf..ce9f27c33 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -33,14 +33,12 @@
#include "cdc_host.h"
-
// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message
#define CDCH_DEBUG 2
-
-#define TU_LOG_CDCH(...) TU_LOG(CDCH_DEBUG, __VA_ARGS__)
+#define TU_LOG_DRV(...) TU_LOG(CDCH_DEBUG, __VA_ARGS__)
//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF
+// Host CDC Interface
//--------------------------------------------------------------------+
typedef struct {
@@ -49,11 +47,12 @@ typedef struct {
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
+ uint8_t serial_drid; // Serial Driver ID
cdc_acm_capability_t acm_capability;
uint8_t ep_notif;
- cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width
- uint8_t line_state; // DTR (bit0), RTS (bit1)
+ uint8_t line_state; // DTR (bit0), RTS (bit1)
+ TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width
tuh_xfer_cb_t user_control_cb;
@@ -70,13 +69,103 @@ typedef struct {
} cdch_interface_t;
+CFG_TUH_MEM_SECTION
+static cdch_interface_t cdch_data[CFG_TUH_CDC];
+
+//--------------------------------------------------------------------+
+// Serial Driver
+//--------------------------------------------------------------------+
+
+//------------- ACM prototypes -------------//
+static void acm_process_config(tuh_xfer_t* xfer);
+
+static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+//------------- FTDI prototypes -------------//
+#if CFG_TUH_CDC_FTDI
+#include "serial/ftdi_sio.h"
+
+static uint16_t const ftdi_pids[] = { TU_FTDI_PID_LIST };
+enum {
+ FTDI_PID_COUNT = sizeof(ftdi_pids) / sizeof(ftdi_pids[0])
+};
+
+// Store last request baudrate since divisor to baudrate is not easy
+static uint32_t _ftdi_requested_baud;
+
+static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len);
+static void ftdi_process_config(tuh_xfer_t* xfer);
+
+static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+#endif
+
+//------------- CP210X prototypes -------------//
+#if CFG_TUH_CDC_CP210X
+#include "serial/cp210x.h"
+
+static uint16_t const cp210x_pids[] = { TU_CP210X_PID_LIST };
+enum {
+ CP210X_PID_COUNT = sizeof(cp210x_pids) / sizeof(cp210x_pids[0])
+};
+
+static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
+static void cp210x_process_config(tuh_xfer_t* xfer);
+
+static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+#endif
+
+enum {
+ SERIAL_DRIVER_ACM = 0,
+
+#if CFG_TUH_CDC_FTDI
+ SERIAL_DRIVER_FTDI,
+#endif
+
+#if CFG_TUH_CDC_CP210X
+ SERIAL_DRIVER_CP210X,
+#endif
+};
+
+typedef struct {
+ void (*const process_set_config)(tuh_xfer_t* xfer);
+ bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+ bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+} cdch_serial_driver_t;
+
+// Note driver list must be in the same order as SERIAL_DRIVER enum
+static const cdch_serial_driver_t serial_drivers[] = {
+ { .process_set_config = acm_process_config,
+ .set_control_line_state = acm_set_control_line_state,
+ .set_baudrate = acm_set_baudrate
+ },
+
+ #if CFG_TUH_CDC_FTDI
+ { .process_set_config = ftdi_process_config,
+ .set_control_line_state = ftdi_sio_set_modem_ctrl,
+ .set_baudrate = ftdi_sio_set_baudrate
+ },
+ #endif
+
+ #if CFG_TUH_CDC_CP210X
+ { .process_set_config = cp210x_process_config,
+ .set_control_line_state = cp210x_set_modem_ctrl,
+ .set_baudrate = cp210x_set_baudrate
+ },
+ #endif
+};
+
+enum {
+ SERIAL_DRIVER_COUNT = sizeof(serial_drivers) / sizeof(serial_drivers[0])
+};
+
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
-CFG_TUH_MEM_SECTION
-static cdch_interface_t cdch_data[CFG_TUH_CDC];
-
static inline cdch_interface_t* get_itf(uint8_t idx)
{
TU_ASSERT(idx < CFG_TUH_CDC, NULL);
@@ -101,16 +190,29 @@ static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr)
}
-static cdch_interface_t* find_new_itf(void)
+static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const *itf_desc)
{
for(uint8_t i=0; idaddr = daddr;
+ p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber;
+ p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass;
+ p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol;
+ p_cdc->line_state = 0;
+ return p_cdc;
+ }
}
return NULL;
}
+static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t const *desc_ep);
+static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num);
+static void cdch_internal_control_complete(tuh_xfer_t* xfer);
+
//--------------------------------------------------------------------+
// APPLICATION API
//--------------------------------------------------------------------+
@@ -270,102 +372,139 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer)
if (xfer->result == XFER_RESULT_SUCCESS)
{
- switch(xfer->setup->bRequest)
- {
- case CDC_REQUEST_SET_CONTROL_LINE_STATE:
- p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue);
- break;
+ switch (p_cdc->serial_drid) {
+ case SERIAL_DRIVER_ACM:
+ switch (xfer->setup->bRequest) {
+ case CDC_REQUEST_SET_CONTROL_LINE_STATE:
+ p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue);
+ break;
- case CDC_REQUEST_SET_LINE_CODING:
- {
- uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength));
- memcpy(&p_cdc->line_coding, xfer->buffer, len);
- }
- break;
+ case CDC_REQUEST_SET_LINE_CODING: {
+ uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength));
+ memcpy(&p_cdc->line_coding, xfer->buffer, len);
+ }
+ break;
+
+ default: break;
+ }
+ break;
+
+ #if CFG_TUH_CDC_FTDI
+ case SERIAL_DRIVER_FTDI:
+ switch (xfer->setup->bRequest) {
+ case FTDI_SIO_MODEM_CTRL:
+ p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff);
+ break;
+
+ case FTDI_SIO_SET_BAUD_RATE:
+ // convert from divisor to baudrate is not supported
+ p_cdc->line_coding.bit_rate = _ftdi_requested_baud;
+ break;
+
+ default: break;
+ }
+ break;
+ #endif
+
+ #if CFG_TUH_CDC_CP210X
+ case SERIAL_DRIVER_CP210X:
+ switch(xfer->setup->bRequest) {
+ case CP210X_SET_MHS:
+ p_cdc->line_state = (uint8_t) (tu_le16toh(xfer->setup->wValue) & 0x00ff);
+ break;
+
+ case CP210X_SET_BAUDRATE: {
+ uint32_t baudrate;
+ memcpy(&baudrate, xfer->buffer, sizeof(uint32_t));
+ p_cdc->line_coding.bit_rate = tu_le32toh(baudrate);
+ }
+ break;
+ }
+ break;
+ #endif
default: break;
}
}
xfer->complete_cb = p_cdc->user_control_cb;
- xfer->complete_cb(xfer);
+ if (xfer->complete_cb) {
+ xfer->complete_cb(xfer);
+ }
}
-bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
-{
+bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
cdch_interface_t* p_cdc = get_itf(idx);
- TU_VERIFY(p_cdc && p_cdc->acm_capability.support_line_request);
+ TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
+ cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid];
- TU_LOG_CDCH("CDC Set Control Line State\r\n");
+ if ( complete_cb ) {
+ return driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data);
+ }else {
+ // blocking
+ xfer_result_t result = XFER_RESULT_INVALID;
+ bool ret = driver->set_control_line_state(p_cdc, line_state, complete_cb, (uintptr_t) &result);
- tusb_control_request_t const request =
- {
- .bmRequestType_bit =
- {
- .recipient = TUSB_REQ_RCPT_INTERFACE,
- .type = TUSB_REQ_TYPE_CLASS,
- .direction = TUSB_DIR_OUT
- },
- .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
- .wValue = tu_htole16(line_state),
- .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber),
- .wLength = 0
- };
+ if (user_data) {
+ // user_data is not NULL, return result via user_data
+ *((xfer_result_t*) user_data) = result;
+ }
- p_cdc->user_control_cb = complete_cb;
- tuh_xfer_t xfer =
- {
- .daddr = p_cdc->daddr,
- .ep_addr = 0,
- .setup = &request,
- .buffer = NULL,
- .complete_cb = cdch_internal_control_complete,
- .user_data = user_data
- };
+ TU_VERIFY(ret && result == XFER_RESULT_SUCCESS);
- TU_ASSERT(tuh_control_xfer(&xfer));
- return true;
+ p_cdc->line_state = (uint8_t) line_state;
+ return true;
+ }
+}
+
+bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
+ cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid];
+
+ if ( complete_cb ) {
+ return driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data);
+ }else {
+ // blocking
+ xfer_result_t result = XFER_RESULT_INVALID;
+ bool ret = driver->set_baudrate(p_cdc, baudrate, complete_cb, (uintptr_t) &result);
+
+ if (user_data) {
+ // user_data is not NULL, return result via user_data
+ *((xfer_result_t*) user_data) = result;
+ }
+
+ TU_VERIFY(ret && result == XFER_RESULT_SUCCESS);
+
+ p_cdc->line_coding.bit_rate = baudrate;
+ return true;
+ }
}
bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
cdch_interface_t* p_cdc = get_itf(idx);
- TU_VERIFY(p_cdc && p_cdc->acm_capability.support_line_request);
+ // only ACM support this set line coding request
+ TU_VERIFY(p_cdc && p_cdc->serial_drid == SERIAL_DRIVER_ACM);
+ TU_VERIFY(p_cdc->acm_capability.support_line_request);
- TU_LOG_CDCH("CDC Set Line Conding\r\n");
+ if ( complete_cb ) {
+ return acm_set_line_coding(p_cdc, line_coding, complete_cb, user_data);
+ }else {
+ // blocking
+ xfer_result_t result = XFER_RESULT_INVALID;
+ bool ret = acm_set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result);
- tusb_control_request_t const request =
- {
- .bmRequestType_bit =
- {
- .recipient = TUSB_REQ_RCPT_INTERFACE,
- .type = TUSB_REQ_TYPE_CLASS,
- .direction = TUSB_DIR_OUT
- },
- .bRequest = CDC_REQUEST_SET_LINE_CODING,
- .wValue = 0,
- .wIndex = tu_htole16(p_cdc->bInterfaceNumber),
- .wLength = tu_htole16(sizeof(cdc_line_coding_t))
- };
+ if (user_data) {
+ // user_data is not NULL, return result via user_data
+ *((xfer_result_t*) user_data) = result;
+ }
- // use usbh enum buf to hold line coding since user line_coding variable may not live long enough
- // for the transfer to complete
- uint8_t* enum_buf = usbh_get_enum_buf();
- memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t));
+ TU_VERIFY(ret && result == XFER_RESULT_SUCCESS);
- p_cdc->user_control_cb = complete_cb;
- tuh_xfer_t xfer =
- {
- .daddr = p_cdc->daddr,
- .ep_addr = 0,
- .setup = &request,
- .buffer = enum_buf,
- .complete_cb = cdch_internal_control_complete,
- .user_data = user_data
- };
-
- TU_ASSERT(tuh_control_xfer(&xfer));
- return true;
+ p_cdc->line_coding = *line_coding;
+ return true;
+ }
}
//--------------------------------------------------------------------+
@@ -397,6 +536,8 @@ void cdch_close(uint8_t daddr)
cdch_interface_t* p_cdc = &cdch_data[idx];
if (p_cdc->daddr == daddr)
{
+ TU_LOG_DRV(" CDCh close addr = %u index = %u\r\n", daddr, idx);
+
// Invoke application callback
if (tuh_cdc_umount_cb) tuh_cdc_umount_cb(idx);
@@ -409,8 +550,7 @@ void cdch_close(uint8_t daddr)
}
}
-bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
-{
+bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) {
// TODO handle stall response, retry failed transfer ...
TU_ASSERT(event == XFER_RESULT_SUCCESS);
@@ -418,32 +558,40 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t
cdch_interface_t * p_cdc = get_itf(idx);
TU_ASSERT(p_cdc);
- if ( ep_addr == p_cdc->stream.tx.ep_addr )
- {
+ if ( ep_addr == p_cdc->stream.tx.ep_addr ) {
// invoke tx complete callback to possibly refill tx fifo
if (tuh_cdc_tx_complete_cb) tuh_cdc_tx_complete_cb(idx);
- if ( 0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx) )
- {
+ if ( 0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx) ) {
// If there is no data left, a ZLP should be sent if:
// - xferred_bytes is multiple of EP Packet size and not zero
tu_edpt_stream_write_zlp_if_needed(&p_cdc->stream.tx, xferred_bytes);
}
}
- else if ( ep_addr == p_cdc->stream.rx.ep_addr )
- {
- tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes);
+ else if ( ep_addr == p_cdc->stream.rx.ep_addr ) {
+ #if CFG_TUH_CDC_FTDI
+ if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) {
+ // FTDI reserve 2 bytes for status
+ // FTDI status
+// uint8_t status[2] = {
+// p_cdc->stream.rx.ep_buf[0],
+// p_cdc->stream.rx.ep_buf[1]
+// };
+ tu_edpt_stream_read_xfer_complete_offset(&p_cdc->stream.rx, xferred_bytes, 2);
+ }else
+ #endif
+ {
+ tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes);
+ }
// invoke receive callback
- if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx);
+ if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx);
// prepare for next transfer if needed
tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
- }else if ( ep_addr == p_cdc->ep_notif )
- {
+ }else if ( ep_addr == p_cdc->ep_notif ) {
// TODO handle notification endpoint
- }else
- {
+ }else {
TU_ASSERT(false);
}
@@ -454,26 +602,122 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t
// Enumeration
//--------------------------------------------------------------------+
+static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
+
+static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const *desc_ep)
+{
+ for(size_t i=0; i<2; i++)
+ {
+ TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType &&
+ TUSB_XFER_BULK == desc_ep->bmAttributes.xfer);
+
+ TU_ASSERT(tuh_edpt_open(p_cdc->daddr, desc_ep));
+
+ if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN )
+ {
+ tu_edpt_stream_open(&p_cdc->stream.rx, p_cdc->daddr, desc_ep);
+ }else
+ {
+ tu_edpt_stream_open(&p_cdc->stream.tx, p_cdc->daddr, desc_ep);
+ }
+
+ desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(desc_ep);
+ }
+
+ return true;
+}
+
bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
{
(void) rhport;
// 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);
+ // Note: Protocol 0xFF can be RNDIS device
+ if ( TUSB_CLASS_CDC == itf_desc->bInterfaceClass &&
+ CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass)
+ {
+ return acm_open(daddr, itf_desc, max_len);
+ }
+ #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X
+ else if ( 0xff == itf_desc->bInterfaceClass )
+ {
+ uint16_t vid, pid;
+ TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid));
+ #if CFG_TUH_CDC_FTDI
+ if (TU_FTDI_VID == vid) {
+ for (size_t i = 0; i < FTDI_PID_COUNT; i++) {
+ if (ftdi_pids[i] == pid) {
+ return ftdi_open(daddr, itf_desc, max_len);
+ }
+ }
+ }
+ #endif
+
+ #if CFG_TUH_CDC_CP210X
+ if (TU_CP210X_VID == vid) {
+ for (size_t i = 0; i < CP210X_PID_COUNT; i++) {
+ if (cp210x_pids[i] == pid) {
+ return cp210x_open(daddr, itf_desc, max_len);
+ }
+ }
+ }
+ #endif
+ }
+ #endif
+
+ return false;
+}
+
+static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) {
+ if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx);
+
+ // Prepare for incoming data
+ tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
+
+ // notify usbh that driver enumeration is complete
+ usbh_driver_set_config_complete(p_cdc->daddr, itf_num);
+}
+
+
+bool cdch_set_config(uint8_t daddr, uint8_t itf_num)
+{
+ tusb_control_request_t request;
+ request.wIndex = tu_htole16((uint16_t) itf_num);
+
+ // fake transfer to kick-off process
+ tuh_xfer_t xfer;
+ xfer.daddr = daddr;
+ xfer.result = XFER_RESULT_SUCCESS;
+ xfer.setup = &request;
+ xfer.user_data = 0; // initial state
+
+ uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num);
+ cdch_interface_t * p_cdc = get_itf(idx);
+ TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
+
+ serial_drivers[p_cdc->serial_drid].process_set_config(&xfer);
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// ACM
+//--------------------------------------------------------------------+
+
+enum {
+ CONFIG_ACM_SET_CONTROL_LINE_STATE = 0,
+ CONFIG_ACM_SET_LINE_CODING,
+ CONFIG_ACM_COMPLETE,
+};
+
+static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
+{
uint8_t const * p_desc_end = ((uint8_t const*) itf_desc) + max_len;
- cdch_interface_t * p_cdc = find_new_itf();
+ cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc);
TU_VERIFY(p_cdc);
- p_cdc->daddr = daddr;
- p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber;
- p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass;
- p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol;
- p_cdc->line_state = 0;
+ p_cdc->serial_drid = SERIAL_DRIVER_ACM;
//------------- Control Interface -------------//
uint8_t const * p_desc = tu_desc_next(itf_desc);
@@ -510,37 +754,13 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d
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 *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
- TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType &&
- TUSB_XFER_BULK == desc_ep->bmAttributes.xfer);
-
- TU_ASSERT(tuh_edpt_open(daddr, desc_ep));
-
- if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN )
- {
- tu_edpt_stream_open(&p_cdc->stream.rx, daddr, desc_ep);
- }else
- {
- tu_edpt_stream_open(&p_cdc->stream.tx, daddr, desc_ep);
- }
-
- p_desc = tu_desc_next(p_desc);
- }
+ TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const *) p_desc));
}
return true;
}
-enum
-{
- CONFIG_SET_CONTROL_LINE_STATE,
- CONFIG_SET_LINE_CODING,
- CONFIG_COMPLETE
-};
-
-static void process_cdc_config(tuh_xfer_t* xfer)
+static void acm_process_config(tuh_xfer_t* xfer)
{
uintptr_t const state = xfer->user_data;
uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
@@ -550,57 +770,407 @@ static void process_cdc_config(tuh_xfer_t* xfer)
switch(state)
{
- case CONFIG_SET_CONTROL_LINE_STATE:
+ case CONFIG_ACM_SET_CONTROL_LINE_STATE:
#if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
if (p_cdc->acm_capability.support_line_request)
{
- TU_ASSERT( tuh_cdc_set_control_line_state(idx, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, process_cdc_config, CONFIG_SET_LINE_CODING), );
+ TU_ASSERT(acm_set_control_line_state(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, acm_process_config,
+ CONFIG_ACM_SET_LINE_CODING), );
break;
}
- #endif
+ #endif
TU_ATTR_FALLTHROUGH;
- case CONFIG_SET_LINE_CODING:
- #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
+ case CONFIG_ACM_SET_LINE_CODING:
+ #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
if (p_cdc->acm_capability.support_line_request)
{
cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
- TU_ASSERT( tuh_cdc_set_line_coding(idx, &line_coding, process_cdc_config, CONFIG_COMPLETE), );
+ TU_ASSERT(acm_set_line_coding(p_cdc, &line_coding, acm_process_config, CONFIG_ACM_COMPLETE), );
break;
}
- #endif
+ #endif
TU_ATTR_FALLTHROUGH;
- case CONFIG_COMPLETE:
- if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx);
-
- // Prepare for incoming data
- tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
-
- // notify usbh that driver enumeration is complete
+ case CONFIG_ACM_COMPLETE:
// itf_num+1 to account for data interface as well
- usbh_driver_set_config_complete(xfer->daddr, itf_num+1);
- break;
+ set_config_complete(p_cdc, idx, itf_num+1);
+ break;
default: break;
}
}
-bool cdch_set_config(uint8_t daddr, uint8_t itf_num)
+static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ TU_VERIFY(p_cdc->acm_capability.support_line_request);
+ TU_LOG_DRV("CDC ACM Set Control Line State\r\n");
+
+ tusb_control_request_t const request = {
+ .bmRequestType_bit = {
+ .recipient = TUSB_REQ_RCPT_INTERFACE,
+ .type = TUSB_REQ_TYPE_CLASS,
+ .direction = TUSB_DIR_OUT
+ },
+ .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
+ .wValue = tu_htole16(line_state),
+ .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber),
+ .wLength = 0
+ };
+
+ p_cdc->user_control_cb = complete_cb;
+
+ tuh_xfer_t xfer = {
+ .daddr = p_cdc->daddr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = NULL,
+ .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call
+ .user_data = user_data
+ };
+
+ TU_ASSERT(tuh_control_xfer(&xfer));
+ return true;
+}
+
+static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ TU_LOG_DRV("CDC ACM Set Line Conding\r\n");
+
+ tusb_control_request_t const request = {
+ .bmRequestType_bit = {
+ .recipient = TUSB_REQ_RCPT_INTERFACE,
+ .type = TUSB_REQ_TYPE_CLASS,
+ .direction = TUSB_DIR_OUT
+ },
+ .bRequest = CDC_REQUEST_SET_LINE_CODING,
+ .wValue = 0,
+ .wIndex = tu_htole16(p_cdc->bInterfaceNumber),
+ .wLength = tu_htole16(sizeof(cdc_line_coding_t))
+ };
+
+ // use usbh enum buf to hold line coding since user line_coding variable does not live long enough
+ uint8_t* enum_buf = usbh_get_enum_buf();
+ memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t));
+
+ p_cdc->user_control_cb = complete_cb;
+ tuh_xfer_t xfer = {
+ .daddr = p_cdc->daddr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = enum_buf,
+ .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call
+ .user_data = user_data
+ };
+
+ TU_ASSERT(tuh_control_xfer(&xfer));
+ return true;
+}
+
+static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ TU_VERIFY(p_cdc->acm_capability.support_line_request);
+ cdc_line_coding_t line_coding = p_cdc->line_coding;
+ line_coding.bit_rate = baudrate;
+ return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data);
+}
+
+//--------------------------------------------------------------------+
+// FTDI
+//--------------------------------------------------------------------+
+#if CFG_TUH_CDC_FTDI
+
+enum {
+ CONFIG_FTDI_RESET = 0,
+ CONFIG_FTDI_MODEM_CTRL,
+ CONFIG_FTDI_SET_BAUDRATE,
+ CONFIG_FTDI_SET_DATA,
+ CONFIG_FTDI_COMPLETE
+};
+
+static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) {
+ // FTDI Interface includes 1 vendor interface + 2 bulk endpoints
+ TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2);
+ TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len);
+
+ cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc);
+ TU_VERIFY(p_cdc);
+
+ TU_LOG_DRV("FTDI opened\r\n");
+
+ p_cdc->serial_drid = SERIAL_DRIVER_FTDI;
+
+ // endpoint pair
+ tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
+
+ // data endpoints expected to be in pairs
+ return open_ep_stream_pair(p_cdc, desc_ep);
+}
+
+// set request without data
+static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ tusb_control_request_t const request = {
+ .bmRequestType_bit = {
+ .recipient = TUSB_REQ_RCPT_DEVICE,
+ .type = TUSB_REQ_TYPE_VENDOR,
+ .direction = TUSB_DIR_OUT
+ },
+ .bRequest = command,
+ .wValue = tu_htole16(value),
+ .wIndex = 0,
+ .wLength = 0
+ };
+
+ tuh_xfer_t xfer = {
+ .daddr = p_cdc->daddr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = NULL,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
+
+ return tuh_control_xfer(&xfer);
+}
+
+static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
- // fake transfer to kick-off process
- tusb_control_request_t request;
- request.wIndex = tu_htole16((uint16_t) itf_num);
+ return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data);
+}
- tuh_xfer_t xfer;
- xfer.daddr = daddr;
- xfer.result = XFER_RESULT_SUCCESS;
- xfer.setup = &request;
- xfer.user_data = CONFIG_SET_CONTROL_LINE_STATE;
+static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ TU_LOG_DRV("CDC FTDI Set Control Line State\r\n");
+ p_cdc->user_control_cb = complete_cb;
+ TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state,
+ complete_cb ? cdch_internal_control_complete : NULL, user_data));
+ return true;
+}
- process_cdc_config(&xfer);
+static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base)
+{
+ const uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
+ uint32_t divisor;
+
+ /* divisor shifted 3 bits to the left */
+ uint32_t divisor3 = base / (2 * baud);
+ divisor = (divisor3 >> 3);
+ divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14;
+
+ /* Deal with special cases for highest baud rates. */
+ if (divisor == 1) { /* 1.0 */
+ divisor = 0;
+ }
+ else if (divisor == 0x4001) { /* 1.5 */
+ divisor = 1;
+ }
+
+ return divisor;
+}
+
+static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud)
+{
+ return ftdi_232bm_baud_base_to_divisor(baud, 48000000u);
+}
+
+static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate);
+ TU_LOG_DRV("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\n", baudrate, divisor);
+
+ p_cdc->user_control_cb = complete_cb;
+ _ftdi_requested_baud = baudrate;
+ TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor,
+ complete_cb ? cdch_internal_control_complete : NULL, user_data));
return true;
}
+static void ftdi_process_config(tuh_xfer_t* xfer) {
+ uintptr_t const state = xfer->user_data;
+ uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
+ cdch_interface_t * p_cdc = get_itf(idx);
+ TU_ASSERT(p_cdc, );
+
+ switch(state) {
+ // Note may need to read FTDI eeprom
+ case CONFIG_FTDI_RESET:
+ TU_ASSERT(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL),);
+ break;
+
+ case CONFIG_FTDI_MODEM_CTRL:
+ #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
+ TU_ASSERT(
+ ftdi_sio_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),);
+ break;
+ #else
+ TU_ATTR_FALLTHROUGH;
+ #endif
+
+ case CONFIG_FTDI_SET_BAUDRATE: {
+ #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
+ cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
+ TU_ASSERT(ftdi_sio_set_baudrate(p_cdc, line_coding.bit_rate, ftdi_process_config, CONFIG_FTDI_SET_DATA),);
+ break;
+ #else
+ TU_ATTR_FALLTHROUGH;
+ #endif
+ }
+
+ case CONFIG_FTDI_SET_DATA: {
+ #if 0 // TODO set data format
+ #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
+ cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
+ TU_ASSERT(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE),);
+ break;
+ #endif
+ #endif
+
+ TU_ATTR_FALLTHROUGH;
+ }
+
+ case CONFIG_FTDI_COMPLETE:
+ set_config_complete(p_cdc, idx, itf_num);
+ break;
+
+ default:
+ break;
+ }
+}
+
+#endif
+
+//--------------------------------------------------------------------+
+// CP210x
+//--------------------------------------------------------------------+
+
+#if CFG_TUH_CDC_CP210X
+
+enum {
+ CONFIG_CP210X_IFC_ENABLE = 0,
+ CONFIG_CP210X_SET_BAUDRATE,
+ CONFIG_CP210X_SET_LINE_CTL,
+ CONFIG_CP210X_SET_DTR_RTS,
+ CONFIG_CP210X_COMPLETE
+};
+
+static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
+ // CP210x Interface includes 1 vendor interface + 2 bulk endpoints
+ TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2);
+ TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len);
+
+ cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc);
+ TU_VERIFY(p_cdc);
+
+ TU_LOG_DRV("CP210x opened\r\n");
+ p_cdc->serial_drid = SERIAL_DRIVER_CP210X;
+
+ // endpoint pair
+ tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
+
+ // data endpoints expected to be in pairs
+ return open_ep_stream_pair(p_cdc, desc_ep);
+}
+
+static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ tusb_control_request_t const request = {
+ .bmRequestType_bit = {
+ .recipient = TUSB_REQ_RCPT_INTERFACE,
+ .type = TUSB_REQ_TYPE_VENDOR,
+ .direction = TUSB_DIR_OUT
+ },
+ .bRequest = command,
+ .wValue = tu_htole16(value),
+ .wIndex = p_cdc->bInterfaceNumber,
+ .wLength = tu_htole16(length)
+ };
+
+ // use usbh enum buf since application variable does not live long enough
+ uint8_t* enum_buf = NULL;
+
+ if (buffer && length > 0) {
+ enum_buf = usbh_get_enum_buf();
+ tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length);
+ }
+
+ tuh_xfer_t xfer = {
+ .daddr = p_cdc->daddr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = enum_buf,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
+
+ return tuh_control_xfer(&xfer);
+}
+
+static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data);
+}
+
+static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ TU_LOG_DRV("CDC CP210x Set BaudRate = %lu\n", baudrate);
+ uint32_t baud_le = tu_htole32(baudrate);
+ p_cdc->user_control_cb = complete_cb;
+ return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4,
+ complete_cb ? cdch_internal_control_complete : NULL, user_data);
+}
+
+static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ TU_LOG_DRV("CDC CP210x Set Control Line State\r\n");
+ p_cdc->user_control_cb = complete_cb;
+ return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0,
+ complete_cb ? cdch_internal_control_complete : NULL, user_data);
+}
+
+static void cp210x_process_config(tuh_xfer_t* xfer) {
+ uintptr_t const state = xfer->user_data;
+ uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
+ cdch_interface_t *p_cdc = get_itf(idx);
+ TU_ASSERT(p_cdc,);
+
+ switch (state) {
+ case CONFIG_CP210X_IFC_ENABLE:
+ TU_ASSERT(cp210x_ifc_enable(p_cdc, 1, cp210x_process_config, CONFIG_CP210X_SET_BAUDRATE),);
+ break;
+
+ case CONFIG_CP210X_SET_BAUDRATE: {
+ #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
+ cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
+ TU_ASSERT(cp210x_set_baudrate(p_cdc, line_coding.bit_rate, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL),);
+ break;
+ #else
+ TU_ATTR_FALLTHROUGH;
+ #endif
+ }
+
+ case CONFIG_CP210X_SET_LINE_CTL: {
+ #if defined(CFG_TUH_CDC_LINE_CODING_ON_ENUM) && 0 // skip for now
+ cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
+ break;
+ #else
+ TU_ATTR_FALLTHROUGH;
+ #endif
+ }
+
+ case CONFIG_CP210X_SET_DTR_RTS:
+ #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
+ TU_ASSERT(
+ cp210x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, cp210x_process_config, CONFIG_CP210X_COMPLETE),);
+ break;
+ #else
+ TU_ATTR_FALLTHROUGH;
+ #endif
+
+ case CONFIG_CP210X_COMPLETE:
+ set_config_complete(p_cdc, idx, itf_num);
+ break;
+
+ default: break;
+ }
+}
+
+#endif
+
#endif
diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h
index a1e78f158..19552f1ee 100644
--- a/src/class/cdc/cdc_host.h
+++ b/src/class/cdc/cdc_host.h
@@ -134,28 +134,39 @@ bool tuh_cdc_read_clear (uint8_t idx);
//--------------------------------------------------------------------+
// Control Endpoint (Request) API
-// Each Function will make a USB transfer request to/from device
+// Each Function will make a USB control transfer request to/from device
+// - If complete_cb is provided, the function will return immediately and invoke
+// the callback when request is complete.
+// - If complete_cb is NULL, the function will block until request is complete.
+// - In this case, user_data should be pointed to xfer_result_t to hold the transfer result.
+// - The function will return true if transfer is successful, false otherwise.
//--------------------------------------------------------------------+
// Request to Set Control Line State: DTR (bit 0), RTS (bit 1)
bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-// Request to Set Line Coding
+// Request to set baudrate
+bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+// Request to Set Line Coding (ACM only)
+// Should only use if you don't work with serial devices such as FTDI/CP210x
bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-// Request to Get Line Coding
+// Request to Get Line Coding (ACM only)
// Should only use if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() never got invoked and
// CFG_TUH_CDC_LINE_CODING_ON_ENUM is not defined
// bool tuh_cdc_get_line_coding(uint8_t idx, cdc_line_coding_t* coding);
// Connect by set both DTR, RTS
-static inline bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+TU_ATTR_ALWAYS_INLINE static inline
+bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data);
}
// Disconnect by clear both DTR, RTS
-static inline bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+TU_ATTR_ALWAYS_INLINE static inline
+bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data);
}
diff --git a/src/class/cdc/serial/cp210x.h b/src/class/cdc/serial/cp210x.h
new file mode 100644
index 000000000..b01417092
--- /dev/null
+++ b/src/class/cdc/serial/cp210x.h
@@ -0,0 +1,64 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Ha Thach (thach@tinyusb.org) for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef TUSB_CP210X_H
+#define TUSB_CP210X_H
+
+// Protocol details can be found at AN571: CP210x Virtual COM Port Interface
+// https://www.silabs.com/documents/public/application-notes/AN571.pdf
+
+#define TU_CP210X_VID 0x10C4
+#define TU_CP210X_PID_LIST \
+ 0xEA60, 0xEA70
+
+/* Config request codes */
+#define CP210X_IFC_ENABLE 0x00
+#define CP210X_SET_BAUDDIV 0x01
+#define CP210X_GET_BAUDDIV 0x02
+#define CP210X_SET_LINE_CTL 0x03 // Set parity, data bits, stop bits
+#define CP210X_GET_LINE_CTL 0x04
+#define CP210X_SET_BREAK 0x05
+#define CP210X_IMM_CHAR 0x06
+#define CP210X_SET_MHS 0x07 // Set DTR, RTS
+#define CP210X_GET_MDMSTS 0x08 // Get modem status (DTR, RTS, CTS, DSR, RI, DCD)
+#define CP210X_SET_XON 0x09
+#define CP210X_SET_XOFF 0x0A
+#define CP210X_SET_EVENTMASK 0x0B
+#define CP210X_GET_EVENTMASK 0x0C
+#define CP210X_SET_CHAR 0x0D
+#define CP210X_GET_CHARS 0x0E
+#define CP210X_GET_PROPS 0x0F
+#define CP210X_GET_COMM_STATUS 0x10
+#define CP210X_RESET 0x11
+#define CP210X_PURGE 0x12
+#define CP210X_SET_FLOW 0x13
+#define CP210X_GET_FLOW 0x14
+#define CP210X_EMBED_EVENTS 0x15
+#define CP210X_GET_EVENTSTATE 0x16
+#define CP210X_SET_CHARS 0x19
+#define CP210X_GET_BAUDRATE 0x1D
+#define CP210X_SET_BAUDRATE 0x1E
+#define CP210X_VENDOR_SPECIFIC 0xFF // GPIO, Recipient must be Device
+
+#endif //TUSB_CP210X_H
diff --git a/src/class/cdc/serial/ftdi_sio.h b/src/class/cdc/serial/ftdi_sio.h
new file mode 100644
index 000000000..6916e4031
--- /dev/null
+++ b/src/class/cdc/serial/ftdi_sio.h
@@ -0,0 +1,249 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Ha Thach (thach@tinyusb.org) for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef TUSB_FTDI_SIO_H
+#define TUSB_FTDI_SIO_H
+
+// VID/PID for matching FTDI devices
+#define TU_FTDI_VID 0x0403
+#define TU_FTDI_PID_LIST \
+ 0x6001, 0x6006, 0x6010, 0x6011, 0x6014, 0x6015, 0x8372, 0xFBFA, \
+ 0xcd18
+
+// Commands
+#define FTDI_SIO_RESET 0 /* Reset the port */
+#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
+#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
+#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */
+#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */
+#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */
+#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */
+#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
+#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */
+#define FTDI_SIO_GET_LATENCY_TIMER 0x0a /* Get the latency timer */
+#define FTDI_SIO_SET_BITMODE 0x0b /* Set bitbang mode */
+#define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */
+#define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */
+
+/* FTDI_SIO_RESET */
+#define FTDI_SIO_RESET_SIO 0
+#define FTDI_SIO_RESET_PURGE_RX 1
+#define FTDI_SIO_RESET_PURGE_TX 2
+
+/*
+ * BmRequestType: 0100 0000B
+ * bRequest: FTDI_SIO_RESET
+ * wValue: Control Value
+ * 0 = Reset SIO
+ * 1 = Purge RX buffer
+ * 2 = Purge TX buffer
+ * wIndex: Port
+ * wLength: 0
+ * Data: None
+ *
+ * The Reset SIO command has this effect:
+ *
+ * Sets flow control set to 'none'
+ * Event char = $0D
+ * Event trigger = disabled
+ * Purge RX buffer
+ * Purge TX buffer
+ * Clear DTR
+ * Clear RTS
+ * baud and data format not reset
+ *
+ * The Purge RX and TX buffer commands affect nothing except the buffers
+ *
+ */
+
+/* FTDI_SIO_MODEM_CTRL */
+/*
+ * BmRequestType: 0100 0000B
+ * bRequest: FTDI_SIO_MODEM_CTRL
+ * wValue: ControlValue (see below)
+ * wIndex: Port
+ * wLength: 0
+ * Data: None
+ *
+ * NOTE: If the device is in RTS/CTS flow control, the RTS set by this
+ * command will be IGNORED without an error being returned
+ * Also - you can not set DTR and RTS with one control message
+ */
+
+#define FTDI_SIO_SET_DTR_MASK 0x1
+#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1)
+#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0)
+#define FTDI_SIO_SET_RTS_MASK 0x2
+#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2)
+#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0)
+
+/*
+ * ControlValue
+ * B0 DTR state
+ * 0 = reset
+ * 1 = set
+ * B1 RTS state
+ * 0 = reset
+ * 1 = set
+ * B2..7 Reserved
+ * B8 DTR state enable
+ * 0 = ignore
+ * 1 = use DTR state
+ * B9 RTS state enable
+ * 0 = ignore
+ * 1 = use RTS state
+ * B10..15 Reserved
+ */
+
+/* FTDI_SIO_SET_FLOW_CTRL */
+#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
+#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
+#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
+#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
+
+/*
+ * BmRequestType: 0100 0000b
+ * bRequest: FTDI_SIO_SET_FLOW_CTRL
+ * wValue: Xoff/Xon
+ * wIndex: Protocol/Port - hIndex is protocol / lIndex is port
+ * wLength: 0
+ * Data: None
+ *
+ * hIndex protocol is:
+ * B0 Output handshaking using RTS/CTS
+ * 0 = disabled
+ * 1 = enabled
+ * B1 Output handshaking using DTR/DSR
+ * 0 = disabled
+ * 1 = enabled
+ * B2 Xon/Xoff handshaking
+ * 0 = disabled
+ * 1 = enabled
+ *
+ * A value of zero in the hIndex field disables handshaking
+ *
+ * If Xon/Xoff handshaking is specified, the hValue field should contain the
+ * XOFF character and the lValue field contains the XON character.
+ */
+
+/* FTDI_SIO_SET_BAUD_RATE */
+/*
+ * BmRequestType: 0100 0000B
+ * bRequest: FTDI_SIO_SET_BAUDRATE
+ * wValue: BaudDivisor value - see below
+ * wIndex: Port
+ * wLength: 0
+ * Data: None
+ * The BaudDivisor values are calculated as follows (too complicated):
+ */
+
+/* FTDI_SIO_SET_DATA */
+#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8)
+#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8)
+#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8)
+#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8)
+#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8)
+#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
+#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
+#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
+#define FTDI_SIO_SET_BREAK (0x1 << 14)
+
+/*
+ * BmRequestType: 0100 0000B
+ * bRequest: FTDI_SIO_SET_DATA
+ * wValue: Data characteristics (see below)
+ * wIndex: Port
+ * wLength: 0
+ * Data: No
+ *
+ * Data characteristics
+ *
+ * B0..7 Number of data bits
+ * B8..10 Parity
+ * 0 = None
+ * 1 = Odd
+ * 2 = Even
+ * 3 = Mark
+ * 4 = Space
+ * B11..13 Stop Bits
+ * 0 = 1
+ * 1 = 1.5
+ * 2 = 2
+ * B14
+ * 1 = TX ON (break)
+ * 0 = TX OFF (normal state)
+ * B15 Reserved
+ *
+ */
+
+/*
+* DATA FORMAT
+*
+* IN Endpoint
+*
+* The device reserves the first two bytes of data on this endpoint to contain
+* the current values of the modem and line status registers. In the absence of
+* data, the device generates a message consisting of these two status bytes
+ * every 40 ms
+ *
+ * Byte 0: Modem Status
+*
+* Offset Description
+* B0 Reserved - must be 1
+* B1 Reserved - must be 0
+* B2 Reserved - must be 0
+* B3 Reserved - must be 0
+* B4 Clear to Send (CTS)
+* B5 Data Set Ready (DSR)
+* B6 Ring Indicator (RI)
+* B7 Receive Line Signal Detect (RLSD)
+*
+* Byte 1: Line Status
+*
+* Offset Description
+* B0 Data Ready (DR)
+* B1 Overrun Error (OE)
+* B2 Parity Error (PE)
+* B3 Framing Error (FE)
+* B4 Break Interrupt (BI)
+* B5 Transmitter Holding Register (THRE)
+* B6 Transmitter Empty (TEMT)
+* B7 Error in RCVR FIFO
+*
+*/
+#define FTDI_RS0_CTS (1 << 4)
+#define FTDI_RS0_DSR (1 << 5)
+#define FTDI_RS0_RI (1 << 6)
+#define FTDI_RS0_RLSD (1 << 7)
+
+#define FTDI_RS_DR 1
+#define FTDI_RS_OE (1<<1)
+#define FTDI_RS_PE (1<<2)
+#define FTDI_RS_FE (1<<3)
+#define FTDI_RS_BI (1<<4)
+#define FTDI_RS_THRE (1<<5)
+#define FTDI_RS_TEMT (1<<6)
+#define FTDI_RS_FIFO (1<<7)
+
+#endif //TUSB_FTDI_SIO_H
diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c
index d95d3ef35..6abe298e5 100644
--- a/src/class/hid/hid_host.c
+++ b/src/class/hid/hid_host.c
@@ -33,6 +33,10 @@
#include "hid_host.h"
+// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message
+#define HIDH_DEBUG 2
+#define TU_LOG_DRV(...) TU_LOG(HIDH_DEBUG, __VA_ARGS__)
+
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
@@ -68,7 +72,7 @@ tu_static hidh_interface_t _hidh_itf[CFG_TUH_HID];
TU_ATTR_ALWAYS_INLINE static inline
hidh_interface_t* get_hid_itf(uint8_t daddr, uint8_t idx)
{
- TU_ASSERT(daddr && idx < CFG_TUH_HID, NULL);
+ TU_ASSERT(daddr > 0 && idx < CFG_TUH_HID, NULL);
hidh_interface_t* p_hid = &_hidh_itf[idx];
return (p_hid->daddr == daddr) ? p_hid : NULL;
}
@@ -207,7 +211,7 @@ static void set_protocol_complete(tuh_xfer_t* xfer)
static bool _hidh_set_protocol(uint8_t daddr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
- TU_LOG2("HID Set Protocol = %d\r\n", protocol);
+ TU_LOG_DRV("HID Set Protocol = %d\r\n", protocol);
tusb_control_request_t const request =
{
@@ -246,7 +250,7 @@ bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol)
static void set_report_complete(tuh_xfer_t* xfer)
{
- TU_LOG2("HID Set Report complete\r\n");
+ TU_LOG_DRV("HID Set Report complete\r\n");
if (tuh_hid_set_report_complete_cb)
{
@@ -266,7 +270,7 @@ bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t r
hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
TU_VERIFY(p_hid);
- TU_LOG2("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len);
+ TU_LOG_DRV("HID Set Report: id = %u, type = %u, len = %u\r\n", report_id, report_type, len);
tusb_control_request_t const request =
{
@@ -298,7 +302,7 @@ bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t r
static bool _hidh_set_idle(uint8_t daddr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
// SET IDLE request, device can stall if not support this request
- TU_LOG2("HID Set Idle \r\n");
+ TU_LOG_DRV("HID Set Idle \r\n");
tusb_control_request_t const request =
{
@@ -367,7 +371,7 @@ bool tuh_hid_send_ready(uint8_t dev_addr, uint8_t idx)
bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const void* report, uint16_t len)
{
- TU_LOG2("HID Send Report %d\r\n", report_id);
+ TU_LOG_DRV("HID Send Report %d\r\n", report_id);
hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
TU_VERIFY(p_hid);
@@ -430,7 +434,7 @@ bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t
if ( dir == TUSB_DIR_IN )
{
- TU_LOG2(" Get Report callback (%u, %u)\r\n", daddr, idx);
+ TU_LOG_DRV(" Get Report callback (%u, %u)\r\n", daddr, idx);
TU_LOG3_MEM(p_hid->epin_buf, xferred_bytes, 2);
tuh_hid_report_received_cb(daddr, idx, p_hid->epin_buf, (uint16_t) xferred_bytes);
}else
@@ -448,8 +452,9 @@ void hidh_close(uint8_t daddr)
hidh_interface_t* p_hid = &_hidh_itf[i];
if (p_hid->daddr == daddr)
{
- if(tuh_hid_umount_cb) tuh_hid_umount_cb(daddr, i);
- p_hid->daddr = 0;
+ TU_LOG_DRV(" HIDh close addr = %u index = %u\r\n", daddr, i);
+ if(tuh_hid_umount_cb) tuh_hid_umount_cb(daddr, i);
+ p_hid->daddr = 0;
}
}
}
@@ -465,7 +470,7 @@ bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *desc_
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass);
- TU_LOG2("[%u] HID opening Interface %u\r\n", daddr, desc_itf->bInterfaceNumber);
+ TU_LOG_DRV("[%u] HID opening Interface %u\r\n", daddr, desc_itf->bInterfaceNumber);
// len = interface + hid + n*endpoints
uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) +
@@ -592,7 +597,7 @@ static void process_set_config(tuh_xfer_t* xfer)
// using usbh enumeration buffer since report descriptor can be very long
if( p_hid->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE )
{
- TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", p_hid->report_desc_len);
+ TU_LOG_DRV("HID Skip Report Descriptor since it is too large %u bytes\r\n", p_hid->report_desc_len);
// Driver is mounted without report descriptor
config_driver_mount_complete(daddr, idx, NULL, 0);
@@ -763,7 +768,7 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr,
for ( uint8_t i = 0; i < report_num; i++ )
{
info = report_info_arr+i;
- TU_LOG2("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage);
+ TU_LOG_DRV("%u: id = %u, usage_page = %u, usage = %u\r\n", i, info->report_id, info->usage_page, info->usage);
}
return report_num;
diff --git a/src/class/midi/midi.h b/src/class/midi/midi.h
index 8b78c6555..8ddcdfda2 100644
--- a/src/class/midi/midi.h
+++ b/src/class/midi/midi.h
@@ -71,8 +71,8 @@ typedef enum
MIDI_CIN_SYSEX_END_1BYTE = 5, // SysEx ends with 1 data, or 1 byte system common message
MIDI_CIN_SYSEX_END_2BYTE = 6, // SysEx ends with 2 data
MIDI_CIN_SYSEX_END_3BYTE = 7, // SysEx ends with 3 data
- MIDI_CIN_NOTE_ON = 8,
- MIDI_CIN_NOTE_OFF = 9,
+ MIDI_CIN_NOTE_OFF = 8,
+ MIDI_CIN_NOTE_ON = 9,
MIDI_CIN_POLY_KEYPRESS = 10,
MIDI_CIN_CONTROL_CHANGE = 11,
MIDI_CIN_PROGRAM_CHANGE = 12,
diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c
index 1b48813ec..138443de4 100644
--- a/src/class/msc/msc_host.c
+++ b/src/class/msc/msc_host.c
@@ -35,7 +35,6 @@
// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message
#define MSCH_DEBUG 2
-
#define TU_LOG_MSCH(...) TU_LOG(MSCH_DEBUG, __VA_ARGS__)
//--------------------------------------------------------------------+
@@ -82,6 +81,7 @@ CFG_TUH_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX];
CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN
static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)];
+// FIXME potential nul reference
TU_ATTR_ALWAYS_INLINE
static inline msch_interface_t* get_itf(uint8_t dev_addr)
{
@@ -305,11 +305,15 @@ void msch_init(void)
void msch_close(uint8_t dev_addr)
{
TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, );
-
msch_interface_t* p_msc = get_itf(dev_addr);
+ TU_VERIFY(p_msc->configured, );
+
+ TU_LOG_MSCH(" MSCh close addr = %d\r\n", dev_addr);
// invoke Application Callback
- if (p_msc->mounted && tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr);
+ if (p_msc->mounted) {
+ if(tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr);
+ }
tu_memclr(p_msc, sizeof(msch_interface_t));
}
diff --git a/src/common/tusb_compiler.h b/src/common/tusb_compiler.h
index 713bbb8d4..5ab56e145 100644
--- a/src/common/tusb_compiler.h
+++ b/src/common/tusb_compiler.h
@@ -138,10 +138,14 @@
#define TU_ATTR_BIT_FIELD_ORDER_BEGIN
#define TU_ATTR_BIT_FIELD_ORDER_END
- #if __has_attribute(__fallthrough__)
- #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough))
- #else
+ #if __GNUC__ < 5
#define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */
+ #else
+ #if __has_attribute(__fallthrough__)
+ #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough))
+ #else
+ #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */
+ #endif
#endif
// Endian conversion use well-known host to network (big endian) naming
@@ -151,8 +155,17 @@
#define TU_BYTE_ORDER TU_BIG_ENDIAN
#endif
- #define TU_BSWAP16(u16) (__builtin_bswap16(u16))
- #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
+ // Unfortunately XC16 doesn't provide builtins for 32bit endian conversion
+ #if defined(__XC16)
+ #define TU_BSWAP16(u16) (__builtin_swap(u16))
+ #define TU_BSWAP32(u32) ((((u32) & 0xff000000) >> 24) | \
+ (((u32) & 0x00ff0000) >> 8) | \
+ (((u32) & 0x0000ff00) << 8) | \
+ (((u32) & 0x000000ff) << 24))
+ #else
+ #define TU_BSWAP16(u16) (__builtin_bswap16(u16))
+ #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
+ #endif
#ifndef __ARMCC_VERSION
// List of obsolete callback function that is renamed and should not be defined.
diff --git a/src/common/tusb_debug.h b/src/common/tusb_debug.h
index 82f682043..36507041f 100644
--- a/src/common/tusb_debug.h
+++ b/src/common/tusb_debug.h
@@ -46,6 +46,7 @@
#if CFG_TUSB_DEBUG >= 2
extern char const* const tu_str_speed[];
extern char const* const tu_str_std_request[];
+extern char const* const tu_str_xfer_result[];
#endif
void tu_print_mem(void const *buf, uint32_t count, uint8_t indent);
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index 95f90f957..48f765674 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -59,14 +59,6 @@
#define TUP_USBIP_OHCI
#define TUP_OHCI_RHPORTS 2
-#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
- // TODO USB0 has 6, USB1 has 4
- #define TUP_USBIP_CHIPIDEA_HS
- #define TUP_USBIP_EHCI
-
- #define TUP_DCD_ENDPOINT_MAX 6
- #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 FS
-
#elif TU_CHECK_MCU(OPT_MCU_LPC51UXX)
#define TUP_DCD_ENDPOINT_MAX 5
@@ -78,12 +70,28 @@
// TODO USB0 has 5, USB1 has 6
#define TUP_DCD_ENDPOINT_MAX 6
+#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
+ // USB0 has 6 with HS PHY, USB1 has 4 only FS
+ #define TUP_USBIP_CHIPIDEA_HS
+ #define TUP_USBIP_EHCI
+
+ #define TUP_DCD_ENDPOINT_MAX 6
+ #define TUP_RHPORT_HIGHSPEED 1
+
+#elif TU_CHECK_MCU(OPT_MCU_MCXN9)
+ // NOTE: MCXN943 port 1 use chipidea HS, port 0 use chipidea FS
+ #define TUP_USBIP_CHIPIDEA_HS
+ #define TUP_USBIP_EHCI
+
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_RHPORT_HIGHSPEED 1
+
#elif TU_CHECK_MCU(OPT_MCU_MIMXRT)
#define TUP_USBIP_CHIPIDEA_HS
#define TUP_USBIP_EHCI
#define TUP_DCD_ENDPOINT_MAX 8
- #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 HS
+ #define TUP_RHPORT_HIGHSPEED 1
#elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32)
#define TUP_USBIP_CHIPIDEA_FS
diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h
index d5541856c..db1ba974d 100644
--- a/src/common/tusb_private.h
+++ b/src/common/tusb_private.h
@@ -148,21 +148,26 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s);
// Must be called in the transfer complete callback
TU_ATTR_ALWAYS_INLINE static inline
-void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes)
-{
+void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) {
tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes);
}
+// Same as tu_edpt_stream_read_xfer_complete but skip the first n bytes
+TU_ATTR_ALWAYS_INLINE static inline
+void tu_edpt_stream_read_xfer_complete_offset(tu_edpt_stream_t* s, uint32_t xferred_bytes, uint32_t skip_offset) {
+ if (skip_offset < xferred_bytes) {
+ tu_fifo_write_n(&s->ff, s->ep_buf + skip_offset, (uint16_t) (xferred_bytes - skip_offset));
+ }
+}
+
// Get the number of bytes available for reading
TU_ATTR_ALWAYS_INLINE static inline
-uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s)
-{
+uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) {
return (uint32_t) tu_fifo_count(&s->ff);
}
TU_ATTR_ALWAYS_INLINE static inline
-bool tu_edpt_stream_peek(tu_edpt_stream_t* s, uint8_t* ch)
-{
+bool tu_edpt_stream_peek(tu_edpt_stream_t* s, uint8_t* ch) {
return tu_fifo_peek(&s->ff, ch);
}
diff --git a/src/device/dcd.h b/src/device/dcd.h
index 00419ff05..f82b8633d 100644
--- a/src/device/dcd.h
+++ b/src/device/dcd.h
@@ -102,6 +102,22 @@ typedef struct TU_ATTR_ALIGNED(4)
//TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct");
+//--------------------------------------------------------------------+
+// Memory API
+//--------------------------------------------------------------------+
+
+// clean/flush data cache: write cache -> memory.
+// Required before an DMA TX transfer to make sure data is in memory
+void dcd_dcache_clean(void* addr, uint32_t data_size) TU_ATTR_WEAK;
+
+// invalidate data cache: mark cache as invalid, next read will read from memory
+// Required BOTH before and after an DMA RX transfer
+void dcd_dcache_invalidate(void* addr, uint32_t data_size) TU_ATTR_WEAK;
+
+// clean and invalidate data cache
+// Required before an DMA transfer where memory is both read/write by DMA
+void dcd_dcache_clean_invalidate(void* addr, uint32_t data_size) TU_ATTR_WEAK;
+
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
diff --git a/src/device/usbd.c b/src/device/usbd.c
index cee56af60..409a5ec10 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -516,9 +516,9 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr)
_usbd_dev.connected = 1;
// mark both in & out control as free
- _usbd_dev.ep_status[0][TUSB_DIR_OUT].busy = false;
+ _usbd_dev.ep_status[0][TUSB_DIR_OUT].busy = 0;
_usbd_dev.ep_status[0][TUSB_DIR_OUT].claimed = 0;
- _usbd_dev.ep_status[0][TUSB_DIR_IN ].busy = false;
+ _usbd_dev.ep_status[0][TUSB_DIR_IN ].busy = 0;
_usbd_dev.ep_status[0][TUSB_DIR_IN ].claimed = 0;
// Process control request
@@ -540,12 +540,13 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr)
TU_LOG(USBD_DBG, "on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len);
- _usbd_dev.ep_status[epnum][ep_dir].busy = false;
+ _usbd_dev.ep_status[epnum][ep_dir].busy = 0;
_usbd_dev.ep_status[epnum][ep_dir].claimed = 0;
if ( 0 == epnum )
{
- usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len);
+ usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete
+ .len);
}
else
{
@@ -553,7 +554,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr)
TU_ASSERT(driver, );
TU_LOG(USBD_DBG, " %s xfer callback\r\n", driver->name);
- driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t)event.xfer_complete.result, event.xfer_complete.len);
+ driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete.len);
}
}
break;
@@ -1244,7 +1245,7 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
// Set busy first since the actual transfer can be complete before dcd_edpt_xfer()
// could return and USBD task can preempt and clear the busy
- _usbd_dev.ep_status[epnum][dir].busy = true;
+ _usbd_dev.ep_status[epnum][dir].busy = 1;
if ( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) )
{
@@ -1252,7 +1253,7 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
}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].busy = 0;
_usbd_dev.ep_status[epnum][dir].claimed = 0;
TU_LOG(USBD_DBG, "FAILED\r\n");
TU_BREAKPOINT();
@@ -1278,7 +1279,7 @@ bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
// Set busy first since the actual transfer can be complete before dcd_edpt_xfer() could return
// and usbd task can preempt and clear the busy
- _usbd_dev.ep_status[epnum][dir].busy = true;
+ _usbd_dev.ep_status[epnum][dir].busy = 1;
if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes))
{
@@ -1287,7 +1288,7 @@ bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
}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].busy = 0;
_usbd_dev.ep_status[epnum][dir].claimed = 0;
TU_LOG(USBD_DBG, "failed\r\n");
TU_BREAKPOINT();
@@ -1317,8 +1318,8 @@ void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
TU_LOG(USBD_DBG, " Stall EP %02X\r\n", ep_addr);
dcd_edpt_stall(rhport, ep_addr);
- _usbd_dev.ep_status[epnum][dir].stalled = true;
- _usbd_dev.ep_status[epnum][dir].busy = true;
+ _usbd_dev.ep_status[epnum][dir].stalled = 1;
+ _usbd_dev.ep_status[epnum][dir].busy = 1;
}
}
@@ -1334,8 +1335,8 @@ void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
{
TU_LOG(USBD_DBG, " Clear Stall EP %02X\r\n", ep_addr);
dcd_edpt_clear_stall(rhport, ep_addr);
- _usbd_dev.ep_status[epnum][dir].stalled = false;
- _usbd_dev.ep_status[epnum][dir].busy = false;
+ _usbd_dev.ep_status[epnum][dir].stalled = 0;
+ _usbd_dev.ep_status[epnum][dir].busy = 0;
}
}
@@ -1366,9 +1367,9 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr)
uint8_t const dir = tu_edpt_dir(ep_addr);
dcd_edpt_close(rhport, ep_addr);
- _usbd_dev.ep_status[epnum][dir].stalled = false;
- _usbd_dev.ep_status[epnum][dir].busy = false;
- _usbd_dev.ep_status[epnum][dir].claimed = false;
+ _usbd_dev.ep_status[epnum][dir].stalled = 0;
+ _usbd_dev.ep_status[epnum][dir].busy = 0;
+ _usbd_dev.ep_status[epnum][dir].claimed = 0;
return;
}
@@ -1403,9 +1404,9 @@ bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep
TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX);
TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed));
- _usbd_dev.ep_status[epnum][dir].stalled = false;
- _usbd_dev.ep_status[epnum][dir].busy = false;
- _usbd_dev.ep_status[epnum][dir].claimed = false;
+ _usbd_dev.ep_status[epnum][dir].stalled = 0;
+ _usbd_dev.ep_status[epnum][dir].busy = 0;
+ _usbd_dev.ep_status[epnum][dir].claimed = 0;
return dcd_edpt_iso_activate(rhport, desc_ep);
}
diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c
index ea8eef285..2afe967b5 100644
--- a/src/device/usbd_control.c
+++ b/src/device/usbd_control.c
@@ -32,7 +32,10 @@
#include "tusb.h"
#include "device/usbd_pvt.h"
-#if CFG_TUSB_DEBUG >= 2
+// Debug level of USBD Control
+#define USBD_CONTROL_DEBUG 2
+
+#if CFG_TUSB_DEBUG >= USBD_CONTROL_DEBUG
extern void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback);
#endif
@@ -188,7 +191,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);
+ TU_LOG_MEM(USBD_CONTROL_DEBUG, _usbd_ctrl_buf, xferred_bytes, 2);
}
_ctrl_xfer.total_xferred += (uint16_t) xferred_bytes;
@@ -205,7 +208,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result
// callback can still stall control in status phase e.g out data does not make sense
if ( _ctrl_xfer.complete_cb )
{
- #if CFG_TUSB_DEBUG >= 2
+ #if CFG_TUSB_DEBUG >= USBD_CONTROL_DEBUG
usbd_driver_print_control_complete_name(_ctrl_xfer.complete_cb);
#endif
diff --git a/src/host/hcd.h b/src/host/hcd.h
index 623c12a12..5a3b0a087 100644
--- a/src/host/hcd.h
+++ b/src/host/hcd.h
@@ -39,8 +39,10 @@
// Configuration
//--------------------------------------------------------------------+
+// Max number of endpoints per device
+// TODO optimize memory usage
#ifndef CFG_TUH_ENDPOINT_MAX
- #define CFG_TUH_ENDPOINT_MAX (CFG_TUH_HUB + CFG_TUH_HID*2 + CFG_TUH_MSC*2 + CFG_TUH_CDC*3)
+ #define CFG_TUH_ENDPOINT_MAX 16
// #ifdef TUP_HCD_ENDPOINT_MAX
// #define CFG_TUH_ENDPPOINT_MAX TUP_HCD_ENDPOINT_MAX
// #else
@@ -102,6 +104,22 @@ typedef struct
uint8_t speed;
} hcd_devtree_info_t;
+//--------------------------------------------------------------------+
+// Memory API
+//--------------------------------------------------------------------+
+
+// clean/flush data cache: write cache -> memory.
+// Required before an DMA TX transfer to make sure data is in memory
+void hcd_dcache_clean(void* addr, uint32_t data_size) TU_ATTR_WEAK;
+
+// invalidate data cache: mark cache as invalid, next read will read from memory
+// Required BOTH before and after an DMA RX transfer
+void hcd_dcache_invalidate(void* addr, uint32_t data_size) TU_ATTR_WEAK;
+
+// clean and invalidate data cache
+// Required before an DMA transfer where memory is both read/write by DMA
+void hcd_dcache_clean_invalidate(void* addr, uint32_t data_size) TU_ATTR_WEAK;
+
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
@@ -157,7 +175,7 @@ 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]);
// clear stall, data toggle is also reset to DATA0
-bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr);
+bool hcd_edpt_clear_stall(uint8_t daddr, uint8_t ep_addr);
//--------------------------------------------------------------------+
// USBH implemented API
@@ -182,6 +200,7 @@ void hcd_event_device_attach(uint8_t rhport, bool in_isr)
event.event_id = HCD_EVENT_DEVICE_ATTACH;
event.connection.hub_addr = 0;
event.connection.hub_port = 0;
+
hcd_event_handler(&event, in_isr);
}
@@ -212,7 +231,6 @@ void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred
event.xfer_complete.result = result;
event.xfer_complete.len = xferred_bytes;
-
hcd_event_handler(&event, in_isr);
}
diff --git a/src/host/hub.c b/src/host/hub.c
index 386ad6aae..182bd6ce8 100644
--- a/src/host/hub.c
+++ b/src/host/hub.c
@@ -33,6 +33,10 @@
#include "usbh_classdriver.h"
#include "hub.h"
+// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message
+#define HUB_DEBUG 2
+#define TU_LOG_DRV(...) TU_LOG(HUB_DEBUG, __VA_ARGS__)
+
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
@@ -218,7 +222,10 @@ void hub_close(uint8_t dev_addr)
TU_VERIFY(dev_addr > CFG_TUH_DEVICE_MAX, );
hub_interface_t* p_hub = get_itf(dev_addr);
- if (p_hub->ep_in) tu_memclr(p_hub, sizeof( hub_interface_t));
+ if (p_hub->ep_in) {
+ TU_LOG_DRV(" HUB close addr = %d\r\n", dev_addr);
+ tu_memclr(p_hub, sizeof( hub_interface_t));
+ }
}
bool hub_edpt_status_xfer(uint8_t dev_addr)
@@ -320,34 +327,35 @@ static void connection_clear_conn_change_complete (tuh_xfer_t* xfer);
static void connection_port_reset_complete (tuh_xfer_t* xfer);
// callback as response of interrupt endpoint polling
-bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
-{
+bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
(void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports
(void) ep_addr;
TU_ASSERT(result == XFER_RESULT_SUCCESS);
hub_interface_t* p_hub = get_itf(dev_addr);
- TU_LOG2(" Hub Status Change = 0x%02X\r\n", p_hub->status_change);
+ uint8_t const status_change = p_hub->status_change;
+ TU_LOG2(" Hub Status Change = 0x%02X\r\n", status_change);
- // Hub bit 0 is for the hub device events
- if (tu_bit_test(p_hub->status_change, 0))
- {
- if (hub_port_get_status(dev_addr, 0, &p_hub->hub_status, hub_get_status_complete, 0) == false)
- {
+ if ( status_change == 0 ) {
+ // The status change event was neither for the hub, nor for any of its ports.
+ // This shouldn't happen, but it does with some devices.
+ // Initiate the next interrupt poll here.
+ return hub_edpt_status_xfer(dev_addr);
+ }
+
+ if (tu_bit_test(status_change, 0)) {
+ // Hub bit 0 is for the hub device events
+ if (hub_port_get_status(dev_addr, 0, &p_hub->hub_status, hub_get_status_complete, 0) == false) {
//Hub status control transfer failed, retry
hub_edpt_status_xfer(dev_addr);
}
}
- else
- {
+ else {
// Hub bits 1 to n are hub port events
- for (uint8_t port=1; port <= p_hub->port_count; port++)
- {
- if ( tu_bit_test(p_hub->status_change, port) )
- {
- if (hub_port_get_status(dev_addr, port, &p_hub->port_status, hub_port_get_status_complete, 0) == false)
- {
+ for (uint8_t port=1; port <= p_hub->port_count; port++) {
+ if ( tu_bit_test(status_change, port) ) {
+ if (hub_port_get_status(dev_addr, port, &p_hub->port_status, hub_port_get_status_complete, 0) == false) {
//Hub status control transfer failed, retry
hub_edpt_status_xfer(dev_addr);
}
@@ -357,7 +365,6 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32
}
// NOTE: next status transfer is queued by usbh.c after handling this request
-
return true;
}
diff --git a/src/host/usbh.c b/src/host/usbh.c
index 3be662c63..7b265c742 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -61,6 +61,8 @@ typedef struct
uint8_t hub_addr;
uint8_t hub_port;
uint8_t speed;
+
+ // enumeration is in progress, done when all interfaces are configured
volatile uint8_t enumerating;
// struct TU_ATTR_PACKED {
@@ -79,10 +81,12 @@ typedef struct {
// Device State
struct TU_ATTR_PACKED {
- volatile uint8_t connected : 1;
- volatile uint8_t addressed : 1;
- volatile uint8_t configured : 1;
- volatile uint8_t suspended : 1;
+ volatile uint8_t connected : 1; // After 1st transfer
+ volatile uint8_t addressed : 1; // After SET_ADDR
+ volatile uint8_t configured : 1; // After SET_CONFIG and all drivers are configured
+ volatile uint8_t suspended : 1; // Bus suspended
+
+ // volatile uint8_t removing : 1; // Physically disconnected, waiting to be processed by usbh
};
// Device Descriptor
@@ -246,7 +250,7 @@ static inline usbh_device_t* get_device(uint8_t dev_addr)
}
static bool enum_new_device(hcd_event_t* event);
-static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
+static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
@@ -286,7 +290,7 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid)
*vid = *pid = 0;
usbh_device_t const* dev = get_device(dev_addr);
- TU_VERIFY(dev && dev->configured);
+ TU_VERIFY(dev && dev->addressed && dev->vid != 0);
*vid = dev->vid;
*pid = dev->pid;
@@ -418,7 +422,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
case HCD_EVENT_DEVICE_REMOVE:
TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
- process_device_unplugged(event.rhport, event.connection.hub_addr, event.connection.hub_port);
+ process_removing_device(event.rhport, event.connection.hub_addr, event.connection.hub_port);
#if CFG_TUH_HUB
// TODO remove
@@ -436,7 +440,8 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const ep_dir = tu_edpt_dir(ep_addr);
- TU_LOG_USBH("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len);
+ TU_LOG_USBH("on EP %02X with %u bytes: %s\r\n", ep_addr, (unsigned int) event.xfer_complete.len,
+ tu_str_xfer_result[event.xfer_complete.result]);
if (event.dev_addr == 0)
{
@@ -447,7 +452,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
else
{
usbh_device_t* dev = get_device(event.dev_addr);
- TU_ASSERT(dev, );
+ TU_VERIFY(dev && dev->connected, );
dev->ep_status[epnum][ep_dir].busy = 0;
dev->ep_status[epnum][ep_dir].claimed = 0;
@@ -571,19 +576,19 @@ bool tuh_control_xfer (tuh_xfer_t* xfer)
TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t*) &_ctrl_xfer.request) );
- while (result == XFER_RESULT_INVALID)
- {
+ while (result == XFER_RESULT_INVALID) {
// Note: this can be called within an callback ie. part of tuh_task()
// therefore event with RTOS tuh_task() still need to be invoked
- if (tuh_task_event_ready())
- {
+ if (tuh_task_event_ready()) {
tuh_task();
}
-
// TODO probably some timeout to prevent hanged
}
- // update transfer result
+ // update transfer result, user_data is expected to point to xfer_result_t
+ if (xfer->user_data != 0) {
+ *((xfer_result_t*) xfer->user_data) = result;
+ }
xfer->result = result;
xfer->actual_len = _ctrl_xfer.actual_len;
}
@@ -736,29 +741,33 @@ void usbh_int_set(bool enabled)
// TODO has some duplication code with device, refactor later
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
{
+ // Note: addr0 only use tuh_control_xfer
usbh_device_t* dev = get_device(dev_addr);
-
- // addr0 only use tuh_control_xfer
- TU_ASSERT(dev);
+ TU_ASSERT(dev && dev->connected);
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
- return tu_edpt_claim(&dev->ep_status[epnum][dir], _usbh_mutex);
+ TU_VERIFY(tu_edpt_claim(&dev->ep_status[epnum][dir], _usbh_mutex));
+ TU_LOG_USBH("[%u] Claimed EP 0x%02x\r\n", dev_addr, ep_addr);
+
+ return true;
}
// TODO has some duplication code with device, refactor later
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
{
+ // Note: addr0 only use tuh_control_xfer
usbh_device_t* dev = get_device(dev_addr);
-
- // addr0 only use tuh_control_xfer
- TU_ASSERT(dev);
+ TU_VERIFY(dev && dev->connected);
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
- return tu_edpt_release(&dev->ep_status[epnum][dir], _usbh_mutex);
+ TU_VERIFY(tu_edpt_release(&dev->ep_status[epnum][dir], _usbh_mutex));
+ TU_LOG_USBH("[%u] Released EP 0x%02x\r\n", dev_addr, ep_addr);
+
+ return true;
}
// TODO has some duplication code with device, refactor later
@@ -866,6 +875,10 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr)
{
switch (event->event_id)
{
+// case HCD_EVENT_DEVICE_REMOVE:
+// // mark device as removing to prevent further xfer before the event is processed in usbh task
+// break;
+
default:
osal_queue_send(_usbh_q, event, in_isr);
break;
@@ -877,7 +890,7 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr)
//--------------------------------------------------------------------+
// generic helper to get a descriptor
-// if blocking, user_data could be pointed to xfer_result
+// if blocking, user_data is pointed to xfer_result
static bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
@@ -905,15 +918,7 @@ static bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t
.user_data = user_data
};
- bool const ret = tuh_control_xfer(&xfer);
-
- // if blocking, user_data could be pointed to xfer_result
- if ( !complete_cb && user_data )
- {
- *((xfer_result_t*) user_data) = xfer.result;
- }
-
- return ret;
+ return tuh_control_xfer(&xfer);
}
bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len,
@@ -971,7 +976,7 @@ bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void*
}
// Get HID report descriptor
-// if blocking, user_data could be pointed to xfer_result
+// if blocking, user_data is pointed to xfer_result
bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
@@ -1000,15 +1005,7 @@ bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_
.user_data = user_data
};
- bool const ret = tuh_control_xfer(&xfer);
-
- // if blocking, user_data could be pointed to xfer_result
- if ( !complete_cb && user_data )
- {
- *((xfer_result_t*) user_data) = xfer.result;
- }
-
- return ret;
+ return tuh_control_xfer(&xfer);
}
bool tuh_configuration_set(uint8_t daddr, uint8_t config_num,
@@ -1040,15 +1037,7 @@ bool tuh_configuration_set(uint8_t daddr, uint8_t config_num,
.user_data = user_data
};
- bool ret = tuh_control_xfer(&xfer);
-
- // if blocking, user_data could be pointed to xfer_result
- if ( !complete_cb && user_data )
- {
- *((xfer_result_t*) user_data) = xfer.result;
- }
-
- return ret;
+ return tuh_control_xfer(&xfer);
}
bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt,
@@ -1080,15 +1069,7 @@ bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt,
.user_data = user_data
};
- bool ret = tuh_control_xfer(&xfer);
-
- // if blocking, user_data could be pointed to xfer_result
- if ( !complete_cb && user_data )
- {
- *((xfer_result_t*) user_data) = xfer.result;
- }
-
- return ret;
+ return tuh_control_xfer(&xfer);
}
//--------------------------------------------------------------------+
@@ -1141,7 +1122,7 @@ uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_i
}
//--------------------------------------------------------------------+
-//
+// Detaching
//--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE
@@ -1150,47 +1131,79 @@ static inline bool is_hub_addr(uint8_t daddr)
return (CFG_TUH_HUB > 0) && (daddr > CFG_TUH_DEVICE_MAX);
}
+//static void mark_removing_device_isr(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) {
+// for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) {
+// usbh_device_t *dev = &_usbh_devices[dev_id];
+// uint8_t const daddr = dev_id + 1;
+//
+// // hub_addr = 0 means roothub, hub_port = 0 means all devices of downstream hub
+// if (dev->rhport == rhport && dev->connected &&
+// (hub_addr == 0 || dev->hub_addr == hub_addr) &&
+// (hub_port == 0 || dev->hub_port == hub_port)) {
+// if (is_hub_addr(daddr)) {
+// // If the device itself is a usb hub, mark all downstream devices.
+// // FIXME recursive calls
+// mark_removing_device_isr(rhport, daddr, 0);
+// }
+//
+// dev->removing = 1;
+// }
+// }
+//}
+
// a device unplugged from rhport:hub_addr:hub_port
-static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port)
+static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port)
{
//------------- find the all devices (star-network) under port that is unplugged -------------//
// TODO mark as disconnected in ISR, also handle dev0
- for ( uint8_t dev_id = 0; dev_id < TU_ARRAY_SIZE(_usbh_devices); dev_id++ )
- {
- usbh_device_t* dev = &_usbh_devices[dev_id];
- uint8_t const dev_addr = dev_id+1;
- // TODO Hub multiple level
- if (dev->rhport == rhport &&
- (hub_addr == 0 || dev->hub_addr == hub_addr) && // hub_addr = 0 means roothub
- (hub_port == 0 || dev->hub_port == hub_port) && // hub_port = 0 means all devices of downstream hub
- dev->connected)
- {
- TU_LOG_USBH(" Address = %u\r\n", dev_addr);
+#if 0
+ // index as hub addr, value is hub port (0xFF for invalid)
+ uint8_t removing_hubs[CFG_TUH_HUB];
+ memset(removing_hubs, TUSB_INDEX_INVALID_8, sizeof(removing_hubs));
- if (is_hub_addr(dev_addr))
- {
- TU_LOG(USBH_DEBUG, "HUB address = %u is unmounted\r\n", dev_addr);
- // If the device itself is a usb hub, unplug downstream devices.
- // FIXME un-roll recursive calls to prevent potential stack overflow
- process_device_unplugged(rhport, dev_addr, 0);
- }else
- {
- // Invoke callback before closing driver
- if (tuh_umount_cb) tuh_umount_cb(dev_addr);
+ removing_hubs[hub_addr-CFG_TUH_DEVICE_MAX] = hub_port;
+
+ // consecutive non-removing hub
+ uint8_t nop_count = 0;
+#endif
+
+ for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) {
+ usbh_device_t *dev = &_usbh_devices[dev_id];
+ uint8_t const daddr = dev_id + 1;
+
+ // hub_addr = 0 means roothub, hub_port = 0 means all devices of downstream hub
+ if (dev->rhport == rhport && dev->connected &&
+ (hub_addr == 0 || dev->hub_addr == hub_addr) &&
+ (hub_port == 0 || dev->hub_port == hub_port)) {
+ TU_LOG_USBH("Device unplugged address = %u\r\n", daddr);
+
+ if (is_hub_addr(daddr)) {
+ TU_LOG(USBH_DEBUG, " is a HUB device\r\n", daddr);
+
+ // Submit removed event If the device itself is a hub (un-rolled recursive)
+ // TODO a better to unroll recursrive is using array of removing_hubs and mark it here
+ hcd_event_t event;
+ event.rhport = rhport;
+ event.event_id = HCD_EVENT_DEVICE_REMOVE;
+ event.connection.hub_addr = daddr;
+ event.connection.hub_port = 0;
+
+ hcd_event_handler(&event, false);
+ } else {
+ // Invoke callback before closing driver (maybe call it later ?)
+ if (tuh_umount_cb) tuh_umount_cb(daddr);
}
// Close class driver
- for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
- {
- TU_LOG_USBH("%s close\r\n", usbh_class_drivers[drv_id].name);
- usbh_class_drivers[drv_id].close(dev_addr);
+ for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++) {
+ usbh_class_drivers[drv_id].close(daddr);
}
- hcd_device_close(rhport, dev_addr);
+ hcd_device_close(rhport, daddr);
clear_device(dev);
// abort on-going control xfer if any
- if (_ctrl_xfer.daddr == dev_addr) _set_control_xfer_stage(CONTROL_STAGE_IDLE);
+ if (_ctrl_xfer.daddr == daddr) _set_control_xfer_stage(CONTROL_STAGE_IDLE);
}
}
}
@@ -1242,6 +1255,7 @@ static void process_enumeration(tuh_xfer_t* xfer)
{
failed_count++;
osal_task_delay(ATTEMPT_DELAY_MS); // delay a bit
+ TU_LOG1("Enumeration attempt %u\r\n", failed_count);
TU_ASSERT(tuh_control_xfer(xfer), );
}else
{
@@ -1481,6 +1495,7 @@ static uint8_t get_new_address(bool is_hub)
{
uint8_t start;
uint8_t end;
+
if ( is_hub )
{
start = CFG_TUH_DEVICE_MAX;
@@ -1491,7 +1506,7 @@ static uint8_t get_new_address(bool is_hub)
end = start + CFG_TUH_DEVICE_MAX;
}
- for ( uint8_t idx = start; idx < end; idx++)
+ for (uint8_t idx = start; idx < end; idx++)
{
if (!_usbh_devices[idx].connected) return (idx+1);
}
diff --git a/src/portable/chipidea/ci_hs/ci_hs_imxrt.h b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
index 2de0d9cb4..ceff893bd 100644
--- a/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
+++ b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
@@ -37,22 +37,53 @@
#define USB2_BASE USB_OTG2_BASE
#endif
+// RT1040 calls its only USB USB_OTG (no 1)
+#if defined(MIMXRT1042_SERIES)
+#define USB_OTG1_IRQn USB_OTG_IRQn
+#endif
+
static const ci_hs_controller_t _ci_controller[] =
{
// RT1010 and RT1020 only has 1 USB controller
#if FSL_FEATURE_SOC_USBHS_COUNT == 1
- { .reg_base = USB_BASE , .irqnum = USB_OTG1_IRQn, .ep_count = 8 }
+ { .reg_base = USB_BASE , .irqnum = USB_OTG1_IRQn }
#else
- { .reg_base = USB1_BASE, .irqnum = USB_OTG1_IRQn, .ep_count = 8 },
- { .reg_base = USB2_BASE, .irqnum = USB_OTG2_IRQn, .ep_count = 8 }
+ { .reg_base = USB1_BASE, .irqnum = USB_OTG1_IRQn},
+ { .reg_base = USB2_BASE, .irqnum = USB_OTG2_IRQn}
#endif
};
+#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
+
+//------------- DCD -------------//
#define CI_DCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
#define CI_DCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+//------------- HCD -------------//
#define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
#define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+//------------- DCache -------------//
+TU_ATTR_ALWAYS_INLINE static inline bool imxrt_is_cache_mem(uint32_t addr) {
+ return !(0x20000000 <= addr && addr < 0x20100000);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void imxrt_dcache_clean(void* addr, uint32_t data_size) {
+ if (imxrt_is_cache_mem((uint32_t) addr)) {
+ SCB_CleanDCache_by_Addr((uint32_t *) addr, (int32_t) data_size);
+ }
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void imxrt_dcache_invalidate(void* addr, uint32_t data_size) {
+ if (imxrt_is_cache_mem((uint32_t) addr)) {
+ SCB_InvalidateDCache_by_Addr(addr, (int32_t) data_size);
+ }
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void imxrt_dcache_clean_invalidate(void* addr, uint32_t data_size) {
+ if (imxrt_is_cache_mem((uint32_t) addr)) {
+ SCB_CleanInvalidateDCache_by_Addr(addr, (int32_t) data_size);
+ }
+}
#endif
diff --git a/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h b/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h
index 8c2e7dfa6..2e84c93e7 100644
--- a/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h
+++ b/src/portable/chipidea/ci_hs/ci_hs_lpc18_43.h
@@ -32,10 +32,12 @@
static const ci_hs_controller_t _ci_controller[] =
{
- { .reg_base = LPC_USB0_BASE, .irqnum = USB0_IRQn, .ep_count = 6 },
- { .reg_base = LPC_USB1_BASE, .irqnum = USB1_IRQn, .ep_count = 4 }
+ { .reg_base = LPC_USB0_BASE, .irqnum = USB0_IRQn },
+ { .reg_base = LPC_USB1_BASE, .irqnum = USB1_IRQn }
};
+#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
+
#define CI_DCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
#define CI_DCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
diff --git a/src/portable/chipidea/ci_hs/ci_hs_mcx.h b/src/portable/chipidea/ci_hs/ci_hs_mcx.h
new file mode 100644
index 000000000..f940f4a9d
--- /dev/null
+++ b/src/portable/chipidea/ci_hs/ci_hs_mcx.h
@@ -0,0 +1,52 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _CI_HS_MCX_H_
+#define _CI_HS_MCX_H_
+
+#include "fsl_device_registers.h"
+
+// NOTE: MCX N9 has 2 different USB Controller
+// - USB0 is KHCI FullSpeed
+// - USB1 is ChipIdea HighSpeed, therefore rhport = 1 is actually index 0
+
+static const ci_hs_controller_t _ci_controller[] = {
+ {.reg_base = USBHS1__USBC_BASE, .irqnum = USB1_HS_IRQn}
+};
+
+TU_ATTR_ALWAYS_INLINE static inline ci_hs_regs_t* CI_HS_REG(uint8_t port) {
+ (void) port;
+ return ((ci_hs_regs_t*) _ci_controller[0].reg_base);
+}
+
+#define CI_DCD_INT_ENABLE(_p) do { (void) _p; NVIC_EnableIRQ (_ci_controller[0].irqnum); } while (0)
+#define CI_DCD_INT_DISABLE(_p) do { (void) _p; NVIC_DisableIRQ(_ci_controller[0].irqnum); } while (0)
+
+#define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
+#define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
+
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/ci_hs_type.h b/src/portable/chipidea/ci_hs/ci_hs_type.h
index 31b5a012d..2f3aa3694 100644
--- a/src/portable/chipidea/ci_hs/ci_hs_type.h
+++ b/src/portable/chipidea/ci_hs/ci_hs_type.h
@@ -31,13 +31,21 @@
extern "C" {
#endif
+// DCCPARAMS
+enum {
+ DCCPARAMS_DEN_MASK = 0x1Fu, ///< DEN bit 4:0
+};
+
// USBCMD
enum {
USBCMD_RUN_STOP = TU_BIT(0),
USBCMD_RESET = TU_BIT(1),
USBCMD_SETUP_TRIPWIRE = TU_BIT(13),
- USBCMD_ADD_QTD_TRIPWIRE = TU_BIT(14) ///< This bit is used as a semaphore to ensure the to proper addition of a new dTD to an active (primed) endpoint’s linked list. This bit is set and cleared by software during the process of adding a new dTD
-// Interrupt Threshold bit 23:16
+ USBCMD_ADD_QTD_TRIPWIRE = TU_BIT(14), // This bit is used as a semaphore to ensure the to proper addition of a
+ // new dTD to an active (primed) endpoint’s linked list. This bit is set and
+ // cleared by software during the process of adding a new dTD
+
+ USBCMD_INTR_THRESHOLD_MASK = 0x00FF0000u, // Interrupt Threshold bit 23:16
};
// PORTSC1
@@ -72,6 +80,7 @@ enum {
// USBMode
enum {
+ USBMOD_CM_MASK = TU_BIT(0) | TU_BIT(1),
USBMODE_CM_DEVICE = 2,
USBMODE_CM_HOST = 3,
@@ -134,7 +143,6 @@ typedef struct
{
uint32_t reg_base;
uint32_t irqnum;
- uint8_t ep_count; // Max bi-directional Endpoints
}ci_hs_controller_t;
#ifdef __cplusplus
diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
index bc6736cf2..850c82e43 100644
--- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c
+++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
@@ -28,35 +28,53 @@
#if CFG_TUD_ENABLED && defined(TUP_USBIP_CHIPIDEA_HS)
-//--------------------------------------------------------------------+
-// INCLUDE
-//--------------------------------------------------------------------+
#include "device/dcd.h"
#include "ci_hs_type.h"
#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
#include "ci_hs_imxrt.h"
-#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
+
+ void dcd_dcache_clean(void* addr, uint32_t data_size) {
+ imxrt_dcache_clean(addr, data_size);
+ }
+
+ void dcd_dcache_invalidate(void* addr, uint32_t data_size) {
+ imxrt_dcache_invalidate(addr, data_size);
+ }
+
+ void dcd_dcache_clean_invalidate(void* addr, uint32_t data_size) {
+ imxrt_dcache_clean_invalidate(addr, data_size);
+ }
+
+#else
+
+#if TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
#include "ci_hs_lpc18_43.h"
+
+#elif TU_CHECK_MCU(OPT_MCU_MCXN9)
+ // MCX N9 only port 1 use this controller
+ #include "ci_hs_mcx.h"
#else
#error "Unsupported MCUs"
#endif
+ TU_ATTR_WEAK void dcd_dcache_clean(void* addr, uint32_t data_size) {
+ (void) addr; (void) data_size;
+ }
+
+ TU_ATTR_WEAK void dcd_dcache_invalidate(void* addr, uint32_t data_size) {
+ (void) addr; (void) data_size;
+ }
+
+ TU_ATTR_WEAK void dcd_dcache_clean_invalidate(void* addr, uint32_t data_size) {
+ (void) addr; (void) data_size;
+ }
+#endif
+
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
-#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
-
-// Clean means to push any cached changes to RAM and invalidate "removes" the
-// entry from the cache.
-#if defined(__CORTEX_M) && __CORTEX_M == 7 && __DCACHE_PRESENT == 1
- #define CleanInvalidateDCache_by_Addr SCB_CleanInvalidateDCache_by_Addr
-#else
- #define CleanInvalidateDCache_by_Addr(_addr, _dsize)
-#endif
-
-
// ENDPTCTRL
enum {
ENDPTCTRL_STALL = TU_BIT(0),
@@ -160,6 +178,16 @@ typedef struct {
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(2048)
static dcd_data_t _dcd_data;
+//--------------------------------------------------------------------+
+// Prototypes and Helper Functions
+//--------------------------------------------------------------------+
+
+TU_ATTR_ALWAYS_INLINE
+static inline uint8_t ci_ep_count(ci_hs_regs_t const* dcd_reg)
+{
+ return dcd_reg->DCCPARAMS & DCCPARAMS_DEN_MASK;
+}
+
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
@@ -174,7 +202,8 @@ static void bus_reset(uint8_t rhport)
// endpoint type of the unused direction must be changed from the control type to any other
// type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior
// for the data PID tracking on the active endpoint.
- for( uint8_t i=1; i < _ci_controller[rhport].ep_count; i++)
+ uint8_t const ep_count = ci_ep_count(dcd_reg);
+ for( uint8_t i=1; i < ep_count; i++)
{
dcd_reg->ENDPTCTRL[i] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS));
}
@@ -202,7 +231,7 @@ static void bus_reset(uint8_t rhport)
_dcd_data.qhd[0][0].int_on_setup = 1; // OUT only
- CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
+ dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
}
void dcd_init(uint8_t rhport)
@@ -211,26 +240,34 @@ void dcd_init(uint8_t rhport)
ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ TU_ASSERT(ci_ep_count(dcd_reg) <= TUP_DCD_ENDPOINT_MAX, );
+
// Reset controller
dcd_reg->USBCMD |= USBCMD_RESET;
while( dcd_reg->USBCMD & USBCMD_RESET ) {}
// Set mode to device, must be set immediately after reset
- dcd_reg->USBMODE = USBMODE_CM_DEVICE;
+ uint32_t usbmode = dcd_reg->USBMODE & ~USBMOD_CM_MASK;
+ usbmode |= USBMODE_CM_DEVICE;
+ dcd_reg->USBMODE = usbmode;
+
dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION;
#if !TUD_OPT_HIGH_SPEED
dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED;
#endif
- CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
+ dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
dcd_reg->ENDPTLISTADDR = (uint32_t) _dcd_data.qhd; // Endpoint List Address has to be 2K alignment
dcd_reg->USBSTS = dcd_reg->USBSTS;
dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_SUSPEND;
- dcd_reg->USBCMD &= ~0x00FF0000; // Interrupt Threshold Interval = 0
- dcd_reg->USBCMD |= USBCMD_RUN_STOP; // Connect
+ uint32_t usbcmd = dcd_reg->USBCMD;
+ usbcmd &= ~USBCMD_INTR_THRESHOLD_MASK; // Interrupt Threshold Interval = 0
+ usbcmd |= USBCMD_RUN_STOP; // run
+
+ dcd_reg->USBCMD = usbcmd;
}
void dcd_int_enable(uint8_t rhport)
@@ -286,7 +323,7 @@ static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes)
{
// Force the CPU to flush the buffer. We increase the size by 31 because the call aligns the
// address to 32-byte boundaries. Buffer must be word aligned
- CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) data_ptr, 4), total_bytes + 31);
+ dcd_dcache_clean_invalidate((uint32_t*) tu_align((uint32_t) data_ptr, 4), total_bytes + 31);
tu_memclr(p_qtd, sizeof(dcd_qtd_t));
@@ -343,8 +380,10 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+
// Must not exceed max endpoint number
- TU_ASSERT( epnum < _ci_controller[rhport].ep_count );
+ TU_ASSERT(epnum < ci_ep_count(dcd_reg));
//------------- Prepare Queue Head -------------//
dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
@@ -359,11 +398,9 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
p_qhd->qtd_overlay.next = QTD_NEXT_INVALID;
- CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
+ dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
// Enable EP Control
- ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
-
uint32_t const epctrl = (p_endpoint_desc->bmAttributes.xfer << ENDPTCTRL_TYPE_POS) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET;
if ( dir == TUSB_DIR_OUT )
@@ -382,7 +419,8 @@ void dcd_edpt_close_all (uint8_t rhport)
ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
// Disable all non-control endpoints
- for( uint8_t epnum=1; epnum < _ci_controller[rhport].ep_count; epnum++)
+ uint8_t const ep_count = ci_ep_count(dcd_reg);
+ for (uint8_t epnum = 1; epnum < ep_count; epnum++)
{
_dcd_data.qhd[epnum][TUSB_DIR_OUT].qtd_overlay.halted = 1;
_dcd_data.qhd[epnum][TUSB_DIR_IN ].qtd_overlay.halted = 1;
@@ -420,7 +458,7 @@ static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir)
p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd
// flush cache
- CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
+ dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
if ( epnum == 0 )
{
@@ -498,7 +536,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
}
}
- CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), total_bytes - fifo_info.len_wrap + 31);
+ dcd_dcache_clean_invalidate((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), total_bytes - fifo_info.len_wrap + 31);
}
else
{
@@ -611,20 +649,11 @@ void dcd_int_handler(uint8_t rhport)
if (int_status & INTR_USB)
{
// Make sure we read the latest version of _dcd_data.
- CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
+ dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
uint32_t const edpt_complete = dcd_reg->ENDPTCOMPLETE;
dcd_reg->ENDPTCOMPLETE = edpt_complete; // acknowledge
- if (dcd_reg->ENDPTSETUPSTAT)
- {
- //------------- Set up Received -------------//
- // 23.10.10.2 Operational model for setup transfers
- dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;
-
- dcd_event_setup_received(rhport, (uint8_t*)(uintptr_t) &_dcd_data.qhd[0][0].setup_request, true);
- }
-
// 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set
// nothing to do, we will submit xfer as error to usbd
// if (int_status & INTR_ERROR) { }
@@ -637,6 +666,15 @@ void dcd_int_handler(uint8_t rhport)
if ( tu_bit_test(edpt_complete, epnum+16) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_IN);
}
}
+
+ // Set up Received
+ // 23.10.10.2 Operational model for setup transfers
+ // Must be after normal transfer complete since it is possible to have both previous control status + new setup
+ // in the same frame and we should handle previous status first.
+ if (dcd_reg->ENDPTSETUPSTAT) {
+ dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;
+ dcd_event_setup_received(rhport, (uint8_t *) (uintptr_t) &_dcd_data.qhd[0][0].setup_request, true);
+ }
}
if (int_status & INTR_SOF)
diff --git a/src/portable/chipidea/ci_hs/hcd_ci_hs.c b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
index d607627b4..8c27abbf6 100644
--- a/src/portable/chipidea/ci_hs/hcd_ci_hs.c
+++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
@@ -41,6 +41,19 @@
#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
#include "ci_hs_imxrt.h"
+
+ void hcd_dcache_clean(void* addr, uint32_t data_size) {
+ imxrt_dcache_clean(addr, data_size);
+ }
+
+ void hcd_dcache_invalidate(void* addr, uint32_t data_size) {
+ imxrt_dcache_invalidate(addr, data_size);
+ }
+
+ void hcd_dcache_clean_invalidate(void* addr, uint32_t data_size) {
+ imxrt_dcache_clean_invalidate(addr, data_size);
+ }
+
#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
#include "ci_hs_lpc18_43.h"
#else
@@ -51,8 +64,6 @@
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
-#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
-
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
@@ -76,6 +87,8 @@ bool hcd_init(uint8_t rhport)
#endif
// FIXME force full speed, still have issue with Highspeed enumeration
+ // 1. Have issue when plug/unplug devices, maybe the port is not reset properly
+ // 2. Also does not seems to detect disconnection
hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
return ehci_init(rhport, (uint32_t) &hcd_reg->CAPLENGTH, (uint32_t) &hcd_reg->USBCMD);
diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c
index 9951aa5da..2b25eee9d 100644
--- a/src/portable/ehci/ehci.c
+++ b/src/portable/ehci/ehci.c
@@ -58,7 +58,8 @@
#define FRAMELIST_SIZE (1024 >> FRAMELIST_SIZE_BIT_VALUE)
-#define QHD_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX)
+// Total queue head pool. TODO should be user configurable and more optimize memory usage in the future
+#define QHD_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX + CFG_TUH_HUB)
#define QTD_MAX QHD_MAX
typedef struct
@@ -79,7 +80,8 @@ typedef struct
ehci_qhd_t qhd_pool[QHD_MAX];
ehci_qtd_t qtd_pool[QTD_MAX] TU_ATTR_ALIGNED(32);
- ehci_registers_t* regs;
+ ehci_registers_t* regs; // operational register
+ ehci_cap_registers_t* cap_regs; // capability register
volatile uint32_t uframe_number;
}ehci_data_t;
@@ -87,6 +89,40 @@ typedef struct
// Periodic frame list must be 4K alignment
CFG_TUH_MEM_SECTION TU_ATTR_ALIGNED(4096) static ehci_data_t ehci_data;
+//--------------------------------------------------------------------+
+// Debug
+//--------------------------------------------------------------------+
+#if CFG_TUSB_DEBUG >= (EHCI_DBG + 1)
+static inline void print_portsc(ehci_registers_t* regs) {
+ TU_LOG_HEX(EHCI_DBG, regs->portsc);
+ TU_LOG(EHCI_DBG, " Connect Status : %u\r\n", regs->portsc_bm.current_connect_status);
+ TU_LOG(EHCI_DBG, " Connect Change : %u\r\n", regs->portsc_bm.connect_status_change);
+ TU_LOG(EHCI_DBG, " Enabled : %u\r\n", regs->portsc_bm.port_enabled);
+ TU_LOG(EHCI_DBG, " Enabled Change : %u\r\n", regs->portsc_bm.port_enable_change);
+
+ TU_LOG(EHCI_DBG, " OverCurr Change: %u\r\n", regs->portsc_bm.over_current_change);
+ TU_LOG(EHCI_DBG, " Force Resume : %u\r\n", regs->portsc_bm.force_port_resume);
+ TU_LOG(EHCI_DBG, " Suspend : %u\r\n", regs->portsc_bm.suspend);
+ TU_LOG(EHCI_DBG, " Reset : %u\r\n", regs->portsc_bm.port_reset);
+ TU_LOG(EHCI_DBG, " Power : %u\r\n", regs->portsc_bm.port_power);
+}
+
+static inline void print_intr(uint32_t intr) {
+ TU_LOG_HEX(EHCI_DBG, intr);
+ TU_LOG(EHCI_DBG, " USB Interrupt : %u\r\n", (intr & EHCI_INT_MASK_USB) ? 1 : 0);
+ TU_LOG(EHCI_DBG, " USB Error : %u\r\n", (intr & EHCI_INT_MASK_ERROR) ? 1 : 0);
+ TU_LOG(EHCI_DBG, " Port Change Detect : %u\r\n", (intr & EHCI_INT_MASK_PORT_CHANGE) ? 1 : 0);
+ TU_LOG(EHCI_DBG, " Frame List Rollover: %u\r\n", (intr & EHCI_INT_MASK_FRAMELIST_ROLLOVER) ? 1 : 0);
+ TU_LOG(EHCI_DBG, " Host System Error : %u\r\n", (intr & EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR) ? 1 : 0);
+ TU_LOG(EHCI_DBG, " Async Advance : %u\r\n", (intr & EHCI_INT_MASK_ASYNC_ADVANCE) ? 1 : 0);
+// TU_LOG(EHCI_DBG, " Interrupt on Async: %u\r\n", (intr & EHCI_INT_MASK_NXP_ASYNC));
+// TU_LOG(EHCI_DBG, " Periodic Schedule : %u\r\n", (intr & EHCI_INT_MASK_NXP_PERIODIC));
+}
+
+#else
+#define print_portsc(_reg)
+#endif
+
//--------------------------------------------------------------------+
// PROTOTYPE
//--------------------------------------------------------------------+
@@ -117,24 +153,26 @@ static inline ehci_qtd_t* qtd_control(uint8_t dev_addr)
static inline ehci_qhd_t* qhd_next (ehci_qhd_t const * p_qhd);
static inline ehci_qhd_t* qhd_find_free (void);
static inline ehci_qhd_t* qhd_get_from_addr (uint8_t dev_addr, uint8_t ep_addr);
-
-// determine if a queue head has bus-related error
-static inline bool qhd_has_xact_error (ehci_qhd_t * p_qhd)
-{
- return (p_qhd->qtd_overlay.buffer_err || p_qhd->qtd_overlay.babble_err || p_qhd->qtd_overlay.xact_err);
- //p_qhd->qtd_overlay.non_hs_period_missed_uframe || p_qhd->qtd_overlay.pingstate_err TODO split transaction error
-}
-
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
+static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd);
static inline ehci_qtd_t* qtd_find_free (void);
-static inline ehci_qtd_t* qtd_next (ehci_qtd_t const * p_qtd);
-static inline void qtd_insert_to_qhd (ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new);
-static inline void qtd_remove_1st_from_qhd (ehci_qhd_t *p_qhd);
-static void qtd_init (ehci_qtd_t* p_qtd, void const* buffer, uint16_t total_bytes);
+static void qtd_init (ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes);
static inline void list_insert (ehci_link_t *current, ehci_link_t *new, uint8_t new_type);
-static inline ehci_link_t* list_next (ehci_link_t *p_link_pointer);
+static inline ehci_link_t* list_next (ehci_link_t const *p_link);
+
+TU_ATTR_WEAK void hcd_dcache_clean(void* addr, uint32_t data_size) {
+ (void) addr; (void) data_size;
+}
+
+TU_ATTR_WEAK void hcd_dcache_invalidate(void* addr, uint32_t data_size) {
+ (void) addr; (void) data_size;
+}
+
+TU_ATTR_WEAK void hcd_dcache_clean_invalidate(void* addr, uint32_t data_size) {
+ (void) addr; (void) data_size;
+}
//--------------------------------------------------------------------+
// HCD API
@@ -152,11 +190,11 @@ void hcd_port_reset(uint8_t rhport)
ehci_registers_t* regs = ehci_data.regs;
-// regs->portsc_bm.port_enabled = 0; // disable port before reset
-// regs->portsc_bm.port_reset = 1;
-
- uint32_t portsc = regs->portsc;
+ // mask out Write-1-to-Clear bits
+ uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_W1C;
+ // EHCI Table 2-16 PortSC
+ // when software writes Port Reset bit to a one, it must also write a zero to the Port Enable bit.
portsc &= ~(EHCI_PORTSC_MASK_PORT_EANBLED);
portsc |= EHCI_PORTSC_MASK_PORT_RESET;
@@ -167,9 +205,14 @@ void hcd_port_reset_end(uint8_t rhport)
{
(void) rhport;
-#if 0
+#if 0 // TODO check if this is necessary
ehci_registers_t* regs = ehci_data.regs;
- regs->portsc_bm.port_reset = 0;
+
+ // mask out all change bits since they are Write 1 to clear
+ uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_CHANGE_ALL;
+ portsc &= ~(EHCI_PORTSC_MASK_PORT_RESET);
+
+ regs->portsc = portsc;
#endif
}
@@ -185,24 +228,22 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport)
return (tusb_speed_t) ehci_data.regs->portsc_bm.nxp_port_speed; // NXP specific port speed
}
-static void list_remove_qhd_by_addr(ehci_link_t* list_head, uint8_t dev_addr)
-{
- for(ehci_link_t* prev = list_head;
- !prev->terminate && (tu_align32(prev->address) != (uint32_t) list_head) && prev != NULL;
- prev = list_next(prev) )
- {
- // TODO check type for ISO iTD and siTD
- // TODO Suppress cast-align warning
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wcast-align"
- ehci_qhd_t* qhd = (ehci_qhd_t*) list_next(prev);
- #pragma GCC diagnostic pop
- if ( qhd->dev_addr == dev_addr )
- {
+static void list_remove_qhd_by_daddr(ehci_link_t* list_head, uint8_t dev_addr) {
+ ehci_link_t* prev = list_head;
+
+ while (prev && !prev->terminate) {
+ ehci_qhd_t* qhd = (ehci_qhd_t*) (uintptr_t) list_next(prev);
+
+ // done if loop back to head
+ if ( (uintptr_t) qhd == (uintptr_t) list_head) {
+ break;
+ }
+
+ if ( qhd->dev_addr == dev_addr ) {
// TODO deactivate all TD, wait for QHD to inactive before removal
prev->address = qhd->next.address;
- // EHCI 4.8.2 link the removed qhd to async head (which always reachable by Host Controller)
+ // EHCI 4.8.2 link the removed qhd's next to async head (which always reachable by Host Controller)
qhd->next.address = ((uint32_t) list_head) | (EHCI_QTYPE_QHD << 1);
if ( qhd->int_smask )
@@ -215,44 +256,91 @@ static void list_remove_qhd_by_addr(ehci_link_t* list_head, uint8_t dev_addr)
// mark as removing, will completely re-usable when async advance isr occurs
qhd->removing = 1;
}
+
+ hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
+ hcd_dcache_clean(prev, sizeof(ehci_qhd_t));
+ }else {
+ prev = list_next(prev);
}
}
}
// Close all opened endpoint belong to this device
-void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
+void hcd_device_close(uint8_t rhport, uint8_t daddr)
{
// skip dev0
- if (dev_addr == 0) return;
+ if (daddr == 0) {
+ return;
+ }
// Remove from async list
- list_remove_qhd_by_addr( (ehci_link_t*) qhd_async_head(rhport), dev_addr );
+ list_remove_qhd_by_daddr((ehci_link_t *) qhd_async_head(rhport), daddr);
// Remove from all interval period list
- for(uint8_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++)
- {
- list_remove_qhd_by_addr( (ehci_link_t*) &ehci_data.period_head_arr[i], dev_addr);
+ for(uint8_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++) {
+ list_remove_qhd_by_daddr((ehci_link_t *) &ehci_data.period_head_arr[i], daddr);
}
// Async doorbell (EHCI 4.8.2 for operational details)
ehci_data.regs->command_bm.async_adv_doorbell = 1;
}
+static void init_periodic_list(uint8_t rhport) {
+ // Build the polling interval tree with 1 ms, 2 ms, 4 ms and 8 ms (framesize) only
+ for ( uint32_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++ ) {
+ ehci_data.period_head_arr[i].int_smask = 1; // queue head in period list must have smask non-zero
+ ehci_data.period_head_arr[i].qtd_overlay.halted = 1; // dummy node, always inactive
+ }
+
+ ehci_link_t * const framelist = ehci_data.period_framelist;
+ ehci_link_t * const period_1ms = get_period_head(rhport, 1u);
+
+ // all links --> period_head_arr[0] (1ms)
+ // 0, 2, 4, 6 etc --> period_head_arr[1] (2ms)
+ // 1, 5 --> period_head_arr[2] (4ms)
+ // 3 --> period_head_arr[3] (8ms)
+
+ // TODO EHCI_FRAMELIST_SIZE with other size than 8
+ for (uint32_t i = 0; i < FRAMELIST_SIZE; i++) {
+ framelist[i].address = (uint32_t) period_1ms;
+ framelist[i].type = EHCI_QTYPE_QHD;
+ }
+
+ for (uint32_t i = 0; i < FRAMELIST_SIZE; i += 2) {
+ list_insert(framelist + i, get_period_head(rhport, 2u), EHCI_QTYPE_QHD);
+ }
+
+ for (uint32_t i = 1; i < FRAMELIST_SIZE; i += 4) {
+ list_insert(framelist + i, get_period_head(rhport, 4u), EHCI_QTYPE_QHD);
+ }
+
+ list_insert(framelist + 3, get_period_head(rhport, 8u), EHCI_QTYPE_QHD);
+
+ period_1ms->terminate = 1;
+}
+
bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
{
- (void) capability_reg; // not used yet
-
tu_memclr(&ehci_data, sizeof(ehci_data_t));
- ehci_data.regs = (ehci_registers_t* ) operatial_reg;
+ ehci_data.regs = (ehci_registers_t*) operatial_reg;
+ ehci_data.cap_regs = (ehci_cap_registers_t*) capability_reg;
ehci_registers_t* regs = ehci_data.regs;
- //------------- CTRLDSSEGMENT Register (skip) -------------//
- //------------- USB INT Register -------------//
- regs->inten = 0; // 1. disable all the interrupt
- regs->status = EHCI_INT_MASK_ALL; // 2. clear all status
+ // EHCI 4.1 Host Controller Initialization
+ //------------- CTRLDSSEGMENT Register (skip) -------------//
+
+ //------------- USB INT Register -------------//
+
+ // disable all the interrupt
+ regs->inten = 0;
+
+ // clear all status except port change since device maybe connected before this driver is initialized
+ regs->status = (EHCI_INT_MASK_ALL & ~EHCI_INT_MASK_PORT_CHANGE);
+
+ // Enable interrupts
regs->inten = EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE | EHCI_INT_MASK_ASYNC_ADVANCE |
EHCI_INT_MASK_NXP_PERIODIC | EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_FRAMELIST_ROLLOVER;
@@ -269,43 +357,10 @@ bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
regs->async_list_addr = (uint32_t) async_head;
//------------- Periodic List -------------//
- // Build the polling interval tree with 1 ms, 2 ms, 4 ms and 8 ms (framesize) only
- for ( uint32_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++ )
- {
- ehci_data.period_head_arr[i].int_smask = 1; // queue head in period list must have smask non-zero
- ehci_data.period_head_arr[i].qtd_overlay.halted = 1; // dummy node, always inactive
- }
+ init_periodic_list(rhport);
+ regs->periodic_list_base = (uint32_t) ehci_data.period_framelist;
- ehci_link_t * const framelist = ehci_data.period_framelist;
- ehci_link_t * const period_1ms = get_period_head(rhport, 1u);
-
- // all links --> period_head_arr[0] (1ms)
- // 0, 2, 4, 6 etc --> period_head_arr[1] (2ms)
- // 1, 5 --> period_head_arr[2] (4ms)
- // 3 --> period_head_arr[3] (8ms)
-
- // TODO EHCI_FRAMELIST_SIZE with other size than 8
- for(uint32_t i=0; iterminate = 1;
-
- regs->periodic_list_base = (uint32_t) framelist;
+ hcd_dcache_clean(&ehci_data, sizeof(ehci_data_t));
//------------- TT Control (NXP only) -------------//
regs->nxp_tt_control = 0;
@@ -316,7 +371,16 @@ bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
FRAMELIST_SIZE_USBCMD_VALUE;
//------------- ConfigFlag Register (skip) -------------//
- regs->portsc_bm.port_power = 1; // enable port power
+
+ // enable port power bit in portsc. The function of this bit depends on the value of the Port
+ // Power Control (PPC) field in the HCSPARAMS register.
+ if (ehci_data.cap_regs->hcsparams_bm.port_power_control) {
+ // mask out all change bits since they are Write 1 to clear
+ uint32_t portsc = (regs->portsc & ~EHCI_PORTSC_MASK_W1C);
+ portsc |= ECHI_PORTSC_MASK_PORT_POWER;
+
+ regs->portsc = portsc;
+ }
return true;
}
@@ -347,15 +411,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
TU_ASSERT (ep_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
//------------- Prepare Queue Head -------------//
- ehci_qhd_t * p_qhd;
-
- if ( ep_desc->bEndpointAddress == 0 )
- {
- p_qhd = qhd_control(dev_addr);
- }else
- {
- p_qhd = qhd_find_free();
- }
+ ehci_qhd_t *p_qhd = (ep_desc->bEndpointAddress == 0) ? qhd_control(dev_addr) : qhd_find_free();
TU_ASSERT(p_qhd);
qhd_init(p_qhd, dev_addr, ep_desc);
@@ -389,6 +445,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
// TODO might need to disable async/period list
list_insert(list_head, (ehci_link_t*) p_qhd, EHCI_QTYPE_QHD);
+ hcd_dcache_clean(p_qhd, sizeof(ehci_qhd_t));
+ hcd_dcache_clean(list_head, sizeof(ehci_qhd_t));
+
return true;
}
@@ -400,16 +459,12 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
ehci_qtd_t* td = &ehci_data.control[dev_addr].qtd;
qtd_init(td, setup_packet, 8);
- td->pid = EHCI_PID_SETUP;
- td->int_on_complete = 1;
- td->next.terminate = 1;
+ td->pid = EHCI_PID_SETUP;
- // sw region
- qhd->p_qtd_list_head = td;
- qhd->p_qtd_list_tail = td;
+ hcd_dcache_clean((void *) setup_packet, 8);
- // attach TD
- qhd->qtd_overlay.next.address = (uint32_t) td;
+ // attach TD to QHD -> start transferring
+ qhd_attach_qtd(qhd, td);
return true;
}
@@ -421,50 +476,45 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
- if ( epnum == 0 )
- {
- ehci_qhd_t* qhd = qhd_control(dev_addr);
- ehci_qtd_t* qtd = qtd_control(dev_addr);
+ ehci_qhd_t* qhd;
+ ehci_qtd_t* qtd;
+
+ if (epnum == 0) {
+ qhd = qhd_control(dev_addr);
+ qtd = qtd_control(dev_addr);
qtd_init(qtd, buffer, buflen);
- // first first data toggle is always 1 (data & setup stage)
+ // first data toggle is always 1 (data & setup stage)
qtd->data_toggle = 1;
qtd->pid = dir ? EHCI_PID_IN : EHCI_PID_OUT;
- qtd->int_on_complete = 1;
- qtd->next.terminate = 1;
+ } else {
+ qhd = qhd_get_from_addr(dev_addr, ep_addr);
+ qtd = qtd_find_free();
+ TU_ASSERT(qtd);
- // sw region
- qhd->p_qtd_list_head = qtd;
- qhd->p_qtd_list_tail = qtd;
-
- // attach TD
- qhd->qtd_overlay.next.address = (uint32_t) qtd;
- }else
- {
- ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr);
- ehci_qtd_t *p_qtd = qtd_find_free();
- TU_ASSERT(p_qtd);
-
- qtd_init(p_qtd, buffer, buflen);
- p_qtd->pid = p_qhd->pid;
-
- // Insert TD to QH
- qtd_insert_to_qhd(p_qhd, p_qtd);
-
- p_qhd->p_qtd_list_tail->int_on_complete = 1;
-
- // attach head QTD to QHD start transferring
- p_qhd->qtd_overlay.next.address = (uint32_t) p_qhd->p_qtd_list_head;
+ qtd_init(qtd, buffer, buflen);
+ qtd->pid = qhd->pid;
}
+ // IN transfer: invalidate buffer, OUT transfer: clean buffer
+ if (dir) {
+ hcd_dcache_invalidate(buffer, buflen);
+ }else {
+ hcd_dcache_clean(buffer, buflen);
+ }
+
+ // attach TD to QHD -> start transferring
+ qhd_attach_qtd(qhd, qtd);
+
return true;
}
-bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
+bool hcd_edpt_clear_stall(uint8_t daddr, uint8_t ep_addr)
{
- ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr);
- p_qhd->qtd_overlay.halted = 0;
+ ehci_qhd_t *qhd = qhd_get_from_addr(daddr, ep_addr);
+ qhd->qtd_overlay.halted = 0;
+ hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
// TODO reset data toggle ?
return true;
}
@@ -476,22 +526,22 @@ bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
// async_advance is handshake between usb stack & ehci controller.
// This isr mean it is safe to modify previously removed queue head from async list.
// In tinyusb, queue head is only removed when device is unplugged.
-static void async_advance_isr(uint8_t rhport)
+TU_ATTR_ALWAYS_INLINE static inline
+void async_advance_isr(uint8_t rhport)
{
(void) rhport;
- ehci_qhd_t* qhd_pool = ehci_data.qhd_pool;
- for(uint32_t i = 0; i < QHD_MAX; i++)
- {
- if ( qhd_pool[i].removing )
- {
+ ehci_qhd_t *qhd_pool = ehci_data.qhd_pool;
+ for (uint32_t i = 0; i < QHD_MAX; i++) {
+ if (qhd_pool[i].removing) {
qhd_pool[i].removing = 0;
- qhd_pool[i].used = 0;
+ qhd_pool[i].used = 0;
}
}
}
-static void port_connect_status_change_isr(uint8_t rhport)
+TU_ATTR_ALWAYS_INLINE static inline
+void port_connect_status_change_isr(uint8_t rhport)
{
// NOTE There is an sequence plug->unplug->…..-> plug if device is powering with pre-plugged device
if (ehci_data.regs->portsc_bm.current_connect_status)
@@ -504,132 +554,169 @@ static void port_connect_status_change_isr(uint8_t rhport)
}
}
-static void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd)
-{
- // free all TDs from the head td to the first active TD
- while(p_qhd->p_qtd_list_head != NULL && !p_qhd->p_qtd_list_head->active)
- {
- ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) p_qhd->p_qtd_list_head;
- bool const is_ioc = (qtd->int_on_complete != 0);
- uint8_t const ep_addr = tu_edpt_addr(p_qhd->ep_number, qtd->pid == EHCI_PID_IN ? 1 : 0);
+TU_ATTR_ALWAYS_INLINE static inline
+void qhd_xfer_complete_isr(ehci_qhd_t * qhd) {
+ // examine TD attached to queue head
+ ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) qhd->attached_qtd;
+ if (qtd == NULL) return; // no TD attached
+ hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
- p_qhd->total_xferred_bytes += qtd->expected_bytes - qtd->total_bytes;
-
- // TD need to be freed and removed from qhd, before invoking callback
- qtd->used = 0; // free QTD
- qtd_remove_1st_from_qhd(p_qhd);
-
- if (is_ioc)
- {
- hcd_event_xfer_complete(p_qhd->dev_addr, ep_addr, p_qhd->total_xferred_bytes, XFER_RESULT_SUCCESS, true);
- p_qhd->total_xferred_bytes = 0;
- }
+ // TD is still active, no need to process
+ if (qtd->active) {
+ return;
}
+
+ uint8_t dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
+ uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
+
+ // invalidate dcache if IN transfer
+ if (dir == 1 && qhd->attached_buffer != 0 && xferred_bytes > 0) {
+ hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
+ }
+
+ // remove and free TD before invoking callback
+ qhd->attached_qtd = NULL;
+ qhd->attached_buffer = 0;
+ qtd->used = 0; // free QTD
+
+ // notify usbh
+ uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
+ hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, XFER_RESULT_SUCCESS, true);
}
-static void async_list_xfer_complete_isr(ehci_qhd_t * const async_head)
+TU_ATTR_ALWAYS_INLINE static inline
+void async_list_xfer_complete_isr(ehci_qhd_t * const async_head)
{
ehci_qhd_t *p_qhd = async_head;
do
{
- if ( !p_qhd->qtd_overlay.halted ) // halted or error is processed in error isr
- {
+ hcd_dcache_invalidate(p_qhd, sizeof(ehci_qhd_t));
+
+ // halted or error is processed in error isr
+ if ( !p_qhd->qtd_overlay.halted ) {
qhd_xfer_complete_isr(p_qhd);
}
+
p_qhd = qhd_next(p_qhd);
}while(p_qhd != async_head); // async list traversal, stop if loop around
}
-static void period_list_xfer_complete_isr(uint8_t hostid, uint32_t interval_ms)
+TU_ATTR_ALWAYS_INLINE static inline
+void period_list_xfer_complete_isr(uint8_t rhport, uint32_t interval_ms)
{
- uint16_t max_loop = 0;
- uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1u);
- ehci_link_t next_item = * get_period_head(hostid, interval_ms);
+ uint32_t const period_1ms_addr = (uint32_t) get_period_head(rhport, 1u);
+ ehci_link_t next_link = * get_period_head(rhport, interval_ms);
- // TODO abstract max loop guard for period
- while( !next_item.terminate &&
- !(interval_ms > 1 && period_1ms_addr == tu_align32(next_item.address)) &&
- max_loop < (QHD_MAX + EHCI_MAX_ITD + EHCI_MAX_SITD)*CFG_TUH_DEVICE_MAX)
- {
- switch ( next_item.type )
- {
- case EHCI_QTYPE_QHD:
- {
- ehci_qhd_t *p_qhd_int = (ehci_qhd_t *) tu_align32(next_item.address);
- if ( !p_qhd_int->qtd_overlay.halted )
- {
- qhd_xfer_complete_isr(p_qhd_int);
+ while (!next_link.terminate) {
+ if (interval_ms > 1 && period_1ms_addr == tu_align32(next_link.address)) {
+ // 1ms period list is end of list for all larger interval
+ break;
+ }
+
+ uintptr_t const entry_addr = tu_align32(next_link.address);
+
+ switch (next_link.type) {
+ case EHCI_QTYPE_QHD: {
+ ehci_qhd_t *qhd = (ehci_qhd_t *) entry_addr;
+ hcd_dcache_invalidate(qhd, sizeof(ehci_qhd_t));
+
+ if (!qhd->qtd_overlay.halted) {
+ qhd_xfer_complete_isr(qhd);
}
}
- break;
+ break;
+
+ case EHCI_QTYPE_ITD:
+ // TODO support hs ISO
+ break;
- case EHCI_QTYPE_ITD: // TODO support hs/fs ISO
case EHCI_QTYPE_SITD:
+ // TODO support split ISO
+ break;
+
case EHCI_QTYPE_FSTN:
-
- default: break;
+ default:
+ break;
}
- next_item = *list_next(&next_item);
- max_loop++;
+ next_link = *list_next(&next_link);
}
}
-static void qhd_xfer_error_isr(ehci_qhd_t * p_qhd)
+// TODO merge with qhd_xfer_complete_isr()
+TU_ATTR_ALWAYS_INLINE static inline
+void qhd_xfer_error_isr(ehci_qhd_t * qhd)
{
- if ( (p_qhd->dev_addr != 0 && p_qhd->qtd_overlay.halted) || // addr0 cannot be protocol STALL
- qhd_has_xact_error(p_qhd) )
- {
- // current qhd has error in transaction
- xfer_result_t error_event;
+ volatile ehci_qtd_t *qtd_overlay = &qhd->qtd_overlay;
- // no error bits are set, endpoint is halted due to STALL
- error_event = qhd_has_xact_error(p_qhd) ? XFER_RESULT_FAILED : XFER_RESULT_STALLED;
+ // TD has error
+ if (qtd_overlay->halted) {
+ xfer_result_t xfer_result;
- p_qhd->total_xferred_bytes += p_qhd->p_qtd_list_head->expected_bytes - p_qhd->p_qtd_list_head->total_bytes;
-
-// if ( XFER_RESULT_FAILED == error_event ) TU_BREAKPOINT(); // TODO skip unplugged device
-
- p_qhd->p_qtd_list_head->used = 0; // free QTD
- qtd_remove_1st_from_qhd(p_qhd);
-
- if ( 0 == p_qhd->ep_number )
- {
- // control cannot be halted --> clear all qtd list
- p_qhd->p_qtd_list_head = NULL;
- p_qhd->p_qtd_list_tail = NULL;
-
- p_qhd->qtd_overlay.next.terminate = 1;
- p_qhd->qtd_overlay.alternate.terminate = 1;
- p_qhd->qtd_overlay.halted = 0;
-
- ehci_qtd_t *p_setup = qtd_control(p_qhd->dev_addr);
- p_setup->used = 0;
+ if (qtd_overlay->xact_err || qtd_overlay->err_count == 0 || qtd_overlay->buffer_err || qtd_overlay->babble_err) {
+ // Error count = 0 often occurs when device disconnected, or other bus-related error
+ xfer_result = XFER_RESULT_FAILED;
+ }else {
+ // no error bits are set, endpoint is halted due to STALL
+ xfer_result = XFER_RESULT_STALLED;
}
- // call USBH callback
- hcd_event_xfer_complete(p_qhd->dev_addr, tu_edpt_addr(p_qhd->ep_number, p_qhd->pid == EHCI_PID_IN ? 1 : 0), p_qhd->total_xferred_bytes, error_event, true);
+// if (XFER_RESULT_FAILED == xfer_result ) {
+// TU_LOG1(" QHD xfer err count: %d\n", qtd_overlay->err_count);
+// TU_BREAKPOINT(); // TODO skip unplugged device
+// }
- p_qhd->total_xferred_bytes = 0;
+ ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) qhd->attached_qtd;
+ TU_ASSERT(qtd, ); // No TD yet, probably a race condition or cache issue !?
+
+ hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
+
+ uint8_t dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
+ uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
+
+ // invalidate dcache if IN transfer
+ if (dir == 1 && qhd->attached_buffer != 0 && xferred_bytes > 0) {
+ hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
+ }
+
+ // remove and free TD before invoking callback
+ qhd->attached_qtd = NULL;
+ qhd->attached_buffer = 0;
+ qtd->used = 0; // free QTD
+
+ if (0 == qhd->ep_number ) {
+ // control cannot be halted
+ qhd->qtd_overlay.next.terminate = 1;
+ qhd->qtd_overlay.alternate.terminate = 1;
+ qhd->qtd_overlay.halted = 0;
+
+ hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
+ }
+
+ // notify usbh
+ uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
+ hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, xfer_result, true);
}
}
-static void xfer_error_isr(uint8_t hostid)
+TU_ATTR_ALWAYS_INLINE static inline
+void xfer_error_isr(uint8_t rhport)
{
//------------- async list -------------//
- ehci_qhd_t * const async_head = qhd_async_head(hostid);
+ ehci_qhd_t * const async_head = qhd_async_head(rhport);
ehci_qhd_t *p_qhd = async_head;
do
{
+ hcd_dcache_invalidate(p_qhd, sizeof(ehci_qhd_t));
qhd_xfer_error_isr( p_qhd );
p_qhd = qhd_next(p_qhd);
}while(p_qhd != async_head); // async list traversal, stop if loop around
//------------- TODO refractor period list -------------//
- uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1u);
+ uint32_t const period_1ms_addr = (uint32_t) get_period_head(rhport, 1u);
for (uint32_t interval_ms=1; interval_ms <= FRAMELIST_SIZE; interval_ms *= 2)
{
- ehci_link_t next_item = * get_period_head(hostid, interval_ms);
+ ehci_link_t next_item = * get_period_head(rhport, interval_ms);
// TODO abstract max loop guard for period
while( !next_item.terminate &&
@@ -640,6 +727,8 @@ static void xfer_error_isr(uint8_t hostid)
case EHCI_QTYPE_QHD:
{
ehci_qhd_t *p_qhd_int = (ehci_qhd_t *) tu_align32(next_item.address);
+ hcd_dcache_invalidate(p_qhd_int, sizeof(ehci_qhd_t));
+
qhd_xfer_error_isr(p_qhd_int);
}
break;
@@ -656,79 +745,67 @@ static void xfer_error_isr(uint8_t hostid)
}
}
-#if CFG_TUSB_DEBUG >= EHCI_DBG
-
-static inline void print_portsc(ehci_registers_t* regs)
-{
- TU_LOG_HEX(EHCI_DBG, regs->portsc);
- TU_LOG(EHCI_DBG, " Current Connect Status: %u\r\n", regs->portsc_bm.current_connect_status);
- TU_LOG(EHCI_DBG, " Connect Status Change : %u\r\n", regs->portsc_bm.connect_status_change);
- TU_LOG(EHCI_DBG, " Port Enabled : %u\r\n", regs->portsc_bm.port_enabled);
- TU_LOG(EHCI_DBG, " Port Enabled Change : %u\r\n", regs->portsc_bm.port_enable_change);
-
- TU_LOG(EHCI_DBG, " Port Reset : %u\r\n", regs->portsc_bm.port_reset);
- TU_LOG(EHCI_DBG, " Port Power : %u\r\n", regs->portsc_bm.port_power);
-}
-
-#else
-
-#define print_portsc(_reg)
-
-#endif
-
//------------- Host Controller Driver's Interrupt Handler -------------//
void hcd_int_handler(uint8_t rhport)
{
ehci_registers_t* regs = ehci_data.regs;
+ uint32_t const int_status = regs->status;
- uint32_t int_status = regs->status;
- int_status &= regs->inten;
-
- regs->status = int_status; // Acknowledge handled interrupt
-
- if (int_status == 0) return;
-
- if (int_status & EHCI_INT_MASK_FRAMELIST_ROLLOVER)
- {
- ehci_data.uframe_number += (FRAMELIST_SIZE << 3);
+ if (int_status & EHCI_INT_MASK_HC_HALTED) {
+ // something seriously wrong, maybe forget to flush/invalidate cache
+ TU_BREAKPOINT();
+ TU_LOG1(" HC halted\n");
+ return;
}
- if (int_status & EHCI_INT_MASK_PORT_CHANGE)
- {
- uint32_t const port_status = regs->portsc & EHCI_PORTSC_MASK_ALL;
+ if (int_status & EHCI_INT_MASK_FRAMELIST_ROLLOVER) {
+ ehci_data.uframe_number += (FRAMELIST_SIZE << 3);
+ regs->status = EHCI_INT_MASK_FRAMELIST_ROLLOVER; // Acknowledge
+ }
+
+ if (int_status & EHCI_INT_MASK_PORT_CHANGE) {
+ // Including: Force port resume, over-current change, enable/disable change and connect status change.
+ uint32_t const port_status = regs->portsc & EHCI_PORTSC_MASK_W1C;
print_portsc(regs);
- if (regs->portsc_bm.connect_status_change)
- {
+ if (regs->portsc_bm.connect_status_change) {
port_connect_status_change_isr(rhport);
}
regs->portsc |= port_status; // Acknowledge change bits in portsc
+ regs->status = EHCI_INT_MASK_PORT_CHANGE; // Acknowledge
}
- if (int_status & EHCI_INT_MASK_ERROR)
- {
+ if (int_status & EHCI_INT_MASK_ERROR) {
xfer_error_isr(rhport);
+ regs->status = EHCI_INT_MASK_ERROR; // Acknowledge
}
//------------- some QTD/SITD/ITD with IOC set is completed -------------//
- if (int_status & EHCI_INT_MASK_NXP_ASYNC)
- {
- async_list_xfer_complete_isr( qhd_async_head(rhport) );
+ if (int_status & EHCI_INT_MASK_NXP_ASYNC) {
+ async_list_xfer_complete_isr(qhd_async_head(rhport));
+ regs->status = EHCI_INT_MASK_NXP_ASYNC; // Acknowledge
}
if (int_status & EHCI_INT_MASK_NXP_PERIODIC)
{
for (uint32_t i=1; i <= FRAMELIST_SIZE; i *= 2)
{
- period_list_xfer_complete_isr( rhport, i );
+ period_list_xfer_complete_isr(rhport, i);
}
+ regs->status = EHCI_INT_MASK_NXP_PERIODIC; // Acknowledge
+ }
+
+ if (int_status & EHCI_INT_MASK_USB) {
+ // TODO standard EHCI xfer complete
+ regs->status = EHCI_INT_MASK_USB; // Acknowledge
}
//------------- There is some removed async previously -------------//
- if (int_status & EHCI_INT_MASK_ASYNC_ADVANCE) // need to place after EHCI_INT_MASK_NXP_ASYNC
- {
+ // need to place after EHCI_INT_MASK_NXP_ASYNC
+ if (int_status & EHCI_INT_MASK_ASYNC_ADVANCE) {
async_advance_isr(rhport);
+ regs->status = EHCI_INT_MASK_ASYNC_ADVANCE; // Acknowledge
}
}
@@ -769,50 +846,10 @@ static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
return NULL;
}
-//------------- TD helper -------------//
-static inline ehci_qtd_t* qtd_find_free(void)
-{
- for (uint32_t i=0; inext.address);
-}
-
-static inline void qtd_remove_1st_from_qhd(ehci_qhd_t *p_qhd)
-{
- if (p_qhd->p_qtd_list_head == p_qhd->p_qtd_list_tail) // last TD --> make it NULL
- {
- p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = NULL;
- }else
- {
- p_qhd->p_qtd_list_head = qtd_next( p_qhd->p_qtd_list_head );
- }
-}
-
-static inline void qtd_insert_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new)
-{
- if (p_qhd->p_qtd_list_head == NULL) // empty list
- {
- p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = p_qtd_new;
- }else
- {
- p_qhd->p_qtd_list_tail->next.address = (uint32_t) p_qtd_new;
- p_qhd->p_qtd_list_tail = p_qtd_new;
- }
-}
-
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
{
// address 0 is used as async head, which always on the list --> cannot be cleared (ehci halted otherwise)
- if (dev_addr != 0)
- {
+ if (dev_addr != 0) {
tu_memclr(p_qhd, sizeof(ehci_qhd_t));
}
@@ -862,58 +899,80 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
p_qhd->int_smask = p_qhd->fl_int_cmask = 0;
}
- p_qhd->fl_hub_addr = devtree_info.hub_addr;
- p_qhd->fl_hub_port = devtree_info.hub_port;
- p_qhd->mult = 1; // TODO not use high bandwidth/park mode yet
+ p_qhd->fl_hub_addr = devtree_info.hub_addr;
+ p_qhd->fl_hub_port = devtree_info.hub_port;
+ p_qhd->mult = 1; // TODO not use high bandwidth/park mode yet
//------------- HCD Management Data -------------//
- p_qhd->used = 1;
- p_qhd->removing = 0;
- p_qhd->p_qtd_list_head = NULL;
- p_qhd->p_qtd_list_tail = NULL;
+ p_qhd->used = 1;
+ p_qhd->removing = 0;
+ p_qhd->attached_qtd = NULL;
p_qhd->pid = tu_edpt_dir(ep_desc->bEndpointAddress) ? EHCI_PID_IN : EHCI_PID_OUT; // PID for TD under this endpoint
//------------- active, but no TD list -------------//
p_qhd->qtd_overlay.halted = 0;
p_qhd->qtd_overlay.next.terminate = 1;
p_qhd->qtd_overlay.alternate.terminate = 1;
+
if (TUSB_XFER_BULK == xfer_type && p_qhd->ep_speed == TUSB_SPEED_HIGH && p_qhd->pid == EHCI_PID_OUT)
{
p_qhd->qtd_overlay.ping_err = 1; // do PING for Highspeed Bulk OUT, EHCI section 4.11
}
}
-static void qtd_init(ehci_qtd_t* p_qtd, void const* buffer, uint16_t total_bytes)
+static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd) {
+ qhd->attached_qtd = qtd;
+ qhd->attached_buffer = qtd->buffer[0];
+
+ // clean and invalidate cache before physically write
+ hcd_dcache_clean_invalidate(qtd, sizeof(ehci_qtd_t));
+
+ qhd->qtd_overlay.next.address = (uint32_t) qtd;
+ hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
+}
+
+
+//------------- TD helper -------------//
+static inline ehci_qtd_t *qtd_find_free(void) {
+ for (uint32_t i = 0; i < QTD_MAX; i++) {
+ if (!ehci_data.qtd_pool[i].used) return &ehci_data.qtd_pool[i];
+ }
+ return NULL;
+}
+
+static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes)
{
- tu_memclr(p_qtd, sizeof(ehci_qtd_t));
+ tu_memclr(qtd, sizeof(ehci_qtd_t));
+ qtd->used = 1;
- p_qtd->used = 1;
+ qtd->next.terminate = 1; // init to null
+ qtd->alternate.terminate = 1; // not used, always set to terminated
+ qtd->active = 1;
+ qtd->err_count = 3; // TODO 3 consecutive errors tolerance
+ qtd->data_toggle = 0;
+ qtd->int_on_complete = 1;
+ qtd->total_bytes = total_bytes;
+ qtd->expected_bytes = total_bytes;
- p_qtd->next.terminate = 1; // init to null
- p_qtd->alternate.terminate = 1; // not used, always set to terminated
- p_qtd->active = 1;
- p_qtd->err_count = 3; // TODO 3 consecutive errors tolerance
- p_qtd->data_toggle = 0;
- p_qtd->total_bytes = total_bytes;
- p_qtd->expected_bytes = total_bytes;
-
- p_qtd->buffer[0] = (uint32_t) buffer;
+ qtd->buffer[0] = (uint32_t) buffer;
for(uint8_t i=1; i<5; i++)
{
- p_qtd->buffer[i] |= tu_align4k( p_qtd->buffer[i-1] ) + 4096;
+ qtd->buffer[i] |= tu_align4k(qtd->buffer[i - 1] ) + 4096;
}
}
//------------- List Managing Helper -------------//
+
+// insert at head
static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type)
{
new->address = current->address;
current->address = ((uint32_t) new) | (new_type << 1);
}
-static inline ehci_link_t* list_next(ehci_link_t *p_link_pointer)
+static inline ehci_link_t* list_next(ehci_link_t const *p_link)
{
- return (ehci_link_t*) tu_align32(p_link_pointer->address);
+ return (ehci_link_t*) tu_align32(p_link->address);
}
#endif
diff --git a/src/portable/ehci/ehci.h b/src/portable/ehci/ehci.h
index 36f8649be..8338fb419 100644
--- a/src/portable/ehci/ehci.h
+++ b/src/portable/ehci/ehci.h
@@ -81,6 +81,8 @@ typedef union {
};
}ehci_link_t;
+TU_VERIFY_STATIC( sizeof(ehci_link_t) == 4, "size is not correct" );
+
/// Queue Element Transfer Descriptor
/// Qtd is used to declare overlay in ehci_qhd_t -> cannot be declared with TU_ATTR_ALIGNED(32)
typedef struct
@@ -162,11 +164,12 @@ typedef struct TU_ATTR_ALIGNED(32)
uint8_t pid;
uint8_t interval_ms; // polling interval in frames (or millisecond)
- uint16_t total_xferred_bytes; // number of bytes xferred until a qtd with ioc bit set
- uint8_t reserved2[2];
+ uint8_t TU_RESERVED[4];
- ehci_qtd_t * volatile p_qtd_list_head; // head of the scheduled TD list
- ehci_qtd_t * volatile p_qtd_list_tail; // tail of the scheduled TD list
+ // Attached TD management, note usbh will only queue 1 TD per QHD.
+ // buffer for dcache invalidate since td's buffer is modified by HC and finding initial buffer address is not trivial
+ uint32_t attached_buffer;
+ ehci_qtd_t * volatile attached_qtd;
} ehci_qhd_t;
TU_VERIFY_STATIC( sizeof(ehci_qhd_t) == 64, "size is not correct" );
@@ -245,14 +248,6 @@ typedef struct TU_ATTR_ALIGNED(32)
/// Word 4-5: Buffer Pointer List
uint32_t buffer[2]; // buffer[1] TP: Transaction Position - T-Count: Transaction Count
-// union{
-// uint32_t BufferPointer1;
-// struct {
-// volatile uint32_t TCount : 3;
-// volatile uint32_t TPosition : 2;
-// };
-// };
-
/*---------- Word 6 ----------*/
ehci_link_t back;
@@ -267,16 +262,22 @@ TU_VERIFY_STATIC( sizeof(ehci_sitd_t) == 32, "size is not correct" );
//--------------------------------------------------------------------+
// EHCI Operational Register
//--------------------------------------------------------------------+
-enum ehci_interrupt_mask_{
+enum {
+ // Bit 0-5 has maskable in interrupt enabled register
EHCI_INT_MASK_USB = TU_BIT(0),
EHCI_INT_MASK_ERROR = TU_BIT(1),
EHCI_INT_MASK_PORT_CHANGE = TU_BIT(2),
-
EHCI_INT_MASK_FRAMELIST_ROLLOVER = TU_BIT(3),
EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR = TU_BIT(4),
EHCI_INT_MASK_ASYNC_ADVANCE = TU_BIT(5),
+
EHCI_INT_MASK_NXP_SOF = TU_BIT(7),
+ EHCI_INT_MASK_HC_HALTED = TU_BIT(12),
+ EHCI_INT_MASK_RECLAIMATION = TU_BIT(13),
+ EHCI_INT_MASK_PERIODIC_SCHED_STATUS = TU_BIT(14),
+ EHCI_INT_MASK_ASYNC_SCHED_STATUS = TU_BIT(15),
+
EHCI_INT_MASK_NXP_ASYNC = TU_BIT(18),
EHCI_INT_MASK_NXP_PERIODIC = TU_BIT(19),
@@ -287,7 +288,7 @@ enum ehci_interrupt_mask_{
EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_NXP_PERIODIC
};
-enum ehci_usbcmd_pos_ {
+enum {
EHCI_USBCMD_POS_RUN_STOP = 0,
EHCI_USBCMD_POS_FRAMELIST_SIZE = 2,
EHCI_USBCMD_POS_PERIOD_ENABLE = 4,
@@ -296,24 +297,27 @@ enum ehci_usbcmd_pos_ {
EHCI_USBCMD_POS_INTERRUPT_THRESHOLD = 16
};
-enum ehci_portsc_change_mask_{
+enum {
EHCI_PORTSC_MASK_CURRENT_CONNECT_STATUS = TU_BIT(0),
EHCI_PORTSC_MASK_CONNECT_STATUS_CHANGE = TU_BIT(1),
EHCI_PORTSC_MASK_PORT_EANBLED = TU_BIT(2),
- EHCI_PORTSC_MASK_PORT_ENABLE_CHAGNE = TU_BIT(3),
+ EHCI_PORTSC_MASK_PORT_ENABLE_CHANGE = TU_BIT(3),
EHCI_PORTSC_MASK_OVER_CURRENT_CHANGE = TU_BIT(5),
+ EHCI_PORTSC_MASK_FORCE_RESUME = TU_BIT(6),
+ EHCI_PORTSC_MASK_PORT_SUSPEND = TU_BIT(7),
EHCI_PORTSC_MASK_PORT_RESET = TU_BIT(8),
+ ECHI_PORTSC_MASK_PORT_POWER = TU_BIT(12),
- EHCI_PORTSC_MASK_ALL =
- EHCI_PORTSC_MASK_CONNECT_STATUS_CHANGE |
- EHCI_PORTSC_MASK_PORT_ENABLE_CHAGNE |
- EHCI_PORTSC_MASK_OVER_CURRENT_CHANGE
+ EHCI_PORTSC_MASK_W1C =
+ EHCI_PORTSC_MASK_CONNECT_STATUS_CHANGE |
+ EHCI_PORTSC_MASK_PORT_ENABLE_CHANGE |
+ EHCI_PORTSC_MASK_OVER_CURRENT_CHANGE
};
typedef volatile struct
{
union {
- uint32_t command;
+ uint32_t command; // 0x00
struct {
uint32_t run_stop : 1 ; ///< 1=Run. 0=Stop
@@ -333,7 +337,7 @@ typedef volatile struct
};
union {
- uint32_t status;
+ uint32_t status; // 0x04
struct {
uint32_t usb : 1 ; ///< qTD with IOC is retired
@@ -357,7 +361,7 @@ typedef volatile struct
};
union{
- uint32_t inten;
+ uint32_t inten; // 0x08
struct {
uint32_t usb : 1 ;
@@ -375,43 +379,87 @@ typedef volatile struct
}inten_bm;
};
- uint32_t frame_index ; ///< Micro frame counter
- uint32_t ctrl_ds_seg ; ///< Control Data Structure Segment
- uint32_t periodic_list_base ; ///< Beginning address of perodic frame list
- uint32_t async_list_addr ; ///< Address of next async QHD to be executed
+ uint32_t frame_index ; ///< 0x0C Micro frame counter
+ uint32_t ctrl_ds_seg ; ///< 0x10 Control Data Structure Segment
+ uint32_t periodic_list_base ; ///< 0x14 Beginning address of perodic frame list
+ uint32_t async_list_addr ; ///< 0x18 Address of next async QHD to be executed
uint32_t nxp_tt_control ; ///< nxp embedded transaction translator (reserved by EHCI specs)
uint32_t reserved[8] ;
- uint32_t config_flag ; ///< not used by NXP
+ uint32_t config_flag ; ///< 0x40 not used by NXP
union {
- uint32_t portsc ; ///< port status and control
- struct {
- uint32_t current_connect_status : 1; ///< 0: No device, 1: Device is present on port
- uint32_t connect_status_change : 1; ///< Change in Current Connect Status
- uint32_t port_enabled : 1; ///< Ports can only be enabled by HC as a part of the reset and enable. SW can write 0 to disable
- uint32_t port_enable_change : 1; ///< Port Enabled has changed
- uint32_t over_current_active : 1; ///< Port has an over-current condition
- uint32_t over_current_change : 1; ///< Change to Over-current Active
- uint32_t force_port_resume : 1; ///< Resume detected/driven on port. This functionality defined for manipulating this bit depends on the value of the Suspend bit.
- uint32_t suspend : 1; ///< Port in suspend state
- uint32_t port_reset : 1; ///< 1=Port is in Reset. 0=Port is not in Reset
- uint32_t nxp_highspeed_status : 1; ///< NXP customized: 0=connected to the port is not in High-speed mode, 1=connected to the port is in High-speed mode
- uint32_t line_status : 2; ///< D+/D- state: 00: SE0, 10: J-state, 01: K-state
- uint32_t port_power : 1; ///< 0= power off, 1= power on
- uint32_t port_owner : 1; ///< not used by NXP
- uint32_t port_indicator_control : 2; ///< 00b: off, 01b: Amber, 10b: green, 11b: undefined
- uint32_t port_test_control : 4; ///< Port test mode, not used by tinyusb
- uint32_t wake_on_connect_enable : 1; ///< Enables device connects as wake-up events
- uint32_t wake_on_disconnect_enable : 1; ///< Enables device disconnects as wake-up events
- uint32_t wake_on_over_current_enable : 1; ///< Enables over-current conditions as wake-up events
- uint32_t nxp_phy_clock_disable : 1; ///< NXP customized: the PHY can be put into Low Power Suspend – Clock Disable when the downstream device has been put into suspend mode or when no downstream device is connected. Low power suspend is completely under the control of software. 0: enable PHY clock, 1: disable PHY clock
- uint32_t nxp_port_force_fullspeed : 1; ///< NXP customized: Writing this bit to a 1 will force the port to only connect at Full Speed. It disables the chirp sequence that allowsthe port to identify itself as High Speed. This is useful for testing FS configurations with a HS host, hub or device.
- uint32_t TU_RESERVED : 1;
- uint32_t nxp_port_speed : 2; ///< NXP customized: This register field indicates the speed atwhich the port is operating. For HS mode operation in the host controllerand HS/FS operation in the device controller the port routing steers data to the Protocol engine. For FS and LS mode operation in the host controller, the port routing steers data to the Protocol Engine w/ Embedded Transaction Translator. 0x0: Fullspeed, 0x1: Lowspeed, 0x2: Highspeed
+ // mixed with RW and R/WC bits, care should be taken when writing to this register
+ uint32_t portsc ; ///< 0x44 port status and control
+ const struct {
+ uint32_t current_connect_status : 1; ///< 00: 0: No device, 1: Device is present on port
+ uint32_t connect_status_change : 1; ///< 01: [R/WC] Change in Current Connect Status
+ uint32_t port_enabled : 1; ///< 02: Ports can only be enabled by HC as a part of the reset and enable. SW can write 0 to disable
+ uint32_t port_enable_change : 1; ///< 03: [R/WC] Port Enabled has changed
+ uint32_t over_current_active : 1; ///< 04: Port has an over-current condition
+ uint32_t over_current_change : 1; ///< 05: [R/WC] Change to Over-current Active
+ uint32_t force_port_resume : 1; ///< 06: Resume detected/driven on port. This functionality defined for manipulating this bit depends on the value of the Suspend bit.
+ uint32_t suspend : 1; ///< 07: Port in suspend state
+ uint32_t port_reset : 1; ///< 08: 1=Port is in Reset. 0=Port is not in Reset
+ uint32_t nxp_highspeed_status : 1; ///< 09: NXP customized: 0=connected to the port is not in High-speed mode, 1=connected to the port is in High-speed mode
+ uint32_t line_status : 2; ///< 10-11: D+/D- state: 00: SE0, 10: J-state, 01: K-state
+ uint32_t port_power : 1; ///< 12: 0= power off, 1= power on
+ uint32_t port_owner : 1; ///< 13: not used by NXP
+ uint32_t port_indicator_control : 2; ///< 14-15: 00b: off, 01b: Amber, 10b: green, 11b: undefined
+ uint32_t port_test_control : 4; ///< 16-19: Port test mode, not used by tinyusb
+ uint32_t wake_on_connect_enable : 1; ///< 20: Enables device connects as wake-up events
+ uint32_t wake_on_disconnect_enable : 1; ///< 21: Enables device disconnects as wake-up events
+ uint32_t wake_on_over_current_enable : 1; ///< 22: Enables over-current conditions as wake-up events
+ uint32_t nxp_phy_clock_disable : 1; ///< 23: NXP customized: the PHY can be put into Low Power Suspend – Clock Disable when the downstream device has been put into suspend mode or when no downstream device is connected. Low power suspend is completely under the control of software. 0: enable PHY clock, 1: disable PHY clock
+ uint32_t nxp_port_force_fullspeed : 1; ///< 24: NXP customized: Writing this bit to a 1 will force the port to only connect at Full Speed. It disables the chirp sequence that allowsthe port to identify itself as High Speed. This is useful for testing FS configurations with a HS host, hub or device.
+ uint32_t TU_RESERVED : 1; ///< 25
+ uint32_t nxp_port_speed : 2; ///< 26-27: NXP customized: This register field indicates the speed atwhich the port is operating. For HS mode operation in the host controllerand HS/FS operation in the device controller the port routing steers data to the Protocol engine. For FS and LS mode operation in the host controller, the port routing steers data to the Protocol Engine w/ Embedded Transaction Translator. 0x0: Fullspeed, 0x1: Lowspeed, 0x2: Highspeed
uint32_t TU_RESERVED : 4;
}portsc_bm;
};
-}ehci_registers_t;
+} ehci_registers_t;
+
+//--------------------------------------------------------------------+
+// Capability Registers
+//--------------------------------------------------------------------+
+typedef volatile struct {
+ uint8_t caplength; // 0x00
+ uint8_t TU_RESERVED; // 0x01
+ uint16_t hciversion; // 0x02
+
+ union {
+ uint32_t hcsparams; // 0x04
+ struct {
+ uint32_t num_ports : 4; // [00:03]
+ uint32_t port_power_control : 1; // [04]
+ uint32_t TU_RESERVED : 2; // [05:06]
+ uint32_t port_route_rule : 1; // [07]
+ uint32_t n_pcc : 4; // [08:11] Number of Ports per Companion Controller
+ uint32_t n_cc : 4; // [12:15] Number of Companion Controllers
+ uint32_t port_ind : 1; // [16] Port Indicators
+ uint32_t TU_RESERVED : 3; // [17:19]
+ uint32_t n_ptt : 4; // [20:23] ChipIdea: Number of Ports per Transaction Translator
+ uint32_t n_tt : 4; // [24:27] ChipIdea: Number of Transaction Translators
+ uint32_t TU_RESERVED : 4; // [28:31]
+ } hcsparams_bm;
+ };
+
+ union {
+ uint32_t hccparams; // 0x08
+ struct {
+ uint32_t addr_64bit : 1; // [00] 64-bit Addressing Capability
+ uint32_t programmable_frame_list_flag : 1; // [01] Programmable Frame List Flag
+ uint32_t async_park_cap : 1; // [02] Asynchronous Schedule Park Capability
+ uint32_t TU_RESERVED : 1; // [03]
+ uint32_t iso_schedule_threshold : 4; // [4:7] Isochronous Scheduling Threshold
+ uint32_t eecp : 8; // [8:15] EHCI Extended Capabilities Pointer
+ uint32_t TU_RESERVED : 16;// [16:31]
+ } hccparams_bm;
+ };
+
+ uint32_t hcsp_portroute; // 0x0C HCSP Port Route Register
+} ehci_cap_registers_t;
+
+TU_VERIFY_STATIC(sizeof(ehci_cap_registers_t) == 16, "size is not correct");
#ifdef __cplusplus
}
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index 661255cf6..02f9968a7 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -562,6 +562,11 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
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) |
(need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0);
+ // START_TRANS bit on SIE_CTRL seems to exhibit the same behavior as the AVAILABLE bit
+ // described in RP2040 Datasheet, release 2.1, section "4.1.2.5.1. Concurrent access".
+ // We write everything except the START_TRANS bit first, then wait some cycles.
+ usb_hw->sie_ctrl = flags & ~USB_SIE_CTRL_START_TRANS_BITS;
+ busy_wait_at_least_cycles(12);
usb_hw->sie_ctrl = flags;
}else
{
@@ -602,6 +607,11 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
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);
+ // START_TRANS bit on SIE_CTRL seems to exhibit the same behavior as the AVAILABLE bit
+ // described in RP2040 Datasheet, release 2.1, section "4.1.2.5.1. Concurrent access".
+ // We write everything except the START_TRANS bit first, then wait some cycles.
+ usb_hw->sie_ctrl = flags & ~USB_SIE_CTRL_START_TRANS_BITS;
+ busy_wait_at_least_cycles(12);
usb_hw->sie_ctrl = flags;
return true;
diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c
index e4743223e..0e6fa1618 100644
--- a/src/portable/renesas/rusb2/hcd_rusb2.c
+++ b/src/portable/renesas/rusb2/hcd_rusb2.c
@@ -407,7 +407,7 @@ static void process_pipe0_bemp(uint8_t rhport)
static void process_pipe_nrdy(uint8_t rhport, unsigned num)
{
(void)rhport;
- unsigned result;
+ xfer_result_t result;
uint16_t volatile *ctr = get_pipectr(num);
// TU_LOG1("NRDY %d %x\n", num, *ctr);
switch (*ctr & RUSB2_PIPE_CTR_PID_Msk) {
diff --git a/src/portable/renesas/rusb2/rusb2_ra.h b/src/portable/renesas/rusb2/rusb2_ra.h
index 5785850cc..5be9f11ce 100644
--- a/src/portable/renesas/rusb2/rusb2_ra.h
+++ b/src/portable/renesas/rusb2/rusb2_ra.h
@@ -36,6 +36,10 @@ extern "C" {
#define RUSB2_REG_BASE (0x40090000)
+#if defined(__ICCARM__)
+ #define __builtin_ctz(x) __iar_builtin_CLZ(__iar_builtin_RBIT(x))
+#endif
+
TU_ATTR_ALWAYS_INLINE static inline void rusb2_int_enable(uint8_t rhport)
{
(void) rhport;
diff --git a/src/tusb.c b/src/tusb.c
index 85fe5a3cc..465b608b0 100644
--- a/src/tusb.c
+++ b/src/tusb.c
@@ -439,6 +439,10 @@ char const* const tu_str_std_request[] =
"Synch Frame"
};
+char const* const tu_str_xfer_result[] = {
+ "OK", "FAILED", "STALLED", "TIMEOUT"
+};
+
#endif
static void dump_str_line(uint8_t const* buf, uint16_t count)
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 44d036ea4..948c9edf3 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -166,6 +166,10 @@
// WCH
#define OPT_MCU_CH32V307 2200 ///< WCH CH32V307
+
+// NXP LPC MCX
+#define OPT_MCU_MCXN9 2300 ///< NXP MCX N9 Series
+
// Helper to check if configured MCU is one of listed
// Apply _TU_CHECK_MCU with || as separator to list of input
#define _TU_CHECK_MCU(_m) (CFG_TUSB_MCU == _m)
@@ -274,7 +278,7 @@
// In case TUP_MCU_STRICT_ALIGN = 1 and TUP_ARCH_STRICT_ALIGN =0, we will not reply on compiler
// to generate unaligned access code.
// LPC_IP3511 Highspeed cannot access unaligned memory on USB_RAM
-#if TUD_OPT_HIGH_SPEED && (CFG_TUSB_MCU == OPT_MCU_LPC54XXX || CFG_TUSB_MCU == OPT_MCU_LPC55XX)
+#if TUD_OPT_HIGH_SPEED && TU_CHECK_MCU(OPT_MCU_LPC54XXX, OPT_MCU_LPC55XX)
#define TUP_MCU_STRICT_ALIGN 1
#else
#define TUP_MCU_STRICT_ALIGN 0
@@ -439,6 +443,16 @@
#define CFG_TUH_CDC 0
#endif
+#ifndef CFG_TUH_CDC_FTDI
+ // FTDI is not part of CDC class, only to re-use CDC driver API
+ #define CFG_TUH_CDC_FTDI 0
+#endif
+
+#ifndef CFG_TUH_CDC_CP210X
+ // CP210X is not part of CDC class, only to re-use CDC driver API
+ #define CFG_TUH_CDC_CP210X 0
+#endif
+
#ifndef CFG_TUH_HID
#define CFG_TUH_HID 0
#endif
diff --git a/tools/build_cmake.py b/tools/build_cmake.py
new file mode 100644
index 000000000..88d27dfb8
--- /dev/null
+++ b/tools/build_cmake.py
@@ -0,0 +1,99 @@
+import os
+import sys
+import time
+import subprocess
+import pathlib
+from multiprocessing import Pool
+
+import build_utils
+
+SUCCEEDED = "\033[32msucceeded\033[0m"
+FAILED = "\033[31mfailed\033[0m"
+SKIPPED = "\033[33mskipped\033[0m"
+
+build_separator = '-' * 106
+
+make_iar_option = 'CC=iccarm'
+
+def filter_with_input(mylist):
+ if len(sys.argv) > 1:
+ input_args = list(set(mylist).intersection(sys.argv))
+ if len(input_args) > 0:
+ mylist[:] = input_args
+
+
+def build_family(family, make_option):
+ all_boards = []
+ for entry in os.scandir("hw/bsp/{}/boards".format(family)):
+ if entry.is_dir() and entry.name != 'pico_sdk':
+ all_boards.append(entry.name)
+ all_boards.sort()
+
+ # success, failed, skipped
+ ret = [0, 0, 0]
+ for board in all_boards:
+ start_time = time.monotonic()
+
+ # Generate build
+ r = subprocess.run(f"cmake examples -B cmake-build-ci-{board} -G \"Ninja\" -DFAMILY={family} -DBOARD"
+ f"={board}", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+
+ # Build
+ if r.returncode == 0:
+ r = subprocess.run(f"cmake --build cmake-build-ci-{board}", shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ duration = time.monotonic() - start_time
+
+ if r.returncode == 0:
+ status = SUCCEEDED
+ ret[0] += 1
+ else:
+ status = FAILED
+ ret[1] += 1
+
+ flash_size = "-"
+ sram_size = "-"
+ example = 'all'
+ print(build_utils.build_format.format(example, board, status, "{:.2f}s".format(duration), flash_size, sram_size))
+
+ if r.returncode != 0:
+ # group output in CI
+ print(f"::group::{board} build error")
+ print(r.stdout.decode("utf-8"))
+ print(f"::endgroup::")
+
+ return ret
+
+
+if __name__ == '__main__':
+ # IAR CC
+ if make_iar_option not in sys.argv:
+ make_iar_option = ''
+
+ # If family are not specified in arguments, build all
+ all_families = []
+ for entry in os.scandir("hw/bsp"):
+ if entry.is_dir() and os.path.isdir(entry.path + "/boards") and entry.name != 'espressif':
+ all_families.append(entry.name)
+ filter_with_input(all_families)
+ all_families.sort()
+
+ print(build_separator)
+ print(build_utils.build_format.format('Example', 'Board', '\033[39mResult\033[0m', 'Time', 'Flash', 'SRAM'))
+ total_time = time.monotonic()
+
+ # succeeded, failed, skipped
+ total_result = [0, 0, 0]
+ for family in all_families:
+ fret = build_family(family, make_iar_option)
+ if len(fret) == len(total_result):
+ total_result = [total_result[i] + fret[i] for i in range(len(fret))]
+
+ total_time = time.monotonic() - total_time
+ print(build_separator)
+ print("Build Summary: {} {}, {} {}, {} {} and took {:.2f}s".format(total_result[0], SUCCEEDED, total_result[1],
+ FAILED, total_result[2], SKIPPED, total_time))
+ print(build_separator)
+
+ sys.exit(total_result[1])
diff --git a/tools/build_family.py b/tools/build_family.py
index f9f7261fe..9b612b4cb 100644
--- a/tools/build_family.py
+++ b/tools/build_family.py
@@ -41,11 +41,11 @@ if __name__ == '__main__':
# If examples are not specified in arguments, build all
all_examples = []
- for dir1 in os.scandir("examples"):
- if dir1.is_dir() and 'cmake-build' not in dir1.name:
- for entry in os.scandir(dir1.path):
- if entry.is_dir():
- all_examples.append(dir1.name + '/' + entry.name)
+ for d in os.scandir("examples"):
+ if d.is_dir() and 'cmake' not in d.name:
+ for entry in os.scandir(d.path):
+ if entry.is_dir() and 'cmake' not in entry.name:
+ all_examples.append(d.name + '/' + entry.name)
filter_with_input(all_examples)
all_examples.sort()
diff --git a/tools/cmake/cpu/cortex-m3.cmake b/tools/cmake/cpu/cortex-m3.cmake
new file mode 100644
index 000000000..b740ee44c
--- /dev/null
+++ b/tools/cmake/cpu/cortex-m3.cmake
@@ -0,0 +1,10 @@
+if (TOOLCHAIN STREQUAL "gcc")
+ list(APPEND TOOLCHAIN_COMMON_FLAGS
+ -mthumb
+ -mcpu=cortex-m3
+ )
+
+ set(FREERTOS_PORT GCC_ARM_CM3 CACHE INTERNAL "")
+else ()
+ # TODO support IAR
+endif ()
diff --git a/tools/cmake/cpu/cortex-m33.cmake b/tools/cmake/cpu/cortex-m33.cmake
new file mode 100644
index 000000000..fda277010
--- /dev/null
+++ b/tools/cmake/cpu/cortex-m33.cmake
@@ -0,0 +1,12 @@
+if (TOOLCHAIN STREQUAL "gcc")
+ list(APPEND TOOLCHAIN_COMMON_FLAGS
+ -mthumb
+ -mcpu=cortex-m33
+ -mfloat-abi=hard
+ -mfpu=fpv5-sp-d16
+ )
+
+ set(FREERTOS_PORT GCC_ARM_CM33_NTZ_NONSECURE CACHE INTERNAL "")
+else ()
+ # TODO support IAR
+endif ()
diff --git a/tools/cmake/cpu/cortex-m4.cmake b/tools/cmake/cpu/cortex-m4.cmake
new file mode 100644
index 000000000..5a2d16c05
--- /dev/null
+++ b/tools/cmake/cpu/cortex-m4.cmake
@@ -0,0 +1,12 @@
+if (TOOLCHAIN STREQUAL "gcc")
+ list(APPEND TOOLCHAIN_COMMON_FLAGS
+ -mthumb
+ -mcpu=cortex-m4
+ -mfloat-abi=hard
+ -mfpu=fpv4-sp-d16
+ )
+
+ set(FREERTOS_PORT GCC_ARM_CM4F CACHE INTERNAL "")
+else ()
+ # TODO support IAR
+endif ()
diff --git a/tools/cmake/cpu/cortex-m7.cmake b/tools/cmake/cpu/cortex-m7.cmake
new file mode 100644
index 000000000..481c86bc5
--- /dev/null
+++ b/tools/cmake/cpu/cortex-m7.cmake
@@ -0,0 +1,12 @@
+if (TOOLCHAIN STREQUAL "gcc")
+ list(APPEND TOOLCHAIN_COMMON_FLAGS
+ -mthumb
+ -mcpu=cortex-m7
+ -mfloat-abi=hard
+ -mfpu=fpv5-d16
+ )
+
+ set(FREERTOS_PORT GCC_ARM_CM7 CACHE INTERNAL "")
+else ()
+ # TODO support IAR
+endif ()
diff --git a/tools/cmake/toolchain/arm_gcc.cmake b/tools/cmake/toolchain/arm_gcc.cmake
new file mode 100644
index 000000000..c7f12f43a
--- /dev/null
+++ b/tools/cmake/toolchain/arm_gcc.cmake
@@ -0,0 +1,64 @@
+set(CMAKE_SYSTEM_NAME Generic)
+
+set(CMAKE_ASM_COMPILER "arm-none-eabi-gcc")
+set(CMAKE_C_COMPILER "arm-none-eabi-gcc")
+set(CMAKE_CXX_COMPILER "arm-none-eabi-g++")
+
+set(CMAKE_SIZE "arm-none-eabi-size" CACHE FILEPATH "")
+set(CMAKE_OBJCOPY "arm-none-eabi-objcopy" CACHE FILEPATH "")
+set(CMAKE_OBJDUMP "arm-none-eabi-objdump" CACHE FILEPATH "")
+
+set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
+
+# Look for includes and libraries only in the target system prefix.
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+
+# pass TOOLCHAIN_CPU to
+set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES CMAKE_SYSTEM_PROCESSOR)
+
+include(${CMAKE_CURRENT_LIST_DIR}/../cpu/${CMAKE_SYSTEM_PROCESSOR}.cmake)
+
+# enable all possible warnings for building examples
+list(APPEND TOOLCHAIN_COMMON_FLAGS
+ -fdata-sections
+ -ffunction-sections
+ -fsingle-precision-constant
+ -fno-strict-aliasing
+ )
+
+list(APPEND TOOLCHAIN_EXE_LINKER_FLAGS
+ -Wl,--print-memory-usage
+ -Wl,--gc-sections
+ -Wl,--cref
+ )
+
+list(APPEND TOOLCHAIN_WARNING_FLAGS
+ -Wall
+ -Wextra
+ -Werror
+ -Wfatal-errors
+ -Wdouble-promotion
+ -Wstrict-prototypes
+ -Wstrict-overflow
+ -Werror-implicit-function-declaration
+ -Wfloat-equal
+ -Wundef
+ -Wshadow
+ -Wwrite-strings
+ -Wsign-compare
+ -Wmissing-format-attribute
+ -Wunreachable-code
+ -Wcast-align
+ -Wcast-function-type
+ -Wcast-qual
+ -Wnull-dereference
+ -Wuninitialized
+ -Wunused
+ -Wreturn-type
+ -Wredundant-decls
+ )
+
+include(${CMAKE_CURRENT_LIST_DIR}/set_flags.cmake)
diff --git a/tools/cmake/toolchain/set_flags.cmake b/tools/cmake/toolchain/set_flags.cmake
new file mode 100644
index 000000000..6f74fe673
--- /dev/null
+++ b/tools/cmake/toolchain/set_flags.cmake
@@ -0,0 +1,24 @@
+include(CMakePrintHelpers)
+foreach (LANG IN ITEMS C CXX ASM)
+ # join the toolchain flags into a single string
+ list(APPEND TOOLCHAIN_${LANG}_FLAGS ${TOOLCHAIN_COMMON_FLAGS})
+ list(JOIN TOOLCHAIN_${LANG}_FLAGS " " TOOLCHAIN_${LANG}_FLAGS)
+ set(CMAKE_${LANG}_FLAGS_INIT "${TOOLCHAIN_${LANG}_FLAGS}")
+
+ #cmake_print_variables(CMAKE_${LANG}_FLAGS_INIT)
+
+ # optimization flags for LOG, LOGGER ?
+ #set(CMAKE_${LANG}_FLAGS_RELEASE_INIT "-Os")
+ #set(CMAKE_${LANG}_FLAGS_DEBUG_INIT "-O0")
+endforeach ()
+
+# Linker
+list(JOIN TOOLCHAIN_EXE_LINKER_FLAGS " " CMAKE_EXE_LINKER_FLAGS_INIT)
+
+# try_compile is cmake test compiling its own example,
+# pass -nostdlib to skip stdlib linking
+get_property(IS_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE)
+if (IS_IN_TRY_COMPILE)
+ set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -nostdlib")
+ set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -nostdlib")
+endif ()
diff --git a/tools/get_deps.py b/tools/get_deps.py
index dfe00b32a..b4739e940 100644
--- a/tools/get_deps.py
+++ b/tools/get_deps.py
@@ -4,67 +4,177 @@ from pathlib import Path
from multiprocessing import Pool
# Mandatory Dependencies that is always fetched
-# path, url, commit (Alphabet sorted by path)
+# path, url, commit, family (Alphabet sorted by path)
deps_mandatory = {
- 'lib/FreeRTOS-Kernel' : ['def7d2df2b0506d3d249334974f51e427c17a41c', 'https://github.com/FreeRTOS/FreeRTOS-Kernel.git' ],
- 'lib/lwip' : ['159e31b689577dbf69cf0683bbaffbd71fa5ee10', 'https://github.com/lwip-tcpip/lwip.git' ],
- 'tools/uf2' : ['19615407727073e36d81bf239c52108ba92e7660', 'https://github.com/microsoft/uf2.git' ],
+ 'lib/FreeRTOS-Kernel': ['https://github.com/FreeRTOS/FreeRTOS-Kernel.git',
+ '5f19e34f878af97810a7662a75eac59bd74d628b',
+ 'all'],
+ 'lib/lwip': ['https://github.com/lwip-tcpip/lwip.git',
+ '159e31b689577dbf69cf0683bbaffbd71fa5ee10',
+ 'all'],
+ 'tools/uf2': ['https://github.com/microsoft/uf2.git',
+ '19615407727073e36d81bf239c52108ba92e7660',
+ 'all'],
}
# Optional Dependencies per MCU
-# path, url, commit (Alphabet sorted by path)
+# path, url, commit, family (Alphabet sorted by path)
deps_optional = {
- 'hw/mcu/allwinner' : ['8e5e89e8e132c0fd90e72d5422e5d3d68232b756', 'https://github.com/hathach/allwinner_driver.git' ],
- 'hw/mcu/bridgetek/ft9xx/ft90x-sdk' : ['91060164afe239fcb394122e8bf9eb24d3194eb1', 'https://github.com/BRTSG-FOSS/ft90x-sdk.git' ],
- 'hw/mcu/broadcom' : ['08370086080759ed54ac1136d62d2ad24c6fa267', 'https://github.com/adafruit/broadcom-peripherals.git' ],
- 'hw/mcu/gd/nuclei-sdk' : ['7eb7bfa9ea4fbeacfafe1d5f77d5a0e6ed3922e7', 'https://github.com/Nuclei-Software/nuclei-sdk.git' ],
- 'hw/mcu/infineon/mtb-xmclib-cat3' : ['daf5500d03cba23e68c2f241c30af79cd9d63880', 'https://github.com/Infineon/mtb-xmclib-cat3.git' ],
- 'hw/mcu/microchip' : ['9e8b37e307d8404033bb881623a113931e1edf27', 'https://github.com/hathach/microchip_driver.git' ],
- 'hw/mcu/mindmotion/mm32sdk' : ['0b79559eb411149d36e073c1635c620e576308d4', 'https://github.com/hathach/mm32sdk.git' ],
- 'hw/mcu/nordic/nrfx' : ['281cc2e178fd9a470d844b3afdea9eb322a0b0e8', 'https://github.com/NordicSemiconductor/nrfx.git' ],
- 'hw/mcu/nuvoton' : ['2204191ec76283371419fbcec207da02e1bc22fa', 'https://github.com/majbthrd/nuc_driver.git' ],
- 'hw/mcu/nxp/lpcopen' : ['43c45c85405a5dd114fff0ea95cca62837740c13', 'https://github.com/hathach/nxp_lpcopen.git' ],
- 'hw/mcu/nxp/mcux-sdk' : ['ae2ab01d9d70ad00cd0e935c2552bd5f0e5c0294', 'https://github.com/NXPmicro/mcux-sdk.git' ],
- 'hw/mcu/nxp/nxp_sdk' : ['845c8fc49b6fb660f06a5c45225494eacb06f00c', 'https://github.com/hathach/nxp_sdk.git' ],
- 'hw/mcu/raspberry_pi/Pico-PIO-USB' : ['c3715ce94b6f6391856de56081d4d9b3e98fa93d', 'https://github.com/sekigon-gonnoc/Pico-PIO-USB.git' ],
- 'hw/mcu/renesas/fsp' : ['8dc14709f2a6518b43f71efad70d900b7718d9f1', 'https://github.com/renesas/fsp.git' ],
- 'hw/mcu/renesas/rx' : ['706b4e0cf485605c32351e2f90f5698267996023', 'https://github.com/kkitayam/rx_device.git' ],
- 'hw/mcu/silabs/cmsis-dfp-efm32gg12b' : ['f1c31b7887669cb230b3ea63f9b56769078960bc', 'https://github.com/cmsis-packs/cmsis-dfp-efm32gg12b.git' ],
- 'hw/mcu/sony/cxd56/spresense-exported-sdk' : ['2ec2a1538362696118dc3fdf56f33dacaf8f4067', 'https://github.com/sonydevworld/spresense-exported-sdk.git' ],
- 'hw/mcu/st/cmsis_device_f0' : ['2fc25ee22264bc27034358be0bd400b893ef837e', 'https://github.com/STMicroelectronics/cmsis_device_f0.git' ],
- 'hw/mcu/st/cmsis_device_f1' : ['6601104a6397299b7304fd5bcd9a491f56cb23a6', 'https://github.com/STMicroelectronics/cmsis_device_f1.git' ],
- 'hw/mcu/st/cmsis_device_f2' : ['182fcb3681ce116816feb41b7764f1b019ce796f', 'https://github.com/STMicroelectronics/cmsis_device_f2.git' ],
- 'hw/mcu/st/cmsis_device_f3' : ['5e4ee5ed7a7b6c85176bb70a9fd3c72d6eb99f1b', 'https://github.com/STMicroelectronics/cmsis_device_f3.git' ],
- 'hw/mcu/st/cmsis_device_f4' : ['2615e866fa48fe1ff1af9e31c348813f2b19e7ec', 'https://github.com/STMicroelectronics/cmsis_device_f4.git' ],
- 'hw/mcu/st/cmsis_device_f7' : ['fc676ef1ad177eb874eaa06444d3d75395fc51f4', 'https://github.com/STMicroelectronics/cmsis_device_f7.git' ],
- 'hw/mcu/st/cmsis_device_g0' : ['3a23e1224417f3f2d00300ecd620495e363f2094', 'https://github.com/STMicroelectronics/cmsis_device_g0.git' ],
- 'hw/mcu/st/cmsis_device_g4' : ['ce822adb1dc552b3aedd13621edbc7fdae124878', 'https://github.com/STMicroelectronics/cmsis_device_g4.git' ],
- 'hw/mcu/st/cmsis_device_h7' : ['60dc2c913203dc8629dc233d4384dcc41c91e77f', 'https://github.com/STMicroelectronics/cmsis_device_h7.git' ],
- 'hw/mcu/st/cmsis_device_l0' : ['06748ca1f93827befdb8b794402320d94d02004f', 'https://github.com/STMicroelectronics/cmsis_device_l0.git' ],
- 'hw/mcu/st/cmsis_device_l1' : ['7f16ec0a1c4c063f84160b4cc6bf88ad554a823e', 'https://github.com/STMicroelectronics/cmsis_device_l1.git' ],
- 'hw/mcu/st/cmsis_device_l4' : ['6ca7312fa6a5a460b5a5a63d66da527fdd8359a6', 'https://github.com/STMicroelectronics/cmsis_device_l4.git' ],
- 'hw/mcu/st/cmsis_device_l5' : ['d922865fc0326a102c26211c44b8e42f52c1e53d', 'https://github.com/STMicroelectronics/cmsis_device_l5.git' ],
- 'hw/mcu/st/cmsis_device_u5' : ['bc00f3c9d8a4e25220f84c26d414902cc6bdf566', 'https://github.com/STMicroelectronics/cmsis_device_u5.git' ],
- 'hw/mcu/st/cmsis_device_wb' : ['9c5d1920dd9fabbe2548e10561d63db829bb744f', 'https://github.com/STMicroelectronics/cmsis_device_wb.git' ],
- 'hw/mcu/st/stm32f0xx_hal_driver' : ['0e95cd88657030f640a11e690a8a5186c7712ea5', 'https://github.com/STMicroelectronics/stm32f0xx_hal_driver.git'],
- 'hw/mcu/st/stm32f1xx_hal_driver' : ['1dd9d3662fb7eb2a7f7d3bc0a4c1dc7537915a29', 'https://github.com/STMicroelectronics/stm32f1xx_hal_driver.git'],
- 'hw/mcu/st/stm32f2xx_hal_driver' : ['c75ace9b908a9aca631193ebf2466963b8ea33d0', 'https://github.com/STMicroelectronics/stm32f2xx_hal_driver.git'],
- 'hw/mcu/st/stm32f3xx_hal_driver' : ['1761b6207318ede021706e75aae78f452d72b6fa', 'https://github.com/STMicroelectronics/stm32f3xx_hal_driver.git'],
- 'hw/mcu/st/stm32f4xx_hal_driver' : ['04e99fbdabd00ab8f370f377c66b0a4570365b58', 'https://github.com/STMicroelectronics/stm32f4xx_hal_driver.git'],
- 'hw/mcu/st/stm32f7xx_hal_driver' : ['f7ffdf6bf72110e58b42c632b0a051df5997e4ee', 'https://github.com/STMicroelectronics/stm32f7xx_hal_driver.git'],
- 'hw/mcu/st/stm32g0xx_hal_driver' : ['e911b12c7f67084d7f6b76157a4c0d4e2ec3779c', 'https://github.com/STMicroelectronics/stm32g0xx_hal_driver.git'],
- 'hw/mcu/st/stm32g4xx_hal_driver' : ['8b4518417706d42eef5c14e56a650005abf478a8', 'https://github.com/STMicroelectronics/stm32g4xx_hal_driver.git'],
- 'hw/mcu/st/stm32h7xx_hal_driver' : ['d8461b980b59b1625207d8c4f2ce0a9c2a7a3b04', 'https://github.com/STMicroelectronics/stm32h7xx_hal_driver.git'],
- 'hw/mcu/st/stm32l0xx_hal_driver' : ['fbdacaf6f8c82a4e1eb9bd74ba650b491e97e17b', 'https://github.com/STMicroelectronics/stm32l0xx_hal_driver.git'],
- 'hw/mcu/st/stm32l1xx_hal_driver' : ['44efc446fa69ed8344e7fd966e68ed11043b35d9', 'https://github.com/STMicroelectronics/stm32l1xx_hal_driver.git'],
- 'hw/mcu/st/stm32l4xx_hal_driver' : ['aee3d5bf283ae5df87532b781bdd01b7caf256fc', 'https://github.com/STMicroelectronics/stm32l4xx_hal_driver.git'],
- 'hw/mcu/st/stm32l5xx_hal_driver' : ['675c32a75df37f39d50d61f51cb0dcf53f07e1cb', 'https://github.com/STMicroelectronics/stm32l5xx_hal_driver.git'],
- 'hw/mcu/st/stm32u5xx_hal_driver' : ['2e1d4cdb386e33391cb261dfff4fefa92e4aa35a', 'https://github.com/STMicroelectronics/stm32u5xx_hal_driver.git'],
- 'hw/mcu/st/stm32wbxx_hal_driver' : ['2c5f06638be516c1b772f768456ba637f077bac8', 'https://github.com/STMicroelectronics/stm32wbxx_hal_driver.git'],
- 'hw/mcu/ti' : ['143ed6cc20a7615d042b03b21e070197d473e6e5', 'https://github.com/hathach/ti_driver.git' ],
- 'hw/mcu/wch/ch32v307' : ['17761f5cf9dbbf2dcf665b7c04934188add20082', 'https://github.com/openwch/ch32v307.git' ],
- 'lib/CMSIS_5' : ['20285262657d1b482d132d20d755c8c330d55c1f', 'https://github.com/ARM-software/CMSIS_5.git' ],
- 'lib/sct_neopixel' : ['e73e04ca63495672d955f9268e003cffe168fcd8', 'https://github.com/gsteiert/sct_neopixel.git' ],
+ 'hw/mcu/allwinner': ['https://github.com/hathach/allwinner_driver.git',
+ '8e5e89e8e132c0fd90e72d5422e5d3d68232b756',
+ 'fc100s'],
+ 'hw/mcu/bridgetek/ft9xx/ft90x-sdk': ['https://github.com/BRTSG-FOSS/ft90x-sdk.git',
+ '91060164afe239fcb394122e8bf9eb24d3194eb1',
+ 'brtmm90x'],
+ 'hw/mcu/broadcom': ['https://github.com/adafruit/broadcom-peripherals.git',
+ '08370086080759ed54ac1136d62d2ad24c6fa267',
+ 'broadcom_32bit broadcom_64bit'],
+ 'hw/mcu/gd/nuclei-sdk': ['https://github.com/Nuclei-Software/nuclei-sdk.git',
+ '7eb7bfa9ea4fbeacfafe1d5f77d5a0e6ed3922e7',
+ 'gd32vf103'],
+ 'hw/mcu/infineon/mtb-xmclib-cat3': ['https://github.com/Infineon/mtb-xmclib-cat3.git',
+ 'daf5500d03cba23e68c2f241c30af79cd9d63880',
+ 'xmc4000'],
+ 'hw/mcu/microchip': ['https://github.com/hathach/microchip_driver.git',
+ '9e8b37e307d8404033bb881623a113931e1edf27',
+ 'sam3x samd11 samd21 samd51 same5x same7x saml2x samg'],
+ 'hw/mcu/mindmotion/mm32sdk': ['https://github.com/hathach/mm32sdk.git',
+ '0b79559eb411149d36e073c1635c620e576308d4',
+ 'mm32'],
+ 'hw/mcu/nordic/nrfx': ['https://github.com/NordicSemiconductor/nrfx.git',
+ '2527e3c8449cfd38aee41598e8af8492f410ed15',
+ 'nrf'],
+ 'hw/mcu/nuvoton': ['https://github.com/majbthrd/nuc_driver.git',
+ '2204191ec76283371419fbcec207da02e1bc22fa',
+ 'nuc'],
+ 'hw/mcu/nxp/lpcopen': ['https://github.com/hathach/nxp_lpcopen.git',
+ '43c45c85405a5dd114fff0ea95cca62837740c13',
+ 'lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43'],
+ 'hw/mcu/nxp/mcux-sdk': ['https://github.com/hathach/mcux-sdk.git',
+ '950819b7de9b32f92c3edf396bc5ffb8d66e7009',
+ 'kinetis_k32l lpc51 lpc54 lpc55 mcx imxrt'],
+ 'hw/mcu/nxp/nxp_sdk': ['https://github.com/hathach/nxp_sdk.git',
+ '845c8fc49b6fb660f06a5c45225494eacb06f00c',
+ 'kinetis_kl'],
+ 'hw/mcu/raspberry_pi/Pico-PIO-USB': ['https://github.com/sekigon-gonnoc/Pico-PIO-USB.git',
+ 'c3715ce94b6f6391856de56081d4d9b3e98fa93d',
+ 'rp2040'],
+ 'hw/mcu/renesas/fsp': ['https://github.com/renesas/fsp.git',
+ '8dc14709f2a6518b43f71efad70d900b7718d9f1',
+ 'ra'],
+ 'hw/mcu/renesas/rx': ['https://github.com/kkitayam/rx_device.git',
+ '706b4e0cf485605c32351e2f90f5698267996023',
+ 'rx'],
+ 'hw/mcu/silabs/cmsis-dfp-efm32gg12b': ['https://github.com/cmsis-packs/cmsis-dfp-efm32gg12b.git',
+ 'f1c31b7887669cb230b3ea63f9b56769078960bc',
+ 'efm32'],
+ 'hw/mcu/sony/cxd56/spresense-exported-sdk': ['https://github.com/sonydevworld/spresense-exported-sdk.git',
+ '2ec2a1538362696118dc3fdf56f33dacaf8f4067',
+ 'spresense'],
+ 'hw/mcu/st/cmsis_device_f0': ['https://github.com/STMicroelectronics/cmsis_device_f0.git',
+ '2fc25ee22264bc27034358be0bd400b893ef837e',
+ 'stm32f0'],
+ 'hw/mcu/st/cmsis_device_f1': ['https://github.com/STMicroelectronics/cmsis_device_f1.git',
+ '6601104a6397299b7304fd5bcd9a491f56cb23a6',
+ 'stm32f1'],
+ 'hw/mcu/st/cmsis_device_f2': ['https://github.com/STMicroelectronics/cmsis_device_f2.git',
+ '182fcb3681ce116816feb41b7764f1b019ce796f',
+ 'stm32f2'],
+ 'hw/mcu/st/cmsis_device_f3': ['https://github.com/STMicroelectronics/cmsis_device_f3.git',
+ '5e4ee5ed7a7b6c85176bb70a9fd3c72d6eb99f1b',
+ 'stm32f3'],
+ 'hw/mcu/st/cmsis_device_f4': ['https://github.com/STMicroelectronics/cmsis_device_f4.git',
+ '2615e866fa48fe1ff1af9e31c348813f2b19e7ec',
+ 'stm32f4'],
+ 'hw/mcu/st/cmsis_device_f7': ['https://github.com/STMicroelectronics/cmsis_device_f7.git',
+ 'fc676ef1ad177eb874eaa06444d3d75395fc51f4',
+ 'stm32f7'],
+ 'hw/mcu/st/cmsis_device_g0': ['https://github.com/STMicroelectronics/cmsis_device_g0.git',
+ '3a23e1224417f3f2d00300ecd620495e363f2094',
+ 'stm32g0'],
+ 'hw/mcu/st/cmsis_device_g4': ['https://github.com/STMicroelectronics/cmsis_device_g4.git',
+ 'ce822adb1dc552b3aedd13621edbc7fdae124878',
+ 'stm32g4'],
+ 'hw/mcu/st/cmsis_device_h7': ['https://github.com/STMicroelectronics/cmsis_device_h7.git',
+ '60dc2c913203dc8629dc233d4384dcc41c91e77f',
+ 'stm32h7'],
+ 'hw/mcu/st/cmsis_device_l0': ['https://github.com/STMicroelectronics/cmsis_device_l0.git',
+ '06748ca1f93827befdb8b794402320d94d02004f',
+ 'stm32l0'],
+ 'hw/mcu/st/cmsis_device_l1': ['https://github.com/STMicroelectronics/cmsis_device_l1.git',
+ '7f16ec0a1c4c063f84160b4cc6bf88ad554a823e',
+ 'stm32l1'],
+ 'hw/mcu/st/cmsis_device_l4': ['https://github.com/STMicroelectronics/cmsis_device_l4.git',
+ '6ca7312fa6a5a460b5a5a63d66da527fdd8359a6',
+ 'stm32l4'],
+ 'hw/mcu/st/cmsis_device_l5': ['https://github.com/STMicroelectronics/cmsis_device_l5.git',
+ 'd922865fc0326a102c26211c44b8e42f52c1e53d',
+ 'stm32l5'],
+ 'hw/mcu/st/cmsis_device_u5': ['https://github.com/STMicroelectronics/cmsis_device_u5.git',
+ 'bc00f3c9d8a4e25220f84c26d414902cc6bdf566',
+ 'stm32u5'],
+ 'hw/mcu/st/cmsis_device_wb': ['https://github.com/STMicroelectronics/cmsis_device_wb.git',
+ '9c5d1920dd9fabbe2548e10561d63db829bb744f',
+ 'stm32wb'],
+ 'hw/mcu/st/stm32f0xx_hal_driver': ['https://github.com/STMicroelectronics/stm32f0xx_hal_driver.git',
+ '0e95cd88657030f640a11e690a8a5186c7712ea5',
+ 'stm32f0'],
+ 'hw/mcu/st/stm32f1xx_hal_driver': ['https://github.com/STMicroelectronics/stm32f1xx_hal_driver.git',
+ '1dd9d3662fb7eb2a7f7d3bc0a4c1dc7537915a29',
+ 'stm32f1'],
+ 'hw/mcu/st/stm32f2xx_hal_driver': ['https://github.com/STMicroelectronics/stm32f2xx_hal_driver.git',
+ 'c75ace9b908a9aca631193ebf2466963b8ea33d0',
+ 'stm32f2'],
+ 'hw/mcu/st/stm32f3xx_hal_driver': ['https://github.com/STMicroelectronics/stm32f3xx_hal_driver.git',
+ '1761b6207318ede021706e75aae78f452d72b6fa',
+ 'stm32f3'],
+ 'hw/mcu/st/stm32f4xx_hal_driver': ['https://github.com/STMicroelectronics/stm32f4xx_hal_driver.git',
+ '04e99fbdabd00ab8f370f377c66b0a4570365b58',
+ 'stm32f4'],
+ 'hw/mcu/st/stm32f7xx_hal_driver': ['https://github.com/STMicroelectronics/stm32f7xx_hal_driver.git',
+ 'f7ffdf6bf72110e58b42c632b0a051df5997e4ee',
+ 'stm32f7'],
+ 'hw/mcu/st/stm32g0xx_hal_driver': ['https://github.com/STMicroelectronics/stm32g0xx_hal_driver.git',
+ 'e911b12c7f67084d7f6b76157a4c0d4e2ec3779c',
+ 'stm32g0'],
+ 'hw/mcu/st/stm32g4xx_hal_driver': ['https://github.com/STMicroelectronics/stm32g4xx_hal_driver.git',
+ '8b4518417706d42eef5c14e56a650005abf478a8',
+ 'stm32g4'],
+ 'hw/mcu/st/stm32h7xx_hal_driver': ['https://github.com/STMicroelectronics/stm32h7xx_hal_driver.git',
+ 'd8461b980b59b1625207d8c4f2ce0a9c2a7a3b04',
+ 'stm32h7'],
+ 'hw/mcu/st/stm32l0xx_hal_driver': ['https://github.com/STMicroelectronics/stm32l0xx_hal_driver.git',
+ 'fbdacaf6f8c82a4e1eb9bd74ba650b491e97e17b',
+ 'stm32l0'],
+ 'hw/mcu/st/stm32l1xx_hal_driver': ['https://github.com/STMicroelectronics/stm32l1xx_hal_driver.git',
+ '44efc446fa69ed8344e7fd966e68ed11043b35d9',
+ 'stm32l1'],
+ 'hw/mcu/st/stm32l4xx_hal_driver': ['https://github.com/STMicroelectronics/stm32l4xx_hal_driver.git',
+ 'aee3d5bf283ae5df87532b781bdd01b7caf256fc',
+ 'stm32l4'],
+ 'hw/mcu/st/stm32l5xx_hal_driver': ['https://github.com/STMicroelectronics/stm32l5xx_hal_driver.git',
+ '675c32a75df37f39d50d61f51cb0dcf53f07e1cb',
+ 'stm32l5'],
+ 'hw/mcu/st/stm32u5xx_hal_driver': ['https://github.com/STMicroelectronics/stm32u5xx_hal_driver.git',
+ '2e1d4cdb386e33391cb261dfff4fefa92e4aa35a',
+ 'stm32u5'],
+ 'hw/mcu/st/stm32wbxx_hal_driver': ['https://github.com/STMicroelectronics/stm32wbxx_hal_driver.git',
+ '2c5f06638be516c1b772f768456ba637f077bac8',
+ 'stm32wb'],
+ 'hw/mcu/ti': ['https://github.com/hathach/ti_driver.git',
+ '143ed6cc20a7615d042b03b21e070197d473e6e5',
+ 'msp430 msp432e4 tm4c123'],
+ 'hw/mcu/wch/ch32v307': ['https://github.com/openwch/ch32v307.git',
+ '17761f5cf9dbbf2dcf665b7c04934188add20082',
+ 'ch32v307'],
+ 'lib/CMSIS_5': ['https://github.com/ARM-software/CMSIS_5.git',
+ '20285262657d1b482d132d20d755c8c330d55c1f',
+ 'imxrt kinetis_k32l lpc51 lpc54 lpc55 mcx mm32 msp432e4 nrf ra saml2x'
+ 'stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32g0 stm32g4 '
+ 'stm32h7 stm32l0 stm32l1 stm32l4 stm32l5 stm32u5 stm32wb'],
+ 'lib/sct_neopixel': ['https://github.com/gsteiert/sct_neopixel.git',
+ 'e73e04ca63495672d955f9268e003cffe168fcd8',
+ 'lpc55'],
}
# combined 2 deps
@@ -78,8 +188,10 @@ def get_a_dep(d):
if d not in deps_all.keys():
print('{} is not found in dependency list')
return 1
- commit = deps_all[d][0]
- url = deps_all[d][1]
+ url = deps_all[d][0]
+ commit = deps_all[d][1]
+ families = deps_all[d][2]
+
print('cloning {} with {}'.format(d, url))
p = Path(TOP / d)
@@ -103,14 +215,26 @@ def get_a_dep(d):
return 0
+# Arguments can be
+# - family name
+# - specific deps path
+# - all
if __name__ == "__main__":
status = 0
deps = list(deps_mandatory.keys())
- # get all if executed with all as argument
+ # get all if 'all' is argument
if len(sys.argv) == 2 and sys.argv[1] == 'all':
- deps += deps_optional
+ deps += deps_optional.keys()
else:
- deps += sys.argv[1:]
+ for arg in sys.argv[1:]:
+ if arg in deps_all.keys():
+ # if arg is a dep, add it
+ deps.append(arg)
+ else:
+ # arg is a family name, add all deps of that family
+ for d in deps_optional:
+ if arg in deps_optional[d][2]:
+ deps.append(d)
with Pool() as pool:
status = sum(pool.map(get_a_dep, deps))
diff --git a/tools/iar_template.ipcf b/tools/iar_template.ipcf
index 2d262c414..6ea1d576d 100644
--- a/tools/iar_template.ipcf
+++ b/tools/iar_template.ipcf
@@ -58,6 +58,13 @@
$TUSB_DIR$/src/host/hub.c
$TUSB_DIR$/src/host/usbh.c
+
+ $TUSB_DIR$/src/portable/bridgetek/ft9xx/dcd_ft9xx.c
+
+
+ $TUSB_DIR$/src/portable/chipidea/ci_hs/dcd_ci_hs.c
+ $TUSB_DIR$/src/portable/chipidea/ci_hs/hcd_ci_hs.c
+
$TUSB_DIR$/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -72,6 +79,7 @@
$TUSB_DIR$/src/portable/mentor/musb/dcd_musb.c
+ $TUSB_DIR$/src/portable/mentor/musb/hcd_musb.c
$TUSB_DIR$/src/portable/microchip/samd/dcd_samd.c
@@ -82,6 +90,12 @@
$TUSB_DIR$/src/portable/microchip/samx7x/dcd_samx7x.c
+
+ $TUSB_DIR$/src/portable/microchip/pic/dcd_pic.c
+
+
+ $TUSB_DIR$/src/portable/microchip/pic32mz/dcd_pic32mz.c
+
$TUSB_DIR$/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
@@ -99,6 +113,7 @@
$TUSB_DIR$/src/portable/nxp/khci/dcd_khci.c
+ $TUSB_DIR$/src/portable/nxp/khci/hcd_khci.c
$TUSB_DIR$/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
@@ -114,14 +129,17 @@
$TUSB_DIR$/src/portable/ohci/ohci.c
+
+ $TUSB_DIR$/src/portable/raspberrypi/pio_usb/dcd_pio_usb.c
+ $TUSB_DIR$/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
+
$TUSB_DIR$/src/portable/raspberrypi/rp2040/dcd_rp2040.c
$TUSB_DIR$/src/portable/raspberrypi/rp2040/hcd_rp2040.c
- $TUSB_DIR$/src/portable/raspberrypi/rp2040/rp2040_usb.c
$TUSB_DIR$/src/portable/renesas/rusb2/dcd_rusb2.c
- $TUSB_DIR$/src/portable/renesas/rusb2/hcd_rusb2.c
+ $TUSB_DIR$/src/portable/renesas/rusb2/hcd_rusb2.c
$TUSB_DIR$/src/portable/sony/cxd56/dcd_cxd56.c
@@ -129,12 +147,18 @@
$TUSB_DIR$/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+
+ $TUSB_DIR$/src/portable/sunxi/dcd_sunxi_musb.c
+
$TUSB_DIR$/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c
$TUSB_DIR$/src/portable/valentyusb/eptri/dcd_eptri.c
+
+ $TUSB_DIR$/src/portable/wch/ch32v307/dcd_usbhs.c
+
$TUSB_DIR$/lib/SEGGER_RTT/RTT/SEGGER_RTT.c
$TUSB_DIR$/lib/SEGGER_RTT/RTT/SEGGER_RTT_printf.c
diff --git a/tools/make/cpu/cortex-m33.mk b/tools/make/cpu/cortex-m33.mk
new file mode 100644
index 000000000..3d12b01fd
--- /dev/null
+++ b/tools/make/cpu/cortex-m33.mk
@@ -0,0 +1,14 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mthumb \
+ -mcpu=cortex-m33 \
+ -mfloat-abi=hard \
+ -mfpu=fpv5-sp-d16 \
+
+ #-mfpu=fpv5-d16 \
+
+ #set(FREERTOS_PORT GCC_ARM_CM33_NONSECURE CACHE INTERNAL "")
+ FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/ARM_CM33_NTZ/non_secure
+else ifeq ($(TOOLCHAIN),iar)
+ # TODO support IAR
+endif
diff --git a/tools/make/cpu/cortex-m4.mk b/tools/make/cpu/cortex-m4.mk
new file mode 100644
index 000000000..890feefe3
--- /dev/null
+++ b/tools/make/cpu/cortex-m4.mk
@@ -0,0 +1,12 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mthumb \
+ -mcpu=cortex-m4 \
+ -mfloat-abi=hard \
+ -mfpu=fpv4-sp-d16 \
+
+ #set(FREERTOS_PORT GCC_ARM_CM4F CACHE INTERNAL "")
+ FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/ARM_CM4F
+else ifeq ($(TOOLCHAIN),iar)
+ # TODO support IAR
+endif
diff --git a/tools/make/cpu/cortex-m7.mk b/tools/make/cpu/cortex-m7.mk
new file mode 100644
index 000000000..504ffd486
--- /dev/null
+++ b/tools/make/cpu/cortex-m7.mk
@@ -0,0 +1,12 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mthumb \
+ -mcpu=cortex-m7 \
+ -mfloat-abi=hard \
+ -mfpu=fpv5-d16 \
+
+ #set(FREERTOS_PORT GCC_ARM_CM7 CACHE INTERNAL "")
+ FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/ARM_CM7/r0p1
+else ifeq ($(TOOLCHAIN),iar)
+ # TODO support IAR
+endif