diff --git a/.circleci/config.yml b/.circleci/config.yml
index fd5631e2e..0b11b50e4 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -20,12 +20,12 @@ jobs:
BUILDSYSTEM_TOOLCHAIN=(
"cmake arm-clang"
+ "cmake esp-idf"
"make aarch64-gcc"
"make arm-gcc"
"make msp430-gcc"
"make riscv-gcc"
"make rx-gcc"
- "cmake esp-idf"
)
# only build IAR if not forked PR, since IAR token is not shared
diff --git a/.circleci/config2.yml b/.circleci/config2.yml
index 3b0294168..d86a3f662 100644
--- a/.circleci/config2.yml
+++ b/.circleci/config2.yml
@@ -10,17 +10,7 @@ commands:
- run:
name: Set toolchain url and key
command: |
- TOOLCHAIN_JSON='{
- "aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz",
- "arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz",
- "arm-gcc": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v13.2.1-1.1/xpack-arm-none-eabi-gcc-13.2.1-1.1-linux-x64.tar.gz",
- "msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2",
- "riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz",
- "rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run",
- "arm-iar": "https://updates.iar.com/FileStore/STANDARD/001/003/322/cxarm-9.60.3.deb"
- }'
- toolchain_url=$(echo $TOOLCHAIN_JSON | jq -r '.["<< parameters.toolchain >>"]')
-
+ toolchain_url=$(jq -r '."<< parameters.toolchain >>"' .github/actions/setup_toolchain/toolchain.json)
# only cache if not a github link
if [[ $toolchain_url != "https://github.com"* ]]; then
echo "<< parameters.toolchain >>-$toolchain_url" > toolchain_key
@@ -121,7 +111,6 @@ commands:
TOOLCHAIN_OPTION="--toolchain clang"
elif [ << parameters.toolchain >> == arm-iar ]; then
TOOLCHAIN_OPTION="--toolchain iar"
- echo IAR_LMS_CLOUD_URL=$IAR_LMS_CLOUD_URL
iccarm --version
elif [ << parameters.toolchain >> == arm-gcc ]; then
TOOLCHAIN_OPTION="--toolchain gcc"
diff --git a/.github/actions/setup_toolchain/action.yml b/.github/actions/setup_toolchain/action.yml
index 8305daa24..6fd5c9d4e 100644
--- a/.github/actions/setup_toolchain/action.yml
+++ b/.github/actions/setup_toolchain/action.yml
@@ -17,7 +17,7 @@ runs:
if: inputs.toolchain == 'arm-gcc'
uses: carlosperate/arm-none-eabi-gcc-action@v1
with:
- release: '13.2.Rel1'
+ release: '14.2.Rel1'
- name: Pull ESP-IDF docker
if: inputs.toolchain == 'esp-idf'
@@ -28,18 +28,10 @@ runs:
- name: Get Toolchain URL
if: >-
inputs.toolchain != 'arm-gcc' &&
- inputs.toolchain != 'arm-iar' &&
inputs.toolchain != 'esp-idf'
id: set-toolchain-url
run: |
- TOOLCHAIN_JSON='{
- "aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz",
- "arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz",
- "msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2",
- "riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz",
- "rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run"
- }'
- TOOLCHAIN_URL=$(echo $TOOLCHAIN_JSON | jq -r '.["${{ inputs.toolchain }}"]')
+ TOOLCHAIN_URL=$(jq -r '."${{ inputs.toolchain }}"' .github/actions/setup_toolchain/toolchain.json)
echo "toolchain_url=$TOOLCHAIN_URL"
echo "toolchain_url=$TOOLCHAIN_URL" >> $GITHUB_OUTPUT
shell: bash
@@ -47,7 +39,6 @@ runs:
- name: Download Toolchain
if: >-
inputs.toolchain != 'arm-gcc' &&
- inputs.toolchain != 'arm-iar' &&
inputs.toolchain != 'esp-idf'
uses: ./.github/actions/setup_toolchain/download
with:
diff --git a/.github/actions/setup_toolchain/download/action.yml b/.github/actions/setup_toolchain/download/action.yml
index 813197208..ce9643010 100644
--- a/.github/actions/setup_toolchain/download/action.yml
+++ b/.github/actions/setup_toolchain/download/action.yml
@@ -23,17 +23,25 @@ runs:
if: steps.cache-toolchain-download.outputs.cache-hit != 'true'
run: |
mkdir -p ~/cache/${{ inputs.toolchain }}
- wget --progress=dot:giga ${{ inputs.toolchain_url }} -O toolchain.tar.gz
+
if [[ ${{ inputs.toolchain }} == rx-gcc ]]; then
- mv toolchain.tar.gz toolchain.run
+ wget --progress=dot:giga ${{ inputs.toolchain_url }} -O toolchain.run
chmod +x toolchain.run
./toolchain.run -p ~/cache/${{ inputs.toolchain }}/gnurx -y
+ elif [[ ${{ inputs.toolchain }} == arm-iar ]]; then
+ wget --progress=dot:giga ${{ inputs.toolchain_url }} -O ~/cache/${{ inputs.toolchain }}/cxarm.deb
else
+ wget --progress=dot:giga ${{ inputs.toolchain_url }} -O toolchain.tar.gz
tar -C ~/cache/${{ inputs.toolchain }} -xaf toolchain.tar.gz
fi
shell: bash
- - name: Set Toolchain Path
+ - name: Setup Toolchain
run: |
- echo >> $GITHUB_PATH `echo ~/cache/${{ inputs.toolchain }}/*/bin`
+ if [[ ${{ inputs.toolchain }} == arm-iar ]]; then
+ sudo apt-get install -y ~/cache/${{ inputs.toolchain }}/cxarm.deb
+ echo >> $GITHUB_PATH "/opt/iar/cxarm/arm/bin"
+ else
+ echo >> $GITHUB_PATH `echo ~/cache/${{ inputs.toolchain }}/*/bin`
+ fi
shell: bash
diff --git a/.github/actions/setup_toolchain/toolchain.json b/.github/actions/setup_toolchain/toolchain.json
new file mode 100644
index 000000000..f7123ef11
--- /dev/null
+++ b/.github/actions/setup_toolchain/toolchain.json
@@ -0,0 +1,9 @@
+{
+ "aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz",
+ "arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz",
+ "arm-gcc": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v14.2.1-1.1/xpack-arm-none-eabi-gcc-14.2.1-1.1-linux-x64.tar.gz",
+ "msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2",
+ "riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz",
+ "rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run",
+ "arm-iar": "https://netstorage.iar.com/FileStore/STANDARD/001/003/583/cxarm-9.60.4.deb"
+}
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 547763bd8..28447cc80 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -8,8 +8,8 @@ on:
- 'examples/**'
- 'lib/**'
- 'hw/**'
- - 'tools/get_deps.py'
- 'tools/build.py'
+ - 'tools/get_deps.py'
- '.github/actions/**'
- '.github/workflows/build.yml'
- '.github/workflows/build_util.yml'
@@ -21,8 +21,9 @@ on:
- 'examples/**'
- 'lib/**'
- 'hw/**'
- - 'tools/get_deps.py'
+ - 'test/hil/**'
- 'tools/build.py'
+ - 'tools/get_deps.py'
- '.github/actions/**'
- '.github/workflows/build.yml'
- '.github/workflows/build_util.yml'
@@ -31,11 +32,20 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
+env:
+ HIL_JSON: test/hil/tinyusb.json
+
jobs:
+ # ---------------------------------------
+ #
+ # Build
+ #
+ # ---------------------------------------
set-matrix:
runs-on: ubuntu-latest
outputs:
json: ${{ steps.set-matrix-json.outputs.matrix }}
+ hil_json: ${{ steps.set-matrix-json.outputs.hil_matrix }}
steps:
- name: Checkout TinyUSB
uses: actions/checkout@v4
@@ -43,9 +53,14 @@ jobs:
- name: Generate matrix json
id: set-matrix-json
run: |
+ # build matrix
MATRIX_JSON=$(python .github/workflows/ci_set_matrix.py)
echo "matrix=$MATRIX_JSON"
echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT
+ # hil matrix
+ HIL_MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py ${{ env.HIL_JSON }})
+ echo "hil_matrix=$HIL_MATRIX_JSON"
+ echo "hil_matrix=$HIL_MATRIX_JSON" >> $GITHUB_OUTPUT
# ---------------------------------------
# Build CMake
@@ -85,7 +100,7 @@ jobs:
- 'msp430-gcc'
- 'riscv-gcc'
- 'rx-gcc'
- - 'esp-idf' # build-system is ignored
+ - 'esp-idf'
with:
build-system: 'make'
toolchain: ${{ matrix.toolchain }}
@@ -110,37 +125,26 @@ jobs:
one-per-family: true
# ---------------------------------------
- # Build IAR on HFP self-hosted
- # Since IAR Token secret is not passed to forked PR, only build on PR from the same repo
+ # Build IAR
+ # Since IAR Token secret is not passed to forked PR, only build non-forked PR with make.
+ # cmake is built by circle-ci. Due to IAR limit capacity, only build oe per family
# ---------------------------------------
arm-iar:
- if: github.repository_owner == 'hathach' && github.event_name == 'push'
+ if: false # disable for now since we got reach capacity limit too often
+ #if: github.event_name == 'push' && github.repository_owner == 'hathach'
needs: set-matrix
- runs-on: [self-hosted, Linux, X64, hifiphile]
- env:
- BUILD_ARGS: ${{ join(fromJSON(needs.set-matrix.outputs.json)['arm-iar'], ' ') }}
- IAR_LMS_CLOUD_URL: ${{ vars.IAR_LMS_CLOUD_URL }}
- IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }}
- steps:
- - name: Clean workspace
- run: |
- echo "Cleaning up previous run"
- rm -rf "${{ github.workspace }}"
- mkdir -p "${{ github.workspace }}"
-
- - name: Toolchain version
- run: |
- echo IAR_LMS_CLOUD_URL=$IAR_LMS_CLOUD_URL
- iccarm --version
-
- - name: Checkout TinyUSB
- uses: actions/checkout@v4
-
- - name: Get Dependencies
- run: python3 tools/get_deps.py $BUILD_ARGS
-
- - name: Build
- run: python3 tools/build.py --one-per-family --toolchain iar $BUILD_ARGS
+ uses: ./.github/workflows/build_util.yml
+ secrets: inherit
+ strategy:
+ fail-fast: false
+ matrix:
+ build-system:
+ - 'make'
+ with:
+ build-system: ${{ matrix.build-system }}
+ toolchain: 'arm-iar'
+ build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)['arm-iar']) }}
+ one-per-family: true
# ---------------------------------------
# Zephyr
@@ -162,3 +166,107 @@ jobs:
run: |
west build -b pca10056 -d examples/device/cdc_msc/build examples/device/cdc_msc -- -DRTOS=zephyr
west build -b pca10056 -d examples/device/msc_dual_lun/build examples/device/msc_dual_lun -- -DRTOS=zephyr
+
+ # ---------------------------------------
+ #
+ # Hardware in the loop (HIL)
+ # Run on PR only (hil-tinyusb), hil-hfp only run on non-forked PR
+ # ---------------------------------------
+
+ # ---------------------------------------
+ # Build arm-gcc
+ # ---------------------------------------
+ hil-build:
+ if: |
+ github.repository_owner == 'hathach' &&
+ (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch')
+ needs: set-matrix
+ uses: ./.github/workflows/build_util.yml
+ strategy:
+ fail-fast: false
+ matrix:
+ toolchain:
+ - 'arm-gcc'
+ - 'esp-idf'
+ with:
+ build-system: 'cmake'
+ toolchain: ${{ matrix.toolchain }}
+ build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.hil_json)[matrix.toolchain]) }}
+ one-per-family: true
+ upload-artifacts: true
+
+ # ---------------------------------------
+ # Hardware in the loop (HIL)
+ # self-hosted on local VM, for attached hardware checkout HIL_JSON
+ # ---------------------------------------
+ hil-tinyusb:
+ if: |
+ github.repository_owner == 'hathach' &&
+ (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch')
+ needs: hil-build
+ runs-on: [self-hosted, X64, hathach, hardware-in-the-loop]
+ steps:
+ - name: Clean workspace
+ run: |
+ echo "Cleaning up previous run"
+ rm -rf "${{ github.workspace }}"
+ mkdir -p "${{ github.workspace }}"
+
+ - name: Checkout TinyUSB
+ uses: actions/checkout@v4
+ with:
+ sparse-checkout: test/hil
+
+ - name: Download Artifacts
+ uses: actions/download-artifact@v4
+ with:
+ path: cmake-build
+ merge-multiple: true
+
+ - name: Test on actual hardware
+ run: |
+ ls cmake-build/
+ python3 test/hil/hil_test.py ${{ env.HIL_JSON }}
+
+ # ---------------------------------------
+ # Hardware in the loop (HIL)
+ # self-hosted by HFP, build with IAR toolchain, for attached hardware checkout test/hil/hfp.json
+ # Since IAR Token secret is not passed to forked PR, only build non-forked PR
+ # ---------------------------------------
+ hil-hfp:
+ if: |
+ github.repository_owner == 'hathach' &&
+ github.event.pull_request.head.repo.fork == false &&
+ (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch')
+ runs-on: [self-hosted, Linux, X64, hifiphile]
+ env:
+ IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }}
+ steps:
+ - name: Clean workspace
+ run: |
+ echo "Cleaning up previous run"
+ rm -rf "${{ github.workspace }}"3
+ mkdir -p "${{ github.workspace }}"
+
+ - name: Toolchain version
+ run: |
+ iccarm --version
+
+ - name: Checkout TinyUSB
+ uses: actions/checkout@v4
+
+ - name: Get build boards
+ run: |
+ MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py test/hil/hfp.json)
+ BUILD_ARGS=$(echo $MATRIX_JSON | jq -r '.["arm-gcc"] | join(" ")')
+ echo "BUILD_ARGS=$BUILD_ARGS"
+ echo "BUILD_ARGS=$BUILD_ARGS" >> $GITHUB_ENV
+
+ - name: Get Dependencies
+ run: python3 tools/get_deps.py $BUILD_ARGS
+
+ - name: Build
+ run: python3 tools/build.py --toolchain iar $BUILD_ARGS
+
+ - name: Test on actual hardware (hardware in the loop)
+ run: python3 test/hil/hil_test.py hfp.json
diff --git a/.github/workflows/build_util.yml b/.github/workflows/build_util.yml
index 2de68c6f3..a2c96f3c0 100644
--- a/.github/workflows/build_util.yml
+++ b/.github/workflows/build_util.yml
@@ -58,6 +58,8 @@ jobs:
shell: bash
- name: Build
+ env:
+ IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }}
run: |
if [ "${{ inputs.toolchain }}" == "esp-idf" ]; then
docker run --rm -v $PWD:/project -w /project espressif/idf:tinyusb python tools/build.py ${{ matrix.arg }}
diff --git a/.github/workflows/ci_set_matrix.py b/.github/workflows/ci_set_matrix.py
index 410508246..fa73dc1b6 100755
--- a/.github/workflows/ci_set_matrix.py
+++ b/.github/workflows/ci_set_matrix.py
@@ -44,9 +44,10 @@ family_list = {
"stm32l0 stm32l4": ["arm-gcc", "arm-clang", "arm-iar"],
"stm32u5 stm32wb": ["arm-gcc", "arm-clang", "arm-iar"],
"xmc4000": ["arm-gcc"],
- "-bespressif_kaluga_1": ["esp-idf"],
- "-bespressif_s3_devkitm": ["esp-idf"],
- "-bespressif_p4_function_ev": ["esp-idf"],
+ "-bespressif_s2_devkitc": ["esp-idf"],
+ # S3, P4 will be built by hil test
+ # "-bespressif_s3_devkitm": ["esp-idf"],
+ # "-bespressif_p4_function_ev": ["esp-idf"],
}
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index be4c2dd87..a22c65c79 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -66,7 +66,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -93,7 +93,7 @@ jobs:
./.github/workflows/codeql-buildscript.sh
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
upload: false
@@ -129,7 +129,7 @@ jobs:
sarif_file: ${{ steps.step1.outputs.sarif-output }}
category: "/language:${{matrix.language}}"
- - name: Archive CodeQL results
+ - name: Upload CodeQL results as an artifact
uses: actions/upload-artifact@v4
with:
name: codeql-results
diff --git a/.github/workflows/hil_test.yml b/.github/workflows/hil_test.yml
deleted file mode 100644
index c890933ec..000000000
--- a/.github/workflows/hil_test.yml
+++ /dev/null
@@ -1,130 +0,0 @@
-name: Hardware Test
-
-on:
- workflow_dispatch:
- pull_request:
- branches: [ master ]
- paths:
- - 'src/**'
- - 'examples/**'
- - 'lib/**'
- - 'hw/**'
- - 'test/hil/**'
- - 'tools/get_deps.py'
- - '.github/actions/**'
- - '.github/workflows/hil_test.yml'
-concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}
- cancel-in-progress: true
-
-env:
- HIL_JSON: test/hil/tinyusb.json
-
-jobs:
- set-matrix:
- runs-on: ubuntu-latest
- outputs:
- json: ${{ steps.set-matrix-json.outputs.matrix }}
- steps:
- - name: Checkout TinyUSB
- uses: actions/checkout@v4
-
- - name: Generate matrix json
- id: set-matrix-json
- run: |
- MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py ${{ env.HIL_JSON }})
- echo "matrix=$MATRIX_JSON"
- echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT
-
- # ---------------------------------------
- # Build arm-gcc
- # ---------------------------------------
- build:
- if: github.repository_owner == 'hathach'
- needs: set-matrix
- uses: ./.github/workflows/build_util.yml
- strategy:
- fail-fast: false
- matrix:
- toolchain:
- - 'arm-gcc'
- - 'esp-idf'
- with:
- build-system: 'cmake'
- toolchain: ${{ matrix.toolchain }}
- build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain]) }}
- one-per-family: true
- upload-artifacts: true
-
- # ---------------------------------------
- # Hardware in the loop (HIL)
- # self-hosted on local VM, for attached hardware checkout HIL_JSON
- # ---------------------------------------
- hil-tinyusb:
- if: github.repository_owner == 'hathach'
- needs: build
- runs-on: [self-hosted, X64, hathach, hardware-in-the-loop]
- steps:
- - name: Clean workspace
- run: |
- echo "Cleaning up previous run"
- rm -rf "${{ github.workspace }}"
- mkdir -p "${{ github.workspace }}"
-
- - name: Checkout TinyUSB
- uses: actions/checkout@v4
- with:
- sparse-checkout: test/hil
-
- - name: Download Artifacts
- uses: actions/download-artifact@v4
- with:
- path: cmake-build
- merge-multiple: true
-
- - name: Test on actual hardware
- run: |
- ls cmake-build/
- python3 test/hil/hil_test.py ${{ env.HIL_JSON }}
-
- # ---------------------------------------
- # Hardware in the loop (HIL)
- # self-hosted by HFP, build with IAR toolchain, for attached hardware checkout test/hil/hfp.json
- # Since IAR Token secret is not passed to forked PR, only build on PR from the same repo
- # ---------------------------------------
- hil-hfp:
- if: github.repository_owner == 'hathach' && github.event.pull_request.head.repo.fork == false
- runs-on: [self-hosted, Linux, X64, hifiphile]
- env:
- IAR_LMS_CLOUD_URL: ${{ vars.IAR_LMS_CLOUD_URL }}
- IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }}
- steps:
- - name: Clean workspace
- run: |
- echo "Cleaning up previous run"
- rm -rf "${{ github.workspace }}"
- mkdir -p "${{ github.workspace }}"
-
- - name: Toolchain version
- run: |
- echo IAR_LMS_CLOUD_URL=$IAR_LMS_CLOUD_URL
- iccarm --version
-
- - name: Checkout TinyUSB
- uses: actions/checkout@v4
-
- - name: Get build boards
- run: |
- MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py test/hil/hfp.json)
- BUILD_ARGS=$(echo $MATRIX_JSON | jq -r '.["arm-gcc"] | join(" ")')
- echo "BUILD_ARGS=$BUILD_ARGS"
- echo "BUILD_ARGS=$BUILD_ARGS" >> $GITHUB_ENV
-
- - name: Get Dependencies
- run: python3 tools/get_deps.py $BUILD_ARGS
-
- - name: Build
- run: python3 tools/build.py --toolchain iar $BUILD_ARGS
-
- - name: Test on actual hardware (hardware in the loop)
- run: python3 test/hil/hil_test.py hfp.json
diff --git a/.idea/cmake.xml b/.idea/cmake.xml
index 7365e13a8..dd219bc77 100644
--- a/.idea/cmake.xml
+++ b/.idea/cmake.xml
@@ -6,13 +6,13 @@
-
-
+
+
-
+
@@ -94,7 +94,8 @@
-
+
+
@@ -166,7 +167,6 @@
-
\ No newline at end of file
diff --git a/.idea/debugServers/esp32s2.xml b/.idea/debugServers/esp32s2.xml
new file mode 100644
index 000000000..6a4aff3da
--- /dev/null
+++ b/.idea/debugServers/esp32s2.xml
@@ -0,0 +1,14 @@
+
+
+
+ $USER_HOME$/.espressif/tools/xtensa-esp-elf-gdb/14.2_20240403/xtensa-esp-elf-gdb/bin/xtensa-esp32s2-elf-gdb
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/debugServers/rp2350.xml b/.idea/debugServers/rp2350.xml
index 5e092f3c4..52243a297 100644
--- a/.idea/debugServers/rp2350.xml
+++ b/.idea/debugServers/rp2350.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/debugServers/rt1060.xml b/.idea/debugServers/rt1060.xml
index 3325cc81f..cbd295b4e 100644
--- a/.idea/debugServers/rt1060.xml
+++ b/.idea/debugServers/rt1060.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/.idea/debugServers/rt1064.xml b/.idea/debugServers/rt1064.xml
index 4dc38ef63..4fb2fdf6a 100644
--- a/.idea/debugServers/rt1064.xml
+++ b/.idea/debugServers/rt1064.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/.idea/debugServers/sam21.xml b/.idea/debugServers/sam21.xml
index d8763b33b..3f6735bd1 100644
--- a/.idea/debugServers/sam21.xml
+++ b/.idea/debugServers/sam21.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/.idea/debugServers/sam51.xml b/.idea/debugServers/sam51.xml
index 0d15ff856..99a92c174 100644
--- a/.idea/debugServers/sam51.xml
+++ b/.idea/debugServers/sam51.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/.idea/debugServers/stm32f769.xml b/.idea/debugServers/stm32f769.xml
new file mode 100644
index 000000000..22a452218
--- /dev/null
+++ b/.idea/debugServers/stm32f769.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/debugServers/stm32h563.xml b/.idea/debugServers/stm32h563.xml
new file mode 100644
index 000000000..637839314
--- /dev/null
+++ b/.idea/debugServers/stm32h563.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/debugServers/stm32h743.xml b/.idea/debugServers/stm32h743.xml
new file mode 100644
index 000000000..b04e4a708
--- /dev/null
+++ b/.idea/debugServers/stm32h743.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/build_system/cmake/cpu/cortex-m0.cmake b/examples/build_system/cmake/cpu/cortex-m0.cmake
index 62019d90d..f837c7eb8 100644
--- a/examples/build_system/cmake/cpu/cortex-m0.cmake
+++ b/examples/build_system/cmake/cpu/cortex-m0.cmake
@@ -1,7 +1,7 @@
if (TOOLCHAIN STREQUAL "gcc")
set(TOOLCHAIN_COMMON_FLAGS
-mthumb
- -mcpu=cortex-m0plus
+ -mcpu=cortex-m0
-mfloat-abi=soft
)
set(FREERTOS_PORT GCC_ARM_CM0 CACHE INTERNAL "")
diff --git a/examples/build_system/make/cpu/cortex-m4.mk b/examples/build_system/make/cpu/cortex-m4.mk
index 4e16819d1..57d6e126d 100644
--- a/examples/build_system/make/cpu/cortex-m4.mk
+++ b/examples/build_system/make/cpu/cortex-m4.mk
@@ -12,8 +12,8 @@ else ifeq ($(TOOLCHAIN),clang)
-mfpu=fpv4-sp-d16 \
else ifeq ($(TOOLCHAIN),iar)
- CFLAGS += --cpu cortex-m4 --fpu VFPv4
- ASFLAGS += --cpu cortex-m4 --fpu VFPv4
+ CFLAGS += --cpu cortex-m4 --fpu VFPv4-SP
+ ASFLAGS += --cpu cortex-m4 --fpu VFPv4-SP
else
$(error "TOOLCHAIN is not supported")
diff --git a/examples/device/cdc_msc/src/msc_disk.c b/examples/device/cdc_msc/src/msc_disk.c
index d325d77fa..9645f4bfc 100644
--- a/examples/device/cdc_msc/src/msc_disk.c
+++ b/examples/device/cdc_msc/src/msc_disk.c
@@ -40,17 +40,15 @@ static bool ejected = false;
If you find any bugs or get any questions, feel free to file an\r\n\
issue at github.com/hathach/tinyusb"
-enum
-{
- DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount
+enum {
+ DISK_BLOCK_NUM = 16,// 8KB is the smallest size that windows allow to mount
DISK_BLOCK_SIZE = 512
};
#ifdef CFG_EXAMPLE_MSC_READONLY
const
#endif
-uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
-{
+uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
//------------- Block0: Boot Sector -------------//
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
// sector_per_cluster = 1; reserved_sectors = 1;
@@ -59,60 +57,59 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
// drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
// filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
// FAT magic code at offset 510-511
- {
- 0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
- 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T' , 'i' , 'n' , 'y' , 'U' ,
- 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
+{
+ 0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
+ 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U',
+ 'S', 'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
- // Zero up to 2 last bytes of FAT magic code
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // Zero up to 2 last bytes of FAT magic code
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
- },
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA},
//------------- Block1: FAT12 Table -------------//
- {
- 0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
+{
+ 0xF8, 0xFF, 0xFF, 0xFF, 0x0F// // first 2 entries must be F8FF, third entry is cluster end of readme file
},
//------------- Block2: Root Directory -------------//
- {
- // first entry is volume label
- 'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x08, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // second entry is readme file
- 'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D,
- 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
- sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes)
+{
+ // first entry is volume label
+ 'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // second entry is readme file
+ 'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, 0x52, 0x6D,
+ 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
+ sizeof(README_CONTENTS) - 1, 0x00, 0x00, 0x00// readme's files size (4 Bytes)
},
//------------- Block3: Readme Content -------------//
@@ -121,23 +118,21 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
// Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
-void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
-{
+void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
(void) lun;
const char vid[] = "TinyUSB";
const char pid[] = "Mass Storage";
const char rev[] = "1.0";
- memcpy(vendor_id , vid, strlen(vid));
- memcpy(product_id , pid, strlen(pid));
+ memcpy(vendor_id, vid, strlen(vid));
+ memcpy(product_id, pid, strlen(pid));
memcpy(product_rev, rev, strlen(rev));
}
// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
-bool tud_msc_test_unit_ready_cb(uint8_t lun)
-{
+bool tud_msc_test_unit_ready_cb(uint8_t lun) {
(void) lun;
// RAM disk is ready until ejected
@@ -152,29 +147,24 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun)
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
// Application update block count and block size
-void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
-{
+void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) {
(void) lun;
*block_count = DISK_BLOCK_NUM;
- *block_size = DISK_BLOCK_SIZE;
+ *block_size = DISK_BLOCK_SIZE;
}
// Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
-bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
-{
+bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
(void) lun;
(void) power_condition;
- if ( load_eject )
- {
- if (start)
- {
+ if (load_eject) {
+ if (start) {
// load disk storage
- }else
- {
+ } else {
// unload disk storage
ejected = true;
}
@@ -185,52 +175,51 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
-int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
-{
+int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) {
(void) lun;
// out of ramdisk
- if ( lba >= DISK_BLOCK_NUM ) {
+ if (lba >= DISK_BLOCK_NUM) {
return -1;
}
// Check for overflow of offset + bufsize
- if ( offset + bufsize > DISK_BLOCK_SIZE ) {
+ if (offset + bufsize > DISK_BLOCK_SIZE) {
return -1;
}
- uint8_t const* addr = msc_disk[lba] + offset;
+ uint8_t const *addr = msc_disk[lba] + offset;
memcpy(buffer, addr, bufsize);
return (int32_t) bufsize;
}
-bool tud_msc_is_writable_cb (uint8_t lun)
-{
+bool tud_msc_is_writable_cb(uint8_t lun) {
(void) lun;
-#ifdef CFG_EXAMPLE_MSC_READONLY
+ #ifdef CFG_EXAMPLE_MSC_READONLY
return false;
-#else
+ #else
return true;
-#endif
+ #endif
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
-int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
-{
+int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
(void) lun;
// out of ramdisk
- if ( lba >= DISK_BLOCK_NUM ) return -1;
+ if (lba >= DISK_BLOCK_NUM) return -1;
-#ifndef CFG_EXAMPLE_MSC_READONLY
- uint8_t* addr = msc_disk[lba] + offset;
+ #ifndef CFG_EXAMPLE_MSC_READONLY
+ uint8_t *addr = msc_disk[lba] + offset;
memcpy(addr, buffer, bufsize);
-#else
- (void) lba; (void) offset; (void) buffer;
-#endif
+ #else
+ (void) lba;
+ (void) offset;
+ (void) buffer;
+ #endif
return (int32_t) bufsize;
}
@@ -238,42 +227,18 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
// Callback invoked when received an SCSI command not in built-in list below
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks
-int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
-{
- // read10 & write10 has their own callback and MUST not be handled here
+int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) {
+ (void) buffer;
+ (void) bufsize;
- void const* response = NULL;
- int32_t resplen = 0;
-
- // most scsi handled is input
- bool in_xfer = true;
-
- switch (scsi_cmd[0])
- {
+ switch (scsi_cmd[0]) {
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
- resplen = -1;
- break;
+ return -1;
}
-
- // return resplen must not larger than bufsize
- if ( resplen > bufsize ) resplen = bufsize;
-
- if ( response && (resplen > 0) )
- {
- if(in_xfer)
- {
- memcpy(buffer, response, (size_t) resplen);
- }else
- {
- // SCSI output
- }
- }
-
- return (int32_t) resplen;
}
#endif
diff --git a/examples/device/msc_dual_lun/src/msc_disk_dual.c b/examples/device/msc_dual_lun/src/msc_disk_dual.c
index b44b77c6c..1f7fb98c7 100644
--- a/examples/device/msc_dual_lun/src/msc_disk_dual.c
+++ b/examples/device/msc_dual_lun/src/msc_disk_dual.c
@@ -55,8 +55,7 @@ If you find any bugs or get any questions, feel free to file an\r\n\
issue at github.com/hathach/tinyusb"
-MSC_CONST uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
-{
+MSC_CONST uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
//------------- Block0: Boot Sector -------------//
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
// sector_per_cluster = 1; reserved_sectors = 1;
@@ -283,9 +282,11 @@ bool tud_msc_is_writable_cb(uint8_t lun) {
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
// out of ramdisk
- if (lba >= DISK_BLOCK_NUM) return -1;
+ if (lba >= DISK_BLOCK_NUM) {
+ return -1;
+ }
-#if defined(CFG_EXAMPLE_MSC_READONLY) || defined(CFG_EXAMPLE_MSC_DUAL_READONLY)
+ #if defined(CFG_EXAMPLE_MSC_READONLY) || defined(CFG_EXAMPLE_MSC_DUAL_READONLY)
(void) lun;
(void) lba;
(void) offset;
@@ -302,11 +303,8 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks (MUST not be handled here)
int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
- void const* response = NULL;
- int32_t resplen = 0;
-
- // most scsi handled is input
- bool in_xfer = true;
+ (void) buffer;
+ (void) bufsize;
switch (scsi_cmd[0]) {
default:
@@ -316,19 +314,6 @@ int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, u
// negative means error -> tinyusb could stall and/or response with failed status
return -1;
}
-
- // return resplen must not larger than bufsize
- if (resplen > bufsize) resplen = bufsize;
-
- if (response && (resplen > 0)) {
- if (in_xfer) {
- memcpy(buffer, response, (size_t) resplen);
- } else {
- // SCSI output
- }
- }
-
- return resplen;
}
#endif
diff --git a/examples/dual/host_hid_to_device_cdc/src/main.c b/examples/dual/host_hid_to_device_cdc/src/main.c
index 633f7a6ac..6f30ca381 100644
--- a/examples/dual/host_hid_to_device_cdc/src/main.c
+++ b/examples/dual/host_hid_to_device_cdc/src/main.c
@@ -190,7 +190,9 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
// look up new key in previous keys
static inline bool find_key_in_report(hid_keyboard_report_t const* report, uint8_t keycode) {
for (uint8_t i = 0; i < 6; i++) {
- if (report->keycode[i] == keycode) return true;
+ if (report->keycode[i] == keycode) {
+ return true;
+ }
}
return false;
@@ -230,7 +232,9 @@ static void process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const* re
// TODO example skips key released
}
- if (flush) tud_cdc_write_flush();
+ if (flush) {
+ tud_cdc_write_flush();
+ }
prev_report = *report;
}
diff --git a/examples/dual/host_info_to_device_cdc/src/main.c b/examples/dual/host_info_to_device_cdc/src/main.c
index 7e593f234..a2a505952 100644
--- a/examples/dual/host_info_to_device_cdc/src/main.c
+++ b/examples/dual/host_info_to_device_cdc/src/main.c
@@ -78,6 +78,22 @@ static void print_device_info(uint8_t daddr, const tusb_desc_device_t* desc_devi
void led_blinking_task(void);
void cdc_task(void);
+#define cdc_printf(...) \
+ do { \
+ char _tempbuf[256]; \
+ char* _bufptr = _tempbuf; \
+ uint32_t count = (uint32_t) sprintf(_tempbuf, __VA_ARGS__); \
+ while (count > 0) { \
+ uint32_t wr_count = tud_cdc_write(_bufptr, count); \
+ count -= wr_count; \
+ _bufptr += wr_count; \
+ if (count > 0){ \
+ tud_task(); \
+ tud_cdc_write_flush(); \
+ } \
+ } \
+ } while(0)
+
/*------------- MAIN -------------*/
int main(void) {
board_init();
@@ -160,22 +176,6 @@ void cdc_task(void) {
//--------------------------------------------------------------------+
// Host Get device information
//--------------------------------------------------------------------+
-#define cdc_printf(...) \
- do { \
- char _tempbuf[256]; \
- char* _bufptr = _tempbuf; \
- uint32_t count = (uint32_t) sprintf(_tempbuf, __VA_ARGS__); \
- while (count > 0) { \
- uint32_t wr_count = tud_cdc_write(_bufptr, count); \
- count -= wr_count; \
- _bufptr += wr_count; \
- if (count > 0){ \
- tud_task();\
- tud_cdc_write_flush(); \
- } \
- } \
- } while(0)
-
static void print_device_info(uint8_t daddr, const tusb_desc_device_t* desc_device) {
// Get String descriptor using Sync API
uint16_t serial[64];
@@ -232,12 +232,14 @@ void tuh_enum_descriptor_device_cb(uint8_t daddr, tusb_desc_device_t const* desc
}
void tuh_mount_cb(uint8_t daddr) {
- printf("mounted device %u\r\n", daddr);
+ cdc_printf("mounted device %u\r\n", daddr);
+ tud_cdc_write_flush();
is_print[daddr] = true;
}
void tuh_umount_cb(uint8_t daddr) {
- printf("unmounted device %u\r\n", daddr);
+ cdc_printf("unmounted device %u\r\n", daddr);
+ tud_cdc_write_flush();
is_print[daddr] = false;
}
@@ -249,7 +251,9 @@ void led_blinking_task(void) {
static bool led_state = false;
// Blink every interval ms
- if (board_millis() - start_ms < blink_interval_ms) return; // not enough time
+ if (board_millis() - start_ms < blink_interval_ms) {
+ return;// not enough time
+ }
start_ms += blink_interval_ms;
board_led_write(led_state);
@@ -300,7 +304,9 @@ static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
}
static void print_utf16(uint16_t *temp_buf, size_t buf_len) {
- if ((temp_buf[0] & 0xff) == 0) return; // empty
+ if ((temp_buf[0] & 0xff) == 0) {
+ return;// empty
+ }
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
size_t utf8_len = (size_t) _count_utf8_bytes(temp_buf + 1, utf16_len);
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len);
diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c
index a751c9c80..6f01d6f45 100644
--- a/examples/host/cdc_msc_hid/src/hid_app.c
+++ b/examples/host/cdc_msc_hid/src/hid_app.c
@@ -29,14 +29,9 @@
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
+#define MAX_REPORT 4
-// If your host terminal support ansi escape code such as TeraTerm
-// it can be use to simulate mouse cursor movement within terminal
-#define USE_ANSI_ESCAPE 0
-
-#define MAX_REPORT 4
-
-static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII };
+static uint8_t const keycode2ascii[128][2] = {HID_KEYCODE_TO_ASCII};
// Each HID instance can has multiple reports
static struct {
@@ -45,8 +40,8 @@ static struct {
} hid_info[CFG_TUH_HID];
static void process_kbd_report(hid_keyboard_report_t const *report);
-static void process_mouse_report(hid_mouse_report_t const * report);
-static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
+static void process_mouse_report(hid_mouse_report_t const *report);
+static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len);
void hid_app_task(void) {
// nothing to do
@@ -70,7 +65,7 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_re
printf("HID Interface Protocol = %s\r\n", protocol_str[itf_protocol]);
- // By default host stack will use activate boot protocol on supported interface.
+ // By default, host stack will use boot protocol on supported interface.
// Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser)
if (itf_protocol == HID_ITF_PROTOCOL_NONE) {
hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT, desc_report, desc_len);
@@ -121,7 +116,7 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
//--------------------------------------------------------------------+
// look up new key in previous keys
-static inline bool find_key_in_report(hid_keyboard_report_t const* report, uint8_t keycode) {
+static inline bool find_key_in_report(hid_keyboard_report_t const *report, uint8_t keycode) {
for (uint8_t i = 0; i < 6; i++) {
if (report->keycode[i] == keycode) {
return true;
@@ -130,28 +125,25 @@ static inline bool find_key_in_report(hid_keyboard_report_t const* report, uint8
return false;
}
-static void process_kbd_report(hid_keyboard_report_t const *report)
-{
- static hid_keyboard_report_t prev_report = { 0, 0, {0} }; // previous report to check key released
+static void process_kbd_report(hid_keyboard_report_t const *report) {
+ static hid_keyboard_report_t prev_report = {0, 0, {0}};// previous report to check key released
//------------- example code ignore control (non-printable) key affects -------------//
- for(uint8_t i=0; i<6; i++)
- {
- if ( report->keycode[i] )
- {
- if ( find_key_in_report(&prev_report, report->keycode[i]) )
- {
+ for (uint8_t i = 0; i < 6; i++) {
+ if (report->keycode[i]) {
+ if (find_key_in_report(&prev_report, report->keycode[i])) {
// exist in previous report means the current key is holding
- }else
- {
+ } else {
// not existed in previous report means the current key is pressed
bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
uint8_t ch = keycode2ascii[report->keycode[i]][is_shift ? 1 : 0];
putchar(ch);
- if ( ch == '\r' ) putchar('\n'); // added new line for enter key
+ if (ch == '\r') {
+ putchar('\n');
+ }
- #ifndef __ICCARM__ // TODO IAR doesn't support stream control ?
- fflush(stdout); // flush right away, else nanolib will wait for newline
+ #ifndef __ICCARM__ // TODO IAR doesn't support stream control ?
+ fflush(stdout);// flush right away, else nanolib will wait for newline
#endif
}
}
@@ -166,55 +158,22 @@ static void process_kbd_report(hid_keyboard_report_t const *report)
//--------------------------------------------------------------------+
static void cursor_movement(int8_t x, int8_t y, int8_t wheel) {
-#if USE_ANSI_ESCAPE
- // Move X using ansi escape
- if ( x < 0)
- {
- printf(ANSI_CURSOR_BACKWARD(%d), (-x)); // move left
- }else if ( x > 0)
- {
- printf(ANSI_CURSOR_FORWARD(%d), x); // move right
- }
-
- // Move Y using ansi escape
- if ( y < 0)
- {
- printf(ANSI_CURSOR_UP(%d), (-y)); // move up
- }else if ( y > 0)
- {
- printf(ANSI_CURSOR_DOWN(%d), y); // move down
- }
-
- // Scroll using ansi escape
- if (wheel < 0)
- {
- printf(ANSI_SCROLL_UP(%d), (-wheel)); // scroll up
- }else if (wheel > 0)
- {
- printf(ANSI_SCROLL_DOWN(%d), wheel); // scroll down
- }
-
- printf("\r\n");
-#else
printf("(%d %d %d)\r\n", x, y, wheel);
-#endif
}
-static void process_mouse_report(hid_mouse_report_t const * report)
-{
- static hid_mouse_report_t prev_report = { 0 };
+static void process_mouse_report(hid_mouse_report_t const *report) {
+ static hid_mouse_report_t prev_report = {0};
- //------------- button state -------------//
+ // button state
uint8_t button_changed_mask = report->buttons ^ prev_report.buttons;
- if ( button_changed_mask & report->buttons)
- {
+ if (button_changed_mask & report->buttons) {
printf(" %c%c%c ",
- report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-',
- report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-',
- report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-');
+ report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-',
+ report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-',
+ report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-');
}
- //------------- cursor movement -------------//
+ // cursor movement
cursor_movement(report->x, report->y, report->wheel);
}
@@ -263,18 +222,23 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c
if (rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP) {
switch (rpt_info->usage) {
case HID_USAGE_DESKTOP_KEYBOARD:
- TU_LOG1("HID receive keyboard report\r\n");
+ TU_LOG2("HID receive keyboard report\r\n");
// Assume keyboard follow boot report layout
process_kbd_report((hid_keyboard_report_t const *) report);
break;
case HID_USAGE_DESKTOP_MOUSE:
- TU_LOG1("HID receive mouse report\r\n");
+ TU_LOG2("HID receive mouse report\r\n");
// Assume mouse follow boot report layout
process_mouse_report((hid_mouse_report_t const *) report);
break;
default:
+ printf("report[%u] ", rpt_info->report_id);
+ for (uint8_t i = 0; i < len; i++) {
+ printf("%02X ", report[i]);
+ }
+ printf("\r\n");
break;
}
}
diff --git a/examples/host/cdc_msc_hid/src/msc_app.c b/examples/host/cdc_msc_hid/src/msc_app.c
index 1d7e18e6e..0e9c99766 100644
--- a/examples/host/cdc_msc_hid/src/msc_app.c
+++ b/examples/host/cdc_msc_hid/src/msc_app.c
@@ -30,13 +30,11 @@
//--------------------------------------------------------------------+
static scsi_inquiry_resp_t inquiry_resp;
-bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
-{
+static bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) {
msc_cbw_t const* cbw = cb_data->cbw;
msc_csw_t const* csw = cb_data->csw;
- if (csw->status != 0)
- {
+ if (csw->status != 0) {
printf("Inquiry failed\r\n");
return false;
}
@@ -55,16 +53,14 @@ bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_da
}
//------------- IMPLEMENTATION -------------//
-void tuh_msc_mount_cb(uint8_t dev_addr)
-{
+void tuh_msc_mount_cb(uint8_t dev_addr) {
printf("A MassStorage device is mounted\r\n");
uint8_t const lun = 0;
tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb, 0);
}
-void tuh_msc_umount_cb(uint8_t dev_addr)
-{
+void tuh_msc_umount_cb(uint8_t dev_addr) {
(void) dev_addr;
printf("A MassStorage device is unmounted\r\n");
}
diff --git a/examples/host/msc_file_explorer/Makefile b/examples/host/msc_file_explorer/Makefile
index c7d6a7cae..f0872376f 100644
--- a/examples/host/msc_file_explorer/Makefile
+++ b/examples/host/msc_file_explorer/Makefile
@@ -22,6 +22,6 @@ SRC_C += \
$(FATFS_PATH)/ffunicode.c \
# suppress warning caused by fatfs
-CFLAGS += -Wno-error=cast-qual
+CFLAGS_GCC += -Wno-error=cast-qual
include ../../build_system/make/rules.mk
diff --git a/hw/bsp/BoardPresets.json b/hw/bsp/BoardPresets.json
index fee8f2c97..24da362da 100644
--- a/hw/bsp/BoardPresets.json
+++ b/hw/bsp/BoardPresets.json
@@ -12,21 +12,31 @@
"BOARD": "${presetName}"
}
},
+ {
+ "name": "default single",
+ "hidden": true,
+ "description": "Configure preset for the ${presetName} board",
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/build/${presetName}",
+ "cacheVariables": {
+ "BOARD": "${presetName}"
+ }
+ },
{
"name": "adafruit_clue",
"inherits": "default"
},
{
"name": "adafruit_feather_esp32_v2",
- "inherits": "default"
+ "inherits": "default single"
},
{
"name": "adafruit_feather_esp32s2",
- "inherits": "default"
+ "inherits": "default single"
},
{
"name": "adafruit_feather_esp32s3",
- "inherits": "default"
+ "inherits": "default single"
},
{
"name": "adafruit_magtag_29gray",
@@ -34,7 +44,7 @@
},
{
"name": "adafruit_metro_esp32s2",
- "inherits": "default"
+ "inherits": "default single"
},
{
"name": "apard32690",
@@ -130,39 +140,39 @@
},
{
"name": "espressif_addax_1",
- "inherits": "default"
+ "inherits": "default single"
},
{
"name": "espressif_c3_devkitc",
- "inherits": "default"
+ "inherits": "default single"
},
{
"name": "espressif_c6_devkitc",
- "inherits": "default"
+ "inherits": "default single"
},
{
"name": "espressif_kaluga_1",
- "inherits": "default"
+ "inherits": "default single"
},
{
"name": "espressif_p4_function_ev",
- "inherits": "default"
+ "inherits": "default single"
},
{
"name": "espressif_s2_devkitc",
- "inherits": "default"
+ "inherits": "default single"
},
{
"name": "espressif_s3_devkitc",
- "inherits": "default"
+ "inherits": "default single"
},
{
"name": "espressif_s3_devkitm",
- "inherits": "default"
+ "inherits": "default single"
},
{
"name": "espressif_saola_1",
- "inherits": "default"
+ "inherits": "default single"
},
{
"name": "f1c100s",
diff --git a/hw/bsp/broadcom_32bit/family.mk b/hw/bsp/broadcom_32bit/family.mk
index a282e9961..9d4a3b76c 100644
--- a/hw/bsp/broadcom_32bit/family.mk
+++ b/hw/bsp/broadcom_32bit/family.mk
@@ -15,7 +15,7 @@ CFLAGS += \
CROSS_COMPILE = arm-none-eabi-
# mcu driver cause following warnings
-CFLAGS += -Wno-error=cast-qual -Wno-error=redundant-decls
+CFLAGS_GCC += -Wno-error=cast-qual -Wno-error=redundant-decls
SRC_C += \
src/portable/synopsys/dwc2/dcd_dwc2.c \
diff --git a/hw/bsp/broadcom_64bit/family.mk b/hw/bsp/broadcom_64bit/family.mk
index 37d381f9f..1ce80e22b 100644
--- a/hw/bsp/broadcom_64bit/family.mk
+++ b/hw/bsp/broadcom_64bit/family.mk
@@ -14,7 +14,7 @@ CFLAGS += \
CROSS_COMPILE = aarch64-none-elf-
# mcu driver cause following warnings
-CFLAGS += -Wno-error=cast-qual -Wno-error=redundant-decls
+CFLAGS_GCC += -Wno-error=cast-qual -Wno-error=redundant-decls
SRC_C += \
src/portable/synopsys/dwc2/dcd_dwc2.c \
diff --git a/hw/bsp/espressif/boards/espressif_p4_function_ev/board.h b/hw/bsp/espressif/boards/espressif_p4_function_ev/board.h
index 6f3229b70..40c4963d9 100644
--- a/hw/bsp/espressif/boards/espressif_p4_function_ev/board.h
+++ b/hw/bsp/espressif/boards/espressif_p4_function_ev/board.h
@@ -41,9 +41,10 @@
#define BUTTON_PIN 35
#define BUTTON_STATE_ACTIVE 0
-// For CI hardware test, to test both device and host on the same HS port with help of
-#define HIL_DEVICE_HOST_MUX_PIN 47
-#define HIL_DEVICE_STATE 1
+// For CI hardware test, to test both device and host on the same HS port with help of TS3USB30
+// https://www.adafruit.com/product/5871
+#define HIL_TS3USB30_MODE_PIN 47
+#define HIL_TS3USB30_MODE_DEVICE 1
#ifdef __cplusplus
}
diff --git a/hw/bsp/espressif/boards/espressif_s2_devkitc/board.h b/hw/bsp/espressif/boards/espressif_s2_devkitc/board.h
index 9c197591f..499a626a6 100644
--- a/hw/bsp/espressif/boards/espressif_s2_devkitc/board.h
+++ b/hw/bsp/espressif/boards/espressif_s2_devkitc/board.h
@@ -36,13 +36,19 @@
extern "C" {
#endif
-// Note: On the production version (v1.2) WS2812 is connected to GPIO 18,
-// however earlier revision v1.1 WS2812 is connected to GPIO 17
#define NEOPIXEL_PIN 18
#define BUTTON_PIN 0
#define BUTTON_STATE_ACTIVE 0
+// SPI for USB host shield
+#define MAX3421_SPI_HOST SPI2_HOST
+#define MAX3421_SCK_PIN 36
+#define MAX3421_MOSI_PIN 35
+#define MAX3421_MISO_PIN 37
+#define MAX3421_CS_PIN 15
+#define MAX3421_INTR_PIN 14
+
#ifdef __cplusplus
}
#endif
diff --git a/hw/bsp/espressif/boards/espressif_s3_devkitc/board.h b/hw/bsp/espressif/boards/espressif_s3_devkitc/board.h
index 6d7a94668..d2483c84f 100644
--- a/hw/bsp/espressif/boards/espressif_s3_devkitc/board.h
+++ b/hw/bsp/espressif/boards/espressif_s3_devkitc/board.h
@@ -36,7 +36,7 @@
extern "C" {
#endif
-#define NEOPIXEL_PIN 48
+#define NEOPIXEL_PIN 38
#define BUTTON_PIN 0
#define BUTTON_STATE_ACTIVE 0
diff --git a/hw/bsp/espressif/boards/espressif_s3_devkitm/board.h b/hw/bsp/espressif/boards/espressif_s3_devkitm/board.h
index d01fdbe5b..5c1914ebe 100644
--- a/hw/bsp/espressif/boards/espressif_s3_devkitm/board.h
+++ b/hw/bsp/espressif/boards/espressif_s3_devkitm/board.h
@@ -49,6 +49,11 @@
#define MAX3421_CS_PIN 15
#define MAX3421_INTR_PIN 14
+// For CI hardware test, to test both device and host on the same HS port with help of TS3USB30
+// https://www.adafruit.com/product/5871
+#define HIL_TS3USB30_MODE_PIN 47
+#define HIL_TS3USB30_MODE_DEVICE 1
+
#ifdef __cplusplus
}
#endif
diff --git a/hw/bsp/espressif/boards/family.c b/hw/bsp/espressif/boards/family.c
index 7049c0415..cf11e2441 100644
--- a/hw/bsp/espressif/boards/family.c
+++ b/hw/bsp/espressif/boards/family.c
@@ -92,10 +92,10 @@ void board_init(void) {
usb_init();
#endif
-#ifdef HIL_DEVICE_HOST_MUX_PIN
- gpio_reset_pin(HIL_DEVICE_HOST_MUX_PIN);
- gpio_set_direction(HIL_DEVICE_HOST_MUX_PIN, GPIO_MODE_OUTPUT);
- gpio_set_level(HIL_DEVICE_HOST_MUX_PIN, CFG_TUD_ENABLED ? HIL_DEVICE_STATE : (1-HIL_DEVICE_STATE));
+#ifdef HIL_TS3USB30_MODE_PIN
+ gpio_reset_pin(HIL_TS3USB30_MODE_PIN);
+ gpio_set_direction(HIL_TS3USB30_MODE_PIN, GPIO_MODE_OUTPUT);
+ gpio_set_level(HIL_TS3USB30_MODE_PIN, CFG_TUD_ENABLED ? HIL_TS3USB30_MODE_DEVICE : (1-HIL_TS3USB30_MODE_DEVICE));
#endif
#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
diff --git a/hw/bsp/espressif/family.cmake b/hw/bsp/espressif/family.cmake
index daa12cdb4..b544689d9 100644
--- a/hw/bsp/espressif/family.cmake
+++ b/hw/bsp/espressif/family.cmake
@@ -34,6 +34,6 @@ endif ()
set(EXTRA_COMPONENT_DIRS "src" "${CMAKE_CURRENT_LIST_DIR}/boards" "${CMAKE_CURRENT_LIST_DIR}/components")
# set SDKCONFIG for each IDF Target
-set(SDKCONFIG ${CMAKE_SOURCE_DIR}/sdkconfig.${IDF_TARGET})
+set(SDKCONFIG ${CMAKE_BINARY_DIR}/sdkconfig)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
diff --git a/hw/bsp/kinetis_k32l2/boards/frdm_k32l2a4s/board.mk b/hw/bsp/kinetis_k32l2/boards/frdm_k32l2a4s/board.mk
index c4dc65b63..fb3eb2a03 100644
--- a/hw/bsp/kinetis_k32l2/boards/frdm_k32l2a4s/board.mk
+++ b/hw/bsp/kinetis_k32l2/boards/frdm_k32l2a4s/board.mk
@@ -3,7 +3,7 @@ MCU = K32L2A41A
CFLAGS += -DCPU_K32L2A41VLH1A
# mcu driver cause following warnings
-CFLAGS += -Wno-error=unused-parameter -Wno-error=redundant-decls -Wno-error=cast-qual
+CFLAGS_GCC += -Wno-error=unused-parameter -Wno-error=redundant-decls -Wno-error=cast-qual
# All source paths should be relative to the top level.
LD_FILE = $(MCU_DIR)/gcc/K32L2A41xxxxA_flash.ld
diff --git a/hw/bsp/lpc15/family.mk b/hw/bsp/lpc15/family.mk
index b83e008e8..3b63580c0 100644
--- a/hw/bsp/lpc15/family.mk
+++ b/hw/bsp/lpc15/family.mk
@@ -15,7 +15,7 @@ CFLAGS += \
LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs
# mcu driver cause following warnings
-CFLAGS += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=unused-variable -Wno-error=cast-qual
+CFLAGS_GCC += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=unused-variable -Wno-error=cast-qual
MCU_DIR = hw/mcu/nxp/lpcopen/lpc15xx/lpc_chip_15xx
diff --git a/hw/bsp/lpc17/family.mk b/hw/bsp/lpc17/family.mk
index d719a47b7..551eb9e62 100644
--- a/hw/bsp/lpc17/family.mk
+++ b/hw/bsp/lpc17/family.mk
@@ -13,7 +13,7 @@ CFLAGS += \
-DRTC_EV_SUPPORT=0
# lpc_types.h cause following errors
-CFLAGS += -Wno-error=strict-prototypes -Wno-error=cast-qual
+CFLAGS_GCC += -Wno-error=strict-prototypes -Wno-error=cast-qual
# caused by freeRTOS port !!
CFLAGS += -Wno-error=maybe-uninitialized
diff --git a/hw/bsp/lpc18/family.mk b/hw/bsp/lpc18/family.mk
index f120f63b2..87b831255 100644
--- a/hw/bsp/lpc18/family.mk
+++ b/hw/bsp/lpc18/family.mk
@@ -12,7 +12,7 @@ CFLAGS += \
-DCFG_TUSB_MCU=OPT_MCU_LPC18XX
# mcu driver cause following warnings
-CFLAGS += -Wno-error=unused-parameter -Wno-error=cast-qual
+CFLAGS_GCC += -Wno-error=unused-parameter -Wno-error=cast-qual
LDFLAGS_GCC += --specs=nosys.specs --specs=nano.specs
diff --git a/hw/bsp/lpc40/family.mk b/hw/bsp/lpc40/family.mk
index ef9fe57b2..06155c760 100644
--- a/hw/bsp/lpc40/family.mk
+++ b/hw/bsp/lpc40/family.mk
@@ -13,7 +13,7 @@ CFLAGS += \
-DCFG_TUSB_MCU=OPT_MCU_LPC40XX
# mcu driver cause following warnings
-CFLAGS += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=cast-qual
+CFLAGS_GCC += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=cast-qual
LDFLAGS_GCC += --specs=nosys.specs --specs=nano.specs
diff --git a/hw/bsp/lpc43/family.mk b/hw/bsp/lpc43/family.mk
index e1406aae7..4a2ba6ec3 100644
--- a/hw/bsp/lpc43/family.mk
+++ b/hw/bsp/lpc43/family.mk
@@ -5,14 +5,14 @@ include ${TOP}/${BOARD_PATH}/board.mk
CPU_CORE ?= cortex-m4
CFLAGS += \
- -flto \
- -nostdlib \
-DCORE_M4 \
-D__USE_LPCOPEN \
-DCFG_TUSB_MCU=OPT_MCU_LPC43XX
# mcu driver cause following warnings
-CFLAGS += \
+CFLAGS_GCC += \
+ -flto \
+ -nostdlib \
-Wno-error=unused-parameter \
-Wno-error=cast-qual \
-Wno-error=incompatible-pointer-types \
diff --git a/hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.cmake b/hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.cmake
new file mode 100644
index 000000000..97621d855
--- /dev/null
+++ b/hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.cmake
@@ -0,0 +1,2 @@
+set(PICO_PLATFORM rp2040)
+set(PICO_BOARD pico_w)
diff --git a/hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.h b/hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.h
new file mode 100644
index 000000000..8af32fc9e
--- /dev/null
+++ b/hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.h
@@ -0,0 +1,70 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ name: Pico
+ url: https://www.raspberrypi.com/products/raspberry-pi-pico/
+*/
+
+#ifndef TUSB_BOARD_H
+#define TUSB_BOARD_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// UART and LED are already defined in pico-sdk board
+
+//--------------------------------------------------------------------+
+// PIO_USB
+//--------------------------------------------------------------------+
+// default to pico brain tester
+#define PICO_DEFAULT_PIO_USB_DP_PIN 20
+#define PICO_DEFAULT_PIO_USB_VBUSEN_PIN 22
+#define PICO_DEFAULT_PIO_USB_VBUSEN_STATE 1
+
+//--------------------------------------------------------------------
+// USB Host MAX3421E
+//--------------------------------------------------------------------
+
+#ifdef PICO_DEFAULT_SPI
+#define MAX3421_SPI PICO_DEFAULT_SPI // sdk v2
+#else
+#define MAX3421_SPI PICO_DEFAULT_SPI_INSTANCE // sdk v1
+#endif
+
+#define MAX3421_SCK_PIN PICO_DEFAULT_SPI_SCK_PIN
+#define MAX3421_MOSI_PIN PICO_DEFAULT_SPI_TX_PIN
+#define MAX3421_MISO_PIN PICO_DEFAULT_SPI_RX_PIN
+#define MAX3421_CS_PIN 10
+#define MAX3421_INTR_PIN 9
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/hw/bsp/rp2040/skip_ci.txt b/hw/bsp/rp2040/skip_ci.txt
new file mode 100644
index 000000000..fe99c9f65
--- /dev/null
+++ b/hw/bsp/rp2040/skip_ci.txt
@@ -0,0 +1,7 @@
+# boards in this files are skipped when running CI with this family
+adafruit_feather_rp2040_usb_host
+adafruit_fruit_jam
+adafruit_metro_rp2350
+feather_rp2040_max3421
+pico_sdk
+raspberry_pi_pico_w
diff --git a/hw/bsp/stm32f2/boards/stm32f207nucleo/board.mk b/hw/bsp/stm32f2/boards/stm32f207nucleo/board.mk
index ba185d199..6e681ef57 100644
--- a/hw/bsp/stm32f2/boards/stm32f207nucleo/board.mk
+++ b/hw/bsp/stm32f2/boards/stm32f207nucleo/board.mk
@@ -1,12 +1,9 @@
-CFLAGS += \
- -DSTM32F207xx \
+MCU_VARIANT = stm32f207xx
+CFLAGS += -DSTM32F207xx
# All source paths should be relative to the top level.
LD_FILE = $(BOARD_PATH)/STM32F207ZGTx_FLASH.ld
-SRC_S += \
- $(ST_CMSIS)/Source/Templates/gcc/startup_stm32f207xx.s
-
# For flash-jlink target
JLINK_DEVICE = stm32f207zg
diff --git a/hw/bsp/stm32f2/family.mk b/hw/bsp/stm32f2/family.mk
index 7af9a76a0..e8f02548d 100644
--- a/hw/bsp/stm32f2/family.mk
+++ b/hw/bsp/stm32f2/family.mk
@@ -1,5 +1,4 @@
ST_FAMILY = f2
-
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
@@ -14,11 +13,10 @@ CPU_CORE ?= cortex-m3
CFLAGS += \
-DCFG_TUSB_MCU=OPT_MCU_STM32F2
+# mcu driver cause following warnings
CFLAGS_GCC += \
-flto \
-
-# mcu driver cause following warnings
-CFLAGS_GCC += -Wno-error=sign-compare
+ -Wno-error=sign-compare
LDFLAGS_GCC += \
-nostdlib -nostartfiles \
@@ -40,3 +38,10 @@ INC += \
$(TOP)/$(ST_CMSIS)/Include \
$(TOP)/$(ST_HAL_DRIVER)/Inc \
$(TOP)/$(BOARD_PATH)
+
+# Startup
+SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}.s
+SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_${MCU_VARIANT}.s
+
+# Linker
+LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf
diff --git a/hw/bsp/stm32f3/boards/stm32f303disco/board.mk b/hw/bsp/stm32f3/boards/stm32f303disco/board.mk
index e387f2d54..6b9a3e283 100644
--- a/hw/bsp/stm32f3/boards/stm32f303disco/board.mk
+++ b/hw/bsp/stm32f3/boards/stm32f303disco/board.mk
@@ -1,12 +1,10 @@
+MCU_VARIANT = stm32f303xc
CFLAGS += \
-DSTM32F303xC \
# All source paths should be relative to the top level.
LD_FILE = $(BOARD_PATH)/STM32F303VCTx_FLASH.ld
-SRC_S += \
- $(ST_CMSIS)/Source/Templates/gcc/startup_stm32f303xc.s
-
# For flash-jlink target
JLINK_DEVICE = stm32f303vc
diff --git a/hw/bsp/stm32f3/family.mk b/hw/bsp/stm32f3/family.mk
index 4fe3aa99d..13734583a 100644
--- a/hw/bsp/stm32f3/family.mk
+++ b/hw/bsp/stm32f3/family.mk
@@ -1,22 +1,17 @@
ST_FAMILY = f3
-
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
-DEPS_SUBMODULES += \
- lib/CMSIS_5 \
- $(ST_CMSIS) \
- $(ST_HAL_DRIVER)
-
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m4
CFLAGS += \
- -flto \
-DCFG_TUSB_MCU=OPT_MCU_STM32F3
# mcu driver cause following warnings
-CFLAGS += -Wno-error=unused-parameter
+CFLAGS_GCC += \
+ -flto \
+ -Wno-error=unused-parameter
LDFLAGS_GCC += \
-nostdlib -nostartfiles \
@@ -36,3 +31,10 @@ INC += \
$(TOP)/$(ST_CMSIS)/Include \
$(TOP)/$(ST_HAL_DRIVER)/Inc \
$(TOP)/$(BOARD_PATH)
+
+# Startup
+SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}.s
+SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_${MCU_VARIANT}.s
+
+# Linker
+LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf
diff --git a/hw/bsp/stm32f4/family.mk b/hw/bsp/stm32f4/family.mk
index 51ff43a60..c3c41dc3f 100644
--- a/hw/bsp/stm32f4/family.mk
+++ b/hw/bsp/stm32f4/family.mk
@@ -1,6 +1,5 @@
UF2_FAMILY_ID = 0x57755a57
ST_FAMILY = f4
-DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
diff --git a/hw/bsp/stm32h7/boards/stm32h743eval/board.h b/hw/bsp/stm32h7/boards/stm32h743eval/board.h
index 334876e51..7c3f6414a 100644
--- a/hw/bsp/stm32h7/boards/stm32h743eval/board.h
+++ b/hw/bsp/stm32h7/boards/stm32h743eval/board.h
@@ -184,7 +184,7 @@ static MFXSTM32L152_Object_t mfx_obj = { 0 };
static MFXSTM32L152_IO_Mode_t* mfx_io = NULL;
static uint32_t mfx_vbus_pin[2] = { MFXSTM32L152_GPIO_PIN_7, MFXSTM32L152_GPIO_PIN_9 };
-int32_t board_i2c_init(void) {
+static int32_t board_i2c_init(void) {
__HAL_RCC_I2C1_CLK_ENABLE();
__HAL_RCC_I2C1_FORCE_RESET();
__HAL_RCC_I2C1_RELEASE_RESET();
@@ -200,16 +200,16 @@ int32_t board_i2c_init(void) {
return 0;
}
-int32_t board_i2c_deinit(void) {
+static int32_t board_i2c_deinit(void) {
return 0;
}
-int32_t i2c_readreg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
+static int32_t i2c_readreg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
TU_ASSERT (HAL_OK == HAL_I2C_Mem_Read(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000));
return 0;
}
-int32_t i2c_writereg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
+static int32_t i2c_writereg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
TU_ASSERT(HAL_OK == HAL_I2C_Mem_Write(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000));
return 0;
}
@@ -249,7 +249,7 @@ static inline void board_init2(void) {
}
// VBUS1 is actually controlled by USB3320C PHY (using dwc2 drivebus signal)
-void board_vbus_set(uint8_t rhport, bool state) {
+static void TU_ATTR_UNUSED board_vbus_set(uint8_t rhport, bool state) {
if (mfx_io) {
mfx_io->IO_WritePin(&mfx_obj, mfx_vbus_pin[rhport], state);
}
diff --git a/hw/bsp/stm32h7/family.c b/hw/bsp/stm32h7/family.c
index e5228b29b..f8723b0c7 100644
--- a/hw/bsp/stm32h7/family.c
+++ b/hw/bsp/stm32h7/family.c
@@ -80,7 +80,7 @@ void OTG_HS_IRQHandler(void) {
}
#ifdef TRACE_ETM
-void trace_etm_init(void) {
+static void trace_etm_init(void) {
// H7 trace pin is PE2 to PE6
GPIO_InitTypeDef gpio_init;
gpio_init.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;
@@ -94,7 +94,7 @@ void trace_etm_init(void) {
DBGMCU->CR |= DBGMCU_CR_DBG_TRACECKEN | DBGMCU_CR_DBG_CKD1EN | DBGMCU_CR_DBG_CKD3EN;
}
#else
- #define trace_etm_init()
+#define trace_etm_init()
#endif
void board_init(void) {
diff --git a/hw/bsp/stm32h7/family.mk b/hw/bsp/stm32h7/family.mk
index 29b83cf7d..19a085424 100644
--- a/hw/bsp/stm32h7/family.mk
+++ b/hw/bsp/stm32h7/family.mk
@@ -45,11 +45,9 @@ CFLAGS += \
-DBOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED} \
# GCC Flags
-CFLAGS_GCC += \
- -flto \
-
# suppress warning caused by vendor mcu driver
CFLAGS_GCC += \
+ -flto \
-Wno-error=cast-align \
-Wno-error=unused-parameter \
diff --git a/hw/bsp/stm32l0/boards/stm32l052dap52/board.mk b/hw/bsp/stm32l0/boards/stm32l052dap52/board.mk
index 0b1348474..e63b41f12 100644
--- a/hw/bsp/stm32l0/boards/stm32l052dap52/board.mk
+++ b/hw/bsp/stm32l0/boards/stm32l052dap52/board.mk
@@ -1,10 +1,9 @@
+MCU_VARIANT = stm32l052xx
CFLAGS += \
-DSTM32L052xx
LD_FILE = $(BOARD_PATH)/STM32L052K8Ux_FLASH.ld
-SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32l052xx.s
-
# For flash-jlink target
JLINK_DEVICE = stm32l052k8
diff --git a/hw/bsp/stm32l0/boards/stm32l0538disco/board.mk b/hw/bsp/stm32l0/boards/stm32l0538disco/board.mk
index deed519ba..f3e6978b0 100644
--- a/hw/bsp/stm32l0/boards/stm32l0538disco/board.mk
+++ b/hw/bsp/stm32l0/boards/stm32l0538disco/board.mk
@@ -1,12 +1,10 @@
+MCU_VARIANT = stm32l053xx
CFLAGS += \
-DSTM32L053xx
# All source paths should be relative to the top level.
LD_FILE = $(BOARD_PATH)/STM32L053C8Tx_FLASH.ld
-SRC_S += \
- $(ST_CMSIS)/Source/Templates/gcc/startup_stm32l053xx.s
-
# For flash-jlink target
JLINK_DEVICE = STM32L053R8
diff --git a/hw/bsp/stm32l0/family.mk b/hw/bsp/stm32l0/family.mk
index fe7561fc2..921b1b413 100644
--- a/hw/bsp/stm32l0/family.mk
+++ b/hw/bsp/stm32l0/family.mk
@@ -1,9 +1,4 @@
ST_FAMILY = l0
-DEPS_SUBMODULES += \
- lib/CMSIS_5 \
- hw/mcu/st/cmsis_device_$(ST_FAMILY) \
- hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
-
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
@@ -11,20 +6,17 @@ include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m0plus
CFLAGS += \
- -flto \
-DCFG_EXAMPLE_MSC_READONLY \
-DCFG_EXAMPLE_VIDEO_READONLY \
-DCFG_TUSB_MCU=OPT_MCU_STM32L0
# mcu driver cause following warnings
CFLAGS_GCC += \
+ -flto \
-Wno-error=unused-parameter \
-Wno-error=redundant-decls \
-Wno-error=cast-align \
-
-ifeq ($(TOOLCHAIN),gcc)
-CFLAGS_GCC += -Wno-error=maybe-uninitialized
-endif
+ -Wno-error=maybe-uninitialized \
CFLAGS_CLANG += \
-Wno-error=parentheses-equality
@@ -48,3 +40,10 @@ INC += \
$(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
$(TOP)/$(ST_CMSIS)/Include \
$(TOP)/$(ST_HAL_DRIVER)/Inc
+
+# Startup
+SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}.s
+SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_${MCU_VARIANT}.s
+
+# Linker
+LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash.icf
diff --git a/hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk b/hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk
index ae63afef3..0a2c47030 100644
--- a/hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk
+++ b/hw/bsp/stm32u5/boards/b_u585i_iot2a/board.mk
@@ -1,11 +1,9 @@
+MCU_VARIANT = stm32u585xx
CFLAGS += \
-DSTM32U585xx \
# All source paths should be relative to the top level.
LD_FILE = ${FAMILY_PATH}/linker/STM32U575xx_FLASH.ld
-SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u575xx.s
-
-MCU_VARIANT = stm32u585xx
# For flash-jlink target
JLINK_DEVICE = stm32u585zi
diff --git a/hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk b/hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk
index 072c595fb..0aba57ce4 100644
--- a/hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk
+++ b/hw/bsp/stm32u5/boards/stm32u545nucleo/board.mk
@@ -1,11 +1,9 @@
+MCU_VARIANT = stm32u545xx
CFLAGS += \
-DSTM32U545xx \
# All source paths should be relative to the top level.
LD_FILE = ${FAMILY_PATH}/linker/STM32U545xx_FLASH.ld
-SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u545xx.s
-
-MCU_VARIANT = stm32u545xx
# For flash-jlink target
JLINK_DEVICE = stm32u545re
diff --git a/hw/bsp/stm32u5/boards/stm32u575eval/board.mk b/hw/bsp/stm32u5/boards/stm32u575eval/board.mk
index fee56f2ba..4bc9fea10 100644
--- a/hw/bsp/stm32u5/boards/stm32u575eval/board.mk
+++ b/hw/bsp/stm32u5/boards/stm32u575eval/board.mk
@@ -1,11 +1,9 @@
+MCU_VARIANT = stm32u575xx
CFLAGS += \
-DSTM32U575xx \
# All source paths should be relative to the top level.
LD_FILE = ${FAMILY_PATH}/linker/STM32U575xx_FLASH.ld
-SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u575xx.s
-
-MCU_VARIANT = stm32u575xx
# For flash-jlink target
JLINK_DEVICE = stm32u575ai
diff --git a/hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk b/hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk
index c83ec3999..d09dc5c46 100644
--- a/hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk
+++ b/hw/bsp/stm32u5/boards/stm32u575nucleo/board.mk
@@ -1,11 +1,9 @@
+MCU_VARIANT = stm32u575xx
CFLAGS += \
-DSTM32U575xx \
# All source paths should be relative to the top level.
LD_FILE = ${FAMILY_PATH}/linker/STM32U575xx_FLASH.ld
-SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u575xx.s
-
-MCU_VARIANT = stm32u575xx
# For flash-jlink target
JLINK_DEVICE = stm32u575zi
diff --git a/hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk b/hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk
index 4bebe3330..c9fdbac1a 100644
--- a/hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk
+++ b/hw/bsp/stm32u5/boards/stm32u5a5nucleo/board.mk
@@ -1,3 +1,4 @@
+MCU_VARIANT = stm32u5a5xx
CFLAGS += \
-DSTM32U5A5xx \
-DHSE_VALUE=16000000UL \
@@ -5,8 +6,5 @@ CFLAGS += \
# All source paths should be relative to the top level.
LD_FILE = ${BOARD_PATH}/STM32U5A5ZJTXQ_FLASH.ld
-SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32u5a5xx.s
-
-MCU_VARIANT = stm32u5a5xx
# For flash-jlink target
JLINK_DEVICE = stm32u575zi
diff --git a/hw/bsp/stm32u5/family.mk b/hw/bsp/stm32u5/family.mk
index 05fe4608a..7fc728dcf 100644
--- a/hw/bsp/stm32u5/family.mk
+++ b/hw/bsp/stm32u5/family.mk
@@ -57,5 +57,12 @@ INC += \
$(TOP)/$(ST_HAL_DRIVER)/Inc \
$(TOP)/$(BOARD_PATH)
+# Startup
+SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_$(MCU_VARIANT).s
+SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT).s
+
+# Linker
+LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash.icf
+
# flash target using on-board stlink
flash: flash-stlink
diff --git a/hw/bsp/stm32wb/boards/stm32wb55nucleo/stm32wb55xx_flash_cm4.ld b/hw/bsp/stm32wb/boards/stm32wb55nucleo/stm32wb55xx_flash_cm4.ld
index 916f11866..c16235586 100644
--- a/hw/bsp/stm32wb/boards/stm32wb55nucleo/stm32wb55xx_flash_cm4.ld
+++ b/hw/bsp/stm32wb/boards/stm32wb55nucleo/stm32wb55xx_flash_cm4.ld
@@ -3,21 +3,26 @@
**
** File : stm32wb55xx_flash_cm4.ld
**
-** Abstract : System Workbench Minimal System calls file
+** Author : STM32CubeIDE
**
-** For more information about which c-functions
-** need which of these lowlevel functions
-** please consult the Newlib libc-manual
+** Abstract : Linker script for STM32WB55xx Device
+** 1024Kbytes FLASH
+** 128Kbytes RAM
**
-** Environment : System Workbench for MCU
+** Set heap size, stack size and stack location according
+** to application requirements.
**
-** Distribution: The file is distributed “as is,” without any warranty
+** Set memory bank area and size if external memory is used.
+**
+** Target : STMicroelectronics STM32
+**
+** Distribution: The file is distributed as is without any warranty
** of any kind.
**
*****************************************************************************
** @attention
**
-** Copyright (c) 2019 STMicroelectronics.
+** Copyright (c) 2019-2022 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
@@ -33,7 +38,7 @@ ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20030000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
-_Min_Heap_Size = 0x400; /* required amount of heap */
+_Min_Heap_Size = 0x400; /* required amount of heap */
_Min_Stack_Size = 0x1000; /* required amount of stack */
/* Specify the memory areas */
@@ -81,14 +86,17 @@ SECTIONS
. = ALIGN(4);
} >FLASH
- .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
+ .ARM.extab :
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
- .preinit_array :
+ .preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
@@ -124,7 +132,6 @@ SECTIONS
_edata = .; /* define a global symbol at data end */
} >RAM1 AT> FLASH
-
/* Uninitialized data section */
. = ALIGN(4);
.bss :
@@ -152,8 +159,6 @@ SECTIONS
. = ALIGN(8);
} >RAM1
-
-
/* Remove information from the standard libraries */
/DISCARD/ :
{
@@ -163,7 +168,15 @@ SECTIONS
}
.ARM.attributes 0 : { *(.ARM.attributes) }
- MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED
- MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED
- MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED
+ MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED
+ MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED
+
+ /* used by the startup to initialize .MB_MEM2 data */
+ _siMB_MEM2 = LOADADDR(.MB_MEM2);
+ .MB_MEM2 :
+ {
+ _sMB_MEM2 = . ;
+ *(MB_MEM2) ;
+ _eMB_MEM2 = . ;
+ } >RAM_SHARED AT> FLASH
}
diff --git a/hw/bsp/stm32wb/family.c b/hw/bsp/stm32wb/family.c
index ba37b7cc3..93aba02fa 100644
--- a/hw/bsp/stm32wb/family.c
+++ b/hw/bsp/stm32wb/family.c
@@ -184,8 +184,7 @@ void HardFault_Handler(void) {
asm("bkpt 1");
}
-// Required by __libc_init_array in startup code if we are compiling using
-// -nostdlib/-nostartfiles.
+// Required by __libc_init_array in startup code if we are compiling using -nostdlib/-nostartfiles.
+void _init(void);
void _init(void) {
-
}
diff --git a/hw/bsp/stm32wb/family.mk b/hw/bsp/stm32wb/family.mk
index de8372eea..a80ff6f5b 100644
--- a/hw/bsp/stm32wb/family.mk
+++ b/hw/bsp/stm32wb/family.mk
@@ -9,14 +9,12 @@ include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m4
CFLAGS += \
- -flto \
- -nostdlib -nostartfiles \
-DCFG_TUSB_MCU=OPT_MCU_STM32WB
-# suppress warning caused by vendor mcu driver
-CFLAGS += -Wno-error=cast-align -Wno-unused-parameter
-
-LD_FILE ?= ${ST_CMSIS}/Source/Templates/gcc/linker/${MCU_VARIANT}_flash_cm4.ld
+CFLAGS_GCC += \
+ -flto \
+ -nostdlib -nostartfiles \
+ -Wno-error=cast-align -Wno-unused-parameter
LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs
@@ -25,19 +23,26 @@ SRC_C += \
$(ST_CMSIS)/Source/Templates/system_${ST_PREFIX}.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_cortex.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pwr.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pwr_ex.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_rcc.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_rcc_ex.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_uart.c \
$(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_gpio.c
-SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}_cm4.s
-
INC += \
$(TOP)/$(BOARD_PATH) \
$(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
$(TOP)/$(ST_CMSIS)/Include \
$(TOP)/$(ST_HAL_DRIVER)/Inc
+# Startup
+SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_$(MCU_VARIANT)_cm4.s
+SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT)_cm4.s
+
+# Linker
+LD_FILE_GCC ?= ${ST_CMSIS}/Source/Templates/gcc/linker/${MCU_VARIANT}_flash_cm4.ld
+LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash_cm4.icf
+
# flash target using on-board stlink
flash: flash-stlink
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index 4058857c5..bf245db3f 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -672,7 +672,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) {
// TODO handle stall response, retry failed transfer ...
- TU_ASSERT(event == XFER_RESULT_SUCCESS);
+ TU_VERIFY(event == XFER_RESULT_SUCCESS);
uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr);
cdch_interface_t * p_cdc = get_itf(idx);
diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c
index a3cc7d6d7..57e437196 100644
--- a/src/class/hid/hid_host.c
+++ b/src/class/hid/hid_host.c
@@ -444,7 +444,7 @@ bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t
hidh_epbuf_t* epbuf = get_hid_epbuf(idx);
if (dir == TUSB_DIR_IN) {
- TU_LOG_DRV(" Get Report callback (%u, %u)\r\n", daddr, idx);
+ TU_LOG_DRV(" [idx=%u] Get Report callback\r\n", idx);
TU_LOG3_MEM(epbuf->epin, xferred_bytes, 2);
tuh_hid_report_received_cb(daddr, idx, epbuf->epin, (uint16_t) xferred_bytes);
} else {
@@ -461,7 +461,9 @@ void hidh_close(uint8_t daddr) {
hidh_interface_t* p_hid = &_hidh_itf[i];
if (p_hid->daddr == daddr) {
TU_LOG_DRV(" HIDh close addr = %u index = %u\r\n", daddr, i);
- if (tuh_hid_umount_cb) tuh_hid_umount_cb(daddr, i);
+ if (tuh_hid_umount_cb) {
+ tuh_hid_umount_cb(daddr, i);
+ }
tu_memclr(p_hid, sizeof(hidh_interface_t));
}
}
diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c
index 6670045aa..87c77c9a7 100644
--- a/src/class/msc/msc_device.c
+++ b/src/class/msc/msc_device.c
@@ -344,7 +344,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
msc_csw_t * p_csw = &p_msc->csw;
switch (p_msc->stage) {
- case MSC_STAGE_CMD:
+ case MSC_STAGE_CMD: {
//------------- new CBW received -------------//
// Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it
if (ep_addr != p_msc->ep_out) {
@@ -441,7 +441,8 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
}
}
}
- break;
+ break;
+ }
case MSC_STAGE_DATA:
TU_LOG_DRV(" SCSI Data [Lun%u]\r\n", p_cbw->lun);
diff --git a/src/common/tusb_debug.h b/src/common/tusb_debug.h
index 2e9f1d9cd..1d0c6f1ad 100644
--- a/src/common/tusb_debug.h
+++ b/src/common/tusb_debug.h
@@ -108,15 +108,13 @@ typedef struct {
} tu_lookup_table_t;
static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) {
- tu_static char not_found[11];
-
for(uint16_t i=0; icount; i++) {
- if (p_table->items[i].key == key) return p_table->items[i].data;
+ if (p_table->items[i].key == key) { return p_table->items[i].data; }
}
// not found return the key value in hex
+ static char not_found[11];
snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key);
-
return not_found;
}
diff --git a/src/host/hcd.h b/src/host/hcd.h
index b20d96d54..d3551bf5b 100644
--- a/src/host/hcd.h
+++ b/src/host/hcd.h
@@ -90,13 +90,6 @@ typedef struct {
};
} hcd_event_t;
-typedef struct {
- uint8_t rhport;
- uint8_t hub_addr;
- uint8_t hub_port;
- uint8_t speed;
-} hcd_devtree_info_t;
-
//--------------------------------------------------------------------+
// Memory API
//--------------------------------------------------------------------+
@@ -186,13 +179,6 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr);
// USBH implemented API
//--------------------------------------------------------------------+
-// Get device tree information of a device
-// USB device tree can be complicated and manged by USBH, this help HCD to retrieve
-// needed topology info to carry out its work
-extern void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info);
-
-//------------- Event API -------------//
-
// Called by HCD to notify stack
extern void hcd_event_handler(hcd_event_t const* event, bool in_isr);
@@ -239,4 +225,4 @@ void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred
}
#endif
-#endif /* _TUSB_HCD_H_ */
+#endif
diff --git a/src/host/hub.c b/src/host/hub.c
index 61efa8ba5..0b172a596 100644
--- a/src/host/hub.c
+++ b/src/host/hub.c
@@ -57,9 +57,11 @@ typedef struct {
TUH_EPBUF_DEF(ctrl_buf, CFG_TUH_HUB_BUFSIZE);
} hub_epbuf_t;
+static tuh_xfer_cb_t user_complete_cb = NULL;
static hub_interface_t hub_itfs[CFG_TUH_HUB];
CFG_TUH_MEM_SECTION static hub_epbuf_t hub_epbufs[CFG_TUH_HUB];
+
TU_ATTR_ALWAYS_INLINE static inline hub_interface_t* get_hub_itf(uint8_t daddr) {
return &hub_itfs[daddr-1-CFG_TUH_DEVICE_MAX];
}
@@ -142,10 +144,23 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
};
TU_LOG_DRV("HUB Set Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port);
- TU_ASSERT( tuh_control_xfer(&xfer) );
+ TU_ASSERT(tuh_control_xfer(&xfer));
return true;
}
+static void port_get_status_complete (tuh_xfer_t* xfer) {
+ if (xfer->result == XFER_RESULT_SUCCESS) {
+ hub_interface_t* p_hub = get_hub_itf(xfer->daddr);
+ p_hub->port_status = *((const hub_port_status_response_t *) (uintptr_t) xfer->buffer);
+ }
+
+ xfer->complete_cb = user_complete_cb;
+ user_complete_cb = NULL;
+ if (xfer->complete_cb) {
+ xfer->complete_cb(xfer);
+ }
+}
+
bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
tusb_control_request_t const request = {
@@ -169,8 +184,25 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
.user_data = user_data
};
+ if (hub_port != 0) {
+ // intercept complete callback to save port status, ignore resp
+ hub_epbuf_t* p_epbuf = get_hub_epbuf(hub_addr);
+ xfer.complete_cb = port_get_status_complete;
+ xfer.buffer = p_epbuf->ctrl_buf;
+ user_complete_cb = complete_cb;
+ } else {
+ user_complete_cb = NULL;
+ }
+
TU_LOG_DRV("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port);
- TU_VERIFY( tuh_control_xfer(&xfer) );
+ TU_VERIFY(tuh_control_xfer(&xfer));
+ return true;
+}
+
+bool hub_port_get_status_local(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp) {
+ (void) hub_port;
+ hub_interface_t* p_hub = get_hub_itf(hub_addr);
+ *resp = p_hub->port_status;
return true;
}
@@ -238,10 +270,10 @@ bool hub_edpt_status_xfer(uint8_t daddr) {
static void config_set_port_power (tuh_xfer_t* xfer);
static void config_port_power_complete (tuh_xfer_t* xfer);
-bool hub_set_config(uint8_t dev_addr, uint8_t itf_num) {
- hub_interface_t* p_hub = get_hub_itf(dev_addr);
+bool hub_set_config(uint8_t daddr, uint8_t itf_num) {
+ hub_interface_t* p_hub = get_hub_itf(daddr);
TU_ASSERT(itf_num == p_hub->itf_num);
- hub_epbuf_t* p_epbuf = get_hub_epbuf(dev_addr);
+ hub_epbuf_t* p_epbuf = get_hub_epbuf(daddr);
// Get Hub Descriptor
tusb_control_request_t const request = {
@@ -257,7 +289,7 @@ bool hub_set_config(uint8_t dev_addr, uint8_t itf_num) {
};
tuh_xfer_t xfer = {
- .daddr = dev_addr,
+ .daddr = daddr,
.ep_addr = 0,
.setup = &request,
.buffer = p_epbuf->ctrl_buf,
@@ -312,11 +344,15 @@ static void config_port_power_complete (tuh_xfer_t* xfer) {
//--------------------------------------------------------------------+
// Connection Changes
//--------------------------------------------------------------------+
-static void get_status_complete (tuh_xfer_t* xfer);
-static void port_get_status_complete (tuh_xfer_t* xfer);
-static void port_clear_feature_complete_stub(tuh_xfer_t* xfer);
-static void connection_clear_conn_change_complete (tuh_xfer_t* xfer);
-static void connection_port_reset_complete (tuh_xfer_t* xfer);
+enum {
+ STATE_IDLE = 0,
+ STATE_HUB_STATUS,
+ STATE_CLEAR_CHANGE,
+ STATE_CHECK_CONN,
+ STATE_COMPLETE
+};
+
+static void process_new_status(tuh_xfer_t* xfer);
// callback as response of interrupt endpoint polling
bool hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
@@ -337,12 +373,12 @@ bool hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t
processed = false;
} else if (tu_bit_test(status_change, 0)) {
// Hub bit 0 is for the hub device events
- processed = hub_get_status(daddr, p_epbuf->ctrl_buf, get_status_complete, 0);
+ processed = hub_get_status(daddr, p_epbuf->ctrl_buf, process_new_status, STATE_HUB_STATUS);
} else {
// Hub bits 1 to n are hub port events
for (uint8_t port=1; port <= p_hub->bNbrPorts; port++) {
if (tu_bit_test(status_change, port)) {
- processed = hub_port_get_status(daddr, port, p_epbuf->ctrl_buf, port_get_status_complete, 0);
+ processed = hub_port_get_status(daddr, port, NULL, process_new_status, STATE_CLEAR_CHANGE);
break; // after completely processed one port, we will re-queue the status poll and handle next one
}
}
@@ -358,117 +394,85 @@ bool hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t
return true;
}
-static void port_clear_feature_complete_stub(tuh_xfer_t* xfer) {
- hub_edpt_status_xfer(xfer->daddr);
-}
-
-static void get_status_complete(tuh_xfer_t *xfer) {
- const uint8_t daddr = xfer->daddr;
-
- bool processed = false; // true if new status is processed
- if (xfer->result == XFER_RESULT_SUCCESS) {
- hub_status_response_t hub_status = *((const hub_status_response_t *) (uintptr_t) xfer->buffer);
-
- TU_LOG_DRV("HUB Got hub status, addr = %u, status = %04x\r\n", daddr, hub_status.change.value);
-
- if (hub_status.change.local_power_source) {
- TU_LOG_DRV(" Local Power Change\r\n");
- processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_LOCAL_POWER_CHANGE, port_clear_feature_complete_stub, 0);
- } else if (hub_status.change.over_current) {
- TU_LOG_DRV(" Over Current\r\n");
- processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_OVER_CURRENT_CHANGE, port_clear_feature_complete_stub, 0);
- }
- }
-
- if (!processed) {
- TU_ASSERT(hub_edpt_status_xfer(daddr), );
- }
-}
-
-static void port_get_status_complete(tuh_xfer_t *xfer) {
- const uint8_t daddr = xfer->daddr;
- bool processed = false; // true if new status is processed
-
- if (xfer->result == XFER_RESULT_SUCCESS) {
- const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
- hub_interface_t *p_hub = get_hub_itf(daddr);
- p_hub->port_status = *((const hub_port_status_response_t *) (uintptr_t) xfer->buffer);
-
- // Clear port status change interrupts
- if (p_hub->port_status.change.connection) {
- // Connection change
- // Port is powered and enabled
- //TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, );
-
- // Acknowledge Port Connection Change
- processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete, 0);
- } else if (p_hub->port_status.change.port_enable) {
- processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_ENABLE_CHANGE, port_clear_feature_complete_stub, 0);
- } else if (p_hub->port_status.change.suspend) {
- processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_SUSPEND_CHANGE, port_clear_feature_complete_stub, 0);
- } else if (p_hub->port_status.change.over_current) {
- processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_OVER_CURRENT_CHANGE, port_clear_feature_complete_stub, 0);
- } else if (p_hub->port_status.change.reset) {
- processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_RESET_CHANGE, port_clear_feature_complete_stub, 0);
- }
- }
-
- if (!processed) {
- TU_ASSERT(hub_edpt_status_xfer(daddr), );
- }
-}
-
-static void connection_clear_conn_change_complete (tuh_xfer_t* xfer) {
+static void process_new_status(tuh_xfer_t* xfer) {
const uint8_t daddr = xfer->daddr;
if (xfer->result != XFER_RESULT_SUCCESS) {
- TU_ASSERT(hub_edpt_status_xfer(daddr), );
+ TU_ASSERT(hub_edpt_status_xfer(daddr),);
return;
}
+ const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
hub_interface_t *p_hub = get_hub_itf(daddr);
- const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ const uintptr_t state = xfer->user_data;
+ bool processed = false; // true if new status is processed
- if (p_hub->port_status.status.connection) {
- // Reset port if attach event
- hub_port_reset(daddr, port_num, connection_port_reset_complete, 0);
- } else {
- // submit detach event
- const hcd_event_t event = {
- .rhport = usbh_get_rhport(daddr),
- .event_id = HCD_EVENT_DEVICE_REMOVE,
- .connection = {
- .hub_addr = daddr,
- .hub_port = port_num
- }
- };
- hcd_event_handler(&event, false);
- }
-}
-
-static void connection_port_reset_complete (tuh_xfer_t* xfer) {
- const uint8_t daddr = xfer->daddr;
-
- if (xfer->result != XFER_RESULT_SUCCESS) {
- // retry port reset if failed
- if (!tuh_control_xfer(xfer)) {
- TU_ASSERT(hub_edpt_status_xfer(daddr), ); // back to status poll if failed to queue request
+ switch (state) {
+ case STATE_HUB_STATUS: {
+ hub_status_response_t hub_status = *((const hub_status_response_t *) (uintptr_t) xfer->buffer);
+ TU_LOG_DRV("HUB Got hub status, addr = %u, status = %04x\r\n", daddr, hub_status.change.value);
+ if (hub_status.change.local_power_source) {
+ TU_LOG_DRV(" Local Power Change\r\n");
+ processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_LOCAL_POWER_CHANGE,
+ process_new_status, STATE_COMPLETE);
+ } else if (hub_status.change.over_current) {
+ TU_LOG_DRV(" Over Current\r\n");
+ processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_OVER_CURRENT_CHANGE,
+ process_new_status, STATE_COMPLETE);
+ }
+ break;
}
- return;
+
+ case STATE_CLEAR_CHANGE:
+ // Get port status complete --> clear change
+ if (p_hub->port_status.change.connection) {
+ // Connection change
+ // Port is powered and enabled
+ //TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, );
+
+ // Acknowledge Port Connection Change
+ processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE,
+ process_new_status, STATE_CHECK_CONN);
+ } else if (p_hub->port_status.change.port_enable) {
+ processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_ENABLE_CHANGE,
+ process_new_status, STATE_COMPLETE);
+ } else if (p_hub->port_status.change.suspend) {
+ processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_SUSPEND_CHANGE,
+ process_new_status, STATE_COMPLETE);
+ } else if (p_hub->port_status.change.over_current) {
+ processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_OVER_CURRENT_CHANGE,
+ process_new_status, STATE_COMPLETE);
+ } else if (p_hub->port_status.change.reset) {
+ processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_RESET_CHANGE,
+ process_new_status, STATE_COMPLETE);
+ }
+ break;
+
+ case STATE_CHECK_CONN: {
+ const hcd_event_t event = {
+ .rhport = usbh_get_rhport(daddr),
+ .event_id = p_hub->port_status.status.connection ? HCD_EVENT_DEVICE_ATTACH : HCD_EVENT_DEVICE_REMOVE,
+ .connection = {
+ .hub_addr = daddr,
+ .hub_port = port_num
+ }
+ };
+ hcd_event_handler(&event, false);
+ // skip status for attach event, usbh will do it after handled this enumeration
+ processed = (event.event_id == HCD_EVENT_DEVICE_ATTACH);
+ break;
+ }
+
+ case STATE_COMPLETE:
+ default:
+ processed = false; // complete this status, queue next status
+ break;
+
}
- const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
-
- // submit attach event
- hcd_event_t event = {
- .rhport = usbh_get_rhport(daddr),
- .event_id = HCD_EVENT_DEVICE_ATTACH,
- .connection = {
- .hub_addr = daddr,
- .hub_port = port_num
- }
- };
- hcd_event_handler(&event, false);
+ if (!processed) {
+ TU_ASSERT(hub_edpt_status_xfer(daddr),);
+ }
}
#endif
diff --git a/src/host/hub.h b/src/host/hub.h
index e4e576661..3587f0ee3 100644
--- a/src/host/hub.h
+++ b/src/host/hub.h
@@ -170,9 +170,13 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Get port status
+// If hub_port != 0, resp is ignored. hub_port_get_status_local() can be used to retrieve the status
bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void *resp,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+// Get port status from local cache. This does not send a request to the device
+bool hub_port_get_status_local(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp);
+
// Get status from Interrupt endpoint
bool hub_edpt_status_xfer(uint8_t daddr);
@@ -188,7 +192,7 @@ bool hub_port_clear_reset_change(uint8_t hub_addr, uint8_t hub_port, tuh_xfer_cb
return hub_port_clear_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET_CHANGE, complete_cb, user_data);
}
-// Get Hub status
+// Get Hub status (port = 0)
TU_ATTR_ALWAYS_INLINE static inline
bool hub_get_status(uint8_t hub_addr, void* resp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return hub_port_get_status(hub_addr, 0, resp, complete_cb, user_data);
@@ -205,7 +209,7 @@ bool hub_clear_feature(uint8_t hub_addr, uint8_t feature, tuh_xfer_cb_t complete
bool hub_init (void);
bool hub_deinit (void);
bool hub_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
-bool hub_set_config (uint8_t dev_addr, uint8_t itf_num);
+bool hub_set_config (uint8_t daddr, uint8_t itf_num);
bool hub_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
void hub_close (uint8_t dev_addr);
diff --git a/src/host/usbh.c b/src/host/usbh.c
index e60db53da..b7d5a05f2 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -28,13 +28,13 @@
#if CFG_TUH_ENABLED
-#include "host/hcd.h"
+#include "hcd.h"
#include "tusb.h"
-#include "host/usbh_pvt.h"
+#include "usbh_pvt.h"
#include "hub.h"
//--------------------------------------------------------------------+
-// USBH Configuration
+// Configuration
//--------------------------------------------------------------------+
#ifndef CFG_TUH_TASK_QUEUE_SZ
#define CFG_TUH_TASK_QUEUE_SZ 16
@@ -89,27 +89,10 @@ TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_si
}
//--------------------------------------------------------------------+
-// USBH-HCD common data structure
+// Data Structure
//--------------------------------------------------------------------+
typedef struct {
- // port
- uint8_t rhport;
- uint8_t hub_addr;
- uint8_t hub_port;
-
- struct TU_ATTR_PACKED {
- uint8_t speed : 4; // packed speed to save footprint
- volatile uint8_t enumerating : 1; // enumeration is in progress, false if not connected or all interfaces are configured
- uint8_t TU_RESERVED : 3;
- };
-} usbh_dev0_t;
-
-typedef struct {
- // port, must be same layout as usbh_dev0_t
- uint8_t rhport;
- uint8_t hub_addr;
- uint8_t hub_port;
- uint8_t speed;
+ tuh_bus_info_t bus_info;
// Device State
struct TU_ATTR_PACKED {
@@ -117,19 +100,16 @@ typedef struct {
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
uint8_t ep0_size;
-
- uint16_t vid;
- uint16_t pid;
-
- uint8_t i_manufacturer;
- uint8_t i_product;
- uint8_t i_serial;
+ uint16_t idVendor;
+ uint16_t idProduct;
+ uint8_t iManufacturer;
+ uint8_t iProduct;
+ uint8_t iSerialNumber;
uint8_t bNumConfigurations;
// Configuration Descriptor
@@ -151,8 +131,60 @@ typedef struct {
} usbh_device_t;
+// sum of end device + hub
+#define TOTAL_DEVICES (CFG_TUH_DEVICE_MAX + CFG_TUH_HUB)
+
+// all devices excluding zero-address
+// hub address start from CFG_TUH_DEVICE_MAX+1
+// TODO: hub can has its own simpler struct to save memory
+static usbh_device_t _usbh_devices[TOTAL_DEVICES];
+
+// Mutex for claiming endpoint
+#if OSAL_MUTEX_REQUIRED
+static osal_mutex_def_t _usbh_mutexdef;
+static osal_mutex_t _usbh_mutex;
+#else
+#define _usbh_mutex NULL
+#endif
+
+// Event queue: usbh_int_set() is used as mutex in OS NONE config
+OSAL_QUEUE_DEF(usbh_int_set, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t);
+static osal_queue_t _usbh_q;
+
+// Control transfers: since most controllers do not support multiple control transfers
+// on multiple devices concurrently and control transfers are not used much except for
+// enumeration, we will only execute control transfers one at a time.
+typedef struct {
+ uint8_t* buffer;
+ tuh_xfer_cb_t complete_cb;
+ uintptr_t user_data;
+
+ volatile uint8_t stage;
+ uint8_t daddr;
+ volatile uint16_t actual_len;
+ uint8_t failed_count;
+} usbh_ctrl_xfer_info_t;
+
+typedef struct {
+ uint8_t controller_id; // controller ID
+ uint8_t enumerating_daddr; // device address of the device being enumerated
+ uint8_t attach_debouncing_bm; // bitmask for roothub port attach debouncing
+ tuh_bus_info_t dev0_bus; // bus info for dev0 in enumeration
+ usbh_ctrl_xfer_info_t ctrl_xfer_info; // control transfer
+} usbh_data_t;
+
+static usbh_data_t _usbh_data = {
+ .controller_id = TUSB_INDEX_INVALID_8,
+};
+
+typedef struct {
+ TUH_EPBUF_TYPE_DEF(tusb_control_request_t, request);
+ TUH_EPBUF_DEF(ctrl, CFG_TUH_ENUMERATION_BUFSIZE);
+} usbh_epbuf_t;
+CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf;
+
//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF
+// Class Driver
//--------------------------------------------------------------------+
#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL
#define DRIVER_NAME(_name) _name
@@ -237,8 +269,8 @@ static usbh_class_driver_t const usbh_class_drivers[] = {
enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) };
// Additional class drivers implemented by application
-tu_static usbh_class_driver_t const * _app_driver = NULL;
-tu_static uint8_t _app_driver_count = 0;
+static usbh_class_driver_t const * _app_driver = NULL;
+static uint8_t _app_driver_count = 0;
#define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT)
@@ -255,66 +287,21 @@ static inline usbh_class_driver_t const *get_driver(uint8_t drv_id) {
}
//--------------------------------------------------------------------+
-// INTERNAL OBJECT & FUNCTION DECLARATION
+// Function Inline and Prototypes
//--------------------------------------------------------------------+
+static bool enum_new_device(hcd_event_t* event);
+static void process_removed_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);
-// sum of end device + hub
-#define TOTAL_DEVICES (CFG_TUH_DEVICE_MAX + CFG_TUH_HUB)
-
-static uint8_t _usbh_controller = TUSB_INDEX_INVALID_8;
-
-// Device with address = 0 for enumeration
-static usbh_dev0_t _dev0;
-
-// all devices excluding zero-address
-// hub address start from CFG_TUH_DEVICE_MAX+1
-// TODO: hub can has its own simpler struct to save memory
-static usbh_device_t _usbh_devices[TOTAL_DEVICES];
-
-// Mutex for claiming endpoint
-#if OSAL_MUTEX_REQUIRED
- static osal_mutex_def_t _usbh_mutexdef;
- static osal_mutex_t _usbh_mutex;
-#else
- #define _usbh_mutex NULL
-#endif
-
-// Event queue
-// usbh_int_set is used as mutex in OS NONE config
-OSAL_QUEUE_DEF(usbh_int_set, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t);
-static osal_queue_t _usbh_q;
-
-// Control transfers: since most controllers do not support multiple control transfers
-// on multiple devices concurrently and control transfers are not used much except for
-// enumeration, we will only execute control transfers one at a time.
-static struct {
- uint8_t* buffer;
- tuh_xfer_cb_t complete_cb;
- uintptr_t user_data;
-
- volatile uint8_t stage;
- uint8_t daddr;
- volatile uint16_t actual_len;
- uint8_t failed_count;
-} _ctrl_xfer;
-
-typedef struct {
- TUH_EPBUF_TYPE_DEF(tusb_control_request_t, request);
- TUH_EPBUF_DEF(ctrl, CFG_TUH_ENUMERATION_BUFSIZE);
-} usbh_epbuf_t;
-
-CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf;
-
-//------------- Helper Function -------------//
TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) {
TU_VERIFY(dev_addr > 0 && dev_addr <= TOTAL_DEVICES, NULL);
return &_usbh_devices[dev_addr-1];
}
-static bool enum_new_device(hcd_event_t* event);
-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);
+TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) {
+ return (CFG_TUH_HUB > 0) && (daddr > CFG_TUH_DEVICE_MAX);
+}
TU_ATTR_ALWAYS_INLINE static inline bool queue_event(hcd_event_t const * event, bool in_isr) {
TU_ASSERT(osal_queue_send(_usbh_q, event, in_isr));
@@ -322,10 +309,40 @@ TU_ATTR_ALWAYS_INLINE static inline bool queue_event(hcd_event_t const * event,
return true;
}
+TU_ATTR_ALWAYS_INLINE static inline void _control_set_xfer_stage(uint8_t stage) {
+ if (_usbh_data.ctrl_xfer_info.stage != stage) {
+ (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
+ _usbh_data.ctrl_xfer_info.stage = stage;
+ (void) osal_mutex_unlock(_usbh_mutex);
+ }
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool usbh_setup_send(uint8_t daddr, const uint8_t setup_packet[8]) {
+ const uint8_t rhport = usbh_get_rhport(daddr);
+ const bool ret = hcd_setup_send(rhport, daddr, setup_packet);
+ if (!ret) {
+ _control_set_xfer_stage(CONTROL_STAGE_IDLE);
+ }
+ return ret;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void usbh_device_close(uint8_t rhport, uint8_t daddr) {
+ hcd_device_close(rhport, daddr);
+
+ // abort any ongoing control transfer
+ if (daddr == _usbh_data.ctrl_xfer_info.daddr) {
+ _control_set_xfer_stage(CONTROL_STAGE_IDLE);
+ }
+
+ // invalidate if enumerating
+ if (daddr == _usbh_data.enumerating_daddr) {
+ _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8;
+ }
+}
+
//--------------------------------------------------------------------+
// Device API
//--------------------------------------------------------------------+
-
bool tuh_mounted(uint8_t dev_addr) {
usbh_device_t *dev = get_device(dev_addr);
TU_VERIFY(dev);
@@ -334,7 +351,7 @@ bool tuh_mounted(uint8_t dev_addr) {
bool tuh_connected(uint8_t daddr) {
if (daddr == 0) {
- return _dev0.enumerating; // dev0 is connected if still enumerating
+ return _usbh_data.enumerating_daddr == 0;
} else {
const usbh_device_t* dev = get_device(daddr);
return dev && dev->connected;
@@ -345,26 +362,27 @@ 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->addressed && dev->vid != 0);
+ TU_VERIFY(dev && dev->addressed && dev->idVendor != 0);
- *vid = dev->vid;
- *pid = dev->pid;
+ *vid = dev->idVendor;
+ *pid = dev->idProduct;
return true;
}
-tusb_speed_t tuh_speed_get(uint8_t dev_addr) {
- usbh_device_t *dev = get_device(dev_addr);
- return (tusb_speed_t) (dev ? get_device(dev_addr)->speed : _dev0.speed);
+tusb_speed_t tuh_speed_get(uint8_t daddr) {
+ tuh_bus_info_t bus_info;
+ tuh_bus_info_get(daddr, &bus_info);
+ return bus_info.speed;
}
bool tuh_rhport_is_active(uint8_t rhport) {
- return _usbh_controller == rhport;
+ return _usbh_data.controller_id == rhport;
}
bool tuh_rhport_reset_bus(uint8_t rhport, bool active) {
TU_VERIFY(tuh_rhport_is_active(rhport));
- if ( active ) {
+ if (active) {
hcd_port_reset(rhport);
} else {
hcd_port_reset_end(rhport);
@@ -375,7 +393,6 @@ bool tuh_rhport_reset_bus(uint8_t rhport, bool active) {
//--------------------------------------------------------------------+
// PUBLIC API (Parameter Verification is required)
//--------------------------------------------------------------------+
-
bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void *cfg_param) {
return hcd_configure(rhport, cfg_id, cfg_param);
}
@@ -387,7 +404,7 @@ static void clear_device(usbh_device_t* dev) {
}
bool tuh_inited(void) {
- return _usbh_controller != TUSB_INDEX_INVALID_8;
+ return _usbh_data.controller_id != TUSB_INDEX_INVALID_8;
}
bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
@@ -400,9 +417,9 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
// Init host stack if not already
if (!tuh_inited()) {
+ TU_LOG_INT_USBH(sizeof(usbh_data_t));
TU_LOG_INT_USBH(sizeof(usbh_device_t));
TU_LOG_INT_USBH(sizeof(hcd_event_t));
- TU_LOG_INT_USBH(sizeof(_ctrl_xfer));
TU_LOG_INT_USBH(sizeof(tuh_xfer_t));
TU_LOG_INT_USBH(sizeof(tu_fifo_t));
TU_LOG_INT_USBH(sizeof(tu_edpt_stream_t));
@@ -423,9 +440,11 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
}
// Device
- tu_memclr(&_dev0, sizeof(_dev0));
tu_memclr(_usbh_devices, sizeof(_usbh_devices));
- tu_memclr(&_ctrl_xfer, sizeof(_ctrl_xfer));
+ tu_memclr(&_usbh_data, sizeof(_usbh_data));
+
+ _usbh_data.controller_id = TUSB_INDEX_INVALID_8;
+ _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8;
for (uint8_t i = 0; i < TOTAL_DEVICES; i++) {
clear_device(&_usbh_devices[i]);
@@ -442,7 +461,7 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
}
// Init host controller
- _usbh_controller = rhport;
+ _usbh_data.controller_id = rhport;
TU_ASSERT(hcd_init(rhport, rh_init));
hcd_int_enable(rhport);
@@ -457,10 +476,10 @@ bool tuh_deinit(uint8_t rhport) {
// deinit host controller
hcd_int_disable(rhport);
hcd_deinit(rhport);
- _usbh_controller = TUSB_INDEX_INVALID_8;
+ _usbh_data.controller_id = TUSB_INDEX_INVALID_8;
// "unplug" all devices on this rhport (hub_addr = 0, hub_port = 0)
- process_removing_device(rhport, 0, 0);
+ process_removed_device(rhport, 0, 0);
// deinit host stack if no controller is active
if (!tuh_inited()) {
@@ -524,46 +543,35 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
switch (event.event_id) {
case HCD_EVENT_DEVICE_ATTACH:
- // due to the shared control buffer, we must complete enumerating one device before enumerating another one.
+ // due to the shared control buffer, we must fully complete enumerating one device first.
// TODO better to have an separated queue for newly attached devices
- if (_dev0.enumerating) {
- // Some device can cause multiple duplicated attach events
- // drop current enumerating and start over for a proper port reset
- if (event.rhport == _dev0.rhport && event.connection.hub_addr == _dev0.hub_addr &&
- event.connection.hub_port == _dev0.hub_port) {
- // abort/cancel current enumeration and start new one
- TU_LOG1("[%u:] USBH Device Attach (duplicated)\r\n", event.rhport);
- tuh_edpt_abort_xfer(0, 0);
- enum_new_device(&event);
- } else {
- TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport);
-
- bool is_empty = osal_queue_empty(_usbh_q);
- queue_event(&event, in_isr);
-
- if (is_empty) {
- // Exit if this is the only event in the queue, otherwise we may loop forever
- return;
- }
- }
- } else {
- TU_LOG1("[%u:] USBH Device Attach\r\n", event.rhport);
- _dev0.enumerating = 1;
+ if (_usbh_data.enumerating_daddr == TUSB_INDEX_INVALID_8) {
+ // New device attached and we are ready
+ TU_LOG_USBH("[%u:] USBH Device Attach\r\n", event.rhport);
+ _usbh_data.enumerating_daddr = 0; // enumerate new device with address 0
enum_new_device(&event);
+ } else {
+ // currently enumerating another device
+ TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport);
+ const bool is_empty = osal_queue_empty(_usbh_q);
+ queue_event(&event, in_isr);
+ if (is_empty) {
+ return; // Exit if this is the only event in the queue, otherwise we loop forever
+ }
}
break;
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_removing_device(event.rhport, event.connection.hub_addr, event.connection.hub_port);
-
- #if CFG_TUH_HUB
- // TODO remove
- if (event.connection.hub_addr != 0 && event.connection.hub_port != 0) {
- // done with hub, waiting for next data on status pipe
- (void) hub_edpt_status_xfer(event.connection.hub_addr);
+ if (_usbh_data.enumerating_daddr == 0 &&
+ event.rhport == _usbh_data.dev0_bus.rhport &&
+ event.connection.hub_addr == _usbh_data.dev0_bus.hub_addr &&
+ event.connection.hub_port == _usbh_data.dev0_bus.hub_port) {
+ // dev0 is unplugged while enumerating (not yet assigned an address)
+ usbh_device_close(_usbh_data.dev0_bus.rhport, 0);
+ } else {
+ process_removed_device(event.rhport, event.connection.hub_addr, event.connection.hub_port);
}
- #endif
break;
case HCD_EVENT_XFER_COMPLETE: {
@@ -571,7 +579,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 = (uint8_t) tu_edpt_dir(ep_addr);
- 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]);
+ TU_LOG_USBH("[:%u] on EP %02X with %u bytes: %s\r\n",
+ event.dev_addr, ep_addr, (unsigned int) event.xfer_complete.len, tu_str_xfer_result[event.xfer_complete.result]);
if (event.dev_addr == 0) {
// device 0 only has control endpoint
@@ -610,7 +619,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
uint8_t drv_id = dev->ep2drv[epnum][ep_dir];
usbh_class_driver_t const* driver = get_driver(drv_id);
if (driver) {
- TU_LOG_USBH("%s xfer callback\r\n", driver->name);
+ TU_LOG_USBH(" %s xfer callback\r\n", driver->name);
driver->xfer_cb(event.dev_addr, ep_addr, (xfer_result_t) event.xfer_complete.result,
event.xfer_complete.len);
} else {
@@ -651,47 +660,44 @@ static void _control_blocking_complete_cb(tuh_xfer_t* xfer) {
bool tuh_control_xfer (tuh_xfer_t* xfer) {
TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); // EP0 with setup packet
const uint8_t daddr = xfer->daddr;
- TU_VERIFY(tuh_connected(daddr)); // Check if device is still connected (enumerating for dev0)
+ TU_VERIFY(tuh_connected(daddr));
- // pre-check to help reducing mutex lock
- TU_VERIFY(_ctrl_xfer.stage == CONTROL_STAGE_IDLE);
+ usbh_ctrl_xfer_info_t* ctrl_info = &_usbh_data.ctrl_xfer_info;
+
+ TU_VERIFY(ctrl_info->stage == CONTROL_STAGE_IDLE); // pre-check to help reducing mutex lock
(void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
-
- bool const is_idle = (_ctrl_xfer.stage == CONTROL_STAGE_IDLE);
+ bool const is_idle = (ctrl_info->stage == CONTROL_STAGE_IDLE);
if (is_idle) {
- _ctrl_xfer.stage = CONTROL_STAGE_SETUP;
- _ctrl_xfer.daddr = daddr;
- _ctrl_xfer.actual_len = 0;
- _ctrl_xfer.failed_count = 0;
+ ctrl_info->stage = CONTROL_STAGE_SETUP;
+ ctrl_info->daddr = daddr;
+ ctrl_info->actual_len = 0;
+ ctrl_info->failed_count = 0;
- _ctrl_xfer.buffer = xfer->buffer;
- _ctrl_xfer.complete_cb = xfer->complete_cb;
- _ctrl_xfer.user_data = xfer->user_data;
+ ctrl_info->buffer = xfer->buffer;
+ ctrl_info->complete_cb = xfer->complete_cb;
+ ctrl_info->user_data = xfer->user_data;
_usbh_epbuf.request = (*xfer->setup);
}
-
(void) osal_mutex_unlock(_usbh_mutex);
TU_VERIFY(is_idle);
- const uint8_t rhport = usbh_get_rhport(daddr);
-
- TU_LOG_USBH("[%u:%u] %s: ", rhport, daddr,
+ TU_LOG_USBH("[%u:%u] %s: ", usbh_get_rhport(daddr), daddr,
(xfer->setup->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME) ?
tu_str_std_request[xfer->setup->bRequest] : "Class Request");
TU_LOG_BUF_USBH(xfer->setup, 8);
if (xfer->complete_cb) {
- TU_ASSERT(hcd_setup_send(rhport, daddr, (uint8_t const *) &_usbh_epbuf.request));
+ TU_ASSERT(usbh_setup_send(daddr, (uint8_t const *) &_usbh_epbuf.request));
}else {
// blocking if complete callback is not provided
// change callback to internal blocking, and result as user argument
volatile xfer_result_t result = XFER_RESULT_INVALID;
// use user_data to point to xfer_result_t
- _ctrl_xfer.user_data = (uintptr_t) &result;
- _ctrl_xfer.complete_cb = _control_blocking_complete_cb;
+ ctrl_info->user_data = (uintptr_t) &result;
+ ctrl_info->complete_cb = _control_blocking_complete_cb;
- TU_ASSERT(hcd_setup_send(rhport, daddr, (uint8_t *) &_usbh_epbuf.request));
+ TU_ASSERT(usbh_setup_send(daddr, (uint8_t const *) &_usbh_epbuf.request));
while (result == XFER_RESULT_INVALID) {
// Note: this can be called within an callback ie. part of tuh_task()
@@ -707,20 +713,15 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) {
*((xfer_result_t*) xfer->user_data) = result;
}
xfer->result = result;
- xfer->actual_len = _ctrl_xfer.actual_len;
+ xfer->actual_len = ctrl_info->actual_len;
}
return true;
}
-TU_ATTR_ALWAYS_INLINE static inline void _set_control_xfer_stage(uint8_t stage) {
- (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
- _ctrl_xfer.stage = stage;
- (void) osal_mutex_unlock(_usbh_mutex);
-}
-
static void _control_xfer_complete(uint8_t daddr, xfer_result_t result) {
TU_LOG_USBH("\r\n");
+ usbh_ctrl_xfer_info_t* ctrl_info = &_usbh_data.ctrl_xfer_info;
// duplicate xfer since user can execute control transfer within callback
tusb_control_request_t const request = _usbh_epbuf.request;
@@ -729,13 +730,13 @@ static void _control_xfer_complete(uint8_t daddr, xfer_result_t result) {
.ep_addr = 0,
.result = result,
.setup = &request,
- .actual_len = (uint32_t) _ctrl_xfer.actual_len,
- .buffer = _ctrl_xfer.buffer,
- .complete_cb = _ctrl_xfer.complete_cb,
- .user_data = _ctrl_xfer.user_data
+ .actual_len = (uint32_t) ctrl_info->actual_len,
+ .buffer = ctrl_info->buffer,
+ .complete_cb = ctrl_info->complete_cb,
+ .user_data = ctrl_info->user_data
};
- _set_control_xfer_stage(CONTROL_STAGE_IDLE);
+ _control_set_xfer_stage(CONTROL_STAGE_IDLE);
if (xfer_temp.complete_cb) {
xfer_temp.complete_cb(&xfer_temp);
@@ -747,6 +748,7 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t
const uint8_t rhport = usbh_get_rhport(daddr);
tusb_control_request_t const * request = &_usbh_epbuf.request;
+ usbh_ctrl_xfer_info_t* ctrl_info = &_usbh_data.ctrl_xfer_info;
switch (result) {
case XFER_RESULT_STALLED:
@@ -756,15 +758,15 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t
break;
case XFER_RESULT_FAILED:
- if (tuh_connected(daddr) && _ctrl_xfer.failed_count < USBH_CONTROL_RETRY_MAX) {
- TU_LOG_USBH("[%u:%u] Control FAILED %u/%u, retrying\r\n", rhport, daddr, _ctrl_xfer.failed_count+1, USBH_CONTROL_RETRY_MAX);
+ if (tuh_connected(daddr) && ctrl_info->failed_count < USBH_CONTROL_RETRY_MAX) {
+ TU_LOG_USBH("[%u:%u] Control FAILED %u/%u, retrying\r\n", rhport, daddr, ctrl_info->failed_count+1, USBH_CONTROL_RETRY_MAX);
(void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
- _ctrl_xfer.stage = CONTROL_STAGE_SETUP;
- _ctrl_xfer.failed_count++;
- _ctrl_xfer.actual_len = 0; // reset actual_len
+ ctrl_info->stage = CONTROL_STAGE_SETUP;
+ ctrl_info->failed_count++;
+ ctrl_info->actual_len = 0; // reset actual_len
(void) osal_mutex_unlock(_usbh_mutex);
- TU_ASSERT(hcd_setup_send(rhport, daddr, (uint8_t const *) request));
+ TU_ASSERT(usbh_setup_send(daddr, (uint8_t const *) request));
} else {
TU_LOG_USBH("[%u:%u] Control FAILED, xferred_bytes = %" PRIu32 "\r\n", rhport, daddr, xferred_bytes);
TU_LOG_BUF_USBH(request, 8);
@@ -773,28 +775,29 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t
break;
case XFER_RESULT_SUCCESS:
- switch(_ctrl_xfer.stage) {
+ switch(ctrl_info->stage) {
case CONTROL_STAGE_SETUP:
if (request->wLength) {
// DATA stage: initial data toggle is always 1
- _set_control_xfer_stage(CONTROL_STAGE_DATA);
- TU_ASSERT( hcd_edpt_xfer(rhport, daddr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength) );
+ _control_set_xfer_stage(CONTROL_STAGE_DATA);
+ const uint8_t ep_data = tu_edpt_addr(0, request->bmRequestType_bit.direction);
+ TU_ASSERT(hcd_edpt_xfer(rhport, daddr, ep_data, ctrl_info->buffer, request->wLength));
return true;
}
- TU_ATTR_FALLTHROUGH;
+ TU_ATTR_FALLTHROUGH;
case CONTROL_STAGE_DATA:
if (request->wLength) {
TU_LOG_USBH("[%u:%u] Control data:\r\n", rhport, daddr);
- TU_LOG_MEM_USBH(_ctrl_xfer.buffer, xferred_bytes, 2);
+ TU_LOG_MEM_USBH(ctrl_info->buffer, xferred_bytes, 2);
}
+ ctrl_info->actual_len = (uint16_t) xferred_bytes;
- _ctrl_xfer.actual_len = (uint16_t) xferred_bytes;
-
- // ACK stage: toggle is always 1
- _set_control_xfer_stage(CONTROL_STAGE_ACK);
- TU_ASSERT( hcd_edpt_xfer(rhport, daddr, tu_edpt_addr(0, 1 - request->bmRequestType_bit.direction), NULL, 0) );
- break;
+ // ACK stage: toggle is always 1
+ _control_set_xfer_stage(CONTROL_STAGE_ACK);
+ const uint8_t ep_status = tu_edpt_addr(0, 1 - request->bmRequestType_bit.direction);
+ TU_ASSERT(hcd_edpt_xfer(rhport, daddr, ep_status, NULL, 0));
+ break;
case CONTROL_STAGE_ACK: {
// Abort all pending transfers if SET_CONFIGURATION request
@@ -843,7 +846,6 @@ bool tuh_edpt_xfer(tuh_xfer_t* xfer) {
bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) {
TU_LOG_USBH("[%u] Aborted transfer on EP %02X\r\n", daddr, ep_addr);
-
const uint8_t epnum = tu_edpt_number(ep_addr);
const uint8_t dir = tu_edpt_dir(ep_addr);
@@ -852,17 +854,17 @@ bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) {
const uint8_t rhport = usbh_get_rhport(daddr);
// control transfer: only 1 control at a time, check if we are aborting the current one
- TU_VERIFY(daddr == _ctrl_xfer.daddr && _ctrl_xfer.stage != CONTROL_STAGE_IDLE);
+ const usbh_ctrl_xfer_info_t* ctrl_info = &_usbh_data.ctrl_xfer_info;
+ TU_VERIFY(daddr == ctrl_info->daddr && ctrl_info->stage != CONTROL_STAGE_IDLE);
hcd_edpt_abort_xfer(rhport, daddr, ep_addr);
- _set_control_xfer_stage(CONTROL_STAGE_IDLE); // reset control transfer state to idle
+ _control_set_xfer_stage(CONTROL_STAGE_IDLE); // reset control transfer state to idle
} else {
usbh_device_t* dev = get_device(daddr);
TU_VERIFY(dev);
TU_VERIFY(dev->ep_status[epnum][dir].busy); // non-control skip if not busy
- hcd_edpt_abort_xfer(dev->rhport, daddr, ep_addr);
-
- // mark as ready and release endpoint if transfer is aborted
+ // abort then mark as ready and release endpoint
+ hcd_edpt_abort_xfer(dev->bus_info.rhport, daddr, ep_addr);
dev->ep_status[epnum][dir].busy = false;
tu_edpt_release(&dev->ep_status[epnum][dir], _usbh_mutex);
}
@@ -874,9 +876,10 @@ bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) {
// USBH API For Class Driver
//--------------------------------------------------------------------+
-uint8_t usbh_get_rhport(uint8_t dev_addr) {
- usbh_device_t *dev = get_device(dev_addr);
- return dev ? dev->rhport : _dev0.rhport;
+uint8_t usbh_get_rhport(uint8_t daddr) {
+ tuh_bus_info_t bus_info;
+ tuh_bus_info_get(daddr, &bus_info);
+ return bus_info.rhport;
}
uint8_t *usbh_get_enum_buf(void) {
@@ -886,9 +889,9 @@ uint8_t *usbh_get_enum_buf(void) {
void usbh_int_set(bool enabled) {
// TODO all host controller if multiple are used since they shared the same event queue
if (enabled) {
- hcd_int_enable(_usbh_controller);
+ hcd_int_enable(_usbh_data.controller_id);
} else {
- hcd_int_disable(_usbh_controller);
+ hcd_int_disable(_usbh_data.controller_id);
}
}
@@ -897,7 +900,6 @@ void usbh_defer_func(osal_task_func_t func, void *param, bool in_isr) {
event.event_id = USBH_EVENT_FUNC_CALL;
event.func_call.func = func;
event.func_call.param = param;
-
queue_event(&event, in_isr);
}
@@ -962,7 +964,7 @@ bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t* bu
dev->ep_callback[epnum][dir].user_data = user_data;
#endif
- if (hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes)) {
+ if (hcd_edpt_xfer(dev->bus_info.rhport, dev_addr, ep_addr, buffer, total_bytes)) {
TU_LOG_USBH("OK\r\n");
return true;
} else {
@@ -1014,31 +1016,30 @@ bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr) {
// HCD Event Handler
//--------------------------------------------------------------------+
-void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info) {
- usbh_device_t const* dev = get_device(dev_addr);
+bool tuh_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info) {
+ usbh_device_t const* dev = get_device(daddr);
if (dev) {
- devtree_info->rhport = dev->rhport;
- devtree_info->hub_addr = dev->hub_addr;
- devtree_info->hub_port = dev->hub_port;
- devtree_info->speed = dev->speed;
+ *bus_info = dev->bus_info;
} else {
- devtree_info->rhport = _dev0.rhport;
- devtree_info->hub_addr = _dev0.hub_addr;
- devtree_info->hub_port = _dev0.hub_port;
- devtree_info->speed = _dev0.speed;
+ *bus_info = _usbh_data.dev0_bus;
}
+ return true;
}
TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr) {
switch (event->event_id) {
+ case HCD_EVENT_DEVICE_ATTACH:
case HCD_EVENT_DEVICE_REMOVE:
- // FIXME device remove from a hub need an HCD API for hcd to free up endpoint
- // mark device as removing to prevent further xfer before the event is processed in usbh task
+ // Attach debouncing on roothub: skip attach/remove while debouncing delay
+ if (event->connection.hub_addr == 0) {
+ if (tu_bit_test(_usbh_data.attach_debouncing_bm, event->rhport)) {
+ return;
+ }
- // Check if dev0 is removed
- if ((event->rhport == _dev0.rhport) && (event->connection.hub_addr == _dev0.hub_addr) &&
- (event->connection.hub_port == _dev0.hub_port)) {
- _dev0.enumerating = 0;
+ if (event->event_id == HCD_EVENT_DEVICE_ATTACH) {
+ // No debouncing, set flag if attach event
+ _usbh_data.attach_debouncing_bm |= TU_BIT(event->rhport);
+ }
}
break;
@@ -1107,24 +1108,24 @@ bool tuh_descriptor_get_manufacturer_string(uint8_t daddr, uint16_t language_id,
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
usbh_device_t const* dev = get_device(daddr);
- TU_VERIFY(dev && dev->i_manufacturer);
- return tuh_descriptor_get_string(daddr, dev->i_manufacturer, language_id, buffer, len, complete_cb, user_data);
+ TU_VERIFY(dev && dev->iManufacturer);
+ return tuh_descriptor_get_string(daddr, dev->iManufacturer, language_id, buffer, len, complete_cb, user_data);
}
// Get product string descriptor
bool tuh_descriptor_get_product_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
usbh_device_t const* dev = get_device(daddr);
- TU_VERIFY(dev && dev->i_product);
- return tuh_descriptor_get_string(daddr, dev->i_product, language_id, buffer, len, complete_cb, user_data);
+ TU_VERIFY(dev && dev->iProduct);
+ return tuh_descriptor_get_string(daddr, dev->iProduct, language_id, buffer, len, complete_cb, user_data);
}
// Get serial string descriptor
bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
usbh_device_t const* dev = get_device(daddr);
- TU_VERIFY(dev && dev->i_serial);
- return tuh_descriptor_get_string(daddr, dev->i_serial, language_id, buffer, len, complete_cb, user_data);
+ TU_VERIFY(dev && dev->iSerialNumber);
+ return tuh_descriptor_get_string(daddr, dev->iSerialNumber, language_id, buffer, len, complete_cb, user_data);
}
// Get HID report descriptor
@@ -1155,6 +1156,33 @@ bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_
return tuh_control_xfer(&xfer);
}
+bool tuh_address_set(uint8_t daddr, uint8_t new_addr,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ TU_LOG_USBH("Set Address = %d\r\n", new_addr);
+ const tusb_control_request_t request = {
+ .bmRequestType_bit = {
+ .recipient = TUSB_REQ_RCPT_DEVICE,
+ .type = TUSB_REQ_TYPE_STANDARD,
+ .direction = TUSB_DIR_OUT
+ },
+ .bRequest = TUSB_REQ_SET_ADDRESS,
+ .wValue = tu_htole16(new_addr),
+ .wIndex = 0,
+ .wLength = 0
+ };
+ tuh_xfer_t xfer = {
+ .daddr = daddr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = NULL,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
+
+ TU_ASSERT(tuh_control_xfer(&xfer));
+ return true;
+}
+
bool tuh_configuration_set(uint8_t daddr, uint8_t config_num,
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
TU_LOG_USBH("Set Configuration = %d\r\n", config_num);
@@ -1216,8 +1244,7 @@ bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt,
TU_VERIFY(_async_func(__VA_ARGS__, NULL, (uintptr_t) &result), XFER_RESULT_TIMEOUT); \
return (uint8_t) result
-uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index,
- void* buffer, uint16_t len) {
+uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get, daddr, type, index, buffer, len);
}
@@ -1225,84 +1252,58 @@ uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len
_CONTROL_SYNC_API(tuh_descriptor_get_device, daddr, buffer, len);
}
-uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index,
- void* buffer, uint16_t len) {
+uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_configuration, daddr, index, buffer, len);
}
-uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index,
- void* buffer, uint16_t len) {
+uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_hid_report, daddr, itf_num, desc_type, index, buffer, len);
}
-uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id,
- void* buffer, uint16_t len) {
+uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_string, daddr, index, language_id, buffer, len);
}
-uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id,
- void* buffer, uint16_t len) {
+uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_manufacturer_string, daddr, language_id, buffer, len);
}
-uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id,
- void* buffer, uint16_t len) {
+uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_product_string, daddr, language_id, buffer, len);
}
-uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id,
- void* buffer, uint16_t len) {
+uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_serial_string, daddr, language_id, buffer, len);
}
//--------------------------------------------------------------------+
// Detaching
//--------------------------------------------------------------------+
-
-TU_ATTR_ALWAYS_INLINE 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_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
- uint32_t removing_hubs = 0;
+static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) {
+ // Find the all devices (star-network) under port that is unplugged
+ #if CFG_TUH_HUB
+ uint8_t removing_hubs[CFG_TUH_HUB] = { 0 };
+ #endif
+
do {
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 (dev->bus_info.rhport == rhport && dev->connected &&
+ (hub_addr == 0 || dev->bus_info.hub_addr == hub_addr) &&
+ (hub_port == 0 || dev->bus_info.hub_port == hub_port)) {
TU_LOG_USBH("[%u:%u:%u] unplugged address = %u\r\n", rhport, hub_addr, hub_port, daddr);
+ #if CFG_TUH_HUB
if (is_hub_addr(daddr)) {
TU_LOG_USBH(" is a HUB device %u\r\n", daddr);
- removing_hubs |= TU_BIT(dev_id - CFG_TUH_DEVICE_MAX);
- } else {
+ removing_hubs[dev_id - CFG_TUH_DEVICE_MAX] = 1;
+ } else
+ #endif
+ {
// Invoke callback before closing driver (maybe call it later ?)
if (tuh_umount_cb) {
tuh_umount_cb(daddr);
@@ -1317,22 +1318,21 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu
}
}
- hcd_device_close(rhport, daddr);
+ usbh_device_close(rhport, daddr);
clear_device(dev);
-
- // abort on-going control xfer on this device if any
- if (_ctrl_xfer.daddr == daddr) _set_control_xfer_stage(CONTROL_STAGE_IDLE);
}
}
- // if removing a hub, we need to remove its downstream devices
- #if CFG_TUH_HUB
- if (removing_hubs == 0) break;
+#if CFG_TUH_HUB
+ // if a hub is removed, we need to remove all of its downstream devices
+ if (tu_mem_is_zero(removing_hubs, CFG_TUH_HUB)) {
+ break;
+ }
// find a marked hub to process
for (uint8_t h_id = 0; h_id < CFG_TUH_HUB; h_id++) {
- if (tu_bit_test(removing_hubs, h_id)) {
- removing_hubs &= ~TU_BIT(h_id);
+ if (removing_hubs[h_id]) {
+ removing_hubs[h_id] = 0;
// update hub_addr and hub_port for next loop
hub_addr = h_id + 1 + CFG_TUH_DEVICE_MAX;
@@ -1340,41 +1340,44 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu
break;
}
}
- #else
- (void) removing_hubs;
+#else
break;
- #endif
+#endif
+
} while(1);
}
//--------------------------------------------------------------------+
// Enumeration Process
-// is a lengthy process with a series of control transfer to configure
-// newly attached device.
+// is a lengthy process with a series of control transfer to configure newly attached device.
// NOTE: due to the shared control buffer, we must complete enumerating
// one device before enumerating another one.
//--------------------------------------------------------------------+
-
-enum {
- ENUM_RESET_DELAY_MS = 50, // USB specs: 10 to 50ms
- ENUM_DEBOUNCING_DELAY_MS = 450, // when plug/unplug a device, physical connection can be bouncing and may
- // generate a series of attach/detach event. This delay wait for stable connection
+enum { // USB 2.0 specs 7.1.7 for timing
+ ENUM_DEBOUNCING_DELAY_MS = 150, // T(ATTDB) minimum 100 ms for stable connection
+ ENUM_RESET_ROOT_DELAY_MS = 50, // T(DRSTr) minimum 50 ms for reset from root port
+ ENUM_RESET_HUB_DELAY_MS = 20, // T(DRST) 10-20 ms for hub reset
+ ENUM_RESET_RECOVERY_DELAY_MS = 10, // T(RSTRCY) minimum 10 ms for reset recovery
+ ENUM_SET_ADDRESS_RECOVERY_DELAY_MS = 2, // USB 2.0 Spec 9.2.6.3 min is 2 ms
};
enum {
ENUM_IDLE,
- ENUM_RESET_1, // 1st reset when attached
- //ENUM_HUB_GET_STATUS_1,
- ENUM_HUB_CLEAR_RESET_1,
+ ENUM_HUB_RERSET,
+ ENUM_HUB_GET_STATUS_AFTER_RESET,
+ ENUM_HUB_CLEAR_RESET,
+ ENUM_HUB_CLEAR_RESET_COMPLETE,
+
ENUM_ADDR0_DEVICE_DESC,
- ENUM_RESET_2, // 2nd reset before set address (not used)
- ENUM_HUB_GET_STATUS_2,
- ENUM_HUB_CLEAR_RESET_2,
ENUM_SET_ADDR,
ENUM_GET_DEVICE_DESC,
+ ENUM_GET_STRING_LANGUAGE_ID_LEN,
ENUM_GET_STRING_LANGUAGE_ID,
+ ENUM_GET_STRING_MANUFACTURER_LEN,
ENUM_GET_STRING_MANUFACTURER,
+ ENUM_GET_STRING_PRODUCT_LEN,
ENUM_GET_STRING_PRODUCT,
+ ENUM_GET_STRING_SERIAL_LEN,
ENUM_GET_STRING_SERIAL,
ENUM_GET_9BYTE_CONFIG_DESC,
ENUM_GET_FULL_CONFIG_DESC,
@@ -1382,9 +1385,69 @@ enum {
ENUM_CONFIG_DRIVER
};
-static bool enum_request_set_addr(tusb_desc_device_t const* desc_device);
+static uint8_t enum_get_new_address(bool is_hub);
static bool enum_parse_configuration_desc (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
static void enum_full_complete(void);
+static void process_enumeration(tuh_xfer_t* xfer);
+
+// start a new enumeration process
+static bool enum_new_device(hcd_event_t* event) {
+ tuh_bus_info_t* dev0_bus = &_usbh_data.dev0_bus;
+ dev0_bus->rhport = event->rhport;
+ dev0_bus->hub_addr = event->connection.hub_addr;
+ dev0_bus->hub_port = event->connection.hub_port;
+
+ // wait until device connection is stable TODO non blocking
+ tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS);
+
+ // clear roothub debouncing delay
+ if (dev0_bus->hub_addr == 0) {
+ _usbh_data.attach_debouncing_bm &= (uint8_t) ~TU_BIT(dev0_bus->rhport);
+ }
+
+ if (dev0_bus->hub_addr == 0) {
+ // connected directly to roothub
+ // USB bus not active and frame number is not available yet.
+ // need to depend on tusb_time_millis_api() TODO non blocking
+
+ if (!hcd_port_connect_status(dev0_bus->rhport)) {
+ TU_LOG_USBH("Device unplugged while debouncing\r\n");
+ enum_full_complete();
+ return true;
+ }
+
+ // reset device
+ hcd_port_reset(dev0_bus->rhport);
+ tusb_time_delay_ms_api(ENUM_RESET_ROOT_DELAY_MS);
+ hcd_port_reset_end(dev0_bus->rhport);
+
+ if (!hcd_port_connect_status(dev0_bus->rhport)) {
+ // device unplugged while delaying
+ enum_full_complete();
+ return true;
+ }
+
+ dev0_bus->speed = hcd_port_speed_get(dev0_bus->rhport);
+ TU_LOG_USBH("%s Speed\r\n", tu_str_speed[dev0_bus->speed]);
+
+ // fake transfer to kick-off the enumeration process
+ tuh_xfer_t xfer;
+ xfer.daddr = 0;
+ xfer.result = XFER_RESULT_SUCCESS;
+ xfer.user_data = ENUM_ADDR0_DEVICE_DESC;
+ process_enumeration(&xfer);
+ }
+ #if CFG_TUH_HUB
+ else {
+ // connected via hub
+ TU_VERIFY(dev0_bus->hub_port != 0);
+ TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL,
+ process_enumeration, ENUM_HUB_RERSET));
+ }
+ #endif // hub
+
+ return true;
+}
// process device enumeration
static void process_enumeration(tuh_xfer_t* xfer) {
@@ -1398,17 +1461,16 @@ static void process_enumeration(tuh_xfer_t* xfer) {
// retry if not reaching max attempt
failed_count++;
- bool retry = _dev0.enumerating && (failed_count < ATTEMPT_COUNT_MAX);
+ bool retry = (_usbh_data.enumerating_daddr != TUSB_INDEX_INVALID_8) && (failed_count < ATTEMPT_COUNT_MAX);
if (retry) {
tusb_time_delay_ms_api(ATTEMPT_DELAY_MS); // delay a bit
- TU_LOG1("Enumeration attempt %u/%u\r\n", failed_count+1, ATTEMPT_COUNT_MAX);
+ TU_LOG_USBH("Enumeration attempt %u/%u\r\n", failed_count+1, ATTEMPT_COUNT_MAX);
retry = tuh_control_xfer(xfer);
}
if (!retry) {
enum_full_complete(); // complete as failed
}
-
return;
}
failed_count = 0;
@@ -1416,169 +1478,212 @@ static void process_enumeration(tuh_xfer_t* xfer) {
uint8_t const daddr = xfer->daddr;
uintptr_t const state = xfer->user_data;
usbh_device_t* dev = get_device(daddr);
+ tuh_bus_info_t* dev0_bus = &_usbh_data.dev0_bus;
+ if (daddr > 0) {
+ TU_ASSERT(dev,);
+ }
uint16_t langid = 0x0409; // default is English
switch (state) {
#if CFG_TUH_HUB
- //case ENUM_HUB_GET_STATUS_1: break;
-
- case ENUM_HUB_CLEAR_RESET_1: {
+ case ENUM_HUB_RERSET: {
hub_port_status_response_t port_status;
- memcpy(&port_status, _usbh_epbuf.ctrl, sizeof(hub_port_status_response_t));
+ hub_port_get_status_local(dev0_bus->hub_addr, dev0_bus->hub_port, &port_status);
if (!port_status.status.connection) {
- // device unplugged while delaying, nothing else to do
+ TU_LOG_USBH("Device unplugged from hub while debouncing\r\n");
enum_full_complete();
return;
}
- _dev0.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH :
- (port_status.status.low_speed) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
-
- // Acknowledge Port Reset Change
- if (port_status.change.reset) {
- hub_port_clear_reset_change(_dev0.hub_addr, _dev0.hub_port,
- process_enumeration, ENUM_ADDR0_DEVICE_DESC);
- }
+ TU_ASSERT(hub_port_reset(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration, ENUM_HUB_GET_STATUS_AFTER_RESET),);
break;
}
- case ENUM_HUB_GET_STATUS_2:
- tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS);
- TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_epbuf.ctrl,
- process_enumeration, ENUM_HUB_CLEAR_RESET_2),);
- break;
+ case ENUM_HUB_GET_STATUS_AFTER_RESET: {
+ tusb_time_delay_ms_api(ENUM_RESET_HUB_DELAY_MS); // wait for reset to take effect
- case ENUM_HUB_CLEAR_RESET_2: {
+ // get status to check for reset change
+ TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration, ENUM_HUB_CLEAR_RESET),);
+ break;
+ }
+
+ case ENUM_HUB_CLEAR_RESET: {
hub_port_status_response_t port_status;
- memcpy(&port_status, _usbh_epbuf.ctrl, sizeof(hub_port_status_response_t));
+ hub_port_get_status_local(dev0_bus->hub_addr, dev0_bus->hub_port, &port_status);
- // Acknowledge Port Reset Change if Reset Successful
if (port_status.change.reset) {
- TU_ASSERT(hub_port_clear_reset_change(_dev0.hub_addr, _dev0.hub_port,
- process_enumeration, ENUM_SET_ADDR),);
+ // Acknowledge Port Reset Change
+ TU_ASSERT(hub_port_clear_reset_change(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration, ENUM_HUB_CLEAR_RESET_COMPLETE),);
+ } else {
+ // maybe retry if reset change not set but we need timeout to prevent infinite loop
+ // TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration, ENUM_HUB_CLEAR_RESET_COMPLETE),);
}
+
break;
}
+
+ case ENUM_HUB_CLEAR_RESET_COMPLETE: {
+ hub_port_status_response_t port_status;
+ hub_port_get_status_local(dev0_bus->hub_addr, dev0_bus->hub_port, &port_status);
+
+ if (!port_status.status.connection) {
+ TU_LOG_USBH("Device unplugged from hub (not addressed yet)\r\n");
+ enum_full_complete();
+ return;
+ }
+
+ dev0_bus->speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH :
+ (port_status.status.low_speed) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
+
+ TU_ATTR_FALLTHROUGH;
+ }
#endif
case ENUM_ADDR0_DEVICE_DESC: {
+ tusb_time_delay_ms_api(ENUM_RESET_RECOVERY_DELAY_MS); // reset recovery
+
// TODO probably doesn't need to open/close each enumeration
uint8_t const addr0 = 0;
TU_ASSERT(usbh_edpt_control_open(addr0, 8),);
- // Get first 8 bytes of device descriptor for Control Endpoint size
+ // Get first 8 bytes of device descriptor for control endpoint size
TU_LOG_USBH("Get 8 byte of Device Descriptor\r\n");
TU_ASSERT(tuh_descriptor_get_device(addr0, _usbh_epbuf.ctrl, 8,
process_enumeration, ENUM_SET_ADDR),);
break;
}
-#if 0
- case ENUM_RESET_2:
- // TODO not used by now, but may be needed for some devices !?
- // Reset device again before Set Address
- TU_LOG_USBH("Port reset2 \r\n");
- if (_dev0.hub_addr == 0) {
- // connected directly to roothub
- hcd_port_reset( _dev0.rhport );
- tusb_time_delay_ms_api(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
- // sof of controller may not running while resetting
- hcd_port_reset_end(_dev0.rhport);
- // TODO: fall through to SET ADDRESS, refactor later
- }
-#if CFG_TUH_HUB
- else {
- // after RESET_DELAY the hub_port_reset() already complete
- TU_ASSERT( hub_port_reset(_dev0.hub_addr, _dev0.hub_port,
- process_enumeration, ENUM_HUB_GET_STATUS_2), );
- break;
- }
-#endif
- TU_ATTR_FALLTHROUGH;
-#endif
+ case ENUM_SET_ADDR: {
+ // Due to physical debouncing, some devices can cause multiple attaches (actually reset) without detach event
+ // Force remove currently mounted with the same bus info (rhport, hub addr, hub port) if exists
+ process_removed_device(dev0_bus->rhport, dev0_bus->hub_addr, dev0_bus->hub_port);
- case ENUM_SET_ADDR:
- enum_request_set_addr((tusb_desc_device_t*) _usbh_epbuf.ctrl);
+ const tusb_desc_device_t *desc_device = (const tusb_desc_device_t *) _usbh_epbuf.ctrl;
+ const uint8_t new_addr = enum_get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
+ TU_ASSERT(new_addr != 0,);
+
+ usbh_device_t* new_dev = get_device(new_addr);
+ new_dev->bus_info = *dev0_bus;
+ new_dev->connected = 1;
+ new_dev->ep0_size = desc_device->bMaxPacketSize0;
+
+ TU_ASSERT(tuh_address_set(0, new_addr, process_enumeration, ENUM_GET_DEVICE_DESC),);
break;
+ }
case ENUM_GET_DEVICE_DESC: {
- // Allow 2ms for address recovery time, Ref USB Spec 9.2.6.3
- tusb_time_delay_ms_api(2);
+ tusb_time_delay_ms_api(ENUM_SET_ADDRESS_RECOVERY_DELAY_MS); // set address recovery
const uint8_t new_addr = (uint8_t) tu_le16toh(xfer->setup->wValue);
usbh_device_t* new_dev = get_device(new_addr);
TU_ASSERT(new_dev,);
new_dev->addressed = 1;
+ _usbh_data.enumerating_daddr = new_addr;
- // Close device 0
- hcd_device_close(_dev0.rhport, 0);
+ usbh_device_close(dev0_bus->rhport, 0); // close dev0
- // open control pipe for new address
- TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),);
+ TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); // open new control endpoint
- // Get full device descriptor
TU_LOG_USBH("Get Device Descriptor\r\n");
TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t),
- process_enumeration, ENUM_GET_STRING_LANGUAGE_ID),);
+ process_enumeration, ENUM_GET_STRING_LANGUAGE_ID_LEN),);
+ break;
+ }
+
+ // For string descriptor (langid, manufacturer, product, serila): always get the first 2 bytes
+ // to determine the length first. otherwise, some device may have buffer overflow.
+ case ENUM_GET_STRING_LANGUAGE_ID_LEN: {
+ // save the received device descriptor
+ tusb_desc_device_t const *desc_device = (tusb_desc_device_t const *) _usbh_epbuf.ctrl;
+ dev->idVendor = desc_device->idVendor;
+ dev->idProduct = desc_device->idProduct;
+ dev->iManufacturer = desc_device->iManufacturer;
+ dev->iProduct = desc_device->iProduct;
+ dev->iSerialNumber = desc_device->iSerialNumber;
+ dev->bNumConfigurations = desc_device->bNumConfigurations;
+
+ tuh_enum_descriptor_device_cb(daddr, desc_device); // callback
+ tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, 2,
+ process_enumeration, ENUM_GET_STRING_LANGUAGE_ID);
break;
}
case ENUM_GET_STRING_LANGUAGE_ID: {
- // save the received device descriptor
- TU_ASSERT(dev,);
- tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl;
- dev->vid = desc_device->idVendor;
- dev->pid = desc_device->idProduct;
- dev->i_manufacturer = desc_device->iManufacturer;
- dev->i_product = desc_device->iProduct;
- dev->i_serial = desc_device->iSerialNumber;
- dev->bNumConfigurations = desc_device->bNumConfigurations;
-
- tuh_enum_descriptor_device_cb(daddr, desc_device); // callback
-
- tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
- process_enumeration, ENUM_GET_STRING_MANUFACTURER);
+ const uint8_t str_len = xfer->buffer[0];
+ tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, str_len,
+ process_enumeration, ENUM_GET_STRING_MANUFACTURER_LEN);
break;
}
- case ENUM_GET_STRING_MANUFACTURER: {
- TU_ASSERT(dev,);
- const tusb_desc_string_t* desc_langid = (tusb_desc_string_t const*) _usbh_epbuf.ctrl;
+ case ENUM_GET_STRING_MANUFACTURER_LEN: {
+ const tusb_desc_string_t* desc_langid = (const tusb_desc_string_t *) _usbh_epbuf.ctrl;
if (desc_langid->bLength >= 4) {
- langid = tu_le16toh(desc_langid->utf16le[0]);
+ langid = tu_le16toh(desc_langid->utf16le[0]); // previous request is langid
}
- if (dev->i_manufacturer != 0) {
- tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
+ if (dev->iManufacturer != 0) {
+ tuh_descriptor_get_string(daddr, dev->iManufacturer, langid, _usbh_epbuf.ctrl, 2,
+ process_enumeration, ENUM_GET_STRING_MANUFACTURER);
+ break;
+ }else {
+ TU_ATTR_FALLTHROUGH;
+ }
+ }
+
+ case ENUM_GET_STRING_MANUFACTURER: {
+ if (dev->iManufacturer != 0) {
+ langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request
+ const uint8_t str_len = xfer->buffer[0];
+ tuh_descriptor_get_string(daddr, dev->iManufacturer, langid, _usbh_epbuf.ctrl, str_len,
+ process_enumeration, ENUM_GET_STRING_PRODUCT_LEN);
+ break;
+ } else {
+ TU_ATTR_FALLTHROUGH;
+ }
+ }
+
+ case ENUM_GET_STRING_PRODUCT_LEN:
+ if (dev->iProduct != 0) {
+ if (state == ENUM_GET_STRING_PRODUCT_LEN) {
+ langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through
+ }
+ tuh_descriptor_get_string(daddr, dev->iProduct, langid, _usbh_epbuf.ctrl, 2,
process_enumeration, ENUM_GET_STRING_PRODUCT);
break;
} else {
TU_ATTR_FALLTHROUGH;
}
- }
case ENUM_GET_STRING_PRODUCT: {
- TU_ASSERT(dev,);
- if (state == ENUM_GET_STRING_PRODUCT) {
- langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet
- }
- if (dev->i_product != 0) {
- tuh_descriptor_get_string(daddr, dev->i_product, 0x0409, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
- process_enumeration, ENUM_GET_STRING_SERIAL);
+ if (dev->iProduct != 0) {
+ langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request
+ const uint8_t str_len = xfer->buffer[0];
+ tuh_descriptor_get_string(daddr, dev->iProduct, langid, _usbh_epbuf.ctrl, str_len,
+ process_enumeration, ENUM_GET_STRING_SERIAL_LEN);
break;
} else {
TU_ATTR_FALLTHROUGH;
}
}
- case ENUM_GET_STRING_SERIAL: {
- TU_ASSERT(dev,);
- if (state == ENUM_GET_STRING_SERIAL) {
- langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet
+ case ENUM_GET_STRING_SERIAL_LEN:
+ if (dev->iSerialNumber != 0) {
+ if (state == ENUM_GET_STRING_SERIAL_LEN) {
+ langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through
+ }
+ tuh_descriptor_get_string(daddr, dev->iSerialNumber, langid, _usbh_epbuf.ctrl, 2,
+ process_enumeration, ENUM_GET_STRING_SERIAL);
+ break;
+ } else {
+ TU_ATTR_FALLTHROUGH;
}
- if (dev->i_serial != 0) {
- tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
- process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC);
+
+ case ENUM_GET_STRING_SERIAL: {
+ if (dev->iSerialNumber != 0) {
+ langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request
+ const uint8_t str_len = xfer->buffer[0];
+ tuh_descriptor_get_string(daddr, dev->iSerialNumber, langid, _usbh_epbuf.ctrl, str_len,
+ process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC);
break;
} else {
TU_ATTR_FALLTHROUGH;
@@ -1627,8 +1732,6 @@ static void process_enumeration(tuh_xfer_t* xfer) {
case ENUM_CONFIG_DRIVER: {
TU_LOG_USBH("Device configured\r\n");
- TU_ASSERT(dev,);
-
dev->configured = 1;
// Parse configuration & set up drivers
@@ -1649,57 +1752,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
}
}
-static bool enum_new_device(hcd_event_t* event) {
- _dev0.rhport = event->rhport;
- _dev0.hub_addr = event->connection.hub_addr;
- _dev0.hub_port = event->connection.hub_port;
-
- if (_dev0.hub_addr == 0) {
- // connected directly to roothub
- hcd_port_reset(_dev0.rhport);
-
- // Since we are in middle of rhport reset, frame number is not available yet.
- // need to depend on tusb_time_millis_api()
- tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS);
-
- hcd_port_reset_end(_dev0.rhport);
-
- // wait until device connection is stable TODO non blocking
- tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS);
-
- // device unplugged while delaying
- if (!hcd_port_connect_status(_dev0.rhport)) {
- enum_full_complete();
- return true;
- }
-
- _dev0.speed = hcd_port_speed_get(_dev0.rhport);
- TU_LOG_USBH("%s Speed\r\n", tu_str_speed[_dev0.speed]);
-
- // fake transfer to kick-off the enumeration process
- tuh_xfer_t xfer;
- xfer.daddr = 0;
- xfer.result = XFER_RESULT_SUCCESS;
- xfer.user_data = ENUM_ADDR0_DEVICE_DESC;
-
- process_enumeration(&xfer);
- }
-#if CFG_TUH_HUB
- else {
- // connected via external hub
- // wait until device connection is stable TODO non blocking
- tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS);
-
- // ENUM_HUB_GET_STATUS
- TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_epbuf.ctrl,
- process_enumeration, ENUM_HUB_CLEAR_RESET_1));
- }
-#endif // hub
-
- return true;
-}
-
-static uint8_t get_new_address(bool is_hub) {
+static uint8_t enum_get_new_address(bool is_hub) {
uint8_t start;
uint8_t end;
@@ -1712,50 +1765,14 @@ static uint8_t get_new_address(bool is_hub) {
}
for (uint8_t idx = start; idx < end; idx++) {
- if (!_usbh_devices[idx].connected) return (idx+1);
+ if (!_usbh_devices[idx].connected) {
+ return (idx + 1);
+ }
}
return 0; // invalid address
}
-static bool enum_request_set_addr(tusb_desc_device_t const* desc_device) {
- // Get new address
- uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
- TU_ASSERT(new_addr != 0);
- TU_LOG_USBH("Set Address = %d\r\n", new_addr);
-
- usbh_device_t* new_dev = get_device(new_addr);
- new_dev->rhport = _dev0.rhport;
- new_dev->hub_addr = _dev0.hub_addr;
- new_dev->hub_port = _dev0.hub_port;
- new_dev->speed = _dev0.speed;
- new_dev->connected = 1;
- new_dev->ep0_size = desc_device->bMaxPacketSize0;
-
- tusb_control_request_t const request = {
- .bmRequestType_bit = {
- .recipient = TUSB_REQ_RCPT_DEVICE,
- .type = TUSB_REQ_TYPE_STANDARD,
- .direction = TUSB_DIR_OUT
- },
- .bRequest = TUSB_REQ_SET_ADDRESS,
- .wValue = tu_htole16(new_addr),
- .wIndex = 0,
- .wLength = 0
- };
- tuh_xfer_t xfer = {
- .daddr = 0, // dev0
- .ep_addr = 0,
- .setup = &request,
- .buffer = NULL,
- .complete_cb = process_enumeration,
- .user_data = ENUM_GET_DEVICE_DESC
- };
-
- TU_ASSERT(tuh_control_xfer(&xfer));
- return true;
-}
-
static bool enum_parse_configuration_desc(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg) {
usbh_device_t* dev = get_device(dev_addr);
uint16_t const total_len = tu_le16toh(desc_cfg->wTotalLength);
@@ -1817,7 +1834,7 @@ static bool enum_parse_configuration_desc(uint8_t dev_addr, tusb_desc_configurat
// Find driver for this interface
for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) {
usbh_class_driver_t const * driver = get_driver(drv_id);
- if (driver && driver->open(dev->rhport, dev_addr, desc_itf, drv_len) ) {
+ if (driver && driver->open(dev->bus_info.rhport, dev_addr, desc_itf, drv_len) ) {
// open successfully
TU_LOG_USBH(" %s opened\r\n", driver->name);
@@ -1836,9 +1853,9 @@ static bool enum_parse_configuration_desc(uint8_t dev_addr, tusb_desc_configurat
break; // exit driver find loop
}
- if ( drv_id == TOTAL_DRIVER_COUNT - 1 ) {
+ if (drv_id == TOTAL_DRIVER_COUNT - 1) {
TU_LOG_USBH("[%u:%u] Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n",
- dev->rhport, dev_addr, desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol);
+ dev->bus_info.rhport, dev_addr, desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol);
}
}
@@ -1882,11 +1899,11 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) {
static void enum_full_complete(void) {
// mark enumeration as complete
- _dev0.enumerating = 0;
+ _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8;
#if CFG_TUH_HUB
- if (_dev0.hub_addr) {
- hub_edpt_status_xfer(_dev0.hub_addr); // get next hub status
+ if (_usbh_data.dev0_bus.hub_addr != 0) {
+ hub_edpt_status_xfer(_usbh_data.dev0_bus.hub_addr); // get next hub status
}
#endif
diff --git a/src/host/usbh.h b/src/host/usbh.h
index 4829a8183..6f34d8bb3 100644
--- a/src/host/usbh.h
+++ b/src/host/usbh.h
@@ -47,7 +47,6 @@
// forward declaration
struct tuh_xfer_s;
typedef struct tuh_xfer_s tuh_xfer_t;
-
typedef void (*tuh_xfer_cb_t)(tuh_xfer_t* xfer);
// Note1: layout and order of this will be changed in near future
@@ -80,6 +79,17 @@ typedef struct {
tusb_desc_interface_t desc;
} tuh_itf_info_t;
+typedef struct {
+ uint8_t rhport;
+ uint8_t hub_addr;
+ uint8_t hub_port;
+ uint8_t speed;
+} tuh_bus_info_t;
+
+// backward compatibility for hcd_devtree_info_t, maybe removed in the future
+#define hcd_devtree_info_t tuh_bus_info_t
+#define hcd_devtree_get_info(_daddr, _bus_info) tuh_bus_info_get(_daddr, _bus_info)
+
// ConfigID for tuh_configure()
enum {
TUH_CFGID_INVALID = 0,
@@ -177,6 +187,8 @@ extern void hcd_int_handler(uint8_t rhport, bool in_isr);
#define _tuh_int_handler_arg0() TU_VERIFY_STATIC(false, "tuh_int_handler() must have 1 or 2 arguments")
#define _tuh_int_handler_arg1(_rhport) hcd_int_handler(_rhport, true)
#define _tuh_int_handler_arg2(_rhport, _in_isr) hcd_int_handler(_rhport, _in_isr)
+
+// 1st argument is rhport (mandatory), 2nd argument in_isr (optional)
#define tuh_int_handler(...) TU_FUNC_OPTIONAL_ARG(_tuh_int_handler, __VA_ARGS__)
// Check if roothub port is initialized and active as a host
@@ -214,6 +226,9 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_ready(uint8_t daddr) {
return tuh_mounted(daddr) && !tuh_suspended(daddr);
}
+// Get bus information of device
+bool tuh_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info);
+
//--------------------------------------------------------------------+
// Transfer API
//--------------------------------------------------------------------+
@@ -238,6 +253,10 @@ bool tuh_edpt_close(uint8_t daddr, uint8_t ep_addr);
// Return true if a queued transfer is aborted, false if there is no transfer to abort
bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr);
+// Set Address (control transfer)
+bool tuh_address_set(uint8_t daddr, uint8_t new_addr,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
// Set Configuration (control transfer)
// config_num = 0 will un-configure device. Note: config_num = config_descriptor_index + 1
// true on success, false if there is on-going control transfer or incorrect parameters
diff --git a/src/host/usbh_pvt.h b/src/host/usbh_pvt.h
index bfa1fb2ba..61b012493 100644
--- a/src/host/usbh_pvt.h
+++ b/src/host/usbh_pvt.h
@@ -63,7 +63,7 @@ usbh_class_driver_t const* usbh_app_driver_get_cb(uint8_t* driver_count) TU_ATTR
// Call by class driver to tell USBH that it has complete the enumeration
void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num);
-uint8_t usbh_get_rhport(uint8_t dev_addr);
+uint8_t usbh_get_rhport(uint8_t daddr);
uint8_t* usbh_get_enum_buf(void);
diff --git a/src/portable/chipidea/ci_hs/hcd_ci_hs.c b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
index c4c342a70..b5324a754 100644
--- a/src/portable/chipidea/ci_hs/hcd_ci_hs.c
+++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
@@ -35,6 +35,7 @@
//--------------------------------------------------------------------+
#include "common/tusb_common.h"
#include "host/hcd.h"
+#include "host/usbh.h"
#include "portable/ehci/ehci_api.h"
#include "ci_hs_type.h"
@@ -92,12 +93,6 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
hcd_reg->USBMODE = USBMODE_CM_HOST;
#endif
- // FIXME force full speed, still have issue with Highspeed enumeration
- // probably due to physical connection bouncing when plug/unplug
- // 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 7451f69a3..da9f49d29 100644
--- a/src/portable/ehci/ehci.c
+++ b/src/portable/ehci/ehci.c
@@ -34,6 +34,7 @@
#include "osal/osal.h"
#include "host/hcd.h"
+#include "host/usbh.h"
#include "ehci_api.h"
#include "ehci.h"
@@ -837,8 +838,8 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
tu_memclr(p_qhd, sizeof(ehci_qhd_t));
}
- hcd_devtree_info_t devtree_info;
- hcd_devtree_get_info(dev_addr, &devtree_info);
+ tuh_bus_info_t bus_info;
+ tuh_bus_info_get(dev_addr, &bus_info);
uint8_t const xfer_type = ep_desc->bmAttributes.xfer;
uint8_t const interval = ep_desc->bInterval;
@@ -846,7 +847,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
p_qhd->dev_addr = dev_addr;
p_qhd->fl_inactive_next_xact = 0;
p_qhd->ep_number = tu_edpt_number(ep_desc->bEndpointAddress);
- p_qhd->ep_speed = devtree_info.speed;
+ p_qhd->ep_speed = bus_info.speed;
p_qhd->data_toggle_control= (xfer_type == TUSB_XFER_CONTROL) ? 1 : 0;
p_qhd->head_list_flag = (dev_addr == 0) ? 1 : 0; // addr0's endpoint is the static async list head
p_qhd->max_packet_size = tu_edpt_packet_size(ep_desc);
@@ -887,8 +888,8 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
default: break;
}
- p_qhd->fl_hub_addr = devtree_info.hub_addr;
- p_qhd->fl_hub_port = devtree_info.hub_port;
+ p_qhd->fl_hub_addr = bus_info.hub_addr;
+ p_qhd->fl_hub_port = bus_info.hub_port;
p_qhd->mult = 1; // TODO not use high bandwidth/park mode yet
//------------- HCD Management Data -------------//
diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c
index 811043d74..dcc023e0b 100644
--- a/src/portable/mentor/musb/hcd_musb.c
+++ b/src/portable/mentor/musb/hcd_musb.c
@@ -36,6 +36,7 @@ _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");
#endif
#include "host/hcd.h"
+#include "host/usbh.h"
#include "musb_type.h"
@@ -695,16 +696,16 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
_hcd.pipe0.length = 8;
_hcd.pipe0.remaining = 0;
- hcd_devtree_info_t devtree;
- hcd_devtree_get_info(dev_addr, &devtree);
- switch (devtree.speed) {
+ tuh_bus_info_t bus_info;
+ tuh_bus_info_get(dev_addr, &bus_info);
+ switch (bus_info.speed) {
default: return false;
case TUSB_SPEED_LOW: USB0->TYPE0 = USB_TYPE0_SPEED_LOW; break;
case TUSB_SPEED_FULL: USB0->TYPE0 = USB_TYPE0_SPEED_FULL; break;
case TUSB_SPEED_HIGH: USB0->TYPE0 = USB_TYPE0_SPEED_HIGH; break;
}
- USB0->TXHUBADDR0 = devtree.hub_addr;
- USB0->TXHUBPORT0 = devtree.hub_port;
+ USB0->TXHUBADDR0 = bus_info.hub_addr;
+ USB0->TXHUBPORT0 = bus_info.hub_port;
USB0->TXFUNCADDR0 = dev_addr;
USB0->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_SETUP;
return true;
@@ -744,9 +745,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
pipe->remaining = 0;
uint8_t pipe_type = 0;
- hcd_devtree_info_t devtree;
- hcd_devtree_get_info(dev_addr, &devtree);
- switch (devtree.speed) {
+ tuh_bus_info_t bus_info;
+ tuh_bus_info_get(dev_addr, &bus_info);
+ switch (bus_info.speed) {
default: return false;
case TUSB_SPEED_LOW: pipe_type |= USB_TXTYPE1_SPEED_LOW; break;
case TUSB_SPEED_FULL: pipe_type |= USB_TXTYPE1_SPEED_FULL; break;
@@ -763,8 +764,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
if (dir_tx) {
fadr->TXFUNCADDR = dev_addr;
- fadr->TXHUBADDR = devtree.hub_addr;
- fadr->TXHUBPORT = devtree.hub_port;
+ fadr->TXHUBADDR = bus_info.hub_addr;
+ fadr->TXHUBPORT = bus_info.hub_port;
regs->TXMAXP = mps;
regs->TXTYPE = pipe_type | epn;
regs->TXINTERVAL = ep_desc->bInterval;
@@ -775,8 +776,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
USB0->TXIE |= TU_BIT(pipenum);
} else {
fadr->RXFUNCADDR = dev_addr;
- fadr->RXHUBADDR = devtree.hub_addr;
- fadr->RXHUBPORT = devtree.hub_port;
+ fadr->RXHUBADDR = bus_info.hub_addr;
+ fadr->RXHUBPORT = bus_info.hub_port;
regs->RXMAXP = mps;
regs->RXTYPE = pipe_type | epn;
regs->RXINTERVAL = ep_desc->bInterval;
diff --git a/src/portable/nxp/khci/hcd_khci.c b/src/portable/nxp/khci/hcd_khci.c
index c3c901c5d..45732a866 100644
--- a/src/portable/nxp/khci/hcd_khci.c
+++ b/src/portable/nxp/khci/hcd_khci.c
@@ -36,6 +36,7 @@
#endif
#include "host/hcd.h"
+#include "host/usbh.h"
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
diff --git a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
index 090d1ba69..fea3e2a66 100644
--- a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
+++ b/src/portable/nxp/lpc17_40/hcd_lpc17_40.c
@@ -31,6 +31,7 @@
#include "chip.h"
#include "host/hcd.h"
+#include "host/usbh.h"
void hcd_int_enable(uint8_t rhport)
{
diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c
index 672ad0443..81091c9a7 100644
--- a/src/portable/ohci/ohci.c
+++ b/src/portable/ohci/ohci.c
@@ -38,6 +38,7 @@
#include "osal/osal.h"
#include "host/hcd.h"
+#include "host/usbh.h"
#include "ohci.h"
// TODO remove
@@ -328,13 +329,13 @@ static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t ep_size, uint8_t
tu_memclr(p_ed, sizeof(ohci_ed_t));
}
- hcd_devtree_info_t devtree_info;
- hcd_devtree_get_info(dev_addr, &devtree_info);
+ tuh_bus_info_t bus_info;
+ tuh_bus_info_get(dev_addr, &bus_info);
p_ed->dev_addr = dev_addr;
p_ed->ep_number = ep_addr & 0x0F;
p_ed->pid = (xfer_type == TUSB_XFER_CONTROL) ? PID_FROM_TD : (tu_edpt_dir(ep_addr) ? PID_IN : PID_OUT);
- p_ed->speed = devtree_info.speed;
+ p_ed->speed = bus_info.speed;
p_ed->is_iso = (xfer_type == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
p_ed->max_packet_size = ep_size;
diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
index 225a44dcf..d59a2b4ee 100644
--- a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
+++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
@@ -114,9 +114,9 @@ void hcd_int_disable(uint8_t rhport) {
//--------------------------------------------------------------------+
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *desc_ep) {
- hcd_devtree_info_t dev_tree;
- hcd_devtree_get_info(dev_addr, &dev_tree);
- bool const need_pre = (dev_tree.hub_addr && dev_tree.speed == TUSB_SPEED_LOW);
+ tuh_bus_info_t bus_info;
+ tuh_bus_info_get(dev_addr, &bus_info);
+ bool const need_pre = (bus_info.hub_addr && bus_info.speed == TUSB_SPEED_LOW);
uint8_t const pio_rhport = RHPORT_PIO(rhport);
return pio_usb_host_endpoint_open(pio_rhport, dev_addr, (uint8_t const *) desc_ep, need_pre);
diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c
index 3e4b36981..6f6d27d0e 100644
--- a/src/portable/renesas/rusb2/hcd_rusb2.c
+++ b/src/portable/renesas/rusb2/hcd_rusb2.c
@@ -30,6 +30,7 @@
#if CFG_TUH_ENABLED && defined(TUP_USBIP_RUSB2)
#include "host/hcd.h"
+#include "host/usbh.h"
#include "rusb2_type.h"
#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
@@ -662,13 +663,13 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
if (0 == epn) {
rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
- hcd_devtree_info_t devtree;
- hcd_devtree_get_info(dev_addr, &devtree);
+ tuh_bus_info_t bus_info;
+ tuh_bus_info_get(dev_addr, &bus_info);
uint16_t volatile *devadd = (uint16_t volatile *)(uintptr_t) &rusb->DEVADD[0];
devadd += dev_addr;
while (rusb->DCPCTR_b.PBUSY) {}
rusb->DCPMAXP = (dev_addr << 12) | mps;
- *devadd = (TUSB_SPEED_FULL == devtree.speed) ? RUSB2_DEVADD_USBSPD_FS : RUSB2_DEVADD_USBSPD_LS;
+ *devadd = (TUSB_SPEED_FULL == bus_info.speed) ? RUSB2_DEVADD_USBSPD_FS : RUSB2_DEVADD_USBSPD_LS;
_hcd.ctl_mps[dev_addr] = mps;
return true;
}
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index c461d9a79..52d675611 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -41,12 +41,6 @@
#include "device/dcd.h"
#include "dwc2_common.h"
-#if TU_CHECK_MCU(OPT_MCU_GD32VF103)
- #define DWC2_EP_COUNT(_dwc2) DWC2_EP_MAX
-#else
- #define DWC2_EP_COUNT(_dwc2) ((_dwc2)->ghwcfg2_bm.num_dev_ep + 1)
-#endif
-
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM
//--------------------------------------------------------------------+
@@ -79,6 +73,16 @@ CFG_TUD_MEM_SECTION static struct {
TUD_EPBUF_DEF(setup_packet, 8);
} _dcd_usbbuf;
+TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_ep_count(const dwc2_regs_t* dwc2) {
+ #if TU_CHECK_MCU(OPT_MCU_GD32VF103)
+ return DWC2_EP_MAX;
+ #else
+ const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
+ return ghwcfg2.num_dev_ep + 1;
+ #endif
+}
+
+
//--------------------------------------------------------------------
// DMA
//--------------------------------------------------------------------
@@ -102,7 +106,8 @@ bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
TU_ATTR_ALWAYS_INLINE static inline bool dma_device_enabled(const dwc2_regs_t* dwc2) {
(void) dwc2;
// Internal DMA only
- return CFG_TUD_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA;
+ const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
+ return CFG_TUD_DWC2_DMA_ENABLE && ghwcfg2.arch == GHWCFG2_ARCH_INTERNAL_DMA;
}
static void dma_setup_prepare(uint8_t rhport) {
@@ -250,20 +255,15 @@ static void edpt_activate(uint8_t rhport, const tusb_desc_endpoint_t* p_endpoint
xfer->interval = p_endpoint_desc->bInterval;
// Endpoint control
- union {
- uint32_t value;
- dwc2_depctl_t bm;
- } depctl;
- depctl.value = 0;
-
- depctl.bm.mps = xfer->max_size;
- depctl.bm.active = 1;
- depctl.bm.type = p_endpoint_desc->bmAttributes.xfer;
+ dwc2_depctl_t depctl = {.value = 0};
+ depctl.mps = xfer->max_size;
+ depctl.active = 1;
+ depctl.type = p_endpoint_desc->bmAttributes.xfer;
if (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS) {
- depctl.bm.set_data0_iso_even = 1;
+ depctl.set_data0_iso_even = 1;
}
if (dir == TUSB_DIR_IN) {
- depctl.bm.tx_fifo_num = epnum;
+ depctl.tx_fifo_num = epnum;
}
dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum];
@@ -343,31 +343,22 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
}
// transfer size: A full OUT transfer (multiple packets, possibly) triggers XFRC.
- union {
- uint32_t value;
- dwc2_ep_tsize_t bm;
- } deptsiz;
- deptsiz.value = 0;
- deptsiz.bm.xfer_size = total_bytes;
- deptsiz.bm.packet_count = num_packets;
-
+ dwc2_ep_tsize_t deptsiz = {.value = 0};
+ deptsiz.xfer_size = total_bytes;
+ deptsiz.packet_count = num_packets;
dep->tsiz = deptsiz.value;
// control
- union {
- dwc2_depctl_t bm;
- uint32_t value;
- } depctl;
- depctl.value = dep->ctl;
-
- depctl.bm.clear_nak = 1;
- depctl.bm.enable = 1;
- if (depctl.bm.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) {
- const uint32_t odd_now = (dwc2->dsts_bm.frame_number & 1u);
+ dwc2_depctl_t depctl = {.value = dep->ctl};
+ depctl.clear_nak = 1;
+ depctl.enable = 1;
+ if (depctl.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) {
+ const dwc2_dsts_t dsts = {.value = dwc2->dsts};
+ const uint32_t odd_now = dsts.frame_number & 1u;
if (odd_now) {
- depctl.bm.set_data0_iso_even = 1;
+ depctl.set_data0_iso_even = 1;
} else {
- depctl.bm.set_data1_iso_odd = 1;
+ depctl.set_data1_iso_odd = 1;
}
}
@@ -410,7 +401,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
// XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required
// when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347)
- if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) {
+ const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
+ if (ghwcfg2.hs_phy_type == GHWCFG2_HSPHY_ULPI) {
dcfg |= DCFG_XCVRDLY;
}
} else {
@@ -641,7 +633,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
// 7.4.1 Initialization on USB Reset
static void handle_bus_reset(uint8_t rhport) {
dwc2_regs_t *dwc2 = DWC2_REG(rhport);
- const uint8_t ep_count = DWC2_EP_COUNT(dwc2);
+ const uint8_t ep_count = dwc2_ep_count(dwc2);
tu_memclr(xfer_status, sizeof(xfer_status));
@@ -671,7 +663,9 @@ static void handle_bus_reset(uint8_t rhport) {
dfifo_device_init(rhport);
// 5. Reset device address
- dwc2->dcfg_bm.address = 0;
+ dwc2_dcfg_t dcfg = {.value = dwc2->dcfg};
+ dcfg.address = 0;
+ dwc2->dcfg = dcfg.value;
// Fixed both control EP0 size to 64 bytes
dwc2->epin[0].ctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos);
@@ -691,8 +685,9 @@ static void handle_bus_reset(uint8_t rhport) {
static void handle_enum_done(uint8_t rhport) {
dwc2_regs_t *dwc2 = DWC2_REG(rhport);
+ const dwc2_dsts_t dsts = {.value = dwc2->dsts};
tusb_speed_t speed;
- switch (dwc2->dsts_bm.enum_speed) {
+ switch (dsts.enum_speed) {
case DCFG_SPEED_HIGH:
speed = TUSB_SPEED_HIGH;
break;
@@ -737,12 +732,12 @@ static void handle_rxflvl_irq(uint8_t rhport) {
const volatile uint32_t* rx_fifo = dwc2->fifo[0];
// Pop control word off FIFO
- const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm;
- const uint8_t epnum = grxstsp_bm.ep_ch_num;
+ const dwc2_grxstsp_t grxstsp = {.value = dwc2->grxstsp};
+ const uint8_t epnum = grxstsp.ep_ch_num;
dwc2_dep_t* epout = &dwc2->epout[epnum];
- switch (grxstsp_bm.packet_status) {
+ switch (grxstsp.packet_status) {
case GRXSTS_PKTSTS_GLOBAL_OUT_NAK:
// Global OUT NAK: do nothing
break;
@@ -764,7 +759,7 @@ static void handle_rxflvl_irq(uint8_t rhport) {
case GRXSTS_PKTSTS_RX_DATA: {
// Out packet received
- const uint16_t byte_count = grxstsp_bm.byte_count;
+ const uint16_t byte_count = grxstsp.byte_count;
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
if (byte_count) {
@@ -778,7 +773,8 @@ static void handle_rxflvl_irq(uint8_t rhport) {
// short packet, minus remaining bytes (xfer_size)
if (byte_count < xfer->max_size) {
- xfer->total_len -= epout->tsiz_bm.xfer_size;
+ const dwc2_ep_tsize_t tsiz = {.value = epout->tsiz};
+ xfer->total_len -= tsiz.xfer_size;
if (epnum == 0) {
xfer->total_len -= _dcd_data.ep0_pending[TUSB_DIR_OUT];
_dcd_data.ep0_pending[TUSB_DIR_OUT] = 0;
@@ -840,11 +836,13 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep
// - 64 bytes or
// - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL)
if (diepint_bm.txfifo_empty && (dwc2->diepempmsk & (1 << epnum))) {
- const uint16_t remain_packets = epin->tsiz_bm.packet_count;
+ dwc2_ep_tsize_t tsiz = {.value = epin->tsiz};
+ const uint16_t remain_packets = tsiz.packet_count;
// Process every single packet (only whole packets can be written to fifo)
for (uint16_t i = 0; i < remain_packets; i++) {
- const uint16_t remain_bytes = (uint16_t) epin->tsiz_bm.xfer_size;
+ tsiz.value = epin->tsiz;
+ const uint16_t remain_bytes = (uint16_t) tsiz.xfer_size;
const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size);
// Check if dtxfsts has enough space available
@@ -863,7 +861,8 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep
}
// Turn off TXFE if all bytes are written.
- if (epin->tsiz_bm.xfer_size == 0) {
+ tsiz.value = epin->tsiz;
+ if (tsiz.xfer_size == 0) {
dwc2->diepempmsk &= ~(1 << epnum);
}
}
@@ -894,7 +893,8 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
// determine actual received bytes
- const uint16_t remain = epout->tsiz_bm.xfer_size;
+ const dwc2_ep_tsize_t tsiz = {.value = epout->tsiz};
+ const uint16_t remain = tsiz.xfer_size;
xfer->total_len -= remain;
// this is ZLP, so prepare EP0 for next setup
@@ -930,7 +930,7 @@ static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepin
static void handle_ep_irq(uint8_t rhport, uint8_t dir) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const bool is_dma = dma_device_enabled(dwc2);
- const uint8_t ep_count = DWC2_EP_COUNT(dwc2);
+ const uint8_t ep_count = dwc2_ep_count(dwc2);
const uint8_t daint_offset = (dir == TUSB_DIR_IN) ? DAINT_IEPINT_Pos : DAINT_OEPINT_Pos;
dwc2_dep_t* ep_base = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][0];
diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c
index f80ae9acb..e1e7d5c1a 100644
--- a/src/portable/synopsys/dwc2/dwc2_common.c
+++ b/src/portable/synopsys/dwc2/dwc2_common.c
@@ -36,6 +36,7 @@
#if CFG_TUH_ENABLED
#include "host/hcd.h"
+#include "host/usbh.h"
#endif
#include "dwc2_common.h"
@@ -88,11 +89,13 @@ static void phy_fs_init(dwc2_regs_t* dwc2) {
static void phy_hs_init(dwc2_regs_t* dwc2) {
uint32_t gusbcfg = dwc2->gusbcfg;
+ const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
+ const dwc2_ghwcfg4_t ghwcfg4 = {.value = dwc2->ghwcfg4};
// De-select FS PHY
gusbcfg &= ~GUSBCFG_PHYSEL;
- if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) {
+ if (ghwcfg2.hs_phy_type == GHWCFG2_HSPHY_ULPI) {
TU_LOG(DWC2_COMMON_DEBUG, "Highspeed ULPI PHY init\r\n");
// Select ULPI PHY (external)
@@ -116,7 +119,7 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
gusbcfg &= ~GUSBCFG_ULPI_UTMI_SEL;
// Set 16-bit interface if supported
- if (dwc2->ghwcfg4_bm.phy_data_width) {
+ if (ghwcfg4.phy_data_width) {
gusbcfg |= GUSBCFG_PHYIF16; // 16 bit
} else {
gusbcfg &= ~GUSBCFG_PHYIF16; // 8 bit
@@ -127,7 +130,7 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
dwc2->gusbcfg = gusbcfg;
// mcu specific phy init
- dwc2_phy_init(dwc2, dwc2->ghwcfg2_bm.hs_phy_type);
+ dwc2_phy_init(dwc2, ghwcfg2.hs_phy_type);
// Reset core after selecting PHY
reset_core(dwc2);
@@ -136,11 +139,11 @@ static void phy_hs_init(dwc2_regs_t* dwc2) {
// - 9 if using 8-bit PHY interface
// - 5 if using 16-bit PHY interface
gusbcfg &= ~GUSBCFG_TRDT_Msk;
- gusbcfg |= (dwc2->ghwcfg4_bm.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos;
+ gusbcfg |= (ghwcfg4.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos;
dwc2->gusbcfg = gusbcfg;
// MCU specific PHY update post reset
- dwc2_phy_update(dwc2, dwc2->ghwcfg2_bm.hs_phy_type);
+ dwc2_phy_update(dwc2, ghwcfg2.hs_phy_type);
}
static bool check_dwc2(dwc2_regs_t* dwc2) {
@@ -171,7 +174,6 @@ static bool check_dwc2(dwc2_regs_t* dwc2) {
//--------------------------------------------------------------------
bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role) {
(void)dwc2;
-
#if CFG_TUD_ENABLED
if (role == TUSB_ROLE_DEVICE && !TUD_OPT_HIGH_SPEED) {
return false;
@@ -183,7 +185,8 @@ bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role) {
}
#endif
- return dwc2->ghwcfg2_bm.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED;
+ const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
+ return ghwcfg2.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED;
}
/* dwc2 has several PHYs option
diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h
index 812096759..0a8dacf5f 100644
--- a/src/portable/synopsys/dwc2/dwc2_type.h
+++ b/src/portable/synopsys/dwc2/dwc2_type.h
@@ -184,415 +184,470 @@ enum {
//--------------------------------------------------------------------
// Common Register Bitfield
//--------------------------------------------------------------------
-typedef struct TU_ATTR_PACKED {
- uint32_t ses_req_scs : 1; // 0 Session request success
- uint32_t ses_req : 1; // 1 Session request
- uint32_t vbval_ov_en : 1; // 2 VBUS valid override enable
- uint32_t vbval_ov_val : 1; // 3 VBUS valid override value
- uint32_t aval_ov_en : 1; // 4 A-peripheral session valid override enable
- uint32_t aval_ov_al : 1; // 5 A-peripheral session valid override value
- uint32_t bval_ov_en : 1; // 6 B-peripheral session valid override enable
- uint32_t bval_ov_val : 1; // 7 B-peripheral session valid override value
- uint32_t hng_scs : 1; // 8 Host negotiation success
- uint32_t hnp_rq : 1; // 9 HNP (host negotiation protocol) request
- uint32_t host_set_hnp_en : 1; // 10 Host set HNP enable
- uint32_t dev_hnp_en : 1; // 11 Device HNP enabled
- uint32_t embedded_host_en : 1; // 12 Embedded host enable
- uint32_t rsv13_14 : 2; // 13.14 Reserved
- uint32_t dbnc_filter_bypass : 1; // 15 Debounce filter bypass
- uint32_t cid_status : 1; // 16 Connector ID status
- uint32_t dbnc_done : 1; // 17 Debounce done
- uint32_t ases_valid : 1; // 18 A-session valid
- uint32_t bses_valid : 1; // 19 B-session valid
- uint32_t otg_ver : 1; // 20 OTG version 0: v1.3, 1: v2.0
- uint32_t current_mode : 1; // 21 Current mode of operation. Only from v3.00a
- uint32_t mult_val_id_bc : 5; // 22..26 Multi-valued input pin ID battery charger
- uint32_t chirp_en : 1; // 27 Chirp detection enable
- uint32_t rsv28_30 : 3; // 28.30: Reserved
- uint32_t test_mode_corr_eusb2 : 1; // 31 Test mode control for eUSB2 PHY
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t ses_req_scs : 1; // 0 Session request success
+ uint32_t ses_req : 1; // 1 Session request
+ uint32_t vbval_ov_en : 1; // 2 VBUS valid override enable
+ uint32_t vbval_ov_val : 1; // 3 VBUS valid override value
+ uint32_t aval_ov_en : 1; // 4 A-peripheral session valid override enable
+ uint32_t aval_ov_al : 1; // 5 A-peripheral session valid override value
+ uint32_t bval_ov_en : 1; // 6 B-peripheral session valid override enable
+ uint32_t bval_ov_val : 1; // 7 B-peripheral session valid override value
+ uint32_t hng_scs : 1; // 8 Host negotiation success
+ uint32_t hnp_rq : 1; // 9 HNP (host negotiation protocol) request
+ uint32_t host_set_hnp_en : 1; // 10 Host set HNP enable
+ uint32_t dev_hnp_en : 1; // 11 Device HNP enabled
+ uint32_t embedded_host_en : 1; // 12 Embedded host enable
+ uint32_t rsv13_14 : 2; // 13.14 Reserved
+ uint32_t dbnc_filter_bypass : 1; // 15 Debounce filter bypass
+ uint32_t cid_status : 1; // 16 Connector ID status
+ uint32_t dbnc_done : 1; // 17 Debounce done
+ uint32_t ases_valid : 1; // 18 A-session valid
+ uint32_t bses_valid : 1; // 19 B-session valid
+ uint32_t otg_ver : 1; // 20 OTG version 0: v1.3, 1: v2.0
+ uint32_t current_mode : 1; // 21 Current mode of operation. Only from v3.00a
+ uint32_t mult_val_id_bc : 5; // 22..26 Multi-valued input pin ID battery charger
+ uint32_t chirp_en : 1; // 27 Chirp detection enable
+ uint32_t rsv28_30 : 3; // 28.30: Reserved
+ uint32_t test_mode_corr_eusb2 : 1; // 31 Test mode control for eUSB2 PHY
+ };
} dwc2_gotgctl_t;
TU_VERIFY_STATIC(sizeof(dwc2_gotgctl_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t rsv0_1 : 2; // 0..1 Reserved
- uint32_t ses_end_det : 1; // 2 Session end detected
- uint32_t rsv3_7 : 5; // 3..7 Reserved
- uint32_t srs_status_change : 1; // 8 Session request success status change
- uint32_t hns_status_change : 1; // 9 Host negotiation success status change
- uint32_t rsv10_16 : 7; // 10..16 Reserved
- uint32_t hng_det : 1; // 17 Host negotiation detected
- uint32_t adev_timeout_change : 1; // 18 A-device timeout change
- uint32_t dbnc_done : 1; // 19 Debounce done
- uint32_t mult_val_lp_change : 1; // 20 Multi-valued input pin change
- uint32_t rsv21_31 :11; // 21..31 Reserved
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t rsv0_1 : 2; // 0..1 Reserved
+ uint32_t ses_end_det : 1; // 2 Session end detected
+ uint32_t rsv3_7 : 5; // 3..7 Reserved
+ uint32_t srs_status_change : 1; // 8 Session request success status change
+ uint32_t hns_status_change : 1; // 9 Host negotiation success status change
+ uint32_t rsv10_16 : 7; // 10..16 Reserved
+ uint32_t hng_det : 1; // 17 Host negotiation detected
+ uint32_t adev_timeout_change : 1; // 18 A-device timeout change
+ uint32_t dbnc_done : 1; // 19 Debounce done
+ uint32_t mult_val_lp_change : 1; // 20 Multi-valued input pin change
+ uint32_t rsv21_31 :11; // 21..31 Reserved
+ };
} dwc2_gotgint_t;
TU_VERIFY_STATIC(sizeof(dwc2_gotgint_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t gintmask : 1; // 0 Global interrupt mask
- uint32_t hbst_len : 4; // 1..4 Burst length/type
- uint32_t dma_en : 1; // 5 DMA enable
- uint32_t rsv6 : 1; // 6 Reserved
- uint32_t nptxf_empty_lvl : 1; // 7 Non-periodic Tx FIFO empty level
- uint32_t ptxf_empty_lvl : 1; // 8 Periodic Tx FIFO empty level
- uint32_t rsv9_20 : 12; // 9.20: Reserved
- uint32_t remote_mem_support : 1; // 21 Remote memory support
- uint32_t notify_all_dma_write : 1; // 22 Notify all DMA writes
- uint32_t ahb_single : 1; // 23 AHB single
- uint32_t inv_desc_endian : 1; // 24 Inverse descriptor endian
- uint32_t rsv25_31 : 7; // 25..31 Reserved
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t gintmask : 1; // 0 Global interrupt mask
+ uint32_t hbst_len : 4; // 1..4 Burst length/type
+ uint32_t dma_en : 1; // 5 DMA enable
+ uint32_t rsv6 : 1; // 6 Reserved
+ uint32_t nptxf_empty_lvl : 1; // 7 Non-periodic Tx FIFO empty level
+ uint32_t ptxf_empty_lvl : 1; // 8 Periodic Tx FIFO empty level
+ uint32_t rsv9_20 : 12; // 9.20: Reserved
+ uint32_t remote_mem_support : 1; // 21 Remote memory support
+ uint32_t notify_all_dma_write : 1; // 22 Notify all DMA writes
+ uint32_t ahb_single : 1; // 23 AHB single
+ uint32_t inv_desc_endian : 1; // 24 Inverse descriptor endian
+ uint32_t rsv25_31 : 7; // 25..31 Reserved
+ };
} dwc2_gahbcfg_t;
TU_VERIFY_STATIC(sizeof(dwc2_gahbcfg_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t timeout_cal : 3; /* 0..2 Timeout calibration.
- The USB standard timeout value for high-speed operation is 736 to 816 (inclusive) bit times. The USB standard
- timeout value for full- speed operation is 16 to 18 (inclusive) bit times. The application must program this field
- based on the speed of enumeration. The number of bit times added per PHY clock are as follows:
- - High-speed: PHY clock One 30-MHz = 16 bit times, One 60-MHz = 8 bit times
- - Full-speed: PHY clock One 30-MHz = 0.4 bit times, One 60-MHz = 0.2 bit times, One 48-MHz = 0.25 bit times */
- uint32_t phy_if16 : 1; // 3 PHY interface. 0: 8 bits, 1: 16 bits
- uint32_t ulpi_utmi_sel : 1; // 4 ULPI/UTMI select. 0: UTMI+, 1: ULPI
- uint32_t fs_intf_sel : 1; // 5 Fullspeed serial interface select. 0: 6-pin, 1: 3-pin
- uint32_t phy_sel : 1; // 6 HS/FS PHY selection. 0: HS UTMI+ or ULPI, 1: FS serial transceiver
- uint32_t ddr_sel : 1; // 7 ULPI DDR select. 0: Single data rate 8-bit, 1: Double data rate 4-bit
- uint32_t srp_capable : 1; // 8 SRP-capable
- uint32_t hnp_capable : 1; // 9 HNP-capable
- uint32_t turnaround_time : 4; // 10..13 Turnaround time. 9: 8-bit UTMI+, 5: 16-bit UTMI+
- uint32_t rsv14 : 1; // 14 Reserved
- uint32_t phy_low_power_clk_sel : 1; /* 15 PHY low-power clock select either 480-MHz or 48-MHz (low-power) PHY mode.
- In FS/LS modes, the PHY can usually operate on a 48-MHz clock to save power. This bit is valid only for UTMI+ PHYs.
- - 0: 480 Mhz internal PLL: the UTMI interface operates at either 60 MHz (8 bit) or 30 MHz (16-bit)
- - 1 48 Mhz external clock: the UTMI interface operates at 48 MHz in FS mode and at either 48 or 6 MHz in LS mode */
- uint32_t otg_i2c_sel : 1; // 16 OTG I2C interface select. 0: UTMI-FS, 1: I2C for OTG signals
- uint32_t ulpi_fsls : 1; /* 17 ULPI FS/LS select. 0: ULPI, 1: ULPI FS/LS.
- valid only when the FS serial transceiver is selected on the ULPI PHY. */
- uint32_t ulpi_auto_resume : 1; // 18 ULPI Auto-resume
- uint32_t ulpi_clk_sus_m : 1; // 19 ULPI Clock SuspendM
- uint32_t ulpi_ext_vbus_drv : 1; // 20 ULPI External VBUS Drive
- uint32_t ulpi_int_vbus_indicator : 1; // 21 ULPI Internal VBUS Indicator
- uint32_t term_sel_dl_pulse : 1; // 22 TermSel DLine pulsing
- uint32_t indicator_complement : 1; // 23 Indicator complement
- uint32_t indicator_pass_through : 1; // 24 Indicator pass through
- uint32_t ulpi_if_protect_disable : 1; // 25 ULPI interface protect disable
- uint32_t ic_usb_capable : 1; // 26 IC_USB Capable
- uint32_t ic_usb_traf_ctl : 1; // 27 IC_USB Traffic Control
- uint32_t tx_end_delay : 1; // 28 TX end delay
- uint32_t force_host_mode : 1; // 29 Force host mode
- uint32_t force_dev_mode : 1; // 30 Force device mode
- uint32_t corrupt_tx_pkt : 1; // 31 Corrupt Tx packet. 0: normal, 1: debug
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t timeout_cal : 3; /* 0..2 Timeout calibration.
+ The USB standard timeout value for high-speed operation is 736 to 816 (inclusive) bit times. The USB standard
+ timeout value for full- speed operation is 16 to 18 (inclusive) bit times. The application must program this field
+ based on the speed of enumeration. The number of bit times added per PHY clock are as follows:
+ - High-speed: PHY clock One 30-MHz = 16 bit times, One 60-MHz = 8 bit times
+ - Full-speed: PHY clock One 30-MHz = 0.4 bit times, One 60-MHz = 0.2 bit times, One 48-MHz = 0.25 bit times */
+ uint32_t phy_if16 : 1; // 3 PHY interface. 0: 8 bits, 1: 16 bits
+ uint32_t ulpi_utmi_sel : 1; // 4 ULPI/UTMI select. 0: UTMI+, 1: ULPI
+ uint32_t fs_intf_sel : 1; // 5 Fullspeed serial interface select. 0: 6-pin, 1: 3-pin
+ uint32_t phy_sel : 1; // 6 HS/FS PHY selection. 0: HS UTMI+ or ULPI, 1: FS serial transceiver
+ uint32_t ddr_sel : 1; // 7 ULPI DDR select. 0: Single data rate 8-bit, 1: Double data rate 4-bit
+ uint32_t srp_capable : 1; // 8 SRP-capable
+ uint32_t hnp_capable : 1; // 9 HNP-capable
+ uint32_t turnaround_time : 4; // 10..13 Turnaround time. 9: 8-bit UTMI+, 5: 16-bit UTMI+
+ uint32_t rsv14 : 1; // 14 Reserved
+ uint32_t phy_low_power_clk_sel : 1; /* 15 PHY low-power clock select either 480-MHz or 48-MHz (low-power) PHY mode.
+ In FS/LS modes, the PHY can usually operate on a 48-MHz clock to save power. This bit is valid only for UTMI+ PHYs.
+ - 0: 480 Mhz internal PLL: the UTMI interface operates at either 60 MHz (8 bit) or 30 MHz (16-bit)
+ - 1 48 Mhz external clock: the UTMI interface operates at 48 MHz in FS mode and at either 48 or 6 MHz in LS mode */
+ uint32_t otg_i2c_sel : 1; // 16 OTG I2C interface select. 0: UTMI-FS, 1: I2C for OTG signals
+ uint32_t ulpi_fsls : 1; /* 17 ULPI FS/LS select. 0: ULPI, 1: ULPI FS/LS.
+ valid only when the FS serial transceiver is selected on the ULPI PHY. */
+ uint32_t ulpi_auto_resume : 1; // 18 ULPI Auto-resume
+ uint32_t ulpi_clk_sus_m : 1; // 19 ULPI Clock SuspendM
+ uint32_t ulpi_ext_vbus_drv : 1; // 20 ULPI External VBUS Drive
+ uint32_t ulpi_int_vbus_indicator : 1; // 21 ULPI Internal VBUS Indicator
+ uint32_t term_sel_dl_pulse : 1; // 22 TermSel DLine pulsing
+ uint32_t indicator_complement : 1; // 23 Indicator complement
+ uint32_t indicator_pass_through : 1; // 24 Indicator pass through
+ uint32_t ulpi_if_protect_disable : 1; // 25 ULPI interface protect disable
+ uint32_t ic_usb_capable : 1; // 26 IC_USB Capable
+ uint32_t ic_usb_traf_ctl : 1; // 27 IC_USB Traffic Control
+ uint32_t tx_end_delay : 1; // 28 TX end delay
+ uint32_t force_host_mode : 1; // 29 Force host mode
+ uint32_t force_dev_mode : 1; // 30 Force device mode
+ uint32_t corrupt_tx_pkt : 1; // 31 Corrupt Tx packet. 0: normal, 1: debug
+ };
} dwc2_gusbcfg_t;
TU_VERIFY_STATIC(sizeof(dwc2_gusbcfg_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t core_soft_rst : 1; // 0 Core Soft Reset
- uint32_t piufs_soft_rst : 1; // 1 PIU FS Dedicated Controller Soft Reset
- uint32_t frame_counter_rst : 1; // 2 Frame Counter Reset (host)
- uint32_t intoken_q_flush : 1; // 3 IN Token Queue Flush
- uint32_t rx_fifo_flush : 1; // 4 RX FIFO Flush
- uint32_t tx_fifo_flush : 1; // 5 TX FIFO Flush
- uint32_t tx_fifo_num : 5; // 6..10 TX FIFO Number
- uint32_t rsv11_28 :18; // 11..28 Reserved
- uint32_t core_soft_rst_done : 1; // 29 Core Soft Reset Done, from v4.20a
- uint32_t dma_req : 1; // 30 DMA Request
- uint32_t ahb_idle : 1; // 31 AHB Idle
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t core_soft_rst : 1; // 0 Core Soft Reset
+ uint32_t piufs_soft_rst : 1; // 1 PIU FS Dedicated Controller Soft Reset
+ uint32_t frame_counter_rst : 1; // 2 Frame Counter Reset (host)
+ uint32_t intoken_q_flush : 1; // 3 IN Token Queue Flush
+ uint32_t rx_fifo_flush : 1; // 4 RX FIFO Flush
+ uint32_t tx_fifo_flush : 1; // 5 TX FIFO Flush
+ uint32_t tx_fifo_num : 5; // 6..10 TX FIFO Number
+ uint32_t rsv11_28 :18; // 11..28 Reserved
+ uint32_t core_soft_rst_done : 1; // 29 Core Soft Reset Done, from v4.20a
+ uint32_t dma_req : 1; // 30 DMA Request
+ uint32_t ahb_idle : 1; // 31 AHB Idle
+ };
} dwc2_grstctl_t;
TU_VERIFY_STATIC(sizeof(dwc2_grstctl_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t ep_ch_num : 4; // 0..3 Endpoint/Channel Number
- uint32_t byte_count :11; // 4..14 Byte Count
- uint32_t dpid : 2; // 15..16 Data PID
- uint32_t packet_status : 4; // 17..20 Packet Status
- uint32_t frame_number : 4; // 21..24 Frame Number
- uint32_t rsv25_31 : 7; // 25..31 Reserved
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t ep_ch_num : 4; // 0..3 Endpoint/Channel Number
+ uint32_t byte_count :11; // 4..14 Byte Count
+ uint32_t dpid : 2; // 15..16 Data PID
+ uint32_t packet_status : 4; // 17..20 Packet Status
+ uint32_t frame_number : 4; // 21..24 Frame Number
+ uint32_t rsv25_31 : 7; // 25..31 Reserved
+ };
} dwc2_grxstsp_t;
TU_VERIFY_STATIC(sizeof(dwc2_grxstsp_t) == 4, "incorrect size");
-// Hardware Configuration
-typedef struct TU_ATTR_PACKED {
- uint32_t op_mode : 3; // 0..2 HNP/SRP Host/Device/OTG mode
- uint32_t arch : 2; // 3..4 Slave/External/Internal DMA
- uint32_t single_point : 1; // 5 0: support hub and split | 1: no hub, no split
- uint32_t hs_phy_type : 2; // 6..7 0: not supported | 1: UTMI+ | 2: ULPI | 3: UTMI+ and ULPI
- uint32_t fs_phy_type : 2; // 8..9 0: not supported | 1: dedicated | 2: UTMI+ | 3: ULPI
- uint32_t num_dev_ep : 4; // 10..13 Number of device endpoints (excluding EP0)
- uint32_t num_host_ch : 4; // 14..17 Number of host channel (excluding control)
- uint32_t period_channel_support : 1; // 18 Support Periodic OUT Host Channel
- uint32_t enable_dynamic_fifo : 1; // 19 Dynamic FIFO Sizing Enabled
- uint32_t mul_proc_intrpt : 1; // 20 Multi-Processor Interrupt enabled (OTG_MULTI_PROC_INTRPT)
- uint32_t reserved21 : 1; // 21 reserved
- uint32_t nptx_q_depth : 2; // 22..23 Non-periodic request queue depth: 0 = 2. 1 = 4, 2 = 8
- uint32_t ptx_q_depth : 2; // 24..25 Host periodic request queue depth: 0 = 2. 1 = 4, 2 = 8
- uint32_t token_q_depth : 5; // 26..30 Device IN token sequence learning queue depth: 0-30
- uint32_t otg_enable_ic_usb : 1; // 31 IC_USB mode specified for mode of operation
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t op_mode : 3; // 0..2 HNP/SRP Host/Device/OTG mode
+ uint32_t arch : 2; // 3..4 Slave/External/Internal DMA
+ uint32_t single_point : 1; // 5 0: support hub and split | 1: no hub, no split
+ uint32_t hs_phy_type : 2; // 6..7 0: not supported | 1: UTMI+ | 2: ULPI | 3: UTMI+ and ULPI
+ uint32_t fs_phy_type : 2; // 8..9 0: not supported | 1: dedicated | 2: UTMI+ | 3: ULPI
+ uint32_t num_dev_ep : 4; // 10..13 Number of device endpoints (excluding EP0)
+ uint32_t num_host_ch : 4; // 14..17 Number of host channel (excluding control)
+ uint32_t period_channel_support : 1; // 18 Support Periodic OUT Host Channel
+ uint32_t enable_dynamic_fifo : 1; // 19 Dynamic FIFO Sizing Enabled
+ uint32_t mul_proc_intrpt : 1; // 20 Multi-Processor Interrupt enabled (OTG_MULTI_PROC_INTRPT)
+ uint32_t reserved21 : 1; // 21 reserved
+ uint32_t nptx_q_depth : 2; // 22..23 Non-periodic request queue depth: 0 = 2. 1 = 4, 2 = 8
+ uint32_t ptx_q_depth : 2; // 24..25 Host periodic request queue depth: 0 = 2. 1 = 4, 2 = 8
+ uint32_t token_q_depth : 5; // 26..30 Device IN token sequence learning queue depth: 0-30
+ uint32_t otg_enable_ic_usb : 1; // 31 IC_USB mode specified for mode of operation
+ };
} dwc2_ghwcfg2_t;
TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg2_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t xfer_size_width : 4; // 0..3 Transfer size counter in bits = 11 + n (max 19 bits)
- uint32_t packet_size_width : 3; // 4..6 Packet size counter in bits = 4 + n (max 10 bits)
- uint32_t otg_enable : 1; // 7 OTG capable
- uint32_t i2c_enable : 1; // 8 I2C interface is available
- uint32_t vendor_ctrl_itf : 1; // 9 Vendor control interface is available
- uint32_t optional_feature_removed : 1; // 10 remove User ID, GPIO, SOF toggle & counter to save gate count
- uint32_t synch_reset : 1; // 11 0: async reset | 1: synch reset
- uint32_t otg_adp_support : 1; // 12 ADP logic is present along with HSOTG controller
- uint32_t otg_enable_hsic : 1; // 13 1: HSIC-capable with shared UTMI PHY interface | 0: non-HSIC
- uint32_t battery_charger_support : 1; // s14 upport battery charger
- uint32_t lpm_mode : 1; // 15 LPM mode
- uint32_t dfifo_depth : 16; // DFIFO depth - EP_LOC_CNT in terms of 32-bit words
-}dwc2_ghwcfg3_t;
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t xfer_size_width : 4; // 0..3 Transfer size counter in bits = 11 + n (max 19 bits)
+ uint32_t packet_size_width : 3; // 4..6 Packet size counter in bits = 4 + n (max 10 bits)
+ uint32_t otg_enable : 1; // 7 OTG capable
+ uint32_t i2c_enable : 1; // 8 I2C interface is available
+ uint32_t vendor_ctrl_itf : 1; // 9 Vendor control interface is available
+ uint32_t optional_feature_removed : 1; // 10 remove User ID, GPIO, SOF toggle & counter to save gate count
+ uint32_t synch_reset : 1; // 11 0: async reset | 1: synch reset
+ uint32_t otg_adp_support : 1; // 12 ADP logic is present along with HSOTG controller
+ uint32_t otg_enable_hsic : 1; // 13 1: HSIC-capable with shared UTMI PHY interface | 0: non-HSIC
+ uint32_t battery_charger_support : 1; // s14 upport battery charger
+ uint32_t lpm_mode : 1; // 15 LPM mode
+ uint32_t dfifo_depth : 16; // DFIFO depth - EP_LOC_CNT in terms of 32-bit words
+ };
+} dwc2_ghwcfg3_t;
TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg3_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t num_dev_period_in_ep : 4; // 0..3 Number of Device Periodic IN Endpoints
- uint32_t partial_powerdown : 1; // 4 Partial Power Down Enabled
- uint32_t ahb_freq_min : 1; // 5 1: minimum of AHB frequency is less than 60 MHz
- uint32_t hibernation : 1; // 6 Hibernation feature is enabled
- uint32_t extended_hibernation : 1; // 7 Extended Hibernation feature is enabled
- uint32_t reserved8 : 1; // 8 Reserved
- uint32_t enhanced_lpm_support1 : 1; // 9 Enhanced LPM Support1
- uint32_t service_interval_flow : 1; // 10 Service Interval flow is supported
- uint32_t ipg_isoc_support : 1; // 11 Interpacket GAP ISO OUT worst-case is supported
- uint32_t acg_support : 1; // 12 Active clock gating is supported
- uint32_t enhanced_lpm_support : 1; // 13 Enhanced LPM Support
- uint32_t phy_data_width : 2; // 14..15 0: 8 bits | 1: 16 bits | 2: 8/16 software selectable
- uint32_t ctrl_ep_num : 4; // 16..19 Number of Device control endpoints in addition to EP0
- uint32_t iddg_filter : 1; // 20 IDDG Filter Enabled
- uint32_t vbus_valid_filter : 1; // 21 VBUS Valid Filter Enabled
- uint32_t a_valid_filter : 1; // 22 A Valid Filter Enabled
- uint32_t b_valid_filter : 1; // 23 B Valid Filter Enabled
- uint32_t session_end_filter : 1; // 24 Session End Filter Enabled
- uint32_t dedicated_fifos : 1; // 25 Dedicated tx fifo for device IN Endpoint
- uint32_t num_dev_in_eps : 4; // 26..29 Number of Device IN Endpoints including EP0
- uint32_t dma_desc_enabled : 1; // scatter/gather DMA configuration enabled
- uint32_t dma_desc_dynamic : 1; // Dynamic scatter/gather DMA
-}dwc2_ghwcfg4_t;
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t num_dev_period_in_ep : 4; // 0..3 Number of Device Periodic IN Endpoints
+ uint32_t partial_powerdown : 1; // 4 Partial Power Down Enabled
+ uint32_t ahb_freq_min : 1; // 5 1: minimum of AHB frequency is less than 60 MHz
+ uint32_t hibernation : 1; // 6 Hibernation feature is enabled
+ uint32_t extended_hibernation : 1; // 7 Extended Hibernation feature is enabled
+ uint32_t reserved8 : 1; // 8 Reserved
+ uint32_t enhanced_lpm_support1 : 1; // 9 Enhanced LPM Support1
+ uint32_t service_interval_flow : 1; // 10 Service Interval flow is supported
+ uint32_t ipg_isoc_support : 1; // 11 Interpacket GAP ISO OUT worst-case is supported
+ uint32_t acg_support : 1; // 12 Active clock gating is supported
+ uint32_t enhanced_lpm_support : 1; // 13 Enhanced LPM Support
+ uint32_t phy_data_width : 2; // 14..15 0: 8 bits | 1: 16 bits | 2: 8/16 software selectable
+ uint32_t ctrl_ep_num : 4; // 16..19 Number of Device control endpoints in addition to EP0
+ uint32_t iddg_filter : 1; // 20 IDDG Filter Enabled
+ uint32_t vbus_valid_filter : 1; // 21 VBUS Valid Filter Enabled
+ uint32_t a_valid_filter : 1; // 22 A Valid Filter Enabled
+ uint32_t b_valid_filter : 1; // 23 B Valid Filter Enabled
+ uint32_t session_end_filter : 1; // 24 Session End Filter Enabled
+ uint32_t dedicated_fifos : 1; // 25 Dedicated tx fifo for device IN Endpoint
+ uint32_t num_dev_in_eps : 4; // 26..29 Number of Device IN Endpoints including EP0
+ uint32_t dma_desc_enabled : 1; // scatter/gather DMA configuration enabled
+ uint32_t dma_desc_dynamic : 1; // Dynamic scatter/gather DMA
+ };
+} dwc2_ghwcfg4_t;
TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg4_t) == 4, "incorrect size");
-//--------------------------------------------------------------------
-// Host Register Bitfield
-//--------------------------------------------------------------------
-
-typedef struct TU_ATTR_PACKED {
- uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO
- uint32_t req_queue_available : 8; // 16..23 Number of spaces available in the NPT transmit request queue for both IN and OU
- // 24..31 is top entry in the request queue that is currently being processed by the MAC
- uint32_t qtop_terminate : 1; // 24 Last entry for selected channel
- uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command
- uint32_t qtop_ch_num : 4; // 27..30 Channel number
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO
+ uint32_t req_queue_available : 8; // 16..23 Number of spaces available in the NPT transmit request queue for both IN and OU
+ // 24..31 is top entry in the request queue that is currently being processed by the MAC
+ uint32_t qtop_terminate : 1; // 24 Last entry for selected channel
+ uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command
+ uint32_t qtop_ch_num : 4; // 27..30 Channel number
+ };
} dwc2_hnptxsts_t;
TU_VERIFY_STATIC(sizeof(dwc2_hnptxsts_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO
- uint32_t req_queue_available : 7; // 16..22 Number of spaces available in the PTX transmit request queue
- uint32_t qtop_terminate : 1; // 23 Last entry for selected channel
- uint32_t qtop_last_period : 1; // 24 Last entry for selected channel is a periodic entry
- uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command
- uint32_t qtop_ch_num : 4; // 27..30 Channel number
- uint32_t qtop_odd_frame : 1; // 31 Send in odd frame
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t fifo_available :16; // 0..15 Number of words available in the Tx FIFO
+ uint32_t req_queue_available : 7; // 16..22 Number of spaces available in the PTX transmit request queue
+ uint32_t qtop_terminate : 1; // 23 Last entry for selected channel
+ uint32_t qtop_last_period : 1; // 24 Last entry for selected channel is a periodic entry
+ uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command
+ uint32_t qtop_ch_num : 4; // 27..30 Channel number
+ uint32_t qtop_odd_frame : 1; // 31 Send in odd frame
+ };
} dwc2_hptxsts_t;
TU_VERIFY_STATIC(sizeof(dwc2_hptxsts_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t conn_status : 1; // 0 Port connect status
- uint32_t conn_detected : 1; // 1 Port connect detected
- uint32_t enable : 1; // 2 Port enable status
- uint32_t enable_change : 1; // 3 Port enable change
- uint32_t over_current_active : 1; // 4 Port Over-current active
- uint32_t over_current_change : 1; // 5 Port Over-current change
- uint32_t resume : 1; // 6 Port resume
- uint32_t suspend : 1; // 7 Port suspend
- uint32_t reset : 1; // 8 Port reset
- uint32_t rsv9 : 1; // 9 Reserved
- uint32_t line_status : 2; // 10..11 Line status
- uint32_t power : 1; // 12 Port power
- uint32_t test_control : 4; // 13..16 Port Test control
- uint32_t speed : 2; // 17..18 Port speed
- uint32_t rsv19_31 :13; // 19..31 Reserved
-}dwc2_hprt_t;
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t conn_status : 1; // 0 Port connect status
+ uint32_t conn_detected : 1; // 1 Port connect detected
+ uint32_t enable : 1; // 2 Port enable status
+ uint32_t enable_change : 1; // 3 Port enable change
+ uint32_t over_current_active : 1; // 4 Port Over-current active
+ uint32_t over_current_change : 1; // 5 Port Over-current change
+ uint32_t resume : 1; // 6 Port resume
+ uint32_t suspend : 1; // 7 Port suspend
+ uint32_t reset : 1; // 8 Port reset
+ uint32_t rsv9 : 1; // 9 Reserved
+ uint32_t line_status : 2; // 10..11 Line status
+ uint32_t power : 1; // 12 Port power
+ uint32_t test_control : 4; // 13..16 Port Test control
+ uint32_t speed : 2; // 17..18 Port speed
+ uint32_t rsv19_31 :13; // 19..31 Reserved
+ };
+} dwc2_hprt_t;
TU_VERIFY_STATIC(sizeof(dwc2_hprt_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t ep_size : 11; // 0..10 Maximum packet size
- uint32_t ep_num : 4; // 11..14 Endpoint number
- uint32_t ep_dir : 1; // 15 Endpoint direction
- uint32_t rsv16 : 1; // 16 Reserved
- uint32_t low_speed_dev : 1; // 17 Low-speed device
- uint32_t ep_type : 2; // 18..19 Endpoint type
- uint32_t err_multi_count : 2; // 20..21 Error (splitEn = 1) / Multi (SplitEn = 0) count
- uint32_t dev_addr : 7; // 22..28 Device address
- uint32_t odd_frame : 1; // 29 Odd frame
- uint32_t disable : 1; // 30 Channel disable
- uint32_t enable : 1; // 31 Channel enable
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t ep_size : 11; // 0..10 Maximum packet size
+ uint32_t ep_num : 4; // 11..14 Endpoint number
+ uint32_t ep_dir : 1; // 15 Endpoint direction
+ uint32_t rsv16 : 1; // 16 Reserved
+ uint32_t low_speed_dev : 1; // 17 Low-speed device
+ uint32_t ep_type : 2; // 18..19 Endpoint type
+ uint32_t err_multi_count : 2; // 20..21 Error (splitEn = 1) / Multi (SplitEn = 0) count
+ uint32_t dev_addr : 7; // 22..28 Device address
+ uint32_t odd_frame : 1; // 29 Odd frame
+ uint32_t disable : 1; // 30 Channel disable
+ uint32_t enable : 1; // 31 Channel enable
+ };
} dwc2_channel_char_t;
TU_VERIFY_STATIC(sizeof(dwc2_channel_char_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t hub_port : 7; // 0..6 Hub port number
- uint32_t hub_addr : 7; // 7..13 Hub address
- uint32_t xact_pos : 2; // 14..15 Transaction position
- uint32_t split_compl : 1; // 16 Split completion
- uint32_t rsv17_30 : 14; // 17..30 Reserved
- uint32_t split_en : 1; // 31 Split enable
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t hub_port : 7; // 0..6 Hub port number
+ uint32_t hub_addr : 7; // 7..13 Hub address
+ uint32_t xact_pos : 2; // 14..15 Transaction position
+ uint32_t split_compl : 1; // 16 Split completion
+ uint32_t rsv17_30 : 14; // 17..30 Reserved
+ uint32_t split_en : 1; // 31 Split enable
+ };
} dwc2_channel_split_t;
TU_VERIFY_STATIC(sizeof(dwc2_channel_split_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t xfer_size : 19; // 0..18 Transfer size in bytes
- uint32_t packet_count : 10; // 19..28 Number of packets
- uint32_t pid : 2; // 29..30 Packet ID
- uint32_t do_ping : 1; // 31 Do PING
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t xfer_size : 19; // 0..18 Transfer size in bytes
+ uint32_t packet_count : 10; // 19..28 Number of packets
+ uint32_t pid : 2; // 29..30 Packet ID
+ uint32_t do_ping : 1; // 31 Do PING
+ };
} dwc2_channel_tsize_t;
TU_VERIFY_STATIC(sizeof(dwc2_channel_tsize_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t num : 16; // 0..15 Frame number
- uint32_t remainning : 16; // 16..31 Frame remaining
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t num : 16; // 0..15 Frame number
+ uint32_t remainning : 16; // 16..31 Frame remaining
+ };
} dwc2_hfnum_t;
TU_VERIFY_STATIC(sizeof(dwc2_hfnum_t) == 4, "incorrect size");
// Host Channel
typedef struct {
- union {
- volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics
- volatile dwc2_channel_char_t hcchar_bm;
- };
- union {
- volatile uint32_t hcsplt; // 504 + 20*ch Host Channel Split Control
- volatile dwc2_channel_split_t hcsplt_bm;
- };
- volatile uint32_t hcint; // 508 + 20*ch Host Channel Interrupt
- volatile uint32_t hcintmsk; // 50C + 20*ch Host Channel Interrupt Mask
- union {
- volatile uint32_t hctsiz; // 510 + 20*ch Host Channel Transfer Size
- volatile dwc2_channel_tsize_t hctsiz_bm;
- };
- volatile uint32_t hcdma; // 514 + 20*ch Host Channel DMA Address
- uint32_t reserved518; // 518 + 20*ch
- volatile uint32_t hcdmab; // 51C + 20*ch Host Channel DMA Address
+ volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics
+ volatile uint32_t hcsplt; // 504 + 20*ch Host Channel Split Control
+ volatile uint32_t hcint; // 508 + 20*ch Host Channel Interrupt
+ volatile uint32_t hcintmsk; // 50C + 20*ch Host Channel Interrupt Mask
+ volatile uint32_t hctsiz; // 510 + 20*ch Host Channel Transfer Size
+ volatile uint32_t hcdma; // 514 + 20*ch Host Channel DMA Address
+ uint32_t reserved518; // 518 + 20*ch
+ volatile uint32_t hcdmab; // 51C + 20*ch Host Channel DMA Address
} dwc2_channel_t;
//--------------------------------------------------------------------
// Device Register Bitfield
//--------------------------------------------------------------------
-typedef struct TU_ATTR_PACKED {
- uint32_t speed : 2; // 0..1 Speed
- uint32_t nzsts_out_handshake : 1; // 2 Non-zero-length status OUT handshake
- uint32_t en_32khz_suspsend : 1; // 3 Enable 32-kHz SUSPEND mode
- uint32_t address : 7; // 4..10 Device address
- uint32_t period_frame_interval : 2; // 11..12 Periodic frame interval
- uint32_t en_out_nak : 1; // 13 Enable Device OUT NAK
- uint32_t xcvr_delay : 1; // 14 Transceiver delay
- uint32_t erratic_int_mask : 1; // 15 Erratic interrupt mask
- uint32_t rsv16 : 1; // 16 Reserved
- uint32_t ipg_iso_support : 1; // 17 Interpacket gap ISO support
- uint32_t epin_mismatch_count : 5; // 18..22 EP IN mismatch count
- uint32_t dma_desc : 1; // 23 Enable scatter/gatter DMA descriptor
- uint32_t period_schedule_interval : 2; // 24..25 Periodic schedule interval for scatter/gatter DMA
- uint32_t resume_valid : 6; // 26..31 Resume valid period
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t speed : 2; // 0..1 Speed
+ uint32_t nzsts_out_handshake : 1; // 2 Non-zero-length status OUT handshake
+ uint32_t en_32khz_suspsend : 1; // 3 Enable 32-kHz SUSPEND mode
+ uint32_t address : 7; // 4..10 Device address
+ uint32_t period_frame_interval : 2; // 11..12 Periodic frame interval
+ uint32_t en_out_nak : 1; // 13 Enable Device OUT NAK
+ uint32_t xcvr_delay : 1; // 14 Transceiver delay
+ uint32_t erratic_int_mask : 1; // 15 Erratic interrupt mask
+ uint32_t rsv16 : 1; // 16 Reserved
+ uint32_t ipg_iso_support : 1; // 17 Interpacket gap ISO support
+ uint32_t epin_mismatch_count : 5; // 18..22 EP IN mismatch count
+ uint32_t dma_desc : 1; // 23 Enable scatter/gather DMA descriptor
+ uint32_t period_schedule_interval : 2; // 24..25 Periodic schedule interval for scatter/gather DMA
+ uint32_t resume_valid : 6; // 26..31 Resume valid period
+ };
} dwc2_dcfg_t;
TU_VERIFY_STATIC(sizeof(dwc2_dcfg_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t remote_wakeup_signal : 1; // 0 Remote wakeup signal
- uint32_t soft_disconnet : 1; // 1 Soft disconnect
- uint32_t gnp_in_nak_status : 1; // 2 Global non-periodic NAK IN status
- uint32_t gout_nak_status : 1; // 3 Global OUT NAK status
- uint32_t test_control : 3; // 4..6 Test control
- uint32_t set_gnp_in_nak : 1; // 7 Set global non-periodic IN NAK
- uint32_t clear_gnp_in_nak : 1; // 8 Clear global non-periodic IN NAK
- uint32_t set_gout_nak : 1; // 9 Set global OUT NAK
- uint32_t clear_gout_nak : 1; // 10 Clear global OUT NAK
- uint32_t poweron_prog_done : 1; // 11 Power-on programming done
- uint32_t rsv12 : 1; // 12 Reserved
- uint32_t global_multi_count : 2; // 13..14 Global multi-count
- uint32_t ignore_frame_number : 1; // 15 Ignore frame number
- uint32_t nak_on_babble : 1; // 16 NAK on babble
- uint32_t en_cont_on_bna : 1; // 17 Enable continue on BNA
- uint32_t deep_sleep_besl_reject : 1; // 18 Deep sleep BESL reject
- uint32_t service_interval : 1; // 19 Service interval for ISO IN endpoint
- uint32_t rsv20_31 :12; // 20..31 Reserved
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t remote_wakeup_signal : 1; // 0 Remote wakeup signal
+ uint32_t soft_disconnet : 1; // 1 Soft disconnect
+ uint32_t gnp_in_nak_status : 1; // 2 Global non-periodic NAK IN status
+ uint32_t gout_nak_status : 1; // 3 Global OUT NAK status
+ uint32_t test_control : 3; // 4..6 Test control
+ uint32_t set_gnp_in_nak : 1; // 7 Set global non-periodic IN NAK
+ uint32_t clear_gnp_in_nak : 1; // 8 Clear global non-periodic IN NAK
+ uint32_t set_gout_nak : 1; // 9 Set global OUT NAK
+ uint32_t clear_gout_nak : 1; // 10 Clear global OUT NAK
+ uint32_t poweron_prog_done : 1; // 11 Power-on programming done
+ uint32_t rsv12 : 1; // 12 Reserved
+ uint32_t global_multi_count : 2; // 13..14 Global multi-count
+ uint32_t ignore_frame_number : 1; // 15 Ignore frame number
+ uint32_t nak_on_babble : 1; // 16 NAK on babble
+ uint32_t en_cont_on_bna : 1; // 17 Enable continue on BNA
+ uint32_t deep_sleep_besl_reject : 1; // 18 Deep sleep BESL reject
+ uint32_t service_interval : 1; // 19 Service interval for ISO IN endpoint
+ uint32_t rsv20_31 :12; // 20..31 Reserved
+ };
} dwc2_dctl_t;
TU_VERIFY_STATIC(sizeof(dwc2_dctl_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t suspend_status : 1; // 0 Suspend status
- uint32_t enum_speed : 2; // 1..2 Enumerated speed
- uint32_t erratic_err : 1; // 3 Erratic error
- uint32_t rsv4_7 : 4; // 4..7 Reserved
- uint32_t frame_number : 14; // 8..21 Frame/MicroFrame number
- uint32_t line_status : 2; // 22..23 Line status
- uint32_t rsv24_31 : 8; // 24..31 Reserved
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t suspend_status : 1; // 0 Suspend status
+ uint32_t enum_speed : 2; // 1..2 Enumerated speed
+ uint32_t erratic_err : 1; // 3 Erratic error
+ uint32_t rsv4_7 : 4; // 4..7 Reserved
+ uint32_t frame_number :14; // 8..21 Frame/MicroFrame number
+ uint32_t line_status : 2; // 22..23 Line status
+ uint32_t rsv24_31 : 8; // 24..31 Reserved
+ };
} dwc2_dsts_t;
TU_VERIFY_STATIC(sizeof(dwc2_dsts_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t xfer_complete : 1; // 0 Transfer complete
- uint32_t disabled : 1; // 1 Endpoint disabled
- uint32_t ahb_err : 1; // 2 AHB error
- uint32_t timeout : 1; // 3 Timeout
- uint32_t in_rx_txfe : 1; // 4 IN token received when TxFIFO is empty
- uint32_t in_rx_ep_mismatch : 1; // 5 IN token received with EP mismatch
- uint32_t in_ep_nak_effective : 1; // 6 IN endpoint NAK effective
- uint32_t txfifo_empty : 1; // 7 TX FIFO empty
- uint32_t txfifo_underrun : 1; // 8 Tx FIFO under run
- uint32_t bna : 1; // 9 Buffer not available
- uint32_t rsv10 : 1; // 10 Reserved
- uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status
- uint32_t babble_err : 1; // 12 Babble error
- uint32_t nak : 1; // 13 NAK
- uint32_t nyet : 1; // 14 NYET
- uint32_t rsv14_31 :17; // 15..31 Reserved
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t xfer_complete : 1; // 0 Transfer complete
+ uint32_t disabled : 1; // 1 Endpoint disabled
+ uint32_t ahb_err : 1; // 2 AHB error
+ uint32_t timeout : 1; // 3 Timeout
+ uint32_t in_rx_txfe : 1; // 4 IN token received when TxFIFO is empty
+ uint32_t in_rx_ep_mismatch : 1; // 5 IN token received with EP mismatch
+ uint32_t in_ep_nak_effective : 1; // 6 IN endpoint NAK effective
+ uint32_t txfifo_empty : 1; // 7 TX FIFO empty
+ uint32_t txfifo_underrun : 1; // 8 Tx FIFO under run
+ uint32_t bna : 1; // 9 Buffer not available
+ uint32_t rsv10 : 1; // 10 Reserved
+ uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status
+ uint32_t babble_err : 1; // 12 Babble error
+ uint32_t nak : 1; // 13 NAK
+ uint32_t nyet : 1; // 14 NYET
+ uint32_t rsv14_31 :17; // 15..31 Reserved
+ };
} dwc2_diepint_t;
TU_VERIFY_STATIC(sizeof(dwc2_diepint_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t mps : 11; // 0..10 Maximum packet size, EP0 only use 2 bit
- uint32_t next_ep : 4; // 11..14 Next endpoint number
- uint32_t active : 1; // 15 Active
- const uint32_t dpid_iso_odd : 1; // 16 DATA0/DATA1 for bulk/interrupt, odd frame for isochronous
- const uint32_t nak_status : 1; // 17 NAK status
- uint32_t type : 2; // 18..19 Endpoint type
- uint32_t rsv20 : 1; // 20 Reserved
- uint32_t stall : 1; // 21 Stall
- uint32_t tx_fifo_num : 4; // 22..25 Tx FIFO number (IN)
- uint32_t clear_nak : 1; // 26 Clear NAK
- uint32_t set_nak : 1; // 27 Set NAK
- uint32_t set_data0_iso_even : 1; // 28 Set DATA0 if bulk/interrupt, even frame for isochronous
- uint32_t set_data1_iso_odd : 1; // 29 Set DATA1 if bulk/interrupt, odd frame for isochronous
- uint32_t disable : 1; // 30 Disable
- uint32_t enable : 1; // 31 Enable
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t mps : 11; // 0..10 Maximum packet size, EP0 only use 2 bits
+ uint32_t next_ep : 4; // 11..14 Next endpoint number
+ uint32_t active : 1; // 15 Active
+ uint32_t dpid_iso_odd : 1; // 16 DATA0/DATA1 for bulk/interrupt, odd frame for isochronous
+ uint32_t nak_status : 1; // 17 NAK status
+ uint32_t type : 2; // 18..19 Endpoint type
+ uint32_t rsv20 : 1; // 20 Reserved
+ uint32_t stall : 1; // 21 Stall
+ uint32_t tx_fifo_num : 4; // 22..25 Tx FIFO number (IN)
+ uint32_t clear_nak : 1; // 26 Clear NAK
+ uint32_t set_nak : 1; // 27 Set NAK
+ uint32_t set_data0_iso_even : 1; // 28 Set DATA0 if bulk/interrupt, even frame for isochronous
+ uint32_t set_data1_iso_odd : 1; // 29 Set DATA1 if bulk/interrupt, odd frame for isochronous
+ uint32_t disable : 1; // 30 Disable
+ uint32_t enable : 1; // 31 Enable
+ };
} dwc2_depctl_t;
TU_VERIFY_STATIC(sizeof(dwc2_depctl_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t xfer_complete : 1; // 0 Transfer complete
- uint32_t disabled : 1; // 1 Endpoint disabled
- uint32_t ahb_err : 1; // 2 AHB error
- uint32_t setup_phase_done : 1; // 3 Setup phase done
- uint32_t out_rx_ep_disabled : 1; // 4 OUT token received when endpoint disabled
- uint32_t status_phase_rx : 1; // 5 Status phase received
- uint32_t setup_b2b : 1; // 6 Setup packet back-to-back
- uint32_t rsv7 : 1; // 7 Reserved
- uint32_t out_packet_err : 1; // 8 OUT packet error
- uint32_t bna : 1; // 9 Buffer not available
- uint32_t rsv10 : 1; // 10 Reserved
- uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status
- uint32_t babble_err : 1; // 12 Babble error
- uint32_t nak : 1; // 13 NAK
- uint32_t nyet : 1; // 14 NYET
- uint32_t setup_packet_rx : 1; // 15 Setup packet received (Buffer DMA Mode only)
- uint32_t rsv16_31 :16; // 16..31 Reserved
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t xfer_complete : 1; // 0 Transfer complete
+ uint32_t disabled : 1; // 1 Endpoint disabled
+ uint32_t ahb_err : 1; // 2 AHB error
+ uint32_t setup_phase_done : 1; // 3 Setup phase done
+ uint32_t out_rx_ep_disabled : 1; // 4 OUT token received when endpoint disabled
+ uint32_t status_phase_rx : 1; // 5 Status phase received
+ uint32_t setup_b2b : 1; // 6 Setup packet back-to-back
+ uint32_t rsv7 : 1; // 7 Reserved
+ uint32_t out_packet_err : 1; // 8 OUT packet error
+ uint32_t bna : 1; // 9 Buffer not available
+ uint32_t rsv10 : 1; // 10 Reserved
+ uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status
+ uint32_t babble_err : 1; // 12 Babble error
+ uint32_t nak : 1; // 13 NAK
+ uint32_t nyet : 1; // 14 NYET
+ uint32_t setup_packet_rx : 1; // 15 Setup packet received (Buffer DMA Mode only)
+ uint32_t rsv16_31 :16; // 16..31 Reserved
+ };
} dwc2_doepint_t;
TU_VERIFY_STATIC(sizeof(dwc2_doepint_t) == 4, "incorrect size");
-typedef struct TU_ATTR_PACKED {
- uint32_t xfer_size : 19; // 0..18 Transfer size in bytes
- uint32_t packet_count : 10; // 19..28 Number of packets
- uint32_t mc_pid : 2; // 29..30 IN: Multi Count, OUT: PID
+typedef union {
+ uint32_t value;
+ struct TU_ATTR_PACKED {
+ uint32_t xfer_size : 19; // 0..18 Transfer size in bytes
+ uint32_t packet_count : 10; // 19..28 Number of packets
+ uint32_t mc_pid : 2; // 29..30 IN: Multi Count, OUT: PID
+ };
} dwc2_ep_tsize_t;
TU_VERIFY_STATIC(sizeof(dwc2_ep_tsize_t) == 4, "incorrect size");
@@ -601,26 +656,19 @@ typedef struct {
union {
volatile uint32_t diepctl;
volatile uint32_t doepctl;
-
volatile uint32_t ctl;
- volatile dwc2_depctl_t ctl_bm;
};
uint32_t rsv04;
union {
volatile uint32_t intr;
-
volatile uint32_t diepint;
- volatile dwc2_diepint_t diepint_bm;
-
volatile uint32_t doepint;
- volatile dwc2_doepint_t doepint_bm;
};
uint32_t rsv0c;
union {
volatile uint32_t dieptsiz;
volatile uint32_t doeptsiz;
volatile uint32_t tsiz;
- volatile dwc2_ep_tsize_t tsiz_bm;
};
union {
volatile uint32_t diepdma;
@@ -628,7 +676,7 @@ typedef struct {
};
volatile uint32_t dtxfsts;
uint32_t rsv1c;
-}dwc2_dep_t;
+} dwc2_dep_t;
TU_VERIFY_STATIC(sizeof(dwc2_dep_t) == 0x20, "incorrect size");
@@ -636,157 +684,108 @@ TU_VERIFY_STATIC(sizeof(dwc2_dep_t) == 0x20, "incorrect size");
// CSR Register Map
//--------------------------------------------------------------------
typedef struct {
- //------------- Core Global -------------//
- union {
- volatile uint32_t gotgctl; // 000 OTG Control and Status
- volatile dwc2_gotgctl_t gotgctl_bm;
- };
- union {
- volatile uint32_t gotgint; // 004 OTG Interrupt
- volatile dwc2_gotgint_t gotgint_bm;
- };
- union {
- volatile uint32_t gahbcfg; // 008 AHB Configuration
- volatile dwc2_gahbcfg_t gahbcfg_bm;
- };
- union {
- volatile uint32_t gusbcfg; // 00c USB Configuration
- volatile dwc2_gusbcfg_t gusbcfg_bm;
- };
- union {
- volatile uint32_t grstctl; // 010 Reset
- volatile dwc2_grstctl_t grstctl_bm;
- };
- volatile uint32_t gintsts; // 014 Interrupt
- volatile uint32_t gintmsk; // 018 Interrupt Mask
- volatile uint32_t grxstsr; // 01c Receive Status Debug Read
- union {
- volatile uint32_t grxstsp; // 020 Receive Status Read/Pop
- volatile dwc2_grxstsp_t grxstsp_bm;
- };
- volatile uint32_t grxfsiz; // 024 Receive FIFO Size
+ //------------- Core Global -------------
+ volatile uint32_t gotgctl; // 000 OTG Control and Status
+ volatile uint32_t gotgint; // 004 OTG Interrupt
+ volatile uint32_t gahbcfg; // 008 AHB Configuration
+ volatile uint32_t gusbcfg; // 00c USB Configuration
+ volatile uint32_t grstctl; // 010 Reset
+ volatile uint32_t gintsts; // 014 Interrupt
+ volatile uint32_t gintmsk; // 018 Interrupt Mask
+ volatile uint32_t grxstsr; // 01c Receive Status Debug Read
+ volatile uint32_t grxstsp; // 020 Receive Status Read/Pop
+ volatile uint32_t grxfsiz; // 024 Receive FIFO Size
union {
volatile uint32_t dieptxf0; // 028 EP0 Tx FIFO Size
volatile uint32_t gnptxfsiz; // 028 Non-periodic Transmit FIFO Size
};
union {
volatile uint32_t hnptxsts; // 02c Non-periodic Transmit FIFO/Queue Status
- volatile dwc2_hnptxsts_t hnptxsts_bm;
volatile uint32_t gnptxsts;
};
- volatile uint32_t gi2cctl; // 030 I2C Address
- volatile uint32_t gpvndctl; // 034 PHY Vendor Control
+ volatile uint32_t gi2cctl; // 030 I2C Address
+ volatile uint32_t gpvndctl; // 034 PHY Vendor Control
union {
volatile uint32_t ggpio; // 038 General Purpose IO
volatile uint32_t stm32_gccfg; // 038 STM32 General Core Configuration
};
- volatile uint32_t guid; // 03C User (Application programmable) ID
- volatile uint32_t gsnpsid; // 040 Synopsys ID + Release version
- volatile uint32_t ghwcfg1; // 044 User Hardware Configuration1: endpoint dir (2 bit per ep)
- union {
- volatile uint32_t ghwcfg2; // 048 User Hardware Configuration2
- volatile dwc2_ghwcfg2_t ghwcfg2_bm;
- };
- union {
- volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3
- volatile dwc2_ghwcfg3_t ghwcfg3_bm;
- };
+ volatile uint32_t guid; // 03C User (Application programmable) ID
+ volatile uint32_t gsnpsid; // 040 Synopsys ID + Release version
+ volatile uint32_t ghwcfg1; // 044 User Hardware Configuration1: endpoint dir (2 bit per ep)
+ volatile uint32_t ghwcfg2; // 048 User Hardware Configuration2
+ volatile uint32_t ghwcfg3; // 04C User Hardware Configuration3
union {
volatile uint32_t ghwcfg4; // 050 User Hardware Configuration4
volatile dwc2_ghwcfg4_t ghwcfg4_bm;
};
- volatile uint32_t glpmcfg; // 054 Core LPM Configuration
- volatile uint32_t gpwrdn; // 058 Power Down
- volatile uint32_t gdfifocfg; // 05C DFIFO Software Configuration
- volatile uint32_t gadpctl; // 060 ADP Timer, Control and Status
- uint32_t reserved64[39]; // 064..0FF
- volatile uint32_t hptxfsiz; // 100 Host Periodic Tx FIFO Size
- volatile uint32_t dieptxf[15]; // 104..13C Device Periodic Transmit FIFO Size
- uint32_t reserved140[176]; // 140..3FF
+ volatile uint32_t glpmcfg; // 054 Core LPM Configuration
+ volatile uint32_t gpwrdn; // 058 Power Down
+ volatile uint32_t gdfifocfg; // 05C DFIFO Software Configuration
+ volatile uint32_t gadpctl; // 060 ADP Timer, Control and Status
+ uint32_t reserved64[39]; // 064..0FF
+ volatile uint32_t hptxfsiz; // 100 Host Periodic Tx FIFO Size
+ volatile uint32_t dieptxf[15]; // 104..13C Device Periodic Transmit FIFO Size
+ uint32_t reserved140[176]; // 140..3FF
- //------------ Host -------------//
- volatile uint32_t hcfg; // 400 Host Configuration
- volatile uint32_t hfir; // 404 Host Frame Interval
- union {
- volatile uint32_t hfnum; // 408 Host Frame Number / Frame Remaining
- volatile dwc2_hfnum_t hfnum_bm;
- };
- uint32_t reserved40c; // 40C
- union {
- volatile uint32_t hptxsts; // 410 Host Periodic TX FIFO / Queue Status
- volatile dwc2_hptxsts_t hptxsts_bm;
- };
- volatile uint32_t haint; // 414 Host All Channels Interrupt
- volatile uint32_t haintmsk; // 418 Host All Channels Interrupt Mask
- volatile uint32_t hflbaddr; // 41C Host Frame List Base Address
- uint32_t reserved420[8]; // 420..43F
- union {
- volatile uint32_t hprt; // 440 Host Port Control and Status
- volatile dwc2_hprt_t hprt_bm;
- };
- uint32_t reserved444[47]; // 444..4FF
+ //------------ Host -------------
+ volatile uint32_t hcfg; // 400 Host Configuration
+ volatile uint32_t hfir; // 404 Host Frame Interval
+ volatile uint32_t hfnum; // 408 Host Frame Number / Frame Remaining
+ uint32_t reserved40c; // 40C
+ volatile uint32_t hptxsts; // 410 Host Periodic TX FIFO / Queue Status
+ volatile uint32_t haint; // 414 Host All Channels Interrupt
+ volatile uint32_t haintmsk; // 418 Host All Channels Interrupt Mask
+ volatile uint32_t hflbaddr; // 41C Host Frame List Base Address
+ uint32_t reserved420[8]; // 420..43F
+ volatile uint32_t hprt; // 440 Host Port Control and Status
+ uint32_t reserved444[47]; // 444..4FF
- //------------- Host Channel -------------//
- dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15
- uint32_t reserved700[64]; // 700..7FF
+ //------------- Host Channel --------
+ dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15
+ uint32_t reserved700[64]; // 700..7FF
- //------------- Device -----------//
- union {
- volatile uint32_t dcfg; // 800 Device Configuration
- volatile dwc2_dcfg_t dcfg_bm;
- };
- union {
- volatile uint32_t dctl; // 804 Device Control
- volatile dwc2_dctl_t dctl_bm;
- };
- union {
- volatile uint32_t dsts; // 808 Device Status (RO)
- volatile dwc2_dsts_t dsts_bm;
- };
- uint32_t reserved80c; // 80C
- union {
- volatile uint32_t diepmsk; // 810 Device IN Endpoint Interrupt Mask
- volatile dwc2_diepint_t diepmsk_bm;
- };
- union {
- volatile uint32_t doepmsk; // 814 Device OUT Endpoint Interrupt Mask
- volatile dwc2_doepint_t doepmsk_bm;
- };
- volatile uint32_t daint; // 818 Device All Endpoints Interrupt
- volatile uint32_t daintmsk; // 81C Device All Endpoints Interrupt Mask
- volatile uint32_t dtknqr1; // 820 Device IN token sequence learning queue read1
- volatile uint32_t dtknqr2; // 824 Device IN token sequence learning queue read2
- volatile uint32_t dvbusdis; // 828 Device VBUS Discharge Time
- volatile uint32_t dvbuspulse; // 82C Device VBUS Pulsing Time
- volatile uint32_t dthrctl; // 830 Device threshold Control
- volatile uint32_t diepempmsk; // 834 Device IN Endpoint FIFO Empty Interrupt Mask
+ //------------- Device -----------
+ volatile uint32_t dcfg; // 800 Device Configuration
+ volatile uint32_t dctl; // 804 Device Control
+ volatile uint32_t dsts; // 808 Device Status (RO)
+ uint32_t reserved80c; // 80C
+ volatile uint32_t diepmsk; // 810 Device IN Endpoint Interrupt Mask
+ volatile uint32_t doepmsk; // 814 Device OUT Endpoint Interrupt Mask
+ volatile uint32_t daint; // 818 Device All Endpoints Interrupt
+ volatile uint32_t daintmsk; // 81C Device All Endpoints Interrupt Mask
+ volatile uint32_t dtknqr1; // 820 Device IN token sequence learning queue read1
+ volatile uint32_t dtknqr2; // 824 Device IN token sequence learning queue read2
+ volatile uint32_t dvbusdis; // 828 Device VBUS Discharge Time
+ volatile uint32_t dvbuspulse; // 82C Device VBUS Pulsing Time
+ volatile uint32_t dthrctl; // 830 Device threshold Control
+ volatile uint32_t diepempmsk; // 834 Device IN Endpoint FIFO Empty Interrupt Mask
- // Device Each Endpoint (IN/OUT) Interrupt/Mask for generating dedicated EP interrupt line
- // require OTG_MULTI_PROC_INTRPT=1
- volatile uint32_t deachint; // 838 Device Each Endpoint Interrupt
- volatile uint32_t deachmsk; // 83C Device Each Endpoint Interrupt mask
- volatile uint32_t diepeachmsk[16]; // 840..87C Device Each IN Endpoint mask
- volatile uint32_t doepeachmsk[16]; // 880..8BF Device Each OUT Endpoint mask
- uint32_t reserved8c0[16]; // 8C0..8FF
+ // Device Each Endpoint (IN/OUT) Interrupt/Mask for generating dedicated EP interrupt line require
+ // OTG_MULTI_PROC_INTRPT=1
+ volatile uint32_t deachint; // 838 Device Each Endpoint Interrupt
+ volatile uint32_t deachmsk; // 83C Device Each Endpoint Interrupt mask
+ volatile uint32_t diepeachmsk[16]; // 840..87C Device Each IN Endpoint mask
+ volatile uint32_t doepeachmsk[16]; // 880..8BF Device Each OUT Endpoint mask
+ uint32_t reserved8c0[16]; // 8C0..8FF
- //------------- Device Endpoint -------------//
- union {
- dwc2_dep_t ep[2][16]; // 0: IN, 1 OUT
- struct {
- dwc2_dep_t epin[16]; // 900..AFF IN Endpoints
- dwc2_dep_t epout[16]; // B00..CFF OUT Endpoints
- };
+ //------------- Device Endpoint -----
+ union {
+ dwc2_dep_t ep[2][16]; // 0: IN, 1 OUT
+ struct {
+ dwc2_dep_t epin[16]; // 900..AFF IN Endpoints
+ dwc2_dep_t epout[16]; // B00..CFF OUT Endpoints
};
- uint32_t reservedd00[64]; // D00..DFF
+ };
+ uint32_t reservedd00[64]; // D00..DFF
- //------------- Power Clock -------------//
- volatile uint32_t pcgcctl; // E00 Power and Clock Gating Characteristic Control
- volatile uint32_t pcgcctl1; // E04 Power and Clock Gating Characteristic Control 1
- uint32_t reservede08[126]; // E08..FFF
+ //------------- Power Clock ---------
+ volatile uint32_t pcgcctl; // E00 Power and Clock Gating Characteristic Control
+ volatile uint32_t pcgcctl1; // E04 Power and Clock Gating Characteristic Control 1
+ uint32_t reservede08[126]; // E08..FFF
- //------------- FIFOs -------------//
- // Word-accessed only using first pointer since it auto shift
- volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO
+ //------------- FIFOs -------------
+ // Word-accessed only using first pointer since it auto shift
+ volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO
} dwc2_regs_t;
TU_VERIFY_STATIC(offsetof(dwc2_regs_t, hcfg ) == 0x0400, "incorrect size");
@@ -2089,9 +2088,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
#define HCTSIZ_DOPING_Pos (31U)
#define HCTSIZ_DOPING_Msk (0x1UL << HCTSIZ_DOPING_Pos) // 0x80000000
#define HCTSIZ_DOPING HCTSIZ_DOPING_Msk // Do PING
-#define HCTSIZ_PID_Pos (29U)
-#define HCTSIZ_PID_Msk (0x3UL << HCTSIZ_PID_Pos) // 0x60000000
-#define HCTSIZ_PID HCTSIZ_PID_Msk // Data PID
+#define HCTSIZ_PID_Pos (29U)
+#define HCTSIZ_PID_Msk (0x3UL << HCTSIZ_PID_Pos) // 0x60000000
+#define HCTSIZ_PID HCTSIZ_PID_Msk // Data PID
/******************** Bit definition for DIEPDMA register ********************/
#define DIEPDMA_DMAADDR_Pos (0U)
diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c
index 7cbef05b7..2de15068a 100644
--- a/src/portable/synopsys/dwc2/hcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/hcd_dwc2.c
@@ -36,6 +36,7 @@
#define DWC2_DEBUG 2
#include "host/hcd.h"
+#include "host/usbh.h"
#include "dwc2_common.h"
// Max number of endpoints application can open, can be larger than DWC2_CHANNEL_COUNT_MAX
@@ -44,8 +45,6 @@
#endif
#define DWC2_CHANNEL_COUNT_MAX 16 // absolute max channel count
-#define DWC2_CHANNEL_COUNT(_dwc2) tu_min8((_dwc2)->ghwcfg2_bm.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX)
-
TU_VERIFY_STATIC(CFG_TUH_DWC2_ENDPOINT_MAX <= 255, "currently only use 8-bit for index");
enum {
@@ -77,9 +76,9 @@ typedef struct {
struct TU_ATTR_PACKED {
uint32_t uframe_interval : 18; // micro-frame interval
- uint32_t speed : 2;
- uint32_t next_pid : 2;
- uint32_t do_ping : 1;
+ uint32_t speed : 2;
+ uint32_t next_pid : 2; // PID for next transfer
+ uint32_t next_do_ping : 1; // Do PING for next transfer if possible (highspeed OUT)
// uint32_t : 9;
};
@@ -97,7 +96,6 @@ typedef struct {
uint8_t err_count : 3;
uint8_t period_split_nyet_count : 3;
uint8_t halted_nyet : 1;
- uint8_t halted_sof_schedule : 1;
};
uint8_t result;
@@ -116,9 +114,15 @@ hcd_data_t _hcd_data;
//--------------------------------------------------------------------
//
//--------------------------------------------------------------------
+TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_channel_count(const dwc2_regs_t* dwc2) {
+ const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
+ return tu_min8(ghwcfg2.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX);
+}
+
TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc2) {
tusb_speed_t speed;
- switch(dwc2->hprt_bm.speed) {
+ const dwc2_hprt_t hprt = {.value = dwc2->hprt};
+ switch(hprt.speed) {
case HPRT_SPEED_HIGH: speed = TUSB_SPEED_HIGH; break;
case HPRT_SPEED_FULL: speed = TUSB_SPEED_FULL; break;
case HPRT_SPEED_LOW : speed = TUSB_SPEED_LOW ; break;
@@ -133,7 +137,8 @@ TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc
TU_ATTR_ALWAYS_INLINE static inline bool dma_host_enabled(const dwc2_regs_t* dwc2) {
(void) dwc2;
// Internal DMA only
- return CFG_TUH_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA;
+ const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
+ return CFG_TUH_DWC2_DMA_ENABLE && ghwcfg2.arch == GHWCFG2_ARCH_INTERNAL_DMA;
}
#if CFG_TUH_MEM_DCACHE_ENABLE
@@ -155,7 +160,7 @@ bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
// Allocate a channel for new transfer
TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) {
- const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
+ const uint8_t max_channel = dwc2_channel_count(dwc2);
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
if (!xfer->allocated) {
@@ -168,15 +173,18 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) {
}
// Check if is periodic (interrupt/isochronous)
-TU_ATTR_ALWAYS_INLINE static inline bool edpt_is_periodic(uint8_t ep_type) {
- return ep_type == HCCHAR_EPTYPE_INTERRUPT || ep_type == HCCHAR_EPTYPE_ISOCHRONOUS;
+TU_ATTR_ALWAYS_INLINE static inline bool channel_is_periodic(uint32_t hcchar) {
+ const dwc2_channel_char_t hcchar_bm = {.value = hcchar};
+ return hcchar_bm.ep_type == HCCHAR_EPTYPE_INTERRUPT || hcchar_bm.ep_type == HCCHAR_EPTYPE_ISOCHRONOUS;
}
TU_ATTR_ALWAYS_INLINE static inline uint8_t req_queue_avail(const dwc2_regs_t* dwc2, bool is_period) {
if (is_period) {
- return dwc2->hptxsts_bm.req_queue_available;
+ const dwc2_hptxsts_t hptxsts = {.value = dwc2->hptxsts};
+ return hptxsts.req_queue_available;
} else {
- return dwc2->hnptxsts_bm.req_queue_available;
+ const dwc2_hnptxsts_t hnptxsts = {.value = dwc2->hnptxsts};
+ return hnptxsts.req_queue_available;
}
}
@@ -188,7 +196,7 @@ TU_ATTR_ALWAYS_INLINE static inline void channel_dealloc(dwc2_regs_t* dwc2, uint
TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) {
// disable also require request queue
- TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type)));
+ TU_ASSERT(req_queue_avail(dwc2, channel_is_periodic(channel->hcchar)));
channel->hcintmsk |= HCINT_HALTED;
channel->hcchar |= HCCHAR_CHDIS | HCCHAR_CHENA; // must set both CHDIS and CHENA
return true;
@@ -196,18 +204,18 @@ TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2
// attempt to send IN token to receive data
TU_ATTR_ALWAYS_INLINE static inline bool channel_send_in_token(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) {
- TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type)));
+ TU_ASSERT(req_queue_avail(dwc2, channel_is_periodic(channel->hcchar)));
channel->hcchar |= HCCHAR_CHENA;
return true;
}
// Find currently enabled channel. Note: EP0 is bidirectional
TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_find_enabled(dwc2_regs_t* dwc2, uint8_t dev_addr, uint8_t ep_num, uint8_t ep_dir) {
- const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
+ const uint8_t max_channel = dwc2_channel_count(dwc2);
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
if (_hcd_data.xfer[ch_id].allocated) {
- const dwc2_channel_char_t hcchar_bm = dwc2->channel[ch_id].hcchar_bm;
- if (hcchar_bm.dev_addr == dev_addr && hcchar_bm.ep_num == ep_num && (ep_num == 0 || hcchar_bm.ep_dir == ep_dir)) {
+ const dwc2_channel_char_t hcchar = {.value = dwc2->channel[ch_id].hcchar};
+ if (hcchar.dev_addr == dev_addr && hcchar.ep_num == ep_num && (ep_num == 0 || hcchar.ep_dir == ep_dir)) {
return ch_id;
}
}
@@ -304,12 +312,13 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t cal_next_pid(uint8_t pid, uint8_t pa
static void dfifo_host_init(uint8_t rhport) {
const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
// Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per channel
const bool is_dma = dma_host_enabled(dwc2);
uint16_t dfifo_top = dwc2_controller->ep_fifo_size/4;
if (is_dma) {
- dfifo_top -= dwc2->ghwcfg2_bm.num_host_ch;
+ dfifo_top -= ghwcfg2.num_host_ch;
}
// fixed allocation for now, improve later:
@@ -319,7 +328,7 @@ static void dfifo_host_init(uint8_t rhport) {
uint32_t ptx_largest = is_highspeed ? TUSB_EPSIZE_ISO_HS_MAX/4 : 256/4;
uint16_t nptxfsiz = 2 * nptx_largest;
- uint16_t rxfsiz = 2 * (ptx_largest + 2) + dwc2->ghwcfg2_bm.num_host_ch;
+ uint16_t rxfsiz = 2 * (ptx_largest + 2) + ghwcfg2.num_host_ch;
TU_ASSERT(dfifo_top >= (nptxfsiz + rxfsiz),);
uint16_t ptxfsiz = dfifo_top - (nptxfsiz + rxfsiz);
@@ -381,7 +390,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
dwc2->hprt = HPRT_POWER; // turn on VBUS
// Enable required interrupts
- dwc2->gintmsk |= GINTSTS_OTGINT | GINTSTS_CONIDSTSCHNG | GINTSTS_HPRTINT | GINTSTS_HCINT;
+ dwc2->gintmsk |= GINTSTS_OTGINT | GINTSTS_CONIDSTSCHNG | GINTSTS_HPRTINT | GINTSTS_HCINT | GINTSTS_DISCINT;
// NPTX can hold at least 2 packet, change interrupt level to half-empty
uint32_t gahbcfg = dwc2->gahbcfg & ~GAHBCFG_TX_FIFO_EPMTY_LVL;
@@ -461,8 +470,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t*
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const tusb_speed_t rh_speed = hprt_speed_get(dwc2);
- hcd_devtree_info_t devtree_info;
- hcd_devtree_get_info(dev_addr, &devtree_info);
+ tuh_bus_info_t bus_info;
+ tuh_bus_info_get(dev_addr, &bus_info);
// find a free endpoint
const uint8_t ep_id = edpt_alloc();
@@ -473,7 +482,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t*
hcchar_bm->ep_size = tu_edpt_packet_size(desc_ep);
hcchar_bm->ep_num = tu_edpt_number(desc_ep->bEndpointAddress);
hcchar_bm->ep_dir = tu_edpt_dir(desc_ep->bEndpointAddress);
- hcchar_bm->low_speed_dev = (devtree_info.speed == TUSB_SPEED_LOW) ? 1 : 0;
+ hcchar_bm->low_speed_dev = (bus_info.speed == TUSB_SPEED_LOW) ? 1 : 0;
hcchar_bm->ep_type = desc_ep->bmAttributes.xfer; // ep_type matches TUSB_XFER_*
hcchar_bm->err_multi_count = 0;
hcchar_bm->dev_addr = dev_addr;
@@ -482,21 +491,21 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t*
hcchar_bm->enable = 1;
dwc2_channel_split_t* hcsplt_bm = &edpt->hcsplt_bm;
- hcsplt_bm->hub_port = devtree_info.hub_port;
- hcsplt_bm->hub_addr = devtree_info.hub_addr;
+ hcsplt_bm->hub_port = bus_info.hub_port;
+ hcsplt_bm->hub_addr = bus_info.hub_addr;
hcsplt_bm->xact_pos = 0;
hcsplt_bm->split_compl = 0;
- hcsplt_bm->split_en = (rh_speed == TUSB_SPEED_HIGH && devtree_info.speed != TUSB_SPEED_HIGH) ? 1 : 0;
+ hcsplt_bm->split_en = (rh_speed == TUSB_SPEED_HIGH && bus_info.speed != TUSB_SPEED_HIGH) ? 1 : 0;
- edpt->speed = devtree_info.speed;
+ edpt->speed = bus_info.speed;
edpt->next_pid = HCTSIZ_PID_DATA0;
if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
edpt->uframe_interval = 1 << (desc_ep->bInterval - 1);
- if (devtree_info.speed == TUSB_SPEED_FULL) {
+ if (bus_info.speed == TUSB_SPEED_FULL) {
edpt->uframe_interval <<= 3;
}
} else if (desc_ep->bmAttributes.xfer == TUSB_XFER_INTERRUPT) {
- if (devtree_info.speed == TUSB_SPEED_HIGH) {
+ if (bus_info.speed == TUSB_SPEED_HIGH) {
edpt->uframe_interval = 1 << (desc_ep->bInterval - 1);
} else {
edpt->uframe_interval = desc_ep->bInterval << 3;
@@ -514,10 +523,11 @@ bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
// clean up channel after part of transfer is done but the whole urb is not complete
static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) {
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
- dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ const dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
- edpt->next_pid = channel->hctsiz_bm.pid; // save PID
+ const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
+ edpt->next_pid = hctsiz.pid; // save PID
/* Since hctsiz.xfersize field reflects the number of bytes transferred via the AHB, not the USB)
* For IN: we can use hctsiz.xfersize as remaining bytes.
@@ -525,9 +535,10 @@ static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) {
* number of packets that have been transferred via the USB. This is always an integral number of packets if the
* transfer was halted before its normal completion.
*/
- const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
- const uint16_t total_packets = cal_packet_count(edpt->buflen, channel->hcchar_bm.ep_size);
- const uint16_t actual_bytes = (total_packets - remain_packets) * channel->hcchar_bm.ep_size;
+ const uint16_t remain_packets = hctsiz.packet_count;
+ const dwc2_channel_char_t hcchar = {.value = channel->hcchar};
+ const uint16_t total_packets = cal_packet_count(edpt->buflen, hcchar.ep_size);
+ const uint16_t actual_bytes = (total_packets - remain_packets) * hcchar.ep_size;
xfer->fifo_bytes = 0;
xfer->xferred_bytes += actual_bytes;
@@ -540,7 +551,7 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) {
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
dwc2_channel_char_t* hcchar_bm = &edpt->hcchar_bm;
dwc2_channel_t* channel = &dwc2->channel[ch_id];
- bool const is_period = edpt_is_periodic(hcchar_bm->ep_type);
+ bool const is_period = channel_is_periodic(edpt->hcchar);
// clear previous state
xfer->fifo_bytes = 0;
@@ -553,13 +564,16 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) {
// hctsiz: zero length packet still count as 1
const uint16_t packet_count = cal_packet_count(edpt->buflen, hcchar_bm->ep_size);
- uint32_t hctsiz = (edpt->next_pid << HCTSIZ_PID_Pos) | (packet_count << HCTSIZ_PKTCNT_Pos) | edpt->buflen;
- if (edpt->do_ping && edpt->speed == TUSB_SPEED_HIGH &&
+ dwc2_channel_tsize_t hctsiz = {.value = 0};
+ hctsiz.pid = edpt->next_pid; // next PID is set in transfer complete interrupt
+ hctsiz.packet_count = packet_count;
+ hctsiz.xfer_size = edpt->buflen;
+ if (edpt->next_do_ping && edpt->speed == TUSB_SPEED_HIGH &&
edpt->next_pid != HCTSIZ_PID_SETUP && hcchar_bm->ep_dir == TUSB_DIR_OUT) {
- hctsiz |= HCTSIZ_DOPING;
+ hctsiz.do_ping = 1;
}
- channel->hctsiz = hctsiz;
- edpt->do_ping = 0;
+ channel->hctsiz = hctsiz.value;
+ edpt->next_do_ping = 0;
// pre-calculate next PID based on packet count, adjusted in transfer complete interrupt if short packet
if (hcchar_bm->ep_num == 0) {
@@ -590,7 +604,7 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) {
hcintmsk |= HCINT_BABBLE_ERR | HCINT_DATATOGGLE_ERR | HCINT_ACK;
} else {
hcintmsk |= HCINT_NYET;
- if (edpt->hcsplt_bm.split_en) {
+ if (edpt->hcsplt_bm.split_en || hctsiz.do_ping) {
hcintmsk |= HCINT_ACK;
}
}
@@ -699,18 +713,23 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
//--------------------------------------------------------------------
// HCD Event Handler
//--------------------------------------------------------------------
+
+// retry an IN transfer, channel must be halted
static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hcint) {
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
- dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+ dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ dwc2_channel_char_t hcchar = {.value = channel->hcchar};
- if (edpt_is_periodic(channel->hcchar_bm.ep_type)){
+ if (channel_is_periodic(hcchar.value)){
+ const dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
// retry immediately for periodic split NYET if we haven't reach max retry
- if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) {
+ if (hcsplt.split_en && hcsplt.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) {
xfer->period_split_nyet_count++;
xfer->halted_nyet = 0;
if (xfer->period_split_nyet_count < HCD_XFER_PERIOD_SPLIT_NYET_MAX) {
- channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
+ hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
+ channel->hcchar = hcchar.value;
channel_send_in_token(dwc2, channel);
return;
} else {
@@ -719,18 +738,24 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
}
}
- // for periodic, de-allocate channel, enable SOF set frame counter for later transfer
- edpt->next_pid = channel->hctsiz_bm.pid; // save PID
- edpt->uframe_countdown = edpt->uframe_interval;
- dwc2->gintmsk |= GINTSTS_SOF;
-
- if (hcint & HCINT_HALTED) {
+ const uint32_t ucount = (hprt_speed_get(dwc2) == TUSB_SPEED_HIGH ? 1 : 8);
+ if (edpt->uframe_interval == ucount) {
+ // retry on next frame if bInterval is 1
+ hcchar.odd_frame = 1 - (dwc2->hfnum & 1);
+ channel->hcchar = hcchar.value;
+ channel_send_in_token(dwc2, channel);
+ } else {
+ // otherwise, de-allocate channel, enable SOF set frame counter for later transfer
+ const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
+ edpt->next_pid = hctsiz.pid; // save PID
+ edpt->uframe_countdown = edpt->uframe_interval - ucount;
+ // enable SOF interrupt if not already enabled
+ if (!(dwc2->gintmsk & GINTMSK_SOFM)) {
+ dwc2->gintsts = GINTSTS_SOF;
+ dwc2->gintmsk |= GINTMSK_SOFM;
+ }
// already halted, de-allocate channel (called from DMA isr)
channel_dealloc(dwc2, ch_id);
- } else {
- // disable channel first if not halted (called slave isr)
- xfer->halted_sof_schedule = 1;
- channel_disable(dwc2, channel);
}
} else {
// for control/bulk: retry immediately
@@ -761,13 +786,13 @@ static void handle_rxflvl_irq(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
// Pop control word off FIFO
- const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm;
- const uint8_t ch_id = grxstsp_bm.ep_ch_num;
+ const dwc2_grxstsp_t grxstsp = {.value= dwc2->grxstsp};
+ const uint8_t ch_id = grxstsp.ep_ch_num;
- switch (grxstsp_bm.packet_status) {
+ switch (grxstsp.packet_status) {
case GRXSTS_PKTSTS_RX_DATA: {
// In packet received, pop this entry --> ACK interrupt
- const uint16_t byte_count = grxstsp_bm.byte_count;
+ const uint16_t byte_count = grxstsp.byte_count;
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,);
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
@@ -801,25 +826,26 @@ static void handle_rxflvl_irq(uint8_t rhport) {
// return true if there is still pending data and need more ISR
static bool handle_txfifo_empty(dwc2_regs_t* dwc2, bool is_periodic) {
// Use period txsts for both p/np to get request queue space available (1-bit difference, it is small enough)
- volatile dwc2_hptxsts_t* txsts_bm = (volatile dwc2_hptxsts_t*) (is_periodic ? &dwc2->hptxsts : &dwc2->hnptxsts);
+ const dwc2_hptxsts_t txsts = {.value = (is_periodic ? dwc2->hptxsts : dwc2->hnptxsts)};
- const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
+ const uint8_t max_channel = dwc2_channel_count(dwc2);
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
dwc2_channel_t* channel = &dwc2->channel[ch_id];
+ const dwc2_channel_char_t hcchar = {.value = channel->hcchar};
// skip writing to FIFO if channel is expecting halted.
- if (!(channel->hcintmsk & HCINT_HALTED) && (channel->hcchar_bm.ep_dir == TUSB_DIR_OUT)) {
+ if (!(channel->hcintmsk & HCINT_HALTED) && (hcchar.ep_dir == TUSB_DIR_OUT)) {
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX);
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
-
- const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
+ const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
+ const uint16_t remain_packets = hctsiz.packet_count;
for (uint16_t i = 0; i < remain_packets; i++) {
const uint16_t remain_bytes = edpt->buflen - xfer->fifo_bytes;
- const uint16_t xact_bytes = tu_min16(remain_bytes, channel->hcchar_bm.ep_size);
+ const uint16_t xact_bytes = tu_min16(remain_bytes, hcchar.ep_size);
// skip if there is not enough space in FIFO and RequestQueue.
// Packet's last word written to FIFO will trigger a request queue
- if ((xact_bytes > (txsts_bm->fifo_available << 2)) || (txsts_bm->req_queue_available == 0)) {
+ if ((xact_bytes > (txsts.fifo_available << 2)) || (txsts.req_queue_available == 0)) {
return true;
}
@@ -836,23 +862,26 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+ dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
+ const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
bool is_done = false;
- // if (channel->hcsplt_bm.split_en) {
+ // if (hcsplt.split_en) {
// if (edpt->hcchar_bm.ep_num == 1) {
- // TU_LOG1("Frame %u, ch %u: ep %u, hcint 0x%04lX ", dwc2->hfnum_bm.num, ch_id, channel->hcchar_bm.ep_num, hcint);
+ // TU_LOG1("Frame %u, ch %u: ep %u, hcint 0x%04lX ", dwc2->hfnum_bm.num, ch_id, hcsplt.ep_num, hcint);
// print_hcint(hcint);
// }
if (hcint & HCINT_XFER_COMPLETE) {
if (edpt->hcchar_bm.ep_num != 0) {
- edpt->next_pid = channel->hctsiz_bm.pid; // save pid (already toggled)
+ edpt->next_pid = hctsiz.pid; // save pid (already toggled)
}
- const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
- if (channel->hcsplt_bm.split_en && remain_packets && xfer->fifo_bytes == edpt->hcchar_bm.ep_size) {
+ const uint16_t remain_packets = hctsiz.packet_count;
+ if (hcsplt.split_en && remain_packets && xfer->fifo_bytes == edpt->hcchar_bm.ep_size) {
// Split can only complete 1 transaction (up to 1 packet) at a time, schedule more
- channel->hcsplt_bm.split_compl = 0;
+ hcsplt.split_compl = 0;
+ channel->hcsplt = hcsplt.value;
} else {
xfer->result = XFER_RESULT_SUCCESS;
}
@@ -871,43 +900,44 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h
channel_disable(dwc2, channel);
} else if (hcint & HCINT_NYET) {
// restart complete split
- channel->hcsplt_bm.split_compl = 1;
+ hcsplt.split_compl = 1;
+ channel->hcsplt = hcsplt.value;
xfer->halted_nyet = 1;
channel_disable(dwc2, channel);
} else if (hcint & HCINT_NAK) {
- // NAK received, re-enable channel if request queue is available
- if (channel->hcsplt_bm.split_en) {
- channel->hcsplt_bm.split_compl = 0; // restart with start-split
+ // NAK received, disable channel to flush all posted request and try again
+ if (hcsplt.split_en) {
+ hcsplt.split_compl = 0; // restart with start-split
+ channel->hcsplt = hcsplt.value;
}
channel_disable(dwc2, channel);
} else if (hcint & HCINT_ACK) {
xfer->err_count = 0;
- if (channel->hcsplt_bm.split_en) {
- if (!channel->hcsplt_bm.split_compl) {
+ if (hcsplt.split_en) {
+ if (!hcsplt.split_compl) {
// start split is ACK --> do complete split
channel->hcintmsk |= HCINT_NYET;
- channel->hcsplt_bm.split_compl = 1;
+ hcsplt.split_compl = 1;
+ channel->hcsplt = hcsplt.value;
channel_send_in_token(dwc2, channel);
} else {
// do nothing for complete split with DATA, this will trigger XferComplete and handled there
}
} else {
// ACK with data
- const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
+ const uint16_t remain_packets = hctsiz.packet_count;
if (remain_packets) {
// still more packet to receive, also reset to start split
- channel->hcsplt_bm.split_compl = 0;
+ hcsplt.split_compl = 0;
+ channel->hcsplt = hcsplt.value;
channel_send_in_token(dwc2, channel);
}
}
} else if (hcint & HCINT_HALTED) {
channel->hcintmsk &= ~HCINT_HALTED;
- if (xfer->halted_sof_schedule) {
- // de-allocate channel but does not complete xfer, we schedule it in the SOF interrupt
- channel_dealloc(dwc2, ch_id);
- } else if (xfer->result != XFER_RESULT_INVALID) {
+ if (xfer->result != XFER_RESULT_INVALID) {
is_done = true;
} else if (xfer->err_count == HCD_XFER_ERROR_MAX) {
xfer->result = XFER_RESULT_FAILED;
@@ -927,23 +957,29 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+ dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
bool is_done = false;
if (hcint & HCINT_XFER_COMPLETE) {
is_done = true;
xfer->result = XFER_RESULT_SUCCESS;
channel->hcintmsk &= ~HCINT_ACK;
+ if (hcint & HCINT_NYET) {
+ // complete transfer with NYET, do ping next time
+ edpt->next_do_ping = 1;
+ }
} else if (hcint & HCINT_STALL) {
xfer->result = XFER_RESULT_STALLED;
channel_disable(dwc2, channel);
} else if (hcint & HCINT_NYET) {
xfer->err_count = 0;
- if (channel->hcsplt_bm.split_en) {
+ if (hcsplt.split_en) {
// retry complete split
- channel->hcsplt_bm.split_compl = 1;
+ hcsplt.split_compl = 1;
+ channel->hcsplt = hcsplt.value;
channel->hcchar |= HCCHAR_CHENA;
} else {
- edpt->do_ping = 1;
+ edpt->next_do_ping = 1;
channel_xfer_out_wrapup(dwc2, ch_id);
channel_disable(dwc2, channel);
}
@@ -956,7 +992,7 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t
channel->hcintmsk |= HCINT_ACK;
} else {
// NAK disable channel to flush all posted request and try again
- edpt->do_ping = 1;
+ edpt->next_do_ping = 1;
xfer->err_count = 0;
}
} else if (hcint & HCINT_HALTED) {
@@ -973,9 +1009,17 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t
} else if (hcint & HCINT_ACK) {
xfer->err_count = 0;
channel->hcintmsk &= ~HCINT_ACK;
- if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) {
- // start split is ACK --> do complete split
- channel->hcsplt_bm.split_compl = 1;
+ if (hcsplt.split_en) {
+ if (!hcsplt.split_compl) {
+ // ACK for start split --> do complete split
+ hcsplt.split_compl = 1;
+ channel->hcsplt = hcsplt.value;
+ channel->hcchar |= HCCHAR_CHENA;
+ }
+ } else {
+ // ACK interrupt is only enabled for Split and PING
+ // ACK for PING, which mean device is ready to receive data
+ channel->hctsiz &= ~HCTSIZ_DOPING; // HC already cleared PING bit, but we clear anyway
channel->hcchar |= HCCHAR_CHENA;
}
}
@@ -994,6 +1038,9 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+ dwc2_channel_char_t hcchar = {.value = channel->hcchar};
+ dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
+ const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
bool is_done = false;
@@ -1001,8 +1048,8 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
if (hcint & HCINT_HALTED) {
if (hcint & (HCINT_XFER_COMPLETE | HCINT_STALL | HCINT_BABBLE_ERR)) {
- const uint16_t remain_bytes = (uint16_t) channel->hctsiz_bm.xfer_size;
- const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
+ const uint16_t remain_bytes = (uint16_t) hctsiz.xfer_size;
+ const uint16_t remain_packets = hctsiz.packet_count;
const uint16_t actual_len = edpt->buflen - remain_bytes;
xfer->xferred_bytes += actual_len;
@@ -1012,13 +1059,14 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
xfer->result = XFER_RESULT_STALLED;
} else if (hcint & HCINT_BABBLE_ERR) {
xfer->result = XFER_RESULT_FAILED;
- } else if (channel->hcsplt_bm.split_en && remain_packets && actual_len == edpt->hcchar_bm.ep_size) {
+ } else if (hcsplt.split_en && remain_packets && actual_len == hcchar.ep_size) {
// Split can only complete 1 transaction (up to 1 packet) at a time, schedule more
is_done = false;
edpt->buffer += actual_len;
edpt->buflen -= actual_len;
- channel->hcsplt_bm.split_compl = 0;
+ hcsplt.split_compl = 0;
+ channel->hcsplt = hcsplt.value;
channel_xfer_in_retry(dwc2, ch_id, hcint);
} else {
xfer->result = XFER_RESULT_SUCCESS;
@@ -1033,33 +1081,38 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
xfer->result = XFER_RESULT_FAILED;
} else {
channel->hcintmsk |= HCINT_ACK | HCINT_NAK | HCINT_DATATOGGLE_ERR;
- channel->hcsplt_bm.split_compl = 0;
+ hcsplt.split_compl = 0;
+ channel->hcsplt = hcsplt.value;
channel_xfer_in_retry(dwc2, ch_id, hcint);
}
} else if (hcint & HCINT_NYET) {
// Must handle nyet before nak or ack. Could get a nyet at the same time as either of those on a BULK/CONTROL
// OUT that started with a PING. The nyet takes precedence.
- if (channel->hcsplt_bm.split_en) {
+ if (hcsplt.split_en) {
// split not yet mean hub has no data, retry complete split
- channel->hcsplt_bm.split_compl = 1;
+ hcsplt.split_compl = 1;
+ channel->hcsplt = hcsplt.value;
channel_xfer_in_retry(dwc2, ch_id, hcint);
}
} else if (hcint & HCINT_ACK) {
xfer->err_count = 0;
channel->hcintmsk &= ~HCINT_ACK;
- if (channel->hcsplt_bm.split_en) {
+ if (hcsplt.split_en) {
// start split is ACK --> do complete split
// TODO: for ISO must use xact_pos to plan complete split based on microframe (up to 187.5 bytes/uframe)
- channel->hcsplt_bm.split_compl = 1;
- if (edpt_is_periodic(channel->hcchar_bm.ep_type)) {
- channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
+ hcsplt.split_compl = 1;
+ channel->hcsplt = hcsplt.value;
+ if (channel_is_periodic(channel->hcchar)) {
+ hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
+ channel->hcchar = hcchar.value;
}
channel_send_in_token(dwc2, channel);
}
} else if (hcint & (HCINT_NAK | HCINT_DATATOGGLE_ERR)) {
xfer->err_count = 0;
channel->hcintmsk &= ~(HCINT_NAK | HCINT_DATATOGGLE_ERR);
- channel->hcsplt_bm.split_compl = 0; // restart with start-split
+ hcsplt.split_compl = 0; // restart with start-split
+ channel->hcsplt = hcsplt.value;
channel_xfer_in_retry(dwc2, ch_id, hcint);
} else if (hcint & HCINT_FARME_OVERRUN) {
// retry start-split in next binterval
@@ -1074,6 +1127,8 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
+ const dwc2_channel_char_t hcchar = {.value = channel->hcchar};
+ dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
bool is_done = false;
@@ -1109,16 +1164,18 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc
}
}
} else if (hcint & HCINT_NYET) {
- if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl) {
+ if (hcsplt.split_en && hcsplt.split_compl) {
// split not yet mean hub has no data, retry complete split
- channel->hcsplt_bm.split_compl = 1;
+ hcsplt.split_compl = 1;
+ channel->hcsplt = hcsplt.value;
channel->hcchar |= HCCHAR_CHENA;
}
} else if (hcint & HCINT_ACK) {
xfer->err_count = 0;
- if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) {
+ if (hcsplt.split_en && !hcsplt.split_compl) {
// start split is ACK --> do complete split
- channel->hcsplt_bm.split_compl = 1;
+ hcsplt.split_compl = 1;
+ channel->hcsplt = hcsplt.value;
channel->hcchar |= HCCHAR_CHENA;
}
}
@@ -1134,14 +1191,14 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc
static void handle_channel_irq(uint8_t rhport, bool in_isr) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const bool is_dma = dma_host_enabled(dwc2);
- const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
+ const uint8_t max_channel = dwc2_channel_count(dwc2);
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
if (tu_bit_test(dwc2->haint, ch_id)) {
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,);
- dwc2_channel_char_t hcchar_bm = channel->hcchar_bm;
+ dwc2_channel_char_t hcchar = {.value = channel->hcchar};
const uint32_t hcint = channel->hcint;
channel->hcint = hcint; // clear interrupt
@@ -1149,7 +1206,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
bool is_done = false;
if (is_dma) {
#if CFG_TUH_DWC2_DMA_ENABLE
- if (hcchar_bm.ep_dir == TUSB_DIR_OUT) {
+ if (hcchar.ep_dir == TUSB_DIR_OUT) {
is_done = handle_channel_out_dma(dwc2, ch_id, hcint);
} else {
is_done = handle_channel_in_dma(dwc2, ch_id, hcint);
@@ -1161,7 +1218,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
#endif
} else {
#if CFG_TUH_DWC2_SLAVE_ENABLE
- if (hcchar_bm.ep_dir == TUSB_DIR_OUT) {
+ if (hcchar.ep_dir == TUSB_DIR_OUT) {
is_done = handle_channel_out_slave(dwc2, ch_id, hcint);
} else {
is_done = handle_channel_in_slave(dwc2, ch_id, hcint);
@@ -1170,8 +1227,8 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
}
if (is_done) {
- const uint8_t ep_addr = tu_edpt_addr(hcchar_bm.ep_num, hcchar_bm.ep_dir);
- hcd_event_xfer_complete(hcchar_bm.dev_addr, ep_addr, xfer->xferred_bytes, xfer->result, in_isr);
+ const uint8_t ep_addr = tu_edpt_addr(hcchar.ep_num, hcchar.ep_dir);
+ hcd_event_xfer_complete(hcchar.dev_addr, ep_addr, xfer->xferred_bytes, (xfer_result_t)xfer->result, in_isr);
channel_dealloc(dwc2, ch_id);
}
}
@@ -1191,7 +1248,7 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) {
for(uint8_t ep_id = 0; ep_id < CFG_TUH_DWC2_ENDPOINT_MAX; ep_id++) {
hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
- if (edpt->hcchar_bm.enable && edpt_is_periodic(edpt->hcchar_bm.ep_type) && edpt->uframe_countdown > 0) {
+ if (edpt->hcchar_bm.enable && channel_is_periodic(edpt->hcchar) && edpt->uframe_countdown > 0) {
edpt->uframe_countdown -= tu_min32(ucount, edpt->uframe_countdown);
if (edpt->uframe_countdown == 0) {
if (!edpt_xfer_kickoff(dwc2, ep_id)) {
@@ -1210,10 +1267,10 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) {
static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
uint32_t hcfg = dwc2->hcfg & ~HCFG_FSLS_PHYCLK_SEL;
- const dwc2_gusbcfg_t gusbcfg_bm = dwc2->gusbcfg_bm;
+ const dwc2_gusbcfg_t gusbcfg = {.value = dwc2->gusbcfg};
uint32_t phy_clock;
- if (gusbcfg_bm.phy_sel) {
+ if (gusbcfg.phy_sel) {
phy_clock = 48; // dedicated FS is 48Mhz
if (speed == TUSB_SPEED_LOW) {
hcfg |= HCFG_FSLS_PHYCLK_SEL_6MHZ;
@@ -1221,11 +1278,11 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
hcfg |= HCFG_FSLS_PHYCLK_SEL_48MHZ;
}
} else {
- if (gusbcfg_bm.ulpi_utmi_sel) {
+ if (gusbcfg.ulpi_utmi_sel) {
phy_clock = 60; // ULPI 8-bit is 60Mhz
} else {
// UTMI+ 16-bit is 30Mhz, 8-bit is 60Mhz
- phy_clock = gusbcfg_bm.phy_if16 ? 30 : 60;
+ phy_clock = gusbcfg.phy_if16 ? 30 : 60;
// Enable UTMI+ low power mode 48Mhz external clock if not highspeed
if (speed == TUSB_SPEED_HIGH) {
@@ -1242,9 +1299,9 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
uint32_t hfir = dwc2->hfir & ~HFIR_FRIVL_Msk;
if (speed == TUSB_SPEED_HIGH) {
- hfir |= 125*phy_clock;
+ hfir |= 125*phy_clock - 1; // The "- 1" is the correct value. The Synopsys databook was corrected in 3.30a
} else {
- hfir |= 1000*phy_clock;
+ hfir |= 1000*phy_clock - 1;
}
dwc2->hfir = hfir;
@@ -1257,21 +1314,19 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
*/
static void handle_hprt_irq(uint8_t rhport, bool in_isr) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
- uint32_t hprt = dwc2->hprt & ~HPRT_W1_MASK;
- const dwc2_hprt_t hprt_bm = dwc2->hprt_bm;
+ const dwc2_hprt_t hprt_bm = {.value = dwc2->hprt};
+ uint32_t hprt = hprt_bm.value & ~HPRT_W1_MASK;
- if (dwc2->hprt & HPRT_CONN_DETECT) {
+ if (hprt_bm.conn_detected) {
// Port Connect Detect
hprt |= HPRT_CONN_DETECT;
if (hprt_bm.conn_status) {
hcd_event_device_attach(rhport, in_isr);
- } else {
- hcd_event_device_remove(rhport, in_isr);
}
}
- if (dwc2->hprt & HPRT_ENABLE_CHANGE) {
+ if (hprt_bm.enable_change) {
// Port enable change
hprt |= HPRT_ENABLE_CHANGE;
@@ -1330,6 +1385,15 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
handle_channel_irq(rhport, in_isr);
}
+ if (gintsts & GINTSTS_DISCINT) {
+ // Device disconnected
+ dwc2->gintsts = GINTSTS_DISCINT;
+
+ if (!(dwc2->hprt & HPRT_CONN_STATUS)) {
+ hcd_event_device_remove(rhport, in_isr);
+ }
+ }
+
#if CFG_TUH_DWC2_SLAVE_ENABLE
// RxFIFO non-empty interrupt handling
if (gintsts & GINTSTS_RXFLVL) {
diff --git a/src/portable/template/hcd_template.c b/src/portable/template/hcd_template.c
index 1202c4ef4..d2f304407 100644
--- a/src/portable/template/hcd_template.c
+++ b/src/portable/template/hcd_template.c
@@ -29,6 +29,7 @@
#if CFG_TUH_ENABLED && CFG_TUSB_MCU == OPT_MCU_NONE
#include "host/hcd.h"
+#include "host/usbh.h"
//--------------------------------------------------------------------+
// Controller API
@@ -106,6 +107,11 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
// Open an endpoint
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) {
(void) rhport; (void) dev_addr; (void) ep_desc;
+
+ // NOTE: ep_desc is allocated on the stack when called from usbh_edpt_control_open()
+ // You need to copy the data into a local variable who maintains the state of the endpoint and transfer.
+ // Check _hcd_data in hcd_dwc2.c for example.
+
return false;
}
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 29fdcb0d6..98f1a91b5 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -35,7 +35,7 @@
#define TUSB_VERSION_REVISION 0
#define TUSB_VERSION_NUMBER (TUSB_VERSION_MAJOR * 10000 + TUSB_VERSION_MINOR * 100 + TUSB_VERSION_REVISION)
-#define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION)
+#define TUSB_VERSION_STRING TU_XSTRING(TUSB_VERSION_MAJOR) "." TU_XSTRING(TUSB_VERSION_MINOR) "." TU_XSTRING(TUSB_VERSION_REVISION)
//--------------------------------------------------------------------+
// Supported MCUs
diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py
index 8b89de66c..f292bca15 100755
--- a/test/hil/hil_test.py
+++ b/test/hil/hil_test.py
@@ -514,6 +514,63 @@ host_test = [
]
+def test_example(board, f1, example):
+ """
+ Test example firmware
+ :param board: board dict
+ :param f1: flags on
+ :param example: example name
+ :return: 0 if success/skip, 1 if failed
+ """
+ name = board['name']
+ err_count = 0
+
+ f1_str = ""
+ if f1 != "":
+ f1_str = '-f1_' + f1.replace(' ', '_')
+
+ fw_dir = f'{TINYUSB_ROOT}/cmake-build/cmake-build-{name}{f1_str}/{example}'
+ if not os.path.exists(fw_dir):
+ fw_dir = f'{TINYUSB_ROOT}/examples/cmake-build-{name}{f1_str}/{example}'
+ fw_name = f'{fw_dir}/{os.path.basename(example)}'
+ print(f'{name+f1_str:40} {example:30} ... ', end='')
+
+ if not os.path.exists(fw_dir) or not (os.path.exists(f'{fw_name}.elf') or os.path.exists(f'{fw_name}.bin')):
+ print('Skip (no binary)')
+ return 0
+
+ if verbose:
+ print(f'Flashing {fw_name}.elf')
+
+ # flash firmware. It may fail randomly, retry a few times
+ max_rety = 3
+ for i in range(max_rety):
+ ret = globals()[f'flash_{board["flasher"]["name"].lower()}'](board, fw_name)
+ if ret.returncode == 0:
+ try:
+ globals()[f'test_{example.replace("/", "_")}'](board)
+ print('OK')
+ break
+ except Exception as e:
+ if i == max_rety - 1:
+ err_count += 1
+ print(STATUS_FAILED)
+ print(f' {e}')
+ else:
+ print()
+ print(f' Test failed: {e}, retry {i+2}/{max_rety}')
+ time.sleep(1)
+ else:
+ print(f'Flashing failed, retry {i+2}/{max_rety}')
+ time.sleep(1)
+
+ if ret.returncode != 0:
+ err_count += 1
+ print(f'Flash {STATUS_FAILED}')
+
+ return err_count
+
+
def test_board(board):
name = board['name']
flasher = board['flasher']
@@ -537,57 +594,17 @@ def test_board(board):
test_list.remove(skip)
print(f'{name:25} {skip:30} ... Skip')
- # board_test is added last to disable board's usb
- test_list.append('device/board_test')
-
err_count = 0
flags_on_list = [""]
if 'build' in board and 'flags_on' in board['build']:
flags_on_list = board['build']['flags_on']
for f1 in flags_on_list:
- f1_str = ""
- if f1 != "":
- f1_str = '-f1_' + f1.replace(' ', '_')
for test in test_list:
- fw_dir = f'{TINYUSB_ROOT}/cmake-build/cmake-build-{name}{f1_str}/{test}'
- if not os.path.exists(fw_dir):
- fw_dir = f'{TINYUSB_ROOT}/examples/cmake-build-{name}{f1_str}/{test}'
- fw_name = f'{fw_dir}/{os.path.basename(test)}'
- print(f'{name+f1_str:40} {test:30} ... ', end='')
+ err_count += test_example(board, f1, test)
- if not os.path.exists(fw_dir) or not (os.path.exists(f'{fw_name}.elf') or os.path.exists(f'{fw_name}.bin')):
- print('Skip (no binary)')
- continue
-
- if verbose:
- print(f'Flashing {fw_name}.elf')
-
- # flash firmware. It may fail randomly, retry a few times
- max_rety = 2
- for i in range(max_rety):
- ret = globals()[f'flash_{flasher["name"].lower()}'](board, fw_name)
- if ret.returncode == 0:
- try:
- globals()[f'test_{test.replace("/", "_")}'](board)
- print('OK')
- break
- except Exception as e:
- if i == max_rety - 1:
- err_count += 1
- print(STATUS_FAILED)
- print(f' {e}')
- else:
- print()
- print(f' Test failed: {e}, retry {i+2}/{max_rety}')
- time.sleep(1)
- else:
- print(f'Flashing failed, retry {i+2}/{max_rety}')
- time.sleep(1)
-
- if ret.returncode != 0:
- err_count += 1
- print(f'Flash {STATUS_FAILED}')
+ # flash board_test last to disable board's usb
+ test_example(board, flags_on_list[0], 'device/board_test')
return err_count
diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json
index a9460bf9d..8a835e4c0 100644
--- a/test/hil/tinyusb.json
+++ b/test/hil/tinyusb.json
@@ -21,16 +21,18 @@
"name": "espressif_s3_devkitm",
"uid": "84F703C084E4",
"build" : {
- "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE"]
+ "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE"]
},
"tests": {
- "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos"]
+ "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"],
+ "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2005402"}]
},
"flasher": {
"name": "esptool",
"uid": "3ea619acd1cdeb11a0a0b806e93fd3f1",
"args": "-b 1500000"
- }
+ },
+ "comment": "Use TS3USB30 mux to test both device and host"
},
{
"name": "feather_nrf52840_express",
@@ -124,6 +126,20 @@
"args": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\""
}
},
+ {
+ "name": "raspberry_pi_pico_w",
+ "uid": "E6614C311B764A37",
+ "tests": {
+ "device": false, "host": true, "dual": false,
+ "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023934"}]
+ },
+ "flasher": {
+ "name": "openocd",
+ "uid": "E6633861A3819D38",
+ "args": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\""
+ },
+ "comment": "Test native host"
+ },
{
"name": "raspberry_pi_pico2",
"uid": "560AE75E1C7152C9",
diff --git a/tools/build.py b/tools/build.py
index 633d2b582..d28ddd929 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -182,9 +182,14 @@ def build_boards_list(boards, toolchain, build_system, build_flags_on):
def build_family(family, toolchain, build_system, build_flags_on, one_per_family, boards):
+ skip_ci = ['pico_sdk']
+ if os.getenv('GITHUB_ACTIONS') or os.getenv('CIRCLECI'):
+ skip_ci_file = Path(f"hw/bsp/{family}/skip_ci.txt")
+ if skip_ci_file.exists():
+ skip_ci = skip_ci_file.read_text().split()
all_boards = []
for entry in os.scandir(f"hw/bsp/{family}/boards"):
- if entry.is_dir() and entry.name != 'pico_sdk':
+ if entry.is_dir() and not entry.name in skip_ci:
all_boards.append(entry.name)
all_boards.sort()
diff --git a/tools/get_deps.py b/tools/get_deps.py
index 1bef5f6a2..e67239438 100755
--- a/tools/get_deps.py
+++ b/tools/get_deps.py
@@ -59,7 +59,7 @@ deps_optional = {
'144f1eb7ea8c06512e12f12b27383601c0272410',
'kinetis_k kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx imxrt'],
'hw/mcu/raspberry_pi/Pico-PIO-USB': ['https://github.com/hathach/Pico-PIO-USB.git',
- '810653f66adadba3e0e4b4b56d5167ac4f7fdbf7',
+ '032a469e79f6a4ba40760d7868e6db26e15002d7',
'rp2040'],
'hw/mcu/renesas/fsp': ['https://github.com/renesas/fsp.git',
'edcc97d684b6f716728a60d7a6fea049d9870bd6',
@@ -125,7 +125,7 @@ deps_optional = {
'5ad9797c54ec3e55eff770fc9b3cd4a1aefc1309',
'stm32u5'],
'hw/mcu/st/cmsis_device_wb': ['https://github.com/STMicroelectronics/cmsis_device_wb.git',
- '9c5d1920dd9fabbe2548e10561d63db829bb744f',
+ 'd6a7fa2e7de084f5e5e47f2ab88b022fe9b50e5a',
'stm32wb'],
'hw/mcu/st/stm32-mfxstm32l152': ['https://github.com/STMicroelectronics/stm32-mfxstm32l152.git',
'7f4389efee9c6a655b55e5df3fceef5586b35f9b',
@@ -249,11 +249,13 @@ def get_a_dep(d):
p.mkdir(parents=True)
run_cmd(f"{git_cmd} init")
run_cmd(f"{git_cmd} remote add origin {url}")
+ head = None
+ else:
+ # Check if commit is already fetched
+ result = run_cmd(f"{git_cmd} rev-parse HEAD")
+ head = result.stdout.decode("utf-8").splitlines()[0]
+ run_cmd(f"{git_cmd} reset --hard")
- # Check if commit is already fetched
- result = run_cmd(f"{git_cmd} rev-parse HEAD")
- head = result.stdout.decode("utf-8").splitlines()[0]
- run_cmd(f"{git_cmd} reset --hard")
if commit != head:
run_cmd(f"{git_cmd} fetch --depth 1 origin {commit}")
run_cmd(f"{git_cmd} checkout FETCH_HEAD")