diff --git a/.circleci/config.yml b/.circleci/config.yml
index fd5631e2e..c2f6c4356 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -19,13 +19,12 @@ jobs:
echo "MATRIX_JSON=$MATRIX_JSON"
BUILDSYSTEM_TOOLCHAIN=(
+ "cmake aarch64-gcc"
"cmake arm-clang"
- "make aarch64-gcc"
- "make arm-gcc"
- "make msp430-gcc"
- "make riscv-gcc"
- "make rx-gcc"
+ "cmake arm-gcc"
"cmake esp-idf"
+ "cmake msp430-gcc"
+ "cmake riscv-gcc"
)
# only build IAR if not forked PR, since IAR token is not shared
@@ -67,7 +66,7 @@ jobs:
FAMILY_LARGE=$(jq -n --argjson family "$FAMILY" --argjson resource "$RESOURCE_LARGE" '$family | map(select(IN($resource[])))')
FAMILY=$(jq -n --argjson family "$FAMILY" --argjson resource "$RESOURCE_LARGE" '$family | map(select(IN($resource[]) | not))')
- if [[ $toolchain == esp-idf ]]; then
+ if [[ $toolchain == esp-idf || $toolchain == arm-iar ]]; then
gen_build_entry "$build_system" "$toolchain" "$FAMILY" "large"
else
gen_build_entry "$build_system" "$toolchain" "$FAMILY" "medium+"
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/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index d00ee78bd..35576a439 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -22,10 +22,17 @@ body:
validations:
required: true
+ - type: input
+ attributes:
+ label: Commit SHA
+ placeholder: e.g 3a042b37da28d0ba1e5593eb1068ca5645d77b56 or version bundled by esp-idf or pico-sdk
+ validations:
+ required: true
+
- type: input
attributes:
label: Board
- placeholder: e.g Feather nRF52840 Express
+ placeholder: e.g Adafruit Feather nRF52840 Express
validations:
required: true
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..5e11f8a29 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,15 @@ 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 }}
+ hil_json: ${{ steps.set-matrix-json.outputs.hil_matrix }}
steps:
- name: Checkout TinyUSB
uses: actions/checkout@v4
@@ -43,33 +48,41 @@ 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
+ # Build CMake: only build on push with one-per-family.
+ # Full built is done by CircleCI in PR
# ---------------------------------------
cmake:
+ if: github.event_name == 'push'
needs: set-matrix
uses: ./.github/workflows/build_util.yml
strategy:
fail-fast: false
matrix:
toolchain:
- # - 'arm-clang' is built by circle-ci in PR
- 'aarch64-gcc'
+ #- 'arm-clang'
- 'arm-gcc'
+ - 'esp-idf'
- 'msp430-gcc'
- 'riscv-gcc'
with:
build-system: 'cmake'
toolchain: ${{ matrix.toolchain }}
build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain]) }}
- one-per-family: ${{ github.event_name == 'push' }}
+ one-per-family: true
# ---------------------------------------
- # Build Make (built by circle-ci in PR, only build on push here)
+ # Build Make: only build on push with one-per-family
# ---------------------------------------
make:
if: github.event_name == 'push'
@@ -79,19 +92,40 @@ jobs:
fail-fast: false
matrix:
toolchain:
- # 'arm-clang'
- - 'arm-gcc'
- 'aarch64-gcc'
+ #- 'arm-clang'
+ - 'arm-gcc'
- 'msp430-gcc'
- 'riscv-gcc'
- 'rx-gcc'
- - 'esp-idf' # build-system is ignored
with:
build-system: 'make'
toolchain: ${{ matrix.toolchain }}
build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain]) }}
one-per-family: true
+ # ---------------------------------------
+ # 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: false # disable for now since we got reach capacity limit too often
+ #if: github.event_name == 'push' && github.repository_owner == 'hathach'
+ needs: set-matrix
+ 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
+
# ---------------------------------------
# Build Make on Windows/MacOS
# ---------------------------------------
@@ -109,39 +143,6 @@ jobs:
build-args: '["stm32h7"]'
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
- # ---------------------------------------
- arm-iar:
- if: github.repository_owner == 'hathach' && github.event_name == 'push'
- 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
-
# ---------------------------------------
# Zephyr
# ---------------------------------------
@@ -162,3 +163,102 @@ 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
+ # ---------------------------------------
+ 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 -j 4 --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..ddb3ee1fb 100755
--- a/.github/workflows/ci_set_matrix.py
+++ b/.github/workflows/ci_set_matrix.py
@@ -24,7 +24,7 @@ family_list = {
"lpc11 lpc13 lpc15": ["arm-gcc", "arm-clang"],
"lpc17 lpc18 lpc40 lpc43": ["arm-gcc", "arm-clang"],
"lpc51 lpc54 lpc55": ["arm-gcc", "arm-clang"],
- "max32650 max32666 max32690 max78002": ["arm-gcc"],
+ "maxim": ["arm-gcc"],
"mcx": ["arm-gcc"],
"mm32": ["arm-gcc"],
"msp430": ["msp430-gcc"],
@@ -40,13 +40,15 @@ family_list = {
"stm32f4": ["arm-gcc", "arm-clang", "arm-iar"],
"stm32f7": ["arm-gcc", "arm-clang", "arm-iar"],
"stm32g0 stm32g4 stm32h5": ["arm-gcc", "arm-clang", "arm-iar"],
- "stm32h7": ["arm-gcc", "arm-clang", "arm-iar"],
+ "stm32h7 stm32h7rs": ["arm-gcc", "arm-clang", "arm-iar"],
"stm32l0 stm32l4": ["arm-gcc", "arm-clang", "arm-iar"],
+ "stm32n6": ["arm-gcc"],
"stm32u5 stm32wb": ["arm-gcc", "arm-clang", "arm-iar"],
"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..dfcca6315 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
@@ -124,12 +124,12 @@ jobs:
output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif
- name: Upload SARIF
- uses: github/codeql-action/upload-sarif@v2
+ uses: github/codeql-action/upload-sarif@v3
with:
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/.gitignore b/.gitignore
index f981110b2..5638a09db 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,14 @@ latex
*.jlink
*.emSession
*.ninja*
+*.eww
+*.ewp
+*.ewt
+*.ewd
+*.hex
+cmake_install.cmake
+CMakeCache.txt
+settings/
.settings/
.vscode/
.gdb_history
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/rp2040.xml b/.idea/debugServers/rp2040.xml
new file mode 100644
index 000000000..f451611f3
--- /dev/null
+++ b/.idea/debugServers/rp2040.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/debugServers/rp2350.xml b/.idea/debugServers/rp2350.xml
new file mode 100644
index 000000000..52243a297
--- /dev/null
+++ b/.idea/debugServers/rp2350.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/debugServers/rt1060.xml b/.idea/debugServers/rt1060.xml
new file mode 100644
index 000000000..cbd295b4e
--- /dev/null
+++ b/.idea/debugServers/rt1060.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/debugServers/rt1064.xml b/.idea/debugServers/rt1064.xml
new file mode 100644
index 000000000..4fb2fdf6a
--- /dev/null
+++ b/.idea/debugServers/rt1064.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/debugServers/sam21.xml b/.idea/debugServers/sam21.xml
new file mode 100644
index 000000000..3f6735bd1
--- /dev/null
+++ b/.idea/debugServers/sam21.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/debugServers/sam51.xml b/.idea/debugServers/sam51.xml
new file mode 100644
index 000000000..99a92c174
--- /dev/null
+++ b/.idea/debugServers/sam51.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
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/CONTRIBUTORS.rst b/CONTRIBUTORS.rst
index 085f8082a..451ac0783 100644
--- a/CONTRIBUTORS.rst
+++ b/CONTRIBUTORS.rst
@@ -31,6 +31,13 @@ Notable contributors
- Most features development
+`Heiko Kuester `__
+--------------------------------------------
+
+- Add CH34x and PL2303 support (CDC host)
+- Improve FTDI and CP210x support (CDC host)
+
+
`Hristo Gochkov `__
-------------------------------------------------
diff --git a/README.rst b/README.rst
index e4ad91e47..b873bc42b 100644
--- a/README.rst
+++ b/README.rst
@@ -15,10 +15,7 @@ TinyUSB Project
.. figure:: docs/assets/logo.svg
:alt: TinyUSB
-TinyUSB is an open-source cross-platform USB Host/Device stack for
-embedded system, designed to be memory-safe with no dynamic allocation
-and thread-safe with all interrupt events are deferred then handled in
-the non-ISR task function. Check out the online `documentation `__ for more details.
+TinyUSB is an open-source cross-platform USB Host/Device stack for embedded system, designed to be memory-safe with no dynamic allocation and thread-safe with all interrupt events are deferred then handled in the non-ISR task function. Check out the online `documentation `__ for more details.
.. figure:: docs/assets/stack.svg
:width: 500px
@@ -32,7 +29,7 @@ the non-ISR task function. Check out the online `documentation `_ for information about using TinyUSB and how it is implemented.
-Check out `Getting Started`_ guide for adding TinyUSB to your project or building the examples. If you are new to TinyUSB, we recommend starting with the `cdc_msc` example. There is a handful of `Supported Boards`_ that should work out of the box.
+Check out `Getting Started`_ guide for adding TinyUSB to your project or building the examples. If you are new to TinyUSB, we recommend starting with the ``cdc_msc`` example. There is a handful of `Supported Boards`_ that should work out of the box.
We use `GitHub Discussions `_ as our forum. It is a great place to ask questions and advice from the community or to discuss your TinyUSB-based projects.
@@ -69,7 +66,7 @@ Supports multiple device configurations by dynamically changing USB descriptors,
- Vendor-specific class support with generic In & Out endpoints. Can be used with MS OS 2.0 compatible descriptor to load winUSB driver without INF file.
- `WebUSB `__ with vendor-specific class
-If you have a special requirement, `usbd_app_driver_get_cb()` can be used to write your own class driver without modifying the stack. Here is how the RPi team added their reset interface `raspberrypi/pico-sdk#197 `_
+If you have a special requirement, ``usbd_app_driver_get_cb()`` can be used to write your own class driver without modifying the stack. Here is how the RPi team added their reset interface `raspberrypi/pico-sdk#197 `_
Host Stack
==========
@@ -77,10 +74,10 @@ Host Stack
- Human Interface Device (HID): Keyboard, Mouse, Generic
- Mass Storage Class (MSC)
- Communication Device Class: CDC-ACM
-- Vendor serial over USB: FTDI, CP210x, CH34x
+- Vendor serial over USB: FTDI, CP210x, CH34x, PL2303
- Hub with multiple-level support
-Similar to the Device Stack, if you have a special requirement, `usbh_app_driver_get_cb()` can be used to write your own class driver without modifying the stack.
+Similar to the Device Stack, if you have a special requirement, ``usbh_app_driver_get_cb()`` can be used to write your own class driver without modifying the stack.
Power Delivery Stack
====================
@@ -170,7 +167,9 @@ Supported CPUs
| | +-------------------+--------+------+-----------+------------------------+-------------------+
| | | 54, 55 | ✔ | | ✔ | lpc_ip3511 | |
| +---------+-------------------+--------+------+-----------+------------------------+-------------------+
-| | MCX | N9, A15 | ✔ | | ✔ | ci_fs, ci_hs | |
+| | MCX | N9 | ✔ | | ✔ | ci_fs, ci_hs | |
+| | +-------------------+--------+------+-----------+------------------------+-------------------+
+| | | A15 | ✔ | | | ci_fs | |
+--------------+---------+-------------------+--------+------+-----------+------------------------+-------------------+
| Raspberry Pi | RP2040, RP2350 | ✔ | ✔ | ✖ | rp2040, pio_usb | |
+--------------+-----+-----------------------+--------+------+-----------+------------------------+-------------------+
@@ -184,15 +183,13 @@ Supported CPUs
+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+
| Sony | CXD56 | ✔ | ✖ | ✔ | cxd56 | |
+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+
-| ST STM32 | F0 | ✔ | ✖ | ✖ | stm32_fsdev | |
+| ST STM32 | F0, F3, L0, L1, L5, WBx5 | ✔ | ✖ | ✖ | stm32_fsdev | |
| +----+------------------------+--------+------+-----------+------------------------+-------------------+
| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | |
| | +------------------------+--------+------+-----------+------------------------+-------------------+
| | | 105, 107 | ✔ | ✔ | ✖ | dwc2 | |
| +----+------------------------+--------+------+-----------+------------------------+-------------------+
-| | F2, F4, F7, H7 | ✔ | ✔ | ✔ | dwc2 | |
-| +-----------------------------+--------+------+-----------+------------------------+-------------------+
-| | F3 | ✔ | ✖ | ✖ | stm32_fsdev | |
+| | F2, F4, F7, H7, H7RS | ✔ | ✔ | ✔ | dwc2 | |
| +-----------------------------+--------+------+-----------+------------------------+-------------------+
| | C0, G0, H5 | ✔ | | ✖ | stm32_fsdev | |
| +-----------------------------+--------+------+-----------+------------------------+-------------------+
@@ -202,25 +199,19 @@ Supported CPUs
| +----+------------------------+--------+------+-----------+------------------------+-------------------+
| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | |
| | +------------------------+--------+------+-----------+------------------------+-------------------+
-| | | 4x5, 4x6 | ✔ | ✔ | ✖ | dwc2 | |
+| | | 4x5, 4x6, 4+ | ✔ | ✔ | ✖ | dwc2 | |
| +----+------------------------+--------+------+-----------+------------------------+-------------------+
-| | L4+ | ✔ | ✔ | ✖ | dwc2 | |
-| +-----------------------------+--------+------+-----------+------------------------+-------------------+
-| | L5 | ✔ | ✖ | ✖ | stm32_fsdev | |
+| | N6 | ✔ | ✔ | ✔ | dwc2 | |
| +----+------------------------+--------+------+-----------+------------------------+-------------------+
| | U5 | 535, 545 | ✔ | | ✖ | stm32_fsdev | |
| | +------------------------+--------+------+-----------+------------------------+-------------------+
| | | 575, 585 | ✔ | ✔ | ✖ | dwc2 | |
| | +------------------------+--------+------+-----------+------------------------+-------------------+
| | | 59x,5Ax,5Fx,5Gx | ✔ | ✔ | ✔ | dwc2 | |
-| +----+------------------------+--------+------+-----------+------------------------+-------------------+
-| | WBx5 | ✔ | ✖ | ✖ | stm32_fsdev | |
-+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+
++--------------+----+------------------------+--------+------+-----------+------------------------+-------------------+
| TI | MSP430 | ✔ | ✖ | ✖ | msp430x5xx | |
| +-----------------------------+--------+------+-----------+------------------------+-------------------+
-| | MSP432E4 | ✔ | | ✖ | musb | |
-| +-----------------------------+--------+------+-----------+------------------------+-------------------+
-| | TM4C123 | ✔ | | ✖ | musb | |
+| | MSP432E4, TM4C123 | ✔ | | ✖ | musb | |
+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+
| ValentyUSB | eptri | ✔ | ✖ | ✖ | eptri | |
+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+
diff --git a/docs/contributing/code_of_conduct.rst b/docs/contributing/code_of_conduct.rst
deleted file mode 120000
index fb1859c75..000000000
--- a/docs/contributing/code_of_conduct.rst
+++ /dev/null
@@ -1 +0,0 @@
-.. include:: ../../CODE_OF_CONDUCT.rst
\ No newline at end of file
diff --git a/docs/contributing/code_of_conduct.rst b/docs/contributing/code_of_conduct.rst
new file mode 100644
index 000000000..fb1859c75
--- /dev/null
+++ b/docs/contributing/code_of_conduct.rst
@@ -0,0 +1 @@
+.. include:: ../../CODE_OF_CONDUCT.rst
\ No newline at end of file
diff --git a/docs/contributing/porting.rst b/docs/contributing/porting.rst
index f81d98782..c3076354c 100644
--- a/docs/contributing/porting.rst
+++ b/docs/contributing/porting.rst
@@ -9,7 +9,7 @@ data transactions on different endpoints. Porting is the process of adding low-l
the rest of the common stack. Once the low-level is implemented, it is very easy to add USB support
for the microcontroller to other projects, especially those already using TinyUSB such as CircuitPython.
-Below are instructions on how to get the cdc_msc device example running on a new microcontroller. Doing so includes adding the common code necessary for other uses while minimizing other extra code. Whenever you see a phrase or word in <> it should be replaced.
+Below are instructions on how to get the cdc_msc device example running on a new microcontroller. Doing so includes adding the common code necessary for other uses while minimizing other extra code. Whenever you see a phrase or word in ``<>`` it should be replaced.
Register defs
-------------
@@ -18,25 +18,27 @@ The first step to adding support is including the register definitions and start
microcontroller in TinyUSB. We write the TinyUSB implementation against these structs instead of higher level functions to keep the code small and to prevent function name collisions in linking of larger projects. For ARM microcontrollers this is the CMSIS definitions. They should be
placed in the ``hw/mcu//`` directory.
-Once this is done, create a directory in ``hw/bsp/`` for the specific board you are using to test the code. (Duplicating an existing board's directory is the best way to get started.) The board should be a readily available development board so that others can also test.
+Once this is done, create a directory in ``hw/bsp/`` for the specific board you are using to test the code (duplicating an existing board's directory is the best way to get started). The board should be a readily available development board so that others can also test.
Build
-----
Now that those directories are in place, we can start our iteration process to get the example building successfully. To build, run from the root of TinyUSB:
-``make -C examples/device/cdc_msc BOARD=``
+.. code-block:: bash
-Unless, you've read ahead, this will fail miserably. Now, lets get it to fail less by updating the files in the board directory. The code in the board's directory is responsible for setting up the microcontroller's clocks and pins so that USB works. TinyUSB itself only operates on the USB peripheral. The board directory also includes information what files are needed to build the example.
+ make -C examples/device/cdc_msc BOARD=
-One of the first things to change is the ``-DCFG_TUSB_MCU`` cflag in the ``board.mk`` file. This is used to tell TinyUSB what platform is being built. So, add an entry to ``src/tusb_option.h`` and update the CFLAG to match.
+Unless you've read ahead, this will fail miserably. Now, lets get it to fail less by updating the files in the board directory. The code in the board's directory is responsible for setting up the microcontroller's clocks and pins so that USB works. TinyUSB itself only operates on the USB peripheral. The board directory also includes information what files are needed to build the example.
-Update ``board.mk``\ 's VENDOR and CHIP_FAMILY values when creating the directory for the struct files. Duplicate one of the other sources from ``src/portable`` into ``src/portable//`` and delete all of the implementation internals. We'll cover what everything there does later. For now, get it compiling.
+One of the first things to change is the ``-DCFG_TUSB_MCU`` C flag in the ``board.mk`` file. This is used to tell TinyUSB what platform is being built. So, add an entry to ``src/tusb_option.h`` and update the ``CFLAGS`` to match.
+
+Update ``board.mk``'s VENDOR and CHIP_FAMILY values when creating the directory for the struct files. Duplicate one of the other sources from ``src/portable`` into ``src/portable//`` and delete all of the implementation internals. We'll cover what everything there does later. For now, get it compiling.
Implementation
--------------
-At this point you should get an error due to an implementation issue and hopefully the build is setup for the new MCU. You will still need to modify the ``board.mk`` to include specific CFLAGS, the linker script, linker flags, source files, include directories. All file paths are relative to the top of the TinyUSB repo.
+At this point you should get an error due to an implementation issue and hopefully the build is setup for the new MCU. You will still need to modify the ``board.mk`` to include specific ``CFLAGS``, the linker script, linker flags, source files, include directories. All file paths are relative to the top of the TinyUSB repo.
Board Support (BSP)
^^^^^^^^^^^^^^^^^^^
@@ -45,17 +47,17 @@ The board support code is only used for self-contained examples and testing. It
It is located in ``hw/bsp//board_.c``.
-board_init
-~~~~~~~~~~
+``board_init()``
+~~~~~~~~~~~~~~~~
-``board_init`` is responsible for starting the MCU, setting up the USB clock and USB pins. It is also responsible for initializing LED pins.
+``board_init()`` is responsible for starting the MCU, setting up the USB clock and USB pins. It is also responsible for initializing LED pins.
One useful clock debugging technique is to set up a PWM output at a known value such as 500hz based on the USB clock so that you can verify it is correct with a logic probe or oscilloscope.
Setup your USB in a crystal-less mode when available. That makes the code easier to port across boards.
-board_led_write
-~~~~~~~~~~~~~~~
+``board_led_write()``
+~~~~~~~~~~~~~~~~~~~~~
Feel free to skip this until you want to verify your demo code is running. To implement, set the pin corresponding to the led to output a value that lights the LED when ``state`` is true.
@@ -64,48 +66,48 @@ OS Abstraction Layer (OSAL)
The OS Abstraction Layer is responsible for providing basic data structures for TinyUSB that may allow for concurrency when used with an RTOS. Without an RTOS it simply handles concurrency issues between the main code and interrupts. The code is almost entirely agnostic of MCU and lives in ``src/osal``.
-In RTOS configurations, tud_task()/tuh_task() blocks behind a synchronization structure when the event queue is empty, so that the scheduler may give the CPU to a different task. To take advantage of the library's capability to yield the CPU when there are no actionable USB device events, ensure that the `CFG_TUSB_OS` symbol is defined, e.g `OPT_OS_FREERTOS` enables the FreeRTOS scheduler to schedule other threads than that which calls `tud_task()/tuh_task()`.
+In RTOS configurations, ``tud_task()``/``tuh_task()`` blocks behind a synchronization structure when the event queue is empty, so that the scheduler may give the CPU to a different task. To take advantage of the library's capability to yield the CPU when there are no actionable USB device events, ensure that the ``CFG_TUSB_OS`` symbol is defined, e.g ``OPT_OS_FREERTOS`` enables the FreeRTOS scheduler to schedule other threads than that which calls ``tud_task()``/``tuh_task()``.
Device API
^^^^^^^^^^
-After the USB device is setup, the USB device code works by processing events on the main thread (by calling ``tud_task``\ ). These events are queued by the USB interrupt handler. So, there are three parts to the device low-level API: device setup, endpoint setup and interrupt processing.
+After the USB device is setup, the USB device code works by processing events on the main thread (by calling ``tud_task()``). These events are queued by the USB interrupt handler. So, there are three parts to the device low-level API: device setup, endpoint setup and interrupt processing.
All of the code for the low-level device API is in ``src/portable///dcd_.c``.
Device Setup
~~~~~~~~~~~~
-dcd_init
-""""""""
+``dcd_init()``
+""""""""""""""
Initializes the USB peripheral for device mode and enables it.
This function should enable internal D+/D- pull-up for enumeration.
-dcd_int_enable / dcd_int_disable
-""""""""""""""""""""""""""""""""
+``dcd_int_enable()`` / ``dcd_int_disable()``
+""""""""""""""""""""""""""""""""""""""""""""
Enables or disables the USB device interrupt(s). May be used to prevent concurrency issues when mutating data structures shared between main code and the interrupt handler.
-dcd_int_handler
-"""""""""""""""
+``dcd_int_handler()``
+"""""""""""""""""""""
Processes all the hardware generated events e.g Bus reset, new data packet from host etc ... It will be called by application in the MCU USB interrupt handler.
-dcd_set_address
-"""""""""""""""
+``dcd_set_address()``
+"""""""""""""""""""""
Called when the device is given a new bus address.
If your peripheral automatically changes address during enumeration (like the nrf52) you may leave this empty and also no queue an event for the corresponding SETUP packet.
-dcd_remote_wakeup
-"""""""""""""""""
+``dcd_remote_wakeup()``
+"""""""""""""""""""""""
Called to remote wake up host when suspended (e.g hid keyboard)
-dcd_connect / dcd_disconnect
-""""""""""""""""""""""""""""
+``dcd_connect()`` / ``dcd_disconnect()``
+""""""""""""""""""""""""""""""""""""""""
Connect or disconnect the data-line pull-up resistor. Define only if MCU has an internal pull-up. (BSP may define for MCU without internal pull-up.)
@@ -114,8 +116,8 @@ Special events
You must let TinyUSB know when certain events occur so that it can continue its work. There are a few methods you can call to queue events for TinyUSB to process.
-dcd_event_bus_signal
-""""""""""""""""""""
+``dcd_event_bus_signal()``
+""""""""""""""""""""""""""
There are a number of events that your peripheral may communicate about the state of the bus. Here is an overview of what they are. Events in **BOLD** must be provided for TinyUSB to work.
@@ -125,51 +127,51 @@ There are a number of events that your peripheral may communicate about the stat
Calls to this look like:
-.. code-block::
+.. code-block:: c
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
-The first ``0`` is the USB peripheral number. Statically saying 0 is common for single USB device MCUs.
+The first ``0`` is the USB peripheral number. Statically saying ``0`` is common for single USB device MCUs.
The ``true`` indicates the call is from an interrupt handler and will always be the case when porting in this way.
-dcd_setup_received
-""""""""""""""""""
+``dcd_setup_received()``
+""""""""""""""""""""""""
SETUP packets are a special type of transaction that can occur at any time on the control endpoint, numbered ``0``. Since they are unique, most peripherals have special handling for them. Their data is always 8 bytes in length as well.
Calls to this look like:
-.. code-block::
+.. code-block:: c
dcd_event_setup_received(0, setup, true);
-As before with ``dcd_event_bus_signal`` the first argument is the USB peripheral number and the third is true to signal its being called from an interrupt handler. The middle argument is byte array of length 8 with the contents of the SETUP packet. It can be stack allocated because it is copied into the queue.
+As before with ``dcd_event_bus_signal()`` the first argument is the USB peripheral number and the third is true to signal its being called from an interrupt handler. The middle argument is byte array of length 8 with the contents of the SETUP packet. It can be stack allocated because it is copied into the queue.
Endpoints
~~~~~~~~~
Endpoints are the core of the USB data transfer process. They come in a few forms such as control, isochronous, bulk, and interrupt. We won't cover the details here except with some caveats in open below. In general, data is transferred by setting up a buffer of a given length to be transferred on a given endpoint address and then waiting for an interrupt to signal that the transfer is finished. Further details below.
-Endpoints within USB have an address which encodes both the number and direction of an endpoint. TinyUSB provides ``tu_edpt_number`` and ``tu_edpt_dir`` to unpack this data from the address. Here is a snippet that does it.
+Endpoints within USB have an address which encodes both the number and direction of an endpoint. TinyUSB provides ``tu_edpt_number()`` and ``tu_edpt_dir()`` to unpack this data from the address. Here is a snippet that does it.
-.. code-block::
+.. code-block:: c
uint8_t epnum = tu_edpt_number(ep_addr);
uint8_t dir = tu_edpt_dir(ep_addr);
-dcd_edpt_open
-"""""""""""""
+``dcd_edpt_open()``
+"""""""""""""""""""
Opening an endpoint is done for all non-control endpoints once the host picks a configuration that the device should use. At this point, the endpoint should be enabled in the peripheral and configured to match the endpoint descriptor. Pay special attention to the direction of the endpoint you can get from the helper methods above. It will likely change what registers you are setting.
Also make sure to enable endpoint specific interrupts.
-dcd_edpt_close
-""""""""""""""
+``dcd_edpt_close()``
+""""""""""""""""""""
Close an endpoint. his function is used for implementing alternate settings.
@@ -177,10 +179,10 @@ After calling this, the device should not respond to any packets directed toward
Implementation is optional. Must be called from the USB task. Interrupts could be disabled or enabled during the call.
-dcd_edpt_xfer
-"""""""""""""
+``dcd_edpt_xfer()``
+"""""""""""""""""""
-``dcd_edpt_xfer`` is responsible for configuring the peripheral to send or receive data from the host. "xfer" is short for "transfer". **This is one of the core methods you must implement for TinyUSB to work (one other is the interrupt handler).** Data from the host is the OUT direction and data to the host is IN. It is used for all endpoints including the control endpoint 0. Make sure to handle the zero-length packet STATUS packet on endpoint 0 correctly. It may be a special transaction to the peripheral.
+``dcd_edpt_xfer()`` is responsible for configuring the peripheral to send or receive data from the host. "xfer" is short for "transfer". **This is one of the core methods you must implement for TinyUSB to work (one other is the interrupt handler).** Data from the host is the OUT direction and data to the host is IN. It is used for all endpoints including the control endpoint 0. Make sure to handle the zero-length packet STATUS packet on endpoint 0 correctly. It may be a special transaction to the peripheral.
Besides that, all other transactions are relatively straight-forward. The endpoint address provides the endpoint
number and direction which usually determines where to write the buffer info. The buffer and its length are usually
@@ -195,21 +197,21 @@ Others (like the nRF52) may need each USB packet queued individually. To make th
some state for yourself and queue up an intermediate USB packet from the interrupt handler.
Once the transaction is going, the interrupt handler will notify TinyUSB of transfer completion.
-During transmission, the IN data buffer is guaranteed to remain unchanged in memory until the ``dcd_xfer_complete`` function is called.
+During transmission, the IN data buffer is guaranteed to remain unchanged in memory until the ``dcd_xfer_complete()`` function is called.
-The dcd_edpt_xfer function must never add zero-length-packets (ZLP) on its own to a transfer. If a ZLP is required,
-then it must be explicitly sent by the stack calling dcd_edpt_xfer(), by calling dcd_edpt_xfer() a second time with len=0.
+The ``dcd_edpt_xfer()`` function must never add zero-length-packets (ZLP) on its own to a transfer. If a ZLP is required,
+then it must be explicitly sent by the stack calling ``dcd_edpt_xfer()``, by calling ``dcd_edpt_xfer()`` a second time with len=0.
For control transfers, this is automatically done in ``usbd_control.c``.
-At the moment, only a single buffer can be transmitted at once. There is no provision for double-buffering. new dcd_edpt_xfer() will not
-be called again on the same endpoint address until the driver calls dcd_xfer_complete() (except in cases of USB resets).
+At the moment, only a single buffer can be transmitted at once. There is no provision for double-buffering. new ``dcd_edpt_xfer()`` will not
+be called again on the same endpoint address until the driver calls ``dcd_xfer_complete()`` (except in cases of USB resets).
-dcd_xfer_complete
-"""""""""""""""""
+``dcd_xfer_complete()``
+"""""""""""""""""""""""
-Once a transfer completes you must call dcd_xfer_complete from the USB interrupt handler to let TinyUSB know that a transaction has completed. Here is a sample call:
+Once a transfer completes you must call ``dcd_xfer_complete()`` from the USB interrupt handler to let TinyUSB know that a transaction has completed. Here is a sample call:
-.. code-block::
+.. code-block:: c
dcd_event_xfer_complete(0, ep_addr, xfer->actual_len, XFER_RESULT_SUCCESS, true);
@@ -219,23 +221,23 @@ The arguments are:
* the USB peripheral number
* the endpoint address
-* the actual length of the transfer. (OUT transfers may be smaller than the buffer given in ``dcd_edpt_xfer``\ )
+* the actual length of the transfer. (OUT transfers may be smaller than the buffer given in ``dcd_edpt_xfer()``)
* the result of the transfer. Failure isn't handled yet.
* ``true`` to note the call is from an interrupt handler.
-dcd_edpt_stall / dcd_edpt_clear_stall
-"""""""""""""""""""""""""""""""""""""
+``dcd_edpt_stall()`` / ``dcd_edpt_clear_stall()``
+"""""""""""""""""""""""""""""""""""""""""""""""""
-Stalling is one way an endpoint can indicate failure such as when an unsupported command is transmitted. The pair of ``dcd_edpt_stall``\ , ``dcd_edpt_clear_stall`` help manage the stall state of all endpoints.
+Stalling is one way an endpoint can indicate failure such as when an unsupported command is transmitted. The pair of ``dcd_edpt_stall()``, ``dcd_edpt_clear_stall()`` help manage the stall state of all endpoints.
Woohoo!
-------
-At this point you should have everything working! ;-) Of course, you may not write perfect code. Here are some tips and tricks for debugging.
+At this point you should have everything working! 🙂 Of course, you may not write perfect code. Here are some tips and tricks for debugging.
Use `WireShark `_ or `a Beagle `_ to sniff the USB traffic. When things aren't working its likely very early in the USB enumeration process. Figuring out where can help clue in where the issue is. For example:
* If the host sends a SETUP packet and its not ACKed then your USB peripheral probably isn't started correctly.
-* If the peripheral is started correctly but it still didn't work, then verify your usb clock is correct. (You did output a PWM based on it right? ;-) )
-* If the SETUP packet is ACKed but nothing is sent back then you interrupt handler isn't queueing the setup packet correctly. (Also, if you are using your own code instead of an example ``tud_task`` may not be called.) If that's OK, the ``dcd_xfer_complete`` may not be setting up the next transaction correctly.
+* If the peripheral is started correctly but it still didn't work, then verify your usb clock is correct. (You did output a PWM based on it right? 🙂)
+* If the SETUP packet is ACKed but nothing is sent back then you interrupt handler isn't queueing the setup packet correctly. (Also, if you are using your own code instead of an example ``tud_task()`` may not be called.) If that's OK, the ``dcd_xfer_complete()`` may not be setting up the next transaction correctly.
diff --git a/docs/info/changelog.rst b/docs/info/changelog.rst
index 0a34c0842..6024bb9e3 100644
--- a/docs/info/changelog.rst
+++ b/docs/info/changelog.rst
@@ -15,12 +15,12 @@ General
- Better support dcache, make sure all usb-transferred buffer are cache line aligned and occupy full cache line
- Build ARM IAR with CircleCI
-- Improve HIL with dual/host_info_to_device_cdc optional for pico/pico2, enable dwc2 dma test
+- Improve HIL with `dual/host_info_to_device_cdc`` optional for pico/pico2, enable dwc2 dma test
API Changes
-----------
-- Change signature of ``tusb_init(rhport, tusb_rhport_init_t*)``, tusb_init(void) is now deprecated but still available for backward compatibility
+- Change signature of ``tusb_init(rhport, tusb_rhport_init_t*)``, ``tusb_init(void)`` is now deprecated but still available for backward compatibility
- Add new ``tusb_int_handler(rhport, in_isr)``
- Add time-related APIs: ``tusb_time_millis_api()`` and ``tusb_time_delay_ms_api()`` for non-RTOS, required for some ports/configuration
- New configuration macros:
@@ -37,17 +37,17 @@ Controller Driver (DCD & HCD)
- Add DMA support for both device and host controller
- Add host driver support including: full/high speed, control/bulk/interrupt (CBI) transfer, split CBI i.e FS/LS attached via highspeed hub, hub support
-- RP2: implement dcd_edpt_iso_alloc() and dcd_edpt_iso_activate() for isochronous endpoint
+- RP2: implement ``dcd_edpt_iso_alloc()`` and ``dcd_edpt_iso_activate()`` for isochronous endpoint
- iMXRT1170 support M4 core
Device Stack
------------
- Vendor Fix class reset
-- NCM fix recursions in tud_network_recv_renew()
-- Audio fix align issue of _audiod_fct.alt_setting
+- NCM fix recursions in ``tud_network_recv_renew()``
+- Audio fix align issue of ``_audiod_fct.alt_setting``
- UVC support format frame based
-- Change dcd_dcache_() return type from void to bool
+- Change ``dcd_dcache_()`` return type from void to bool
- HID add Usage Table for Physical Input Device Page (0x0F)
Host Stack
@@ -89,20 +89,20 @@ Controller Driver (DCD & HCD)
- Add support for ch32 usbd e.g ch32v203
- Add support for STM32G4 and STM32U5 microcontrollers.
- Fix h5 (32-bit) errata 2.15.1: Buffer description table update completes after CTR interrupt triggers
- - ISO EP buffer allocation improvements, implement dcd_edpt_close_all()
+ - ISO EP buffer allocation improvements, implement ``dcd_edpt_close_all()``
- Fix ch32v203 race condition and stability issue with
- fix ch32v203 seems to unconditionally accept ZLP on EP0 OUT.
- fix v203 race condition between rx bufsize and RX_STAT which cause PMAOVR, occurs with WRITE10
- - correctly handle setup prepare at dcd_edpt0_status_complete(), which fixes the race condition with windows where we could miss setup packet (setup bit set, but count = 0)
+ - correctly handle setup prepare at ``dcd_edpt0_status_complete()``, which fixes the race condition with windows where we could miss setup packet (setup bit set, but count = 0)
- MAX3421E
- Add support for rp2040, esp32 (c3, c6, h2, etc..)
- - Add hcd_deinit() for max3421
+ - Add ``hcd_deinit()`` for max3421
- Retry NAK handling next frame to reduce CPU and SPI bus usage
- - add cpuctl and pinctl to tuh_configure() option for max3421
+ - add ``cpuctl`` and ``pinctl`` to ``tuh_configure()`` option for max3421
- Implement hcd abort transfer for Max3421
- Properly Handle NAK Response in MAX3421E driver: correctly switch and skip writing to 2 FIFOs when NAK received. Otherwise, the driver may hang in certain conditions.
@@ -114,7 +114,7 @@ Controller Driver (DCD & HCD)
- nRF
- - Fix dcd_edpt_open for iso endpoint
+ - Fix ``dcd_edpt_open()`` for iso endpoint
- Handle ISOOUT CRC errors
- Add compile support with old nordic sdk
- Fix a few race conditions
@@ -141,7 +141,7 @@ Controller Driver (DCD & HCD)
Device Stack
------------
-- Add tud_deinit() and class driver deinit() to deinitialize TinyUSB device stack.
+- Add ``tud_deinit()`` and ``class driver deinit()`` to deinitialize TinyUSB device stack.
- Add support for generic SOF callback.
- Add set address recovery time 2ms per USB spec.
@@ -157,7 +157,7 @@ Device Stack
- CDC
- - Add tud_cdc_configure_fifo() to make RX/TX buffer persistent (not clear when disconnected)
+ - Add ``tud_cdc_configure_fifo()`` to make RX/TX buffer persistent (not clear when disconnected)
- Add missing capability bit for CDC ACM serial break support
- Enhanced CDC class with better handling of large data transmissions.
- Add missing capability bit for CDC ACM serial break support
@@ -175,39 +175,39 @@ Device Stack
- Net
- Rewrite of NCM device driver to improve throughput
- - removed obsolete tud_network_link_state_cb()
+ - removed obsolete ``tud_network_link_state_cb()``
- USBTMC Added notification support
- Vendor
- Migrate to new endpoint stream API, support non-buffered TX/RX
- - Add ZLP for write() when needed
+ - Add ZLP for ``write()`` when needed
- Video
- Enhance UVC descriptors and example
- Video Added support for USB Video Class (UVC) with MJPEG.
- Fix multiple interfaces, add an example of 2ch video capture.
- - Fix race for tud_video_n_streaming check
+ - Fix race for ``tud_video_n_streaming()`` check
Host Stack
----------
-- Added tuh_deinit() to de-initialize TinyUSB host stack.
+- Added ``tuh_deinit()`` to de-initialize TinyUSB host stack.
- Added support for new USB mass storage class APIs.
- Improved error handling and retry mechanisms for unstable devices.
- CDC Serial
- Add support for ch34x
- - Allow to overwrite CFG_TUH_CDC_FTDI/CP210X/CH32X_VID_PID_LIST
+ - Allow to overwrite ``CFG_TUH_CDC_FTDI/CP210X/CH32X_VID_PID_LIST``
- Enhanced stability of CDC-ACM devices during enumeration.
- HID
- - Add tuh_hid_receive_abort()
- - Add tuh_hid_get_report()
+ - Add ``tuh_hid_receive_abort()``
+ - Add ``tuh_hid_get_report()``
- Hub
@@ -224,14 +224,14 @@ Host Stack
- Remove submodules and use python script to manage repo dependencies #1947
- Add CMake support for most families and boards, move build file from tools/ to examples/build_system
- Add ETM trace support with JTrace for nrf52840, nrf5340, mcb1857, stm32h743eval, ra6m5
-- [osal] Make it possible to override the osal_task_delay() in osal_none
+- [osal] Make it possible to override the ``osal_task_delay()`` in osal_none
- Add CDC+UAC2 composite device example
- Enhance Hardware-in-the-loop (HIL) testing with more boards: rp2040, stm32l412nucleo, stm32f746disco, lpcxpresso43s67
Controller Driver (DCD & HCD)
-----------------------------
-- Add new ISO endpoint API: dcd_edpt_iso_alloc() and dcd_edpt_iso_activate()
+- Add new ISO endpoint API: ``dcd_edpt_iso_alloc()`` and ``dcd_edpt_iso_activate()``
- Remove legacy driver st/synopsys
- EHCI
@@ -244,10 +244,10 @@ Controller Driver (DCD & HCD)
- Fix error on EHCI causes xfer error in non-queued qhd which cause memory fault
- Un-roll recursive hub removal with usbh queue
- Fix issue when removing queue head
- - Implement hcd_edpt_abort_xfer()
+ - Implement ``hcd_edpt_abort_xfer()``
- use standard USB complete interrupt instead of custom chipidea async/period interrupt to be more compatible with other ehci implementation
- refactor usb complete & error isr processing, merge, update. Fix EHCI QHD reuses QTD on wrong endpoint
- - Improve bus reset, fix send_setup() not carried out if halted previously
+ - Improve bus reset, fix ``send_setup()`` not carried out if halted previously
- Fix clear qhd halted bit if not caused by STALL protocol to allow for next transfer
- ChipIdea Highspeed
@@ -273,12 +273,12 @@ Controller Driver (DCD & HCD)
- rp2040
- [dcd] Make writes to SIE_CTRL aware of concurrent access
- - [hcd] add hcd_frame_number(), hcd_edpt_abort_xfer() for pio-usb host
+ - [hcd] add ``hcd_frame_number()``, ``hcd_edpt_abort_xfer()`` for pio-usb host
- stm32 fsdev:
- Add STM32L5 support
- - Implement dcd_edpt_iso_alloc() and dcd_edpt_iso_activate()
+ - Implement ``dcd_edpt_iso_alloc()`` and ``dcd_edpt_iso_activate()``
- OHCI
@@ -292,7 +292,7 @@ Controller Driver (DCD & HCD)
Device Stack
------------
-- Add optional hooks tud_event_hook_cb()
+- Add optional hooks ``tud_event_hook_cb()``
- Audio (UAC2)
- Fix feedback EP buffer alignment.
@@ -310,12 +310,12 @@ Device Stack
- MIDI
- - Fix stream_write() always writes system messages to cable 0
+ - Fix ``stream_write()`` always writes system messages to cable 0
- Fix incorrect NOTE_ON, NOTE_OFF definitions
- USBTMC: Fix tmc488 bit order
-- Vendor: fix read()/write() race condition
+- Vendor: fix ``read()``/``write()`` race condition
- Video (UVC)
@@ -326,26 +326,26 @@ Host Stack
- USBH
- - Add new APIs: tuh_interface_set(), tuh_task_event_ready(), tuh_edpt_abort_xfer(), tuh_rhport_reset_bus(), tuh_rhport_is_active()
+ - Add new APIs: ``tuh_interface_set()``, ``tuh_task_event_ready()``, ``tuh_edpt_abort_xfer()``, ``tuh_rhport_reset_bus()``, ``tuh_rhport_is_active()``
- Fix issue when device generate multiple attach/detach/attach when plugging in
- Prefer application callback over built-in driver on transfer complete event
- - Correct hcd_edpt_clear_stall() API signature
+ - Correct ``hcd_edpt_clear_stall()`` API signature
- Separate bus reset delay and contact debouncing delay in enumeration
- - Support usbh_app_driver_get_cb() for application drivers
+ - Support ``usbh_app_driver_get_cb()`` for application drivers
- Fix usbh enumeration removal race condition
- - Add optional hooks tuh_event_hook_cb()
+ - Add optional hooks ``tuh_event_hook_cb()``
- CDC
- - Breaking: change tuh_cdc_itf_get_info() to use tuh_itf_info_t instead of tuh_cdc_info_t
+ - Breaking: change ``tuh_cdc_itf_get_info()`` to use tuh_itf_info_t instead of tuh_cdc_info_t
- Fix cdc host enumeration issue when device does not support line request
- Add support for vendor usb2uart serial: ftdi, cp210x, ch9102f
- - Improve sync control API e.g tuh_cdc_set_control_line_state(), tuh_cdc_set_line_coding()
+ - Improve sync control API e.g ``tuh_cdc_set_control_line_state()``, ``tuh_cdc_set_line_coding()``
- HID
- - Add new APIs tuh_hid_send_report(), tuh_hid_itf_get_info(), tuh_hid_receive_ready(), tuh_hid_send_ready(), tuh_hid_set_default_protocol()
- - Change meaning of CFG_TUH_HID to total number of HID interfaces supported. Previously CFG_TUH_HID is max number of interfaces per device which is rather limited and consume more resources than needed.
+ - Add new APIs ``tuh_hid_send_report()``, ``tuh_hid_itf_get_info()``, ``tuh_hid_receive_ready()``, ``tuh_hid_send_ready()``, ``tuh_hid_set_default_protocol()``
+ - Change meaning of CFG_TUH_HID to total number of HID interfaces supported. Previously ``CFG_TUH_HID`` is max number of interfaces per device which is rather limited and consume more resources than needed.
- HUB
@@ -354,7 +354,7 @@ Host Stack
- MSC
- - Fix bug in tuh_msc_ready()
+ - Fix bug in ``tuh_msc_ready()``
- Fix host msc get maxlun not using aligned section memory
0.15.0
@@ -385,7 +385,7 @@ Controller Driver (DCD & HCD)
- [rp2040]
- [dcd] Implement workaround for Errata 15. This enable SOF when bulk-in endpoint is in use and reduce its bandwidth to only 80%
- - [hcd] Fix shared irq slots filling up when hcd_init() is called multiple times
+ - [hcd] Fix shared irq slots filling up when ``hcd_init()`` is called multiple times
- [hcd] Support host bulk endpoint using hw "interrupt" endpoint. Note speed limit is 64KB/s
- [samd][dcd] Add support for ISO endpoint
@@ -410,12 +410,12 @@ Device Stack
- [HID]
- Add FIDO descriptor template
- - change length in tud_hid_report_complete_cb() from uint8 to uint16
+ - change length in ``tud_hid_report_complete_cb()`` from ``uint8_t`` to ``uint16_t``
- [CDC]
- Fix autoflush for FIFO < MPS
- - Fix tx fifo memory overflown when DTR is not set and tud_cdc_write() is called repeatedly with large enough data
+ - Fix tx fifo memory overflown when DTR is not set and ``tud_cdc_write()`` is called repeatedly with large enough data
- [USBTMC] Fix packet size with highspeed
@@ -423,7 +423,7 @@ Host Stack
----------
- Retry a few times with transfers in enumeration since device can be unstable when starting up
-- [MSC] Rework host masstorage API. Add new **host/msc_file_explorer** example
+- [MSC] Rework host masstorage API. Add new ``host/msc_file_explorer`` example
- [CDC]
- Add support for host cdc
@@ -433,22 +433,22 @@ Host Stack
======
- Improve compiler support for CCRX and IAR
-- Add timeout to osal_queue_receive()
-- Add tud_task_ext(timeout, in_isr) as generic version of tud_task(). Same as tuh_task_ext(), tuh_task()
-- Enable more warnings -Wnull-dereference -Wuninitialized -Wunused -Wredundant-decls -Wconversion
+- Add timeout to ``osal_queue_receive()``
+- Add ``tud_task_ext(timeout, in_isr)`` as generic version of ``tud_task()``. Same as ``tuh_task_ext()``, ``tuh_task()``
+- Enable more warnings ``-Wnull-dereference -Wuninitialized -Wunused -Wredundant-decls -Wconversion``
- Add new examples
- - host/bare_api to demonstrate generic (app-level) enumeration and endpoint transfer
- - dual/host_hid_to_device_cdc to run both device and host stack concurrently, get HID report from host and print out to device CDC. This example only work with multiple-controller MCUs and rp2040 with the help of pio-usb as added controller.
+ - ``host/bare_api`` to demonstrate generic (app-level) enumeration and endpoint transfer
+ - ``dual/host_hid_to_device_cdc`` to run both device and host stack concurrently, get HID report from host and print out to device CDC. This example only work with multiple-controller MCUs and rp2040 with the help of pio-usb as added controller.
Controller Driver (DCD & HCD)
-----------------------------
- Enhance rhports management to better support dual roles
- - CFG_TUD_ENABLED/CFG_TUH_ENABLED, CFG_TUD_MAX_SPEED/CFG_TUH_MAX_SPEED can be used to replace CFG_TUSB_RHPORT0_MODE/CFG_TUSB_RHPORT1_MODE
- - tud_init(rphort), tuh_init(rhport) can be used to init stack on specified roothub port (controller) instead of tusb_init(void)
-- Add dcd/hcd port specific defines `TUP_` (stand for tinyusb port-specific)
+ - ``CFG_TUD_ENABLED``/``CFG_TUH_ENABLED``, ``CFG_TUD_MAX_SPEED``/``CFG_TUH_MAX_SPEED`` can be used to replace ``CFG_TUSB_RHPORT0_MODE``/``CFG_TUSB_RHPORT1_MODE``
+ - ``tud_init(rphort)``, ``tuh_init(rhport)`` can be used to init stack on specified roothub port (controller) instead of ``tusb_init(void)``
+- Add dcd/hcd port specific defines ``TUP_`` (stand for tinyusb port-specific)
- [dwc2]
- Update to support stm32 h72x, h73x with only 1 otg controller
@@ -469,10 +469,10 @@ Device Stack
- [Audio] Add support for feedback endpoint computation
- - New API tud_audio_feedback_params_cb(), tud_audio_feedback_interval_isr().
+ - New API ``tud_audio_feedback_params_cb()``, ``tud_audio_feedback_interval_isr()``.
- Supported computation method are: frequency with fixed/float or power of 2. Feedback with fifo count is not yet supported.
- - Fix nitfs (should be 3) in TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR
- - Fix typo in audiod_rx_done_cb()
+ - Fix nitfs (should be 3) in ``TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR``
+ - Fix typo in ``audiod_rx_done_cb()``
- [DFU] Fix coexistence with other interfaces BTH, RNDIS
- [MSC] Fix inquiry response additional length field
@@ -481,23 +481,23 @@ Device Stack
Host Stack
----------
-- Add new API tuh_configure(rhport, cfg_id, cfg_param) for dynamnic port specific behavior configuration
+- Add new API ``tuh_configure(rhport, cfg_id, cfg_param)`` for dynamnic port specific behavior configuration
- [HID] Open OUT endpoint if available
- [Hub] hub clear port and device interrupts
- [USBH] Major improvement
- - Rework usbh control transfer with complete callback. New API tuh_control_xfer() though still only carry 1 usbh (no queueing) at a time.
- - Add generic endpoint transfer with tuh_edpt_open(), tuh_edpt_xfer(). Require `CFG_TUH_API_EDPT_XFER=1`
+ - Rework usbh control transfer with complete callback. New API ``tuh_control_xfer()`` though still only carry 1 usbh (no queueing) at a time.
+ - Add generic endpoint transfer with ``tuh_edpt_open()``, ``tuh_edpt_xfer()``. Require ``CFG_TUH_API_EDPT_XFER=1``
- Support app-level enumeration with new APIs
- - tuh_descriptor_get(), tuh_descriptor_get_device(), tuh_descriptor_get_configuration(), tuh_descriptor_get_hid_report()
- - tuh_descriptor_get_string(), tuh_descriptor_get_manufacturer_string(), tuh_descriptor_get_product_string(), tuh_descriptor_get_serial_string()
- - Also add _sync() as sync/blocking version for above APIs
+ - ``tuh_descriptor_get()``, ``tuh_descriptor_get_device()``, ``tuh_descriptor_get_configuration()``, ``tuh_descriptor_get_hid_report()``
+ - ``tuh_descriptor_get_string()``, ``tuh_descriptor_get_manufacturer_string()``, ``tuh_descriptor_get_product_string()``, ``tuh_descriptor_get_serial_string()``
+ - Also add ``_sync()`` as sync/blocking version for above APIs
0.13.0
======
-- [tu_fifo] Fix locked mutex when full, and return type in peek_n()
+- [tu_fifo] Fix locked mutex when full, and return type in ``peek_n()``
Controller Driver (DCD & HCD)
-----------------------------
@@ -526,7 +526,7 @@ Device Stack
------------
- [Audio] Support disabling feedback format correction (16.16 <-> 10.14 format)
-- [MSC] Add tud_msc_request_sense_cb() callback, change most default sense error to medium not present (0x02, 0x3A, 0x00)
+- [MSC] Add ``tud_msc_request_sense_cb()`` callback, change most default sense error to medium not present (0x02, 0x3A, 0x00)
- [Video] Fix video_capture example fails enumeration when 8FPS
Host Stack
@@ -537,22 +537,22 @@ No notable changes
0.12.0
======
-- add CFG_TUSB_OS_INC_PATH for os include path
+- add ``CFG_TUSB_OS_INC_PATH`` for os include path
Device Controller Driver (DCD)
------------------------------
- Getting device stack to pass USB Compliance Verification test (chapter9, HID, MSC). Ports are tested:
nRF, SAMD 21/51, rp2040, stm32f4, Renesas RX, iMXRT, ESP32-S2/3, Kinetic KL25/32, DA146xx
-- Added dcd_edpt_close_all() for switching configuration
-- [Transdimension] Support dcd_edpt_xfer_fifo() with auto wrap over if fifo buffer is 4K aligned and size is multiple of 4K.
+- Added ``dcd_edpt_close_all()`` for switching configuration
+- [Transdimension] Support ``dcd_edpt_xfer_fifo()`` with auto wrap over if fifo buffer is 4K aligned and size is multiple of 4K.
- [DA146xx] Improve vbus, reset, suspend, resume detection, and remote wakeup.
Device Stack
------------
-- Add new network driver Network Control Model (CDC-NCM), update net_lwip_webserver to work with NCM (need re-configure example)
-- Add new USB Video Class UVC 1.5 driver and video_capture example ((work in progress)
+- Add new network driver Network Control Model (CDC-NCM), update ``net_lwip_webserver`` to work with NCM (need re-configure example)
+- Add new USB Video Class UVC 1.5 driver and video_capture example (work in progress)
- Fix potential buffer overflow for HID, bluetooth drivers
Host Controller Driver (HCD)
@@ -589,13 +589,13 @@ Synopsys
^^^^^^^^
- Fix Synopsys set address bug which could cause re-enumeration failed
-- Fix dcd_synopsys driver integer overflow in HS mode (issue #968)
+- Fix ``dcd_synopsys`` driver integer overflow in HS mode (issue #968)
nRF5x
^^^^^
- Add nRF5x suspend, resume and remote wakeup
-- Fix nRF5x race condition with TASKS_EP0RCVOUT
+- Fix nRF5x race condition with ``TASKS_EP0RCVOUT``
RP2040
^^^^^^
@@ -610,8 +610,8 @@ USBD
^^^^
- Better support big endian mcu
-- Add tuh_inited() and tud_inited(), will separate tusb_init/inited() to tud/tuh init/inited
-- Add dcd_attr.h for defining common controller attribute such as max endpoints
+- Add ``tuh_inited()`` and ``tud_inited()``, will separate ``tusb_init/inited()`` to ``tud/tuh_init/inited()``
+- Add ``dcd_attr.h`` for defining common controller attribute such as max endpoints
Bluetooth
^^^^^^^^^
@@ -621,8 +621,8 @@ Bluetooth
DFU
^^^
-- Enhance DFU implementation to support multiple alternate interface and better support bwPollTimeout
-- Rename CFG_TUD_DFU_MODE to simply CFG_TUD_DFU
+- Enhance DFU implementation to support multiple alternate interface and better support ``bwPollTimeout``
+- Rename ``CFG_TUD_DFU_MODE`` to simply ``CFG_TUD_DFU``
HID
^^^
@@ -647,7 +647,7 @@ Vendor
^^^^^^
- Fix vendor fifo deadlock in certain case
-- Add tud_vendor_n_read_flush
+- Add ``tud_vendor_n_read_flush()``
Host Controller Driver (HCD)
----------------------------
@@ -664,7 +664,7 @@ Host Stack
- Major update and rework most of host stack, still needs more improvement
- Lots of improvement and update in parsing configuration and control
- Rework and major update to HID driver. Will default to enable boot interface if available
-- Separate CFG_TUH_DEVICE_MAX and CFG_TUH_HUB for better management and reduce SRAM usage
+- Separate ``CFG_TUH_DEVICE_MAX`` and ``CFG_TUH_HUB`` for better management and reduce SRAM usage
0.10.1 (2021-06-03)
===================
@@ -676,9 +676,9 @@ Host Controller Driver (HCD)
- Fix rp2040 host driver: incorrect PID with low speed device with max packet size of 8 bytes
- Improve hub driver
-- Remove obsolete hcd_pipe_queue_xfer()/hcd_pipe_xfer()
-- Use hcd_frame_number() instead of micro frame
-- Fix OHCI endpoint address and xferred_bytes in xfer complete event
+- Remove obsolete ``hcd_pipe_queue_xfer()``/``hcd_pipe_xfer()``
+- Use ``hcd_frame_number()`` instead of micro frame
+- Fix OHCI endpoint address and ``xferred_bytes`` in xfer complete event
0.10.0 (2021-05-28)
===================
@@ -697,7 +697,7 @@ Device Controller Driver (DCD)
- Fix build with nRF5340
- Fix build with lpc15 and lpc54
- Fix build with lpc177x_8x
-- STM32 Synopsys: greatly improve Isochronous transfer with edpt_xfer_fifo API
+- STM32 Synopsys: greatly improve Isochronous transfer with ``edpt_xfer_fifo()`` API
- Support LPC55 port1 highspeed
- Add support for Espressif esp32s3
- nRF: fix race condition that could cause drop packet of Bulk OUT transfer
@@ -705,14 +705,14 @@ Device Controller Driver (DCD)
USB Device Driver (USBD)
------------------------
-- Add new (optional) endpoint ADPI usbd_edpt_xfer_fifo
+- Add new (optional) endpoint ADPI ``usbd_edpt_xfer_fifo()``
Device Class Driver
-------------------
CDC
-- [Breaking] tud_cdc_peek(), tud_vendor_peek() no longer support random offset and dropped position parameter.
+- [Breaking] ``tud_cdc_peek()``, ``tud_vendor_peek()`` no longer support random offset and dropped position parameter.
DFU
@@ -724,19 +724,19 @@ HID
- Add more hid keys constant from 0x6B to 0xA4
- [Breaking] rename API
- - HID_PROTOCOL_NONE/KEYBOARD/MOUST to HID_ITF_PROTOCOL_NONE/KEYBOARD/MOUSE
- - tud_hid_boot_mode() to tud_hid_get_protocol()
- - tud_hid_boot_mode_cb() to tud_hid_set_protocol_cb()
+ - ``HID_PROTOCOL_NONE/KEYBOARD/MOUSE`` to ``HID_ITF_PROTOCOL_NONE/KEYBOARD/MOUSE``
+ - ``tud_hid_boot_mode()`` to ``tud_hid_get_protocol()``
+ - ``tud_hid_boot_mode_cb()`` to ``tud_hid_set_protocol_cb()``
MIDI
- Fix MIDI buffer overflow issue
- [Breaking] rename API
- - Rename tud_midi_read() to tud_midi_stream_read()
- - Rename tud_midi_write() to tud_midi_stream_write()
- - Rename tud_midi_receive() to tud_midi_packet_read()
- - Rename tud_midi_send() to tud_midi_packet_write()
+ - Rename ``tud_midi_read()`` to ``tud_midi_stream_read()``
+ - Rename ``tud_midi_write()`` to ``tud_midi_stream_write()``
+ - Rename ``tud_midi_receive()`` to ``tud_midi_packet_read()``
+ - Rename ``tud_midi_send()`` to ``tud_midi_packet_write()``
Host Controller Driver (HCD)
----------------------------
@@ -783,7 +783,7 @@ NXP Transdimention
USB Device Driver (USBD)
^^^^^^^^^^^^^^^^^^^^^^^^
-- Fix issue with status zlp (tud_control_status) is returned by class driver with SET/CLEAR_FEATURE for endpoint.
+- Fix issue with status zlp (``tud_control_status()``) is returned by class driver with SET/CLEAR_FEATURE for endpoint.
- Correct endpoint size check for fullspeed bulk, can be 8, 16, 32, 64
- Ack SET_INTERFACE even if it is not implemented by class driver.
@@ -792,34 +792,34 @@ Device Class Driver
DFU Runtime
-- rename dfu_rt to dfu_runtime for easy reading
+- rename ``dfu_rt()`` to ``dfu_runtime()`` for easy reading
CDC
-- Add tud_cdc_send_break_cb() to support break request
-- Improve CDC receive, minor behavior changes: when tud_cdc_rx_wanted_cb() is invoked wanted_char may not be the last byte in the fifo
+- Add ``tud_cdc_send_break_cb()`` to support break request
+- Improve CDC receive, minor behavior changes: when ``tud_cdc_rx_wanted_cb()`` is invoked wanted_char may not be the last byte in the fifo
HID
- [Breaking] Add itf argument to hid API to support multiple instances, follow API has signature changes
- - tud_hid_descriptor_report_cb()
- - tud_hid_get_report_cb()
- - tud_hid_set_report_cb()
- - tud_hid_boot_mode_cb()
- - tud_hid_set_idle_cb()
+ - ``tud_hid_descriptor_report_cb()``
+ - ``tud_hid_get_report_cb()``
+ - ``tud_hid_set_report_cb()``
+ - ``tud_hid_boot_mode_cb()``
+ - ``tud_hid_set_idle_cb()``
-- Add report complete callback tud_hid_report_complete_cb() API
+- Add report complete callback ``tud_hid_report_complete_cb()`` API
- Add DPad/Hat support for HID Gamepad
- - `TUD_HID_REPORT_DESC_GAMEPAD()` now support 16 buttons, 2 joysticks, 1 hat/dpad
- - Add hid_gamepad_report_t along with `GAMEPAD_BUTTON_` and `GAMEPAD_HAT_` enum
- - Add Gamepad to hid_composite / hid_composite_freertos example
+ - ``TUD_HID_REPORT_DESC_GAMEPAD()`` now support 16 buttons, 2 joysticks, 1 hat/dpad
+ - Add ``hid_gamepad_report_t`` along with ``GAMEPAD_BUTTON_`` and ``GAMEPAD_HAT_`` enum
+ - Add Gamepad to ``hid_composite`` / ``hid_composite_freertos`` example
MIDI
- Fix dropping MIDI sysex message when fifo is full
-- Fix typo in tud_midi_write24(), make example less ambiguous for cable and channel
+- Fix typo in ``tud_midi_write24()``, make example less ambiguous for cable and channel
- Fix incorrect endpoint descriptor length, MIDI v1 use Audio v1 which has 9-byte endpoint descriptor (instead of 7)
Host Stack
@@ -828,14 +828,14 @@ Host Stack
Host Controller Driver (HCD)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- Add rhport to hcd_init()
+- Add rhport to ``hcd_init()``
- Improve EHCI/OHCI driver abstraction
- Move echi/ohci files to portable/
- - Rename hcd_lpc18_43 to hcd_transdimension
- - Sub hcd API with hcd_ehci_init(), hcd_ehci_register_addr()
+ - Rename ``hcd_lpc18_43`` to ``hcd_transdimension``
+ - Sub hcd API with ``hcd_ehci_init()``, ``hcd_ehci_register_addr()``
-- Update NXP transdimention hcd_init() to reset controller to host mode
+- Update NXP transdimension ``hcd_init()`` to reset controller to host mode
- Ported hcd to rt10xx
@@ -849,20 +849,20 @@ Host Class Driver
MSC
-- Rename tuh_msc_scsi_inquiry() to tuh_msc_inquiry()
-- Rename tuh_msc_mounted_cb/tuh_msc_unmounted_cb to tuh_msc_mount_cb/tuh_msc_unmount_cb to match device stack naming
-- Change tuh_msc_is_busy() to tuh_msc_ready()
-- Add read10 and write10 function: tuh_msc_read10(), tuh_msc_write10()
+- Rename ``tuh_msc_scsi_inquiry()`` to ``tuh_msc_inquiry()``
+- Rename ``tuh_msc_mounted_cb()``/``tuh_msc_unmounted_cb()`` to ``tuh_msc_mount_cb()``/``tuh_msc_unmount_cb()`` to match device stack naming
+- Change ``tuh_msc_is_busy()`` to ``tuh_msc_ready()``
+- Add read10 and write10 function: ``tuh_msc_read10()``, ``tuh_msc_write10()``
- Read_Capacity is invoked as part of enumeration process
-- Add tuh_msc_get_block_count(), tuh_msc_get_block_size()
-- Add CFG_TUH_MSC_MAXLUN (default to 4) to hold lun capacities
+- Add ``tuh_msc_get_block_count()``, ``tuh_msc_get_block_size()``
+- Add ``CFG_TUH_MSC_MAXLUN`` (default to 4) to hold lun capacities
Others
------
- Add basic support for rt-thread OS
- Change zero bitfield length to more explicit padding
-- Build example now fetch required submodules on the fly while running `make` without prio submodule init for mcu drivers
+- Build example now fetch required submodules on the fly while running ``make`` without prior submodule init for mcu drivers
- Update pico-sdk to v1.1.0
**New Boards**
@@ -880,7 +880,7 @@ Device Controller Driver
- Added new device support for Raspberry Pi RP2040
- Added new device support for NXP Kinetis KL25ZXX
-- Use dcd_event_bus_reset() with link speed to replace bus_signal
+- Use ``dcd_event_bus_reset()`` with link speed to replace bus_signal
- ESP32-S2:
- Add bus suspend and wakeup support
@@ -902,8 +902,8 @@ USB Device
**USBD**
- Rework usbd control transfer to have additional stage parameter for setup, data, status
-- Fix tusb_init() return true instead of TUSB_ERROR_NONE
-- Added new API tud_connected() that return true after device got out of bus reset and received the very first setup packet
+- Fix ``tusb_init()`` return true instead of ``TUSB_ERROR_NONE``
+- Added new API ``tud_connected()`` that return true after device got out of bus reset and received the very first setup packet
**Class Driver**
@@ -911,22 +911,22 @@ USB Device
- Allow to transmit data, even if the host does not support control line states i.e set DTR
- HID
- - change default CFG_TUD_HID_EP_BUFSIZE from 16 to 64
+ - change default ``CFG_TUD_HID_EP_BUFSIZE`` from 16 to 64
- MIDI
- Fix midi sysex sending bug
- MSC
- Invoke only scsi complete callback after status transaction is complete.
- - Fix scsi_mode_sense6_t padding, which cause IAR compiler internal error.
+ - Fix ``scsi_mode_sense6_t`` padding, which cause IAR compiler internal error.
- USBTMC
- Change interrupt endpoint example size to 8 instead of 2 for better compatibility with mcu
**Example**
-- Support make from windows cmd.exe
-- Add HID Consumer Control (media keys) to hid_composite & hid_composite_freertos examples
+- Support make from windows ``cmd.exe``
+- Add HID Consumer Control (media keys) to ``hid_composite`` & ``hid_composite_freertos`` examples
USB Host
@@ -967,28 +967,28 @@ Device Controller Driver
- Support multiple usb ports with rhport=1 is highspeed on selected MCUs e.g H743, F23. It is possible to have OTG_HS to run on Fullspeed PHY (e.g lacking external PHY)
- Add ISO transfer, fix odd/even frame
- Fix FIFO flush during stall
- - Implement dcd_edpt_close() API
+ - Implement ``dcd_edpt_close()`` API
- Support F105, F107
- Enhance STM32 fsdev
- Improve dcd fifo allocation
- Fix ISTR race condition
- Support remap USB IRQ on supported MCUs
- - Implement dcd_edpt_close() API
+ - Implement ``dcd_edpt_close()`` API
- Enhance NUC 505: enhance set configure behavior
- Enhance SAMD
- Fix race condition with setup packet
- - Add SAMD11 option `OPT_MCU_SAMD11`
- - Add SAME5x option `OPT_MCU_SAME5X`
+ - Add SAMD11 option ``OPT_MCU_SAMD11``
+ - Add SAME5x option ``OPT_MCU_SAME5X``
- Fix SAMG control data toggle and stall race condition
- Enhance nRF
- - Fix hanged when tud_task() is called within critical section (disabled interrupt)
+ - Fix hanged when ``tud_task()`` is called within critical section (disabled interrupt)
- Fix disconnect bus event not submitted
- - Implement ISO transfer and dcd_edpt_close()
+ - Implement ISO transfer and ``dcd_edpt_close()``
USB Device
@@ -997,26 +997,26 @@ USB Device
**USBD**
- Add new class driver for **Bluetooth HCI** class driver with example can be found in [mynewt-tinyusb-example](https://github.com/hathach/mynewt-tinyusb-example) since it needs mynewt OS to run with.
-- Fix USBD endpoint usage racing condition with `usbd_edpt_claim()/usbd_edpt_release()`
-- Added `tud_task_event_ready()` and `osal_queue_empty()`. This API is needed to check before enter low power mode with WFI/WFE
-- Rename USB IRQ Handler to `dcd_int_handler()`. Application must define IRQ handler in which it calls this API.
-- Add `dcd_connect()` and `dcd_disconnect()` to enable/disable internal pullup on D+/D- on supported MCUs.
-- Add `usbd_edpt_open()`
-- Remove `dcd_set_config()`
-- Add *OPT_OS_CUMSTOM* as hook for application to overwrite and/or add their own OS implementation
+- Fix USBD endpoint usage racing condition with ``usbd_edpt_claim()``/``usbd_edpt_release()``
+- Added ``tud_task_event_ready()`` and ``osal_queue_empty()``. This API is needed to check before enter low power mode with WFI/WFE
+- Rename USB IRQ Handler to ``dcd_int_handler()``. Application must define IRQ handler in which it calls this API.
+- Add ``dcd_connect()`` and ``dcd_disconnect()`` to enable/disable internal pullup on D+/D- on supported MCUs.
+- Add ``usbd_edpt_open()``
+- Remove ``dcd_set_config()``
+- Add ``OPT_OS_CUMSTOM`` as hook for application to overwrite and/or add their own OS implementation
- Support SET_INTERFACE, GET_INTERFACE request
-- Add Logging for debug with optional uart/rtt/swo printf retarget or `CFG_TUSB_DEBUG_PRINTF` hook
+- Add Logging for debug with optional uart/rtt/swo printf retarget or ``CFG_TUSB_DEBUG_PRINTF`` hook
- Add IAR compiler support
-- Support multiple configuration descriptors. `TUD_CONFIG_DESCRIPTOR()` template has extra config_num as 1st argument
-- Improve USB Highspeed support with actual link speed detection with `dcd_event_bus_reset()`
+- Support multiple configuration descriptors. ``TUD_CONFIG_DESCRIPTOR()`` template has extra config_num as 1st argument
+- Improve USB Highspeed support with actual link speed detection with ``dcd_event_bus_reset()``
- Enhance class driver management
- - `usbd_driver_open()` add max length argument, and return length of interface (0 for not supported). Return value is used for finding appropriate driver
- - Add application implemented class driver via `usbd_app_driver_get_cb()`
+ - ``usbd_driver_open()`` add max length argument, and return length of interface (0 for not supported). Return value is used for finding appropriate driver
+ - Add application implemented class driver via ``usbd_app_driver_get_cb()``
- IAD is handled to assign driver id
-- Added `tud_descriptor_device_qualifier_cb()` callback
-- Optimize `tu_fifo` bulk write/read transfer
+- Added ``tud_descriptor_device_qualifier_cb()`` callback
+- Optimize ``tu_fifo`` bulk write/read transfer
- Forward non-std control request to class driver
- Let application handle Microsoft OS 1.0 Descriptors (the 0xEE index string)
- Fix OSAL FreeRTOS yield from ISR
@@ -1028,8 +1028,8 @@ USB Device
- CDC:
- Send zero length packet for end of data when needed
- - Add `tud_cdc_tx_complete_cb()` callback
- - Change tud_cdc_n_write_flush() return number of bytes forced to transfer, and flush when writing enough data to fifo
+ - Add ``tud_cdc_tx_complete_cb()`` callback
+ - Change ``tud_cdc_n_write_flush()`` return number of bytes forced to transfer, and flush when writing enough data to fifo
- MIDI:
- Add packet interface
@@ -1039,10 +1039,10 @@ USB Device
- DFU Runtime: fix response to SET_INTERFACE and DFU_GETSTATUS request
- Rename some configure macro to make it clear that those are used directly for endpoint transfer
- - CFG_TUD_HID_BUFSIZE to CFG_TUD_HID_EP_BUFSIZE
- - CFG_TUD_CDC_EPSIZE to CFG_TUD_CDC_EP_BUFSIZE
- - CFG_TUD_MSC_BUFSIZE to CFG_TUD_MSC_EP_BUFSIZE
- - CFG_TUD_MIDI_EPSIZE to CFG_TUD_MIDI_EP_BUFSIZE
+ - ``CFG_TUD_HID_BUFSIZE`` to ``CFG_TUD_HID_EP_BUFSIZE``
+ - ``CFG_TUD_CDC_EPSIZE`` to ``CFG_TUD_CDC_EP_BUFSIZE``
+ - ``CFG_TUD_MSC_BUFSIZE`` to ``CFG_TUD_MSC_EP_BUFSIZE``
+ - ``CFG_TUD_MIDI_EPSIZE`` to ``CFG_TUD_MIDI_EP_BUFSIZE``
- HID:
- Fix gamepad template descriptor
@@ -1061,15 +1061,15 @@ USB Host
Examples
--------
-- Add new hid_composite_freertos
-- Add new dynamic_configuration to demonstrate how to switch configuration descriptors
-- Add new hid_multiple_interface
+- Add new ``hid_composite_freertos``
+- Add new ``dynamic_configuration`` to demonstrate how to switch configuration descriptors
+- Add new ``hid_multiple_interface``
-- Enhance `net_lwip_webserver` example
+- Enhance ``net_lwip_webserver`` example
- Add multiple configuration: RNDIS for Windows, CDC-ECM for macOS (Linux will work with both)
- - Update lwip to STABLE-2_1_2_RELEASE for net_lwip_webserver
+ - Update lwip to STABLE-2_1_2_RELEASE for ``net_lwip_webserver``
-- Added new Audio example: audio_test uac2_headsest
+- Added new Audio example: ``audio_test`` ``uac2_headsest``
New Boards
----------
@@ -1110,37 +1110,37 @@ Added
- Added multiple instances support for CDC and MIDI
- Added a handful of unit test with Ceedling.
- Added LOG support for debugging with CFG_TUSB_DEBUG
-- Added `tud_descriptor_bos_cb()` for BOS descriptor (required for USB 2.1)
-- Added `dcd_edpt0_status_complete()` as optional API for DCD
+- Added ``tud_descriptor_bos_cb()`` for BOS descriptor (required for USB 2.1)
+- Added ``dcd_edpt0_status_complete()`` as optional API for DCD
**Examples**
Following examples are added:
-- board_test
-- cdc_dual_ports
-- dfu_rt
-- hid_composite
-- net_lwip_webserver
-- usbtmc
-- webusb_serial
+- ``board_test``
+- ``cdc_dual_ports``
+- ``dfu_rt``
+- ``hid_composite``
+- ``net_lwip_webserver``
+- ``usbtmc``
+- ``webusb_serial``
Changed
-------
-- Changed `tud_descriptor_string_cb()` to have additional Language ID argument
-- Merged hal_nrf5x.c into dcd_nrf5x.c
-- Merged dcd_samd21.c and dcd_samd51.c into dcd_samd.c
-- Generalized dcd_stm32f4.c to dcd_synopsys.c
-- Changed cdc_msc_hid to cdc_msc (drop hid) due to limited endpoints number of some MCUs
+- Changed ``tud_descriptor_string_cb()`` to have additional Language ID argument
+- Merged ``hal_nrf5x.c`` into ``dcd_nrf5x.c``
+- Merged ``dcd_samd21.c`` and ``dcd_samd51.c`` into ``dcd_samd.c``
+- Generalized ``dcd_stm32f4.c`` to ``dcd_synopsys.c``
+- Changed ``cdc_msc_hid`` to ``cdc_msc`` (drop hid) due to limited endpoints number of some MCUs
- Improved DCD SAMD stability, fix missing setup packet occasionally
-- Improved usbd/usbd_control with proper handling of zero-length packet (ZLP)
+- Improved ``usbd/usbd_control`` with proper handling of zero-length packet (ZLP)
- Improved STM32 DCD FSDev
- Improved STM32 DCD Synopsys
- Migrated CI from Travis to Github Action
- Updated nrfx submodule to 2.1.0
- Fixed mynewt osal queue definition
-- Fixed cdc_msc_freertos example build for all MCUs
+- Fixed ``cdc_msc_freertos`` example build for all MCUs
0.5.0 (2019-06)
diff --git a/docs/info/contributors.rst b/docs/info/contributors.rst
deleted file mode 120000
index 35e0b05f5..000000000
--- a/docs/info/contributors.rst
+++ /dev/null
@@ -1 +0,0 @@
-.. include:: ../../CONTRIBUTORS.rst
\ No newline at end of file
diff --git a/docs/info/contributors.rst b/docs/info/contributors.rst
new file mode 100644
index 000000000..35e0b05f5
--- /dev/null
+++ b/docs/info/contributors.rst
@@ -0,0 +1 @@
+.. include:: ../../CONTRIBUTORS.rst
\ No newline at end of file
diff --git a/docs/reference/boards.rst b/docs/reference/boards.rst
index 4739467bc..41e765683 100644
--- a/docs/reference/boards.rst
+++ b/docs/reference/boards.rst
@@ -7,25 +7,25 @@ It is responsible for getting the MCU started and the USB peripheral clocked wit
- One LED : for status
- One Button : to get input from user
-- One UART : optional for device, but required for host examples
+- One UART : needed for logging with LOGGER=uart, maybe required for host/dual examples
Following boards are supported
Analog Devices
--------------
-============= ================ ======== =========================================================================================================================== ======
-Board Name Family URL Note
-============= ================ ======== =========================================================================================================================== ======
-max32650evkit MAX32650 EVKIT max32650 https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32650-evkit.html#eb-overview
-max32650fthr MAX32650 Feather max32650 https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32650fthr.html
-max32651evkit MAX32651 EVKIT max32650 https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32651-evkit.html
-max32666evkit MAX32666 EVKIT max32666 https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32666evkit.html
-max32666fthr MAX32666 Feather max32666 https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32666fthr.html
-apard32690 APARD32690-SL max32690 https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/ad-apard32690-sl.html
-max32690evkit MAX32690 EVKIT max32690 https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32690evkit.html
-max78002evkit MAX78002 EVKIT max78002 https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max78002evkit.html
-============= ================ ======== =========================================================================================================================== ======
+============= ================ ======== ================================================================================================================= ======
+Board Name Family URL Note
+============= ================ ======== ================================================================================================================= ======
+apard32690 APARD32690-SL maxim https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/ad-apard32690-sl.html
+max32650evkit MAX32650 EVKIT maxim https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32650-evkit.html
+max32650fthr MAX32650 Feather maxim https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32650fthr.html
+max32651evkit MAX32651 EVKIT maxim https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32651-evkit.html
+max32666evkit MAX32666 EVKIT maxim https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32666evkit.html
+max32666fthr MAX32666 Feather maxim https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32666fthr.html
+max32690evkit MAX32690 EVKIT maxim https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32690evkit.html
+max78002evkit MAX78002 EVKIT maxim https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max78002evkit.html
+============= ================ ======== ================================================================================================================= ======
Bridgetek
---------
@@ -43,6 +43,7 @@ Espressif
Board Name Family URL Note
========================= ============================== ========= ======================================================================================================== ======
adafruit_feather_esp32_v2 Adafruit Feather ESP32 v2 espressif https://www.adafruit.com/product/5400
+adafruit_feather_esp32c6 Adafruit Feather EPS32-C6 espressif https://www.adafruit.com/product/5933
adafruit_feather_esp32s2 Adafruit Feather ESP32S2 espressif https://www.adafruit.com/product/5000
adafruit_feather_esp32s3 Adafruit Feather ESP32S3 espressif https://www.adafruit.com/product/5323
adafruit_magtag_29gray Adafruit MagTag 2.9" Grayscale espressif https://www.adafruit.com/product/4800
@@ -165,6 +166,7 @@ lpcxpresso55s28 LPCXpresso55s28 lpc55 ht
lpcxpresso55s69 LPCXpresso55s69 lpc55 https://www.nxp.com/design/design-center/software/development-software/mcuxpresso-software-and-tools-/lpcxpresso-boards/lpcxpresso55s69-development-board:LPC55S69-EVK
mcu_link MCU Link lpc55 https://www.nxp.com/design/design-center/software/development-software/mcuxpresso-software-and-tools-/mcu-link-debug-probe:MCU-LINK
frdm_mcxa153 Freedom MCXA153 mcx https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-MCXA153
+frdm_mcxa156 Freedom MCXA156 mcx https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-MCXA156
frdm_mcxn947 Freedom MCXN947 mcx https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-MCXN947
mcxn947brk MCXN947 Breakout mcx n/a
================== ========================================= ============= ========================================================================================================================================================================= ======
@@ -190,13 +192,19 @@ pca10100 Nordic nRF52833 DK nrf ht
Raspberry Pi
------------
-================= ================= ============== ========================================================== ======
-Board Name Family URL Note
-================= ================= ============== ========================================================== ======
-raspberrypi_zero Raspberry Pi Zero broadcom_32bit https://www.raspberrypi.org/products/raspberry-pi-zero/
-raspberrypi_cm4 Raspberry CM4 broadcom_64bit https://www.raspberrypi.org/products/compute-module-4
-raspberrypi_zero2 Raspberry Zero2 broadcom_64bit https://www.raspberrypi.org/products/raspberry-pi-zero-2-w
-================= ================= ============== ========================================================== ======
+================================ ============================================ ============== ========================================================== ======
+Board Name Family URL Note
+================================ ============================================ ============== ========================================================== ======
+raspberrypi_zero Raspberry Pi Zero broadcom_32bit https://www.raspberrypi.org/products/raspberry-pi-zero/
+raspberrypi_cm4 Raspberry CM4 broadcom_64bit https://www.raspberrypi.org/products/compute-module-4
+raspberrypi_zero2 Raspberry Zero2 broadcom_64bit https://www.raspberrypi.org/products/raspberry-pi-zero-2-w
+adafruit_feather_rp2040_usb_host Adafruit Feather RP2040 with USB Type A Host rp2040 https://www.adafruit.com/product/5723
+adafruit_fruit_jam Adafruit Fruit Jam - Mini RP2350 rp2040 https://www.adafruit.com/product/6200
+adafruit_metro_rp2350 Adafruit Metro RP2350 rp2040 https://www.adafruit.com/product/6003
+raspberry_pi_pico Pico rp2040 https://www.raspberrypi.com/products/raspberry-pi-pico/
+raspberry_pi_pico2 Pico2 rp2040 https://www.raspberrypi.com/products/raspberry-pi-pico-2/
+raspberry_pi_pico_w Pico rp2040 https://www.raspberrypi.com/products/raspberry-pi-pico/
+================================ ============================================ ============== ========================================================== ======
Renesas
-------
@@ -219,62 +227,64 @@ uno_r4 Arduino UNO R4 ra https://store-usa.arduino
STMicroelectronics
------------------
-=================== ================================= ======== ================================================================= ======
-Board Name Family URL Note
-=================== ================================= ======== ================================================================= ======
-stm32c071nucleo STM32C071 Nucleo stm32c0 https://www.st.com/en/evaluation-tools/nucleo-g071rb.html
-stm32f070rbnucleo STM32 F070 Nucleo stm32f0 https://www.st.com/en/evaluation-tools/nucleo-f070rb.html
-stm32f072disco STM32 F072 Discovery stm32f0 https://www.st.com/en/evaluation-tools/32f072bdiscovery.html
-stm32f072eval STM32 F072 Eval stm32f0 https://www.st.com/en/evaluation-tools/stm32072b-eval.html
-stm32f103_bluepill STM32 F103 Bluepill stm32f1 https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill
-stm32f103_mini_2 STM32 F103 Mini v2 stm32f1 https://stm32-base.org/boards/STM32F103RCT6-STM32-Mini-V2.0
-stm32f103ze_iar IAR STM32 F103ze starter kit stm32f1 n/a
-stm32f207nucleo STM32 F207 Nucleo stm32f2 https://www.st.com/en/evaluation-tools/nucleo-f207zg.html
-stm32f303disco STM32 F303 Discovery stm32f3 https://www.st.com/en/evaluation-tools/stm32f3discovery.html
-feather_stm32f405 Adafruit Feather STM32F405 stm32f4 https://www.adafruit.com/product/4382
-pyboardv11 Pyboard v1.1 stm32f4 https://www.adafruit.com/product/2390
-stm32f401blackpill STM32 F401 Blackpill stm32f4 https://stm32-base.org/boards/STM32F401CCU6-WeAct-Black-Pill-V1.2
-stm32f407blackvet STM32 F407 Blackvet stm32f4 https://stm32-base.org/boards/STM32F407VET6-STM32-F4VE-V2.0
-stm32f407disco STM32 F407 Discovery stm32f4 https://www.st.com/en/evaluation-tools/stm32f4discovery.html
-stm32f411blackpill STM32 F411 Blackpill stm32f4 https://stm32-base.org/boards/STM32F411CEU6-WeAct-Black-Pill-V2.0
-stm32f411disco STM32 F411 Discovery stm32f4 https://www.st.com/en/evaluation-tools/32f411ediscovery.html
-stm32f412disco STM32 F412 Discovery stm32f4 https://www.st.com/en/evaluation-tools/32f412gdiscovery.html
-stm32f412nucleo STM32 F412 Nucleo stm32f4 https://www.st.com/en/evaluation-tools/nucleo-f412zg.html
-stm32f439nucleo STM32 F439 Nucleo stm32f4 https://www.st.com/en/evaluation-tools/nucleo-f439zi.html
-stlinkv3mini Stlink-v3 mini stm32f7 https://www.st.com/en/development-tools/stlink-v3mini.html
-stm32f723disco STM32 F723 Discovery stm32f7 https://www.st.com/en/evaluation-tools/32f723ediscovery.html
-stm32f746disco STM32 F746 Discovery stm32f7 https://www.st.com/en/evaluation-tools/32f746gdiscovery.html
-stm32f746nucleo STM32 F746 Nucleo stm32f7 https://www.st.com/en/evaluation-tools/nucleo-f746zg.html
-stm32f767nucleo STM32 F767 Nucleo stm32f7 https://www.st.com/en/evaluation-tools/nucleo-f767zi.html
-stm32f769disco STM32 F769 Discovery stm32f7 https://www.st.com/en/evaluation-tools/32f769idiscovery.html
-stm32g0b1nucleo STM32 G0B1 Nucleo stm32g0 https://www.st.com/en/evaluation-tools/nucleo-g0b1re.html
-b_g474e_dpow1 STM32 B-G474E-DPOW1 Discovery kit stm32g4 https://www.st.com/en/evaluation-tools/b-g474e-dpow1.html
-stm32g474nucleo STM32 G474 Nucleo stm32g4 https://www.st.com/en/evaluation-tools/nucleo-g474re.html
-stm32g491nucleo STM32 G491 Nucleo stm32g4 https://www.st.com/en/evaluation-tools/nucleo-g491re.html
-stm32h503nucleo STM32 H503 Nucleo stm32h5 https://www.st.com/en/evaluation-tools/nucleo-h503rb.html
-stm32h563nucleo STM32 H563 Nucleo stm32h5 https://www.st.com/en/evaluation-tools/nucleo-h563zi.html
-stm32h573i_dk STM32 H573i Discovery stm32h5 https://www.st.com/en/evaluation-tools/stm32h573i-dk.html
-daisyseed Daisy Seed stm32h7 https://electro-smith.com/products/daisy-seed
-stm32h723nucleo STM32 H723 Nucleo stm32h7 https://www.st.com/en/evaluation-tools/nucleo-h723zg.html
-stm32h743eval STM32 H743 Eval stm32h7 https://www.st.com/en/evaluation-tools/stm32h743i-eval.html
-stm32h743nucleo STM32 H743 Nucleo stm32h7 https://www.st.com/en/evaluation-tools/nucleo-h743zi.html
-stm32h745disco STM32 H745 Discovery stm32h7 https://www.st.com/en/evaluation-tools/stm32h745i-disco.html
-stm32h750_weact STM32 H750 WeAct stm32h7 https://www.adafruit.com/product/5032
-stm32h750bdk STM32 H750b Discovery Kit stm32h7 https://www.st.com/en/evaluation-tools/stm32h750b-dk.html
-waveshare_openh743i Waveshare Open H743i stm32h7 https://www.waveshare.com/openh743i-c-standard.htm
-stm32l052dap52 STM32 L052 DAP stm32l0 n/a
-stm32l0538disco STM32 L0538 Discovery stm32l0 https://www.st.com/en/evaluation-tools/32l0538discovery.html
-stm32l412nucleo STM32 L412 Nucleo stm32l4 https://www.st.com/en/evaluation-tools/nucleo-l412kb.html
-stm32l476disco STM32 L476 Disco stm32l4 https://www.st.com/en/evaluation-tools/32l476gdiscovery.html
-stm32l4p5nucleo STM32 L4P5 Nucleo stm32l4 https://www.st.com/en/evaluation-tools/nucleo-l4p5zg.html
-stm32l4r5nucleo STM32 L4R5 Nucleo stm32l4 https://www.st.com/en/evaluation-tools/nucleo-l4r5zi.html
-b_u585i_iot2a STM32 B-U585i IOT2A Discovery kit stm32u5 https://www.st.com/en/evaluation-tools/b-u585i-iot02a.html
-stm32u545nucleo STM32 U545 Nucleo stm32u5 https://www.st.com/en/evaluation-tools/nucleo-u545re-q.html
-stm32u575eval STM32 U575 Eval stm32u5 https://www.st.com/en/evaluation-tools/stm32u575i-ev.html
-stm32u575nucleo STM32 U575 Nucleo stm32u5 https://www.st.com/en/evaluation-tools/nucleo-u575zi-q.html
-stm32u5a5nucleo STM32 U5a5 Nucleo stm32u5 https://www.st.com/en/evaluation-tools/nucleo-u5a5zj-q.html
-stm32wb55nucleo STM32 P-NUCLEO-WB55 stm32wb https://www.st.com/en/evaluation-tools/p-nucleo-wb55.html
-=================== ================================= ======== ================================================================= ======
+=================== ================================= ========= ================================================================= ======
+Board Name Family URL Note
+=================== ================================= ========= ================================================================= ======
+stm32c071nucleo STM32C071 Nucleo stm32c0 https://www.st.com/en/evaluation-tools/nucleo-g071rb.html
+stm32f070rbnucleo STM32 F070 Nucleo stm32f0 https://www.st.com/en/evaluation-tools/nucleo-f070rb.html
+stm32f072disco STM32 F072 Discovery stm32f0 https://www.st.com/en/evaluation-tools/32f072bdiscovery.html
+stm32f072eval STM32 F072 Eval stm32f0 https://www.st.com/en/evaluation-tools/stm32072b-eval.html
+stm32f103_bluepill STM32 F103 Bluepill stm32f1 https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill
+stm32f103_mini_2 STM32 F103 Mini v2 stm32f1 https://stm32-base.org/boards/STM32F103RCT6-STM32-Mini-V2.0
+stm32f103ze_iar IAR STM32 F103ze starter kit stm32f1 n/a
+stm32f207nucleo STM32 F207 Nucleo stm32f2 https://www.st.com/en/evaluation-tools/nucleo-f207zg.html
+stm32f303disco STM32 F303 Discovery stm32f3 https://www.st.com/en/evaluation-tools/stm32f3discovery.html
+feather_stm32f405 Adafruit Feather STM32F405 stm32f4 https://www.adafruit.com/product/4382
+pyboardv11 Pyboard v1.1 stm32f4 https://www.adafruit.com/product/2390
+stm32f401blackpill STM32 F401 Blackpill stm32f4 https://stm32-base.org/boards/STM32F401CCU6-WeAct-Black-Pill-V1.2
+stm32f407blackvet STM32 F407 Blackvet stm32f4 https://stm32-base.org/boards/STM32F407VET6-STM32-F4VE-V2.0
+stm32f407disco STM32 F407 Discovery stm32f4 https://www.st.com/en/evaluation-tools/stm32f4discovery.html
+stm32f411blackpill STM32 F411 Blackpill stm32f4 https://stm32-base.org/boards/STM32F411CEU6-WeAct-Black-Pill-V2.0
+stm32f411disco STM32 F411 Discovery stm32f4 https://www.st.com/en/evaluation-tools/32f411ediscovery.html
+stm32f412disco STM32 F412 Discovery stm32f4 https://www.st.com/en/evaluation-tools/32f412gdiscovery.html
+stm32f412nucleo STM32 F412 Nucleo stm32f4 https://www.st.com/en/evaluation-tools/nucleo-f412zg.html
+stm32f439nucleo STM32 F439 Nucleo stm32f4 https://www.st.com/en/evaluation-tools/nucleo-f439zi.html
+stlinkv3mini Stlink-v3 mini stm32f7 https://www.st.com/en/development-tools/stlink-v3mini.html
+stm32f723disco STM32 F723 Discovery stm32f7 https://www.st.com/en/evaluation-tools/32f723ediscovery.html
+stm32f746disco STM32 F746 Discovery stm32f7 https://www.st.com/en/evaluation-tools/32f746gdiscovery.html
+stm32f746nucleo STM32 F746 Nucleo stm32f7 https://www.st.com/en/evaluation-tools/nucleo-f746zg.html
+stm32f767nucleo STM32 F767 Nucleo stm32f7 https://www.st.com/en/evaluation-tools/nucleo-f767zi.html
+stm32f769disco STM32 F769 Discovery stm32f7 https://www.st.com/en/evaluation-tools/32f769idiscovery.html
+stm32g0b1nucleo STM32 G0B1 Nucleo stm32g0 https://www.st.com/en/evaluation-tools/nucleo-g0b1re.html
+b_g474e_dpow1 STM32 B-G474E-DPOW1 Discovery kit stm32g4 https://www.st.com/en/evaluation-tools/b-g474e-dpow1.html
+stm32g474nucleo STM32 G474 Nucleo stm32g4 https://www.st.com/en/evaluation-tools/nucleo-g474re.html
+stm32g491nucleo STM32 G491 Nucleo stm32g4 https://www.st.com/en/evaluation-tools/nucleo-g491re.html
+stm32h503nucleo STM32 H503 Nucleo stm32h5 https://www.st.com/en/evaluation-tools/nucleo-h503rb.html
+stm32h563nucleo STM32 H563 Nucleo stm32h5 https://www.st.com/en/evaluation-tools/nucleo-h563zi.html
+stm32h573i_dk STM32 H573i Discovery stm32h5 https://www.st.com/en/evaluation-tools/stm32h573i-dk.html
+daisyseed Daisy Seed stm32h7 https://electro-smith.com/products/daisy-seed
+stm32h723nucleo STM32 H723 Nucleo stm32h7 https://www.st.com/en/evaluation-tools/nucleo-h723zg.html
+stm32h743eval STM32 H743 Eval stm32h7 https://www.st.com/en/evaluation-tools/stm32h743i-eval.html
+stm32h743nucleo STM32 H743 Nucleo stm32h7 https://www.st.com/en/evaluation-tools/nucleo-h743zi.html
+stm32h745disco STM32 H745 Discovery stm32h7 https://www.st.com/en/evaluation-tools/stm32h745i-disco.html
+stm32h750_weact STM32 H750 WeAct stm32h7 https://www.adafruit.com/product/5032
+stm32h750bdk STM32 H750b Discovery Kit stm32h7 https://www.st.com/en/evaluation-tools/stm32h750b-dk.html
+waveshare_openh743i Waveshare Open H743i stm32h7 https://www.waveshare.com/openh743i-c-standard.htm
+stm32h7s3nucleo STM32 H7S3L8 Nucleo stm32h7rs https://www.st.com/en/evaluation-tools/nucleo-h7s3l8.html
+stm32l052dap52 STM32 L052 DAP stm32l0 n/a
+stm32l0538disco STM32 L0538 Discovery stm32l0 https://www.st.com/en/evaluation-tools/32l0538discovery.html
+stm32l412nucleo STM32 L412 Nucleo stm32l4 https://www.st.com/en/evaluation-tools/nucleo-l412kb.html
+stm32l476disco STM32 L476 Disco stm32l4 https://www.st.com/en/evaluation-tools/32l476gdiscovery.html
+stm32l4p5nucleo STM32 L4P5 Nucleo stm32l4 https://www.st.com/en/evaluation-tools/nucleo-l4p5zg.html
+stm32l4r5nucleo STM32 L4R5 Nucleo stm32l4 https://www.st.com/en/evaluation-tools/nucleo-l4r5zi.html
+stm32n657nucleo STM32 N657X0-Q Nucleo stm32n6 https://www.st.com/en/evaluation-tools/nucleo-n657x0-q.html
+b_u585i_iot2a STM32 B-U585i IOT2A Discovery kit stm32u5 https://www.st.com/en/evaluation-tools/b-u585i-iot02a.html
+stm32u545nucleo STM32 U545 Nucleo stm32u5 https://www.st.com/en/evaluation-tools/nucleo-u545re-q.html
+stm32u575eval STM32 U575 Eval stm32u5 https://www.st.com/en/evaluation-tools/stm32u575i-ev.html
+stm32u575nucleo STM32 U575 Nucleo stm32u5 https://www.st.com/en/evaluation-tools/nucleo-u575zi-q.html
+stm32u5a5nucleo STM32 U5a5 Nucleo stm32u5 https://www.st.com/en/evaluation-tools/nucleo-u5a5zj-q.html
+stm32wb55nucleo STM32 P-NUCLEO-WB55 stm32wb https://www.st.com/en/evaluation-tools/p-nucleo-wb55.html
+=================== ================================= ========= ================================================================= ======
Sunxi
-----
diff --git a/docs/reference/dependencies.rst b/docs/reference/dependencies.rst
index e124466da..5104c6456 100644
--- a/docs/reference/dependencies.rst
+++ b/docs/reference/dependencies.rst
@@ -4,70 +4,74 @@ Dependencies
MCU low-level peripheral driver and external libraries for building TinyUSB examples
-======================================== ============================================================== ======================================== ====================================================================================================================================================================================================================================================================================================================================
-Local Path Repo Commit Required by
-======================================== ============================================================== ======================================== ====================================================================================================================================================================================================================================================================================================================================
-hw/mcu/allwinner https://github.com/hathach/allwinner_driver.git 8e5e89e8e132c0fd90e72d5422e5d3d68232b756 fc100s
-hw/mcu/analog/max32 https://github.com/analogdevicesinc/msdk.git b20b398d3e5e2007594e54a74ba3d2a2e50ddd75 max32650 max32666 max32690 max78002
-hw/mcu/bridgetek/ft9xx/ft90x-sdk https://github.com/BRTSG-FOSS/ft90x-sdk.git 91060164afe239fcb394122e8bf9eb24d3194eb1 brtmm90x
-hw/mcu/broadcom https://github.com/adafruit/broadcom-peripherals.git 08370086080759ed54ac1136d62d2ad24c6fa267 broadcom_32bit broadcom_64bit
-hw/mcu/gd/nuclei-sdk https://github.com/Nuclei-Software/nuclei-sdk.git 7eb7bfa9ea4fbeacfafe1d5f77d5a0e6ed3922e7 gd32vf103
-hw/mcu/infineon/mtb-xmclib-cat3 https://github.com/Infineon/mtb-xmclib-cat3.git daf5500d03cba23e68c2f241c30af79cd9d63880 xmc4000
-hw/mcu/microchip https://github.com/hathach/microchip_driver.git 9e8b37e307d8404033bb881623a113931e1edf27 sam3x samd11 samd21 samd51 samd5x_e5x same5x same7x saml2x samg
-hw/mcu/mindmotion/mm32sdk https://github.com/hathach/mm32sdk.git b93e856211060ae825216c6a1d6aa347ec758843 mm32
-hw/mcu/nordic/nrfx https://github.com/NordicSemiconductor/nrfx.git 7c47cc0a56ce44658e6da2458e86cd8783ccc4a2 nrf
-hw/mcu/nuvoton https://github.com/majbthrd/nuc_driver.git 2204191ec76283371419fbcec207da02e1bc22fa nuc
-hw/mcu/nxp/lpcopen https://github.com/hathach/nxp_lpcopen.git b41cf930e65c734d8ec6de04f1d57d46787c76ae lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43
-hw/mcu/nxp/mcux-sdk https://github.com/hathach/mcux-sdk.git 144f1eb7ea8c06512e12f12b27383601c0272410 kinetis_k kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx imxrt
-hw/mcu/raspberry_pi/Pico-PIO-USB https://github.com/sekigon-gonnoc/Pico-PIO-USB.git fe9133fc513b82cc3dc62c67cb51f2339cf29ef7 rp2040
-hw/mcu/renesas/fsp https://github.com/renesas/fsp.git edcc97d684b6f716728a60d7a6fea049d9870bd6 ra
-hw/mcu/renesas/rx https://github.com/kkitayam/rx_device.git 706b4e0cf485605c32351e2f90f5698267996023 rx
-hw/mcu/silabs/cmsis-dfp-efm32gg12b https://github.com/cmsis-packs/cmsis-dfp-efm32gg12b.git f1c31b7887669cb230b3ea63f9b56769078960bc efm32
-hw/mcu/sony/cxd56/spresense-exported-sdk https://github.com/sonydevworld/spresense-exported-sdk.git 2ec2a1538362696118dc3fdf56f33dacaf8f4067 spresense
-hw/mcu/st/cmsis_device_c0 https://github.com/STMicroelectronics/cmsis_device_c0.git fb56b1b70c73b74eacda2a4bcc36886444364ab3 stm32c0
-hw/mcu/st/cmsis_device_f0 https://github.com/STMicroelectronics/cmsis_device_f0.git 2fc25ee22264bc27034358be0bd400b893ef837e stm32f0
-hw/mcu/st/cmsis_device_f1 https://github.com/STMicroelectronics/cmsis_device_f1.git 6601104a6397299b7304fd5bcd9a491f56cb23a6 stm32f1
-hw/mcu/st/cmsis_device_f2 https://github.com/STMicroelectronics/cmsis_device_f2.git 182fcb3681ce116816feb41b7764f1b019ce796f stm32f2
-hw/mcu/st/cmsis_device_f3 https://github.com/STMicroelectronics/cmsis_device_f3.git 5e4ee5ed7a7b6c85176bb70a9fd3c72d6eb99f1b stm32f3
-hw/mcu/st/cmsis_device_f4 https://github.com/STMicroelectronics/cmsis_device_f4.git 2615e866fa48fe1ff1af9e31c348813f2b19e7ec stm32f4
-hw/mcu/st/cmsis_device_f7 https://github.com/STMicroelectronics/cmsis_device_f7.git 25b0463439303b7a38f0d27b161f7d2f3c096e79 stm32f7
-hw/mcu/st/cmsis_device_g0 https://github.com/STMicroelectronics/cmsis_device_g0.git 3a23e1224417f3f2d00300ecd620495e363f2094 stm32g0
-hw/mcu/st/cmsis_device_g4 https://github.com/STMicroelectronics/cmsis_device_g4.git ce822adb1dc552b3aedd13621edbc7fdae124878 stm32g4
-hw/mcu/st/cmsis_device_h5 https://github.com/STMicroelectronics/cmsis_device_h5.git cd2d1d579743de57b88ccaf61a968b9c05848ffc stm32h5
-hw/mcu/st/cmsis_device_h7 https://github.com/STMicroelectronics/cmsis_device_h7.git 60dc2c913203dc8629dc233d4384dcc41c91e77f stm32h7
-hw/mcu/st/cmsis_device_l0 https://github.com/STMicroelectronics/cmsis_device_l0.git 69cd5999fd40ae6e546d4905b21635c6ca1bcb92 stm32l0
-hw/mcu/st/cmsis_device_l1 https://github.com/STMicroelectronics/cmsis_device_l1.git 7f16ec0a1c4c063f84160b4cc6bf88ad554a823e stm32l1
-hw/mcu/st/cmsis_device_l4 https://github.com/STMicroelectronics/cmsis_device_l4.git 6ca7312fa6a5a460b5a5a63d66da527fdd8359a6 stm32l4
-hw/mcu/st/cmsis_device_l5 https://github.com/STMicroelectronics/cmsis_device_l5.git d922865fc0326a102c26211c44b8e42f52c1e53d stm32l5
-hw/mcu/st/cmsis_device_u5 https://github.com/STMicroelectronics/cmsis_device_u5.git 5ad9797c54ec3e55eff770fc9b3cd4a1aefc1309 stm32u5
-hw/mcu/st/cmsis_device_wb https://github.com/STMicroelectronics/cmsis_device_wb.git 9c5d1920dd9fabbe2548e10561d63db829bb744f stm32wb
-hw/mcu/st/stm32-mfxstm32l152 https://github.com/STMicroelectronics/stm32-mfxstm32l152.git 7f4389efee9c6a655b55e5df3fceef5586b35f9b stm32h7
-hw/mcu/st/stm32c0xx_hal_driver https://github.com/STMicroelectronics/stm32c0xx_hal_driver.git 41253e2f1d7ae4a4d0c379cf63f5bcf71fcf8eb3 stm32c0
-hw/mcu/st/stm32f0xx_hal_driver https://github.com/STMicroelectronics/stm32f0xx_hal_driver.git 0e95cd88657030f640a11e690a8a5186c7712ea5 stm32f0
-hw/mcu/st/stm32f1xx_hal_driver https://github.com/STMicroelectronics/stm32f1xx_hal_driver.git 1dd9d3662fb7eb2a7f7d3bc0a4c1dc7537915a29 stm32f1
-hw/mcu/st/stm32f2xx_hal_driver https://github.com/STMicroelectronics/stm32f2xx_hal_driver.git c75ace9b908a9aca631193ebf2466963b8ea33d0 stm32f2
-hw/mcu/st/stm32f3xx_hal_driver https://github.com/STMicroelectronics/stm32f3xx_hal_driver.git 1761b6207318ede021706e75aae78f452d72b6fa stm32f3
-hw/mcu/st/stm32f4xx_hal_driver https://github.com/STMicroelectronics/stm32f4xx_hal_driver.git 04e99fbdabd00ab8f370f377c66b0a4570365b58 stm32f4
-hw/mcu/st/stm32f7xx_hal_driver https://github.com/STMicroelectronics/stm32f7xx_hal_driver.git f7ffdf6bf72110e58b42c632b0a051df5997e4ee stm32f7
-hw/mcu/st/stm32g0xx_hal_driver https://github.com/STMicroelectronics/stm32g0xx_hal_driver.git e911b12c7f67084d7f6b76157a4c0d4e2ec3779c stm32g0
-hw/mcu/st/stm32g4xx_hal_driver https://github.com/STMicroelectronics/stm32g4xx_hal_driver.git 8b4518417706d42eef5c14e56a650005abf478a8 stm32g4
-hw/mcu/st/stm32h5xx_hal_driver https://github.com/STMicroelectronics/stm32h5xx_hal_driver.git 2cf77de584196d619cec1b4586c3b9e2820a254e stm32h5
-hw/mcu/st/stm32h7xx_hal_driver https://github.com/STMicroelectronics/stm32h7xx_hal_driver.git d8461b980b59b1625207d8c4f2ce0a9c2a7a3b04 stm32h7
-hw/mcu/st/stm32l0xx_hal_driver https://github.com/STMicroelectronics/stm32l0xx_hal_driver.git fbdacaf6f8c82a4e1eb9bd74ba650b491e97e17b stm32l0
-hw/mcu/st/stm32l1xx_hal_driver https://github.com/STMicroelectronics/stm32l1xx_hal_driver.git 44efc446fa69ed8344e7fd966e68ed11043b35d9 stm32l1
-hw/mcu/st/stm32l4xx_hal_driver https://github.com/STMicroelectronics/stm32l4xx_hal_driver.git aee3d5bf283ae5df87532b781bdd01b7caf256fc stm32l4
-hw/mcu/st/stm32l5xx_hal_driver https://github.com/STMicroelectronics/stm32l5xx_hal_driver.git 675c32a75df37f39d50d61f51cb0dcf53f07e1cb stm32l5
-hw/mcu/st/stm32u5xx_hal_driver https://github.com/STMicroelectronics/stm32u5xx_hal_driver.git 4d93097a67928e9377e655ddd14622adc31b9770 stm32u5
-hw/mcu/st/stm32wbxx_hal_driver https://github.com/STMicroelectronics/stm32wbxx_hal_driver.git 2c5f06638be516c1b772f768456ba637f077bac8 stm32wb
-hw/mcu/ti https://github.com/hathach/ti_driver.git 143ed6cc20a7615d042b03b21e070197d473e6e5 msp430 msp432e4 tm4c
-hw/mcu/wch/ch32f20x https://github.com/openwch/ch32f20x.git 77c4095087e5ed2c548ec9058e655d0b8757663b ch32f20x
-hw/mcu/wch/ch32v103 https://github.com/openwch/ch32v103.git 7578cae0b21f86dd053a1f781b2fc6ab99d0ec17 ch32v10x
-hw/mcu/wch/ch32v20x https://github.com/openwch/ch32v20x.git c4c38f507e258a4e69b059ccc2dc27dde33cea1b ch32v20x
-hw/mcu/wch/ch32v307 https://github.com/openwch/ch32v307.git 184f21b852cb95eed58e86e901837bc9fff68775 ch32v307
-lib/CMSIS_5 https://github.com/ARM-software/CMSIS_5.git 2b7495b8535bdcb306dac29b9ded4cfb679d7e5c imxrt kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx mm32 msp432e4 nrf saml2x lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43 stm32c0 stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32g0 stm32g4 stm32h5 stm32h7 stm32l0 stm32l1 stm32l4 stm32l5 stm32u5 stm32wb sam3x samd11 samd21 samd51 samd5x_e5x same5x same7x saml2x samg tm4c
-lib/CMSIS_6 https://github.com/ARM-software/CMSIS_6.git b0bbb0423b278ca632cfe1474eb227961d835fd2 ra
-lib/FreeRTOS-Kernel https://github.com/FreeRTOS/FreeRTOS-Kernel.git cc0e0707c0c748713485b870bb980852b210877f all
-lib/lwip https://github.com/lwip-tcpip/lwip.git 159e31b689577dbf69cf0683bbaffbd71fa5ee10 all
-lib/sct_neopixel https://github.com/gsteiert/sct_neopixel.git e73e04ca63495672d955f9268e003cffe168fcd8 lpc55
-tools/uf2 https://github.com/microsoft/uf2.git c594542b2faa01cc33a2b97c9fbebc38549df80a all
-======================================== ============================================================== ======================================== ====================================================================================================================================================================================================================================================================================================================================
+======================================== ================================================================ ======================================== ======================================================================================================================================================================================================================================================================================================================================================
+Local Path Repo Commit Required by
+======================================== ================================================================ ======================================== ======================================================================================================================================================================================================================================================================================================================================================
+hw/mcu/allwinner https://github.com/hathach/allwinner_driver.git 8e5e89e8e132c0fd90e72d5422e5d3d68232b756 fc100s
+hw/mcu/analog/msdk https://github.com/analogdevicesinc/msdk.git b20b398d3e5e2007594e54a74ba3d2a2e50ddd75 maxim
+hw/mcu/bridgetek/ft9xx/ft90x-sdk https://github.com/BRTSG-FOSS/ft90x-sdk.git 91060164afe239fcb394122e8bf9eb24d3194eb1 brtmm90x
+hw/mcu/broadcom https://github.com/adafruit/broadcom-peripherals.git 08370086080759ed54ac1136d62d2ad24c6fa267 broadcom_32bit broadcom_64bit
+hw/mcu/gd/nuclei-sdk https://github.com/Nuclei-Software/nuclei-sdk.git 7eb7bfa9ea4fbeacfafe1d5f77d5a0e6ed3922e7 gd32vf103
+hw/mcu/infineon/mtb-xmclib-cat3 https://github.com/Infineon/mtb-xmclib-cat3.git daf5500d03cba23e68c2f241c30af79cd9d63880 xmc4000
+hw/mcu/microchip https://github.com/hathach/microchip_driver.git 9e8b37e307d8404033bb881623a113931e1edf27 sam3x samd11 samd21 samd51 samd5x_e5x same5x same7x saml2x samg
+hw/mcu/mindmotion/mm32sdk https://github.com/hathach/mm32sdk.git b93e856211060ae825216c6a1d6aa347ec758843 mm32
+hw/mcu/nordic/nrfx https://github.com/NordicSemiconductor/nrfx.git 7c47cc0a56ce44658e6da2458e86cd8783ccc4a2 nrf
+hw/mcu/nuvoton https://github.com/majbthrd/nuc_driver.git 2204191ec76283371419fbcec207da02e1bc22fa nuc
+hw/mcu/nxp/lpcopen https://github.com/hathach/nxp_lpcopen.git b41cf930e65c734d8ec6de04f1d57d46787c76ae lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43
+hw/mcu/nxp/mcux-sdk https://github.com/nxp-mcuxpresso/mcux-sdk a1bdae309a14ec95a4f64a96d3315a4f89c397c6 kinetis_k kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx imxrt
+hw/mcu/raspberry_pi/Pico-PIO-USB https://github.com/sekigon-gonnoc/Pico-PIO-USB.git 3c1eec341a5232640e4c00628b889b641af34b28 rp2040
+hw/mcu/renesas/fsp https://github.com/renesas/fsp.git edcc97d684b6f716728a60d7a6fea049d9870bd6 ra
+hw/mcu/renesas/rx https://github.com/kkitayam/rx_device.git 706b4e0cf485605c32351e2f90f5698267996023 rx
+hw/mcu/silabs/cmsis-dfp-efm32gg12b https://github.com/cmsis-packs/cmsis-dfp-efm32gg12b.git f1c31b7887669cb230b3ea63f9b56769078960bc efm32
+hw/mcu/sony/cxd56/spresense-exported-sdk https://github.com/sonydevworld/spresense-exported-sdk.git 2ec2a1538362696118dc3fdf56f33dacaf8f4067 spresense
+hw/mcu/st/cmsis_device_c0 https://github.com/STMicroelectronics/cmsis_device_c0.git fb56b1b70c73b74eacda2a4bcc36886444364ab3 stm32c0
+hw/mcu/st/cmsis_device_f0 https://github.com/STMicroelectronics/cmsis_device_f0.git 2fc25ee22264bc27034358be0bd400b893ef837e stm32f0
+hw/mcu/st/cmsis_device_f1 https://github.com/STMicroelectronics/cmsis_device_f1.git 6601104a6397299b7304fd5bcd9a491f56cb23a6 stm32f1
+hw/mcu/st/cmsis_device_f2 https://github.com/STMicroelectronics/cmsis_device_f2.git 182fcb3681ce116816feb41b7764f1b019ce796f stm32f2
+hw/mcu/st/cmsis_device_f3 https://github.com/STMicroelectronics/cmsis_device_f3.git 5e4ee5ed7a7b6c85176bb70a9fd3c72d6eb99f1b stm32f3
+hw/mcu/st/cmsis_device_f4 https://github.com/STMicroelectronics/cmsis_device_f4.git 2615e866fa48fe1ff1af9e31c348813f2b19e7ec stm32f4
+hw/mcu/st/cmsis_device_f7 https://github.com/STMicroelectronics/cmsis_device_f7.git 25b0463439303b7a38f0d27b161f7d2f3c096e79 stm32f7
+hw/mcu/st/cmsis_device_g0 https://github.com/STMicroelectronics/cmsis_device_g0.git 3a23e1224417f3f2d00300ecd620495e363f2094 stm32g0
+hw/mcu/st/cmsis_device_g4 https://github.com/STMicroelectronics/cmsis_device_g4.git ce822adb1dc552b3aedd13621edbc7fdae124878 stm32g4
+hw/mcu/st/cmsis_device_h5 https://github.com/STMicroelectronics/cmsis_device_h5.git cd2d1d579743de57b88ccaf61a968b9c05848ffc stm32h5
+hw/mcu/st/cmsis_device_h7 https://github.com/STMicroelectronics/cmsis_device_h7.git 60dc2c913203dc8629dc233d4384dcc41c91e77f stm32h7
+hw/mcu/st/cmsis_device_h7rs https://github.com/STMicroelectronics/cmsis_device_h7rs.git 832649d1fd09bd901e9f68e979522e5c209ebf20 stm32h7rs
+hw/mcu/st/cmsis_device_l0 https://github.com/STMicroelectronics/cmsis_device_l0.git 69cd5999fd40ae6e546d4905b21635c6ca1bcb92 stm32l0
+hw/mcu/st/cmsis_device_l1 https://github.com/STMicroelectronics/cmsis_device_l1.git 7f16ec0a1c4c063f84160b4cc6bf88ad554a823e stm32l1
+hw/mcu/st/cmsis_device_l4 https://github.com/STMicroelectronics/cmsis_device_l4.git 6ca7312fa6a5a460b5a5a63d66da527fdd8359a6 stm32l4
+hw/mcu/st/cmsis_device_l5 https://github.com/STMicroelectronics/cmsis_device_l5.git d922865fc0326a102c26211c44b8e42f52c1e53d stm32l5
+hw/mcu/st/cmsis_device_n6 https://github.com/STMicroelectronics/cmsis-device-n6.git f818b00f775444e8d19ef6cad822534c345e054f stm32n6
+hw/mcu/st/cmsis_device_u5 https://github.com/STMicroelectronics/cmsis_device_u5.git 5ad9797c54ec3e55eff770fc9b3cd4a1aefc1309 stm32u5
+hw/mcu/st/cmsis_device_wb https://github.com/STMicroelectronics/cmsis_device_wb.git d6a7fa2e7de084f5e5e47f2ab88b022fe9b50e5a stm32wb
+hw/mcu/st/stm32-mfxstm32l152 https://github.com/STMicroelectronics/stm32-mfxstm32l152.git 7f4389efee9c6a655b55e5df3fceef5586b35f9b stm32h7
+hw/mcu/st/stm32c0xx_hal_driver https://github.com/STMicroelectronics/stm32c0xx_hal_driver.git 41253e2f1d7ae4a4d0c379cf63f5bcf71fcf8eb3 stm32c0
+hw/mcu/st/stm32f0xx_hal_driver https://github.com/STMicroelectronics/stm32f0xx_hal_driver.git 0e95cd88657030f640a11e690a8a5186c7712ea5 stm32f0
+hw/mcu/st/stm32f1xx_hal_driver https://github.com/STMicroelectronics/stm32f1xx_hal_driver.git 1dd9d3662fb7eb2a7f7d3bc0a4c1dc7537915a29 stm32f1
+hw/mcu/st/stm32f2xx_hal_driver https://github.com/STMicroelectronics/stm32f2xx_hal_driver.git c75ace9b908a9aca631193ebf2466963b8ea33d0 stm32f2
+hw/mcu/st/stm32f3xx_hal_driver https://github.com/STMicroelectronics/stm32f3xx_hal_driver.git 1761b6207318ede021706e75aae78f452d72b6fa stm32f3
+hw/mcu/st/stm32f4xx_hal_driver https://github.com/STMicroelectronics/stm32f4xx_hal_driver.git 04e99fbdabd00ab8f370f377c66b0a4570365b58 stm32f4
+hw/mcu/st/stm32f7xx_hal_driver https://github.com/STMicroelectronics/stm32f7xx_hal_driver.git f7ffdf6bf72110e58b42c632b0a051df5997e4ee stm32f7
+hw/mcu/st/stm32g0xx_hal_driver https://github.com/STMicroelectronics/stm32g0xx_hal_driver.git e911b12c7f67084d7f6b76157a4c0d4e2ec3779c stm32g0
+hw/mcu/st/stm32g4xx_hal_driver https://github.com/STMicroelectronics/stm32g4xx_hal_driver.git 8b4518417706d42eef5c14e56a650005abf478a8 stm32g4
+hw/mcu/st/stm32h5xx_hal_driver https://github.com/STMicroelectronics/stm32h5xx_hal_driver.git 2cf77de584196d619cec1b4586c3b9e2820a254e stm32h5
+hw/mcu/st/stm32h7rsxx_hal_driver https://github.com/STMicroelectronics/stm32h7rsxx-hal-driver.git 7ca2e07ca21bc66b53654e845b4c85c884343b60 stm32h7rs
+hw/mcu/st/stm32h7xx_hal_driver https://github.com/STMicroelectronics/stm32h7xx_hal_driver.git d8461b980b59b1625207d8c4f2ce0a9c2a7a3b04 stm32h7
+hw/mcu/st/stm32l0xx_hal_driver https://github.com/STMicroelectronics/stm32l0xx_hal_driver.git fbdacaf6f8c82a4e1eb9bd74ba650b491e97e17b stm32l0
+hw/mcu/st/stm32l1xx_hal_driver https://github.com/STMicroelectronics/stm32l1xx_hal_driver.git 44efc446fa69ed8344e7fd966e68ed11043b35d9 stm32l1
+hw/mcu/st/stm32l4xx_hal_driver https://github.com/STMicroelectronics/stm32l4xx_hal_driver.git aee3d5bf283ae5df87532b781bdd01b7caf256fc stm32l4
+hw/mcu/st/stm32l5xx_hal_driver https://github.com/STMicroelectronics/stm32l5xx_hal_driver.git 675c32a75df37f39d50d61f51cb0dcf53f07e1cb stm32l5
+hw/mcu/st/stm32n6xx_hal_driver https://github.com/STMicroelectronics/stm32n6xx-hal-driver.git 49f9989d10cf6817d4b07ac01848956b46bd0fd6 stm32n6
+hw/mcu/st/stm32u5xx_hal_driver https://github.com/STMicroelectronics/stm32u5xx_hal_driver.git 4d93097a67928e9377e655ddd14622adc31b9770 stm32u5
+hw/mcu/st/stm32wbxx_hal_driver https://github.com/STMicroelectronics/stm32wbxx_hal_driver.git 2c5f06638be516c1b772f768456ba637f077bac8 stm32wb
+hw/mcu/ti https://github.com/hathach/ti_driver.git 143ed6cc20a7615d042b03b21e070197d473e6e5 msp430 msp432e4 tm4c
+hw/mcu/wch/ch32f20x https://github.com/openwch/ch32f20x.git 77c4095087e5ed2c548ec9058e655d0b8757663b ch32f20x
+hw/mcu/wch/ch32v103 https://github.com/openwch/ch32v103.git 7578cae0b21f86dd053a1f781b2fc6ab99d0ec17 ch32v10x
+hw/mcu/wch/ch32v20x https://github.com/openwch/ch32v20x.git c4c38f507e258a4e69b059ccc2dc27dde33cea1b ch32v20x
+hw/mcu/wch/ch32v307 https://github.com/openwch/ch32v307.git 184f21b852cb95eed58e86e901837bc9fff68775 ch32v307
+lib/CMSIS_5 https://github.com/ARM-software/CMSIS_5.git 2b7495b8535bdcb306dac29b9ded4cfb679d7e5c imxrt kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx mm32 msp432e4 nrf saml2x lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43 stm32c0 stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32g0 stm32g4 stm32h5 stm32h7 stm32h7rs stm32l0 stm32l1 stm32l4 stm32l5 stm32n6 stm32u5 stm32wb sam3x samd11 samd21 samd51 samd5x_e5x same5x same7x saml2x samg tm4c
+lib/CMSIS_6 https://github.com/ARM-software/CMSIS_6.git b0bbb0423b278ca632cfe1474eb227961d835fd2 ra
+lib/FreeRTOS-Kernel https://github.com/FreeRTOS/FreeRTOS-Kernel.git cc0e0707c0c748713485b870bb980852b210877f all
+lib/lwip https://github.com/lwip-tcpip/lwip.git 159e31b689577dbf69cf0683bbaffbd71fa5ee10 all
+lib/sct_neopixel https://github.com/gsteiert/sct_neopixel.git e73e04ca63495672d955f9268e003cffe168fcd8 lpc55
+tools/uf2 https://github.com/microsoft/uf2.git c594542b2faa01cc33a2b97c9fbebc38549df80a all
+======================================== ================================================================ ======================================== ======================================================================================================================================================================================================================================================================================================================================================
diff --git a/docs/reference/getting_started.rst b/docs/reference/getting_started.rst
index 963420f7b..bb9ff1cb4 100644
--- a/docs/reference/getting_started.rst
+++ b/docs/reference/getting_started.rst
@@ -5,19 +5,19 @@ Getting Started
Add TinyUSB to your project
---------------------------
-It is relatively simple to incorporate tinyusb to your project
+To incorporate tinyusb to your project
-* Copy or ``git submodule`` this repo into your project in a subfolder. Let's say it is *your_project/tinyusb*
-* Add all the .c in the ``tinyusb/src`` folder to your project
-* Add *your_project/tinyusb/src* to your include path. Also make sure your current include path also contains the configuration file tusb_config.h.
-* Make sure all required macros are all defined properly in tusb_config.h (configure file in demo application is sufficient, but you need to add a few more such as ``CFG_TUSB_MCU``, ``CFG_TUSB_OS`` since they are passed by IDE/compiler to maintain a unique configure for all boards).
+* Copy or ``git submodule`` this repo into your project in a subfolder. Let's say it is ``your_project/tinyusb``
+* Add all the ``.c`` in the ``tinyusb/src`` folder to your project
+* Add ``your_project/tinyusb/src`` to your include path. Also make sure your current include path also contains the configuration file ``tusb_config.h``.
+* Make sure all required macros are all defined properly in ``tusb_config.h`` (configure file in demo application is sufficient, but you need to add a few more such as ``CFG_TUSB_MCU``, ``CFG_TUSB_OS`` since they are passed by make/cmake to maintain a unique configure for all boards).
* If you use the device stack, make sure you have created/modified usb descriptors for your own need. Ultimately you need to implement all **tud descriptor** callbacks for the stack to work.
-* Add tusb_init(rhport, role) call to your reset initialization code.
+* Add ``tusb_init(rhport, role)`` call to your reset initialization code.
* Call ``tusb_int_handler(rhport, in_isr)`` in your USB IRQ Handler
* Implement all enabled classes's callbacks.
-* If you don't use any RTOSes at all, you need to continuously and/or periodically call tud_task()/tuh_task() function. All of the callbacks and functionality are handled and invoked within the call of that task runner.
+* If you don't use any RTOSes at all, you need to continuously and/or periodically call ``tud_task()``/``tuh_task()`` function. All of the callbacks and functionality are handled and invoked within the call of that task runner.
-.. code-block::
+.. code-block:: c
int main(void) {
tusb_rhport_init_t dev_init = {
@@ -50,9 +50,9 @@ It is relatively simple to incorporate tinyusb to your project
Examples
--------
-For your convenience, TinyUSB contains a handful of examples for both host and device with/without RTOS to quickly test the functionality as well as demonstrate how API() should be used. Most examples will work on most of `the supported boards `_. Firstly we need to ``git clone`` if not already
+For your convenience, TinyUSB contains a handful of examples for both host and device with/without RTOS to quickly test the functionality as well as demonstrate how API should be used. Most examples will work on most of `the supported boards `_. Firstly we need to ``git clone`` if not already
-.. code-block::
+.. code-block:: bash
$ git clone https://github.com/hathach/tinyusb tinyusb
$ cd tinyusb
@@ -62,41 +62,53 @@ Some ports will also require a port-specific SDK (e.g. RP2040) or binary (e.g. S
Dependencies
^^^^^^^^^^^^
-The hardware code is located in ``hw/bsp`` folder, and is organized by family/boards. e.g raspberry_pi_pico is located in ``hw/bsp/rp2040/boards/raspberry_pi_pico`` where FAMILY=rp2040 and BOARD=raspberry_pi_pico. Before building, we firstly need to download dependencies such as: MCU low-level peripheral driver and external libraries e.g FreeRTOS (required by some examples). We can do that by either ways:
+The hardware code is located in ``hw/bsp`` folder, and is organized by family/boards. e.g raspberry_pi_pico is located in ``hw/bsp/rp2040/boards/raspberry_pi_pico`` where ``FAMILY=rp2040`` and ``BOARD=raspberry_pi_pico``. Before building, we firstly need to download dependencies such as: MCU low-level peripheral driver and external libraries e.g FreeRTOS (required by some examples). We can do that by either ways:
1. Run ``tools/get_deps.py {FAMILY}`` script to download all dependencies for a family as follow. Note: For TinyUSB developer to download all dependencies, use FAMILY=all.
-.. code-block::
+.. code-block:: bash
$ python tools/get_deps.py rp2040
2. Or run the ``get-deps`` target in one of the example folder as follow.
-.. code-block::
+.. code-block:: bash
$ cd examples/device/cdc_msc
- $ make BOARD=raspberry_pi_pico get-deps
+ $ make BOARD=feather_nrf52840_express get-deps
You only need to do this once per family. Check out `complete list of dependencies and their designated path here `_
-Build
-^^^^^
+Build Examples
+^^^^^^^^^^^^^^
-To build example, first change directory to an example folder.
+Examples support make and cmake build system for most MCUs, however some MCU families such as espressif or rp2040 only support cmake. First change directory to an example folder.
-.. code-block::
+.. code-block:: bash
$ cd examples/device/cdc_msc
-Then compile with ``make BOARD={board_name} all`` , for example
+Then compile with make or cmake
-.. code-block::
+.. code-block:: bash
- $ make BOARD=raspberry_pi_pico all
+ $ # make
+ $ make BOARD=feather_nrf52840_express all
+
+ $ # cmake
+ $ mkdir build && cd build
+ $ cmake -DBOARD=raspberry_pi_pico ..
+ $ make
+
+To list all available targets with cmake
+
+.. code-block:: bash
+
+ $ cmake --build . --target help
Note: some examples especially those that uses Vendor class (e.g webUSB) may requires udev permission on Linux (and/or macOS) to access usb device. It depends on your OS distro, typically copy ``99-tinyusb.rules`` and reload your udev is good to go
-.. code-block::
+.. code-block:: bash
$ cp examples/device/99-tinyusb.rules /etc/udev/rules.d/
$ sudo udevadm control --reload-rules && sudo udevadm trigger
@@ -104,27 +116,31 @@ Note: some examples especially those that uses Vendor class (e.g webUSB) may req
RootHub Port Selection
~~~~~~~~~~~~~~~~~~~~~~
-If a board has several ports, one port is chosen by default in the individual board.mk file. Use option ``PORT=x`` To choose another port. For example to select the HS port of a STM32F746Disco board, use:
+If a board has several ports, one port is chosen by default in the individual board.mk file. Use option ``RHPORT_DEVICE=x`` or ``RHPORT_HOST=x`` To choose another port. For example to select the HS port of a STM32F746Disco board, use:
-.. code-block::
+.. code-block:: bash
- $ make BOARD=stm32f746disco PORT=1 all
+ $ make BOARD=stm32f746disco RHPORT_DEVICE=1 all
+
+ $ cmake -DBOARD=stm32f746disco -DRHPORT_DEVICE=1 ..
Port Speed
~~~~~~~~~~
-A MCU can support multiple operational speed. By default, the example build system will use the fastest supported on the board. Use option ``SPEED=full/high`` e.g To force F723 operate at full instead of default high speed
+A MCU can support multiple operational speed. By default, the example build system will use the fastest supported on the board. Use option ``RHPORT_DEVICE_SPEED=OPT_MODE_FULL/HIGH_SPEED/`` or ``RHPORT_HOST_SPEED=OPT_MODE_FULL/HIGH_SPEED/`` e.g To force F723 operate at full instead of default high speed
-.. code-block::
+.. code-block:: bash
- $ make BOARD=stm32f746disco SPEED=full all
+ $ make BOARD=stm32f746disco RHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED all
+
+ $ cmake -DBOARD=stm32f746disco -DRHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED ..
Size Analysis
~~~~~~~~~~~~~
-First install `linkermap tool `_ then ``linkermap`` target can be used to analyze code size. You may want to compile with ``NO_LTO=1`` since -flto merges code across .o files and make it difficult to analyze.
+First install `linkermap tool `_ then ``linkermap`` target can be used to analyze code size. You may want to compile with ``NO_LTO=1`` since ``-flto`` merges code across ``.o`` files and make it difficult to analyze.
-.. code-block::
+.. code-block:: bash
$ make BOARD=feather_nrf52840_express NO_LTO=1 all linkermap
@@ -133,19 +149,23 @@ Debug
To compile for debugging add ``DEBUG=1``\ , for example
-.. code-block::
+.. code-block:: bash
$ make BOARD=feather_nrf52840_express DEBUG=1 all
+ $ cmake -DBOARD=feather_nrf52840_express -DCMAKE_BUILD_TYPE=Debug ..
+
Log
~~~
-Should you have an issue running example and/or submitting an bug report. You could enable TinyUSB built-in debug logging with optional ``LOG=``. LOG=1 will only print out error message, LOG=2 print more information with on-going events. LOG=3 or higher is not used yet.
+Should you have an issue running example and/or submitting an bug report. You could enable TinyUSB built-in debug logging with optional ``LOG=``. ``LOG=1`` will only print out error message, ``LOG=2`` print more information with on-going events. ``LOG=3`` or higher is not used yet.
-.. code-block::
+.. code-block:: bash
$ make BOARD=feather_nrf52840_express LOG=2 all
+ $ cmake -DBOARD=feather_nrf52840_express -DLOG=2 ..
+
Logger
~~~~~~
@@ -164,74 +184,80 @@ By default log message is printed via on-board UART which is slow and take lots
* Pros: should be compatible with more debugger that support SWO.
* Software viewer should be provided along with your debugger driver.
-.. code-block::
+.. code-block:: bash
$ make BOARD=feather_nrf52840_express LOG=2 LOGGER=rtt all
$ make BOARD=feather_nrf52840_express LOG=2 LOGGER=swo all
+ $ cmake -DBOARD=feather_nrf52840_express -DLOG=2 -DLOGGER=rtt ..
+ $ cmake -DBOARD=feather_nrf52840_express -DLOG=2 -DLOGGER=swo ..
+
Flash
^^^^^
``flash`` target will use the default on-board debugger (jlink/cmsisdap/stlink/dfu) to flash the binary, please install those support software in advance. Some board use bootloader/DFU via serial which is required to pass to make command
-.. code-block::
+.. code-block:: bash
$ make BOARD=feather_nrf52840_express flash
$ make SERIAL=/dev/ttyACM0 BOARD=feather_nrf52840_express flash
-Since jlink can be used with most of the boards, there is also ``flash-jlink`` target for your convenience.
+Since jlink/openocd can be used with most of the boards, there is also ``flash-jlink/openocd`` (make) and ``EXAMPLE-jlink/openocd`` target for your convenience. Note for stm32 board with stlink, you can use ``flash-stlink`` target as well.
-.. code-block::
+.. code-block:: bash
$ make BOARD=feather_nrf52840_express flash-jlink
+ $ make BOARD=feather_nrf52840_express flash-openocd
+
+ $ cmake --build . --target cdc_msc-jlink
+ $ cmake --build . --target cdc_msc-openocd
Some board use uf2 bootloader for drag & drop in to mass storage device, uf2 can be generated with ``uf2`` target
-.. code-block::
+.. code-block:: bash
$ make BOARD=feather_nrf52840_express all uf2
+ $ cmake --build . --target cdc_msc-uf2
+
IAR Support
------------
+^^^^^^^^^^^
Use project connection
-^^^^^^^^^^^^^^^^^^^^^^
+~~~~~~~~~~~~~~~~~~~~~~
IAR Project Connection files are provided to import TinyUSB stack into your project.
-* A buldable project of your MCU need to be created in advance.
-
+* A buildable project of your MCU need to be created in advance.
* Take example of STM32F0:
- - You need `stm32l0xx.h`, `startup_stm32f0xx.s`, `system_stm32f0xx.c`.
+ - You need ``stm32l0xx.h``, ``startup_stm32f0xx.s``, ``system_stm32f0xx.c``.
- - `STM32L0xx_HAL_Driver` is only needed to run examples, TinyUSB stack itself doesn't rely on MCU's SDKs.
+ - ``STM32L0xx_HAL_Driver`` is only needed to run examples, TinyUSB stack itself doesn't rely on MCU's SDKs.
-* Open ``Tools -> Configure Custom Argument Variables`` (Switch to `Global` tab if you want to do it for all your projects)
- Click `New Group ...`, name it to `TUSB`, Click `Add Variable ...`, name it to `TUSB_DIR`, change it's value to the path of your TinyUSB stack,
- for example `C:\\tinyusb`
+* Open ``Tools -> Configure Custom Argument Variables`` (Switch to ``Global`` tab if you want to do it for all your projects)
+ Click ``New Group ...``, name it to ``TUSB``, Click ``Add Variable ...``, name it to ``TUSB_DIR``, change it's value to the path of your TinyUSB stack,
+ for example ``C:\\tinyusb``
-Import stack only
-~~~~~~~~~~~~~~~~~
+**Import stack only**
-1. Open ``Project -> Add project Connection ...``, click `OK`, choose `tinyusb\\tools\\iar_template.ipcf`.
+Open ``Project -> Add project Connection ...``, click ``OK``, choose ``tinyusb\\tools\\iar_template.ipcf``.
-Run examples
-~~~~~~~~~~~~
+**Run examples**
-1. (Python3 is needed) Run ``iar_gen.py`` to generate .ipcf files of examples:
+1. Run ``iar_gen.py`` to generate .ipcf files of examples:
.. code-block::
- cd C:\tinyusb\tools
- python iar_gen.py
+ > cd C:\tinyusb\tools
+ > python iar_gen.py
-2. Open `Project -> Add project Connection ...`, click `OK`, choose `tinyusb\\examples\\(.ipcf of example)`.
- For example `C:\\tinyusb\\examples\\device\\cdc_msc\\iar_cdc_msc.ipcf`
+2. Open ``Project -> Add project Connection ...``, click ``OK``, choose ``tinyusb\\examples\\(.ipcf of example)``.
+ For example ``C:\\tinyusb\\examples\\device\\cdc_msc\\iar_cdc_msc.ipcf``
-Native CMake support (9.50.1+)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Native CMake support
+~~~~~~~~~~~~~~~~~~~~
With 9.50.1 release, IAR added experimental native CMake support (strangely not mentioned in public release note). Now it's possible to import CMakeLists.txt then build and debug as a normal project.
@@ -239,5 +265,5 @@ Following these steps:
1. Add IAR compiler binary path to system ``PATH`` environment variable, such as ``C:\Program Files\IAR Systems\Embedded Workbench 9.2\arm\bin``.
2. Create new project in IAR, in Tool chain dropdown menu, choose CMake for Arm then Import ``CMakeLists.txt`` from chosen example directory.
-3. Set up board option in ``Option - CMake/CMSIS-TOOLBOX - CMake``, for example :code:`-DBOARD=stm32f439nucleo -DTOOLCHAIN=iar`, **Uncheck 'Override tools in env'**.
+3. Set up board option in ``Option - CMake/CMSIS-TOOLBOX - CMake``, for example ``-DBOARD=stm32f439nucleo -DTOOLCHAIN=iar``, **Uncheck 'Override tools in env'**.
4. (For debug only) Choose correct CPU model in ``Option - General Options - Target``, to profit register and memory view.
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/cmake/cpu/cortex-m55.cmake b/examples/build_system/cmake/cpu/cortex-m55.cmake
new file mode 100644
index 000000000..a7a57957c
--- /dev/null
+++ b/examples/build_system/cmake/cpu/cortex-m55.cmake
@@ -0,0 +1,26 @@
+if (TOOLCHAIN STREQUAL "gcc")
+ set(TOOLCHAIN_COMMON_FLAGS
+ -mthumb
+ -mcpu=cortex-m55
+ -mfloat-abi=hard
+ -mfpu=fpv5-d16
+ -mcmse
+ )
+ set(FREERTOS_PORT GCC_ARM_CM55_NTZ_NONSECURE CACHE INTERNAL "")
+
+elseif (TOOLCHAIN STREQUAL "clang")
+ set(TOOLCHAIN_COMMON_FLAGS
+ --target=arm-none-eabi
+ -mcpu=cortex-m55
+ -mfpu=fpv5-d16
+ )
+ set(FREERTOS_PORT GCC_ARM_CM55_NTZ_NONSECURE CACHE INTERNAL "")
+
+elseif (TOOLCHAIN STREQUAL "iar")
+ set(TOOLCHAIN_COMMON_FLAGS
+ --cpu cortex-m55
+ --fpu VFPv5_D16
+ )
+ set(FREERTOS_PORT IAR_ARM_CM55_NTZ_NONSECURE CACHE INTERNAL "")
+
+endif ()
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/build_system/make/cpu/cortex-m55.mk b/examples/build_system/make/cpu/cortex-m55.mk
new file mode 100644
index 000000000..de627caed
--- /dev/null
+++ b/examples/build_system/make/cpu/cortex-m55.mk
@@ -0,0 +1,28 @@
+ifeq ($(TOOLCHAIN),gcc)
+ CFLAGS += \
+ -mthumb \
+ -mcpu=cortex-m55 \
+ -mfloat-abi=hard \
+ -mfpu=fpv5-d16 \
+ -mcmse
+
+else ifeq ($(TOOLCHAIN),clang)
+ CFLAGS += \
+ --target=arm-none-eabi \
+ -mcpu=cortex-m55 \
+ -mfpu=fpv5-d16 \
+
+else ifeq ($(TOOLCHAIN),iar)
+ CFLAGS += \
+ --cpu cortex-m55 \
+ --fpu VFPv5_D16 \
+
+ ASFLAGS += \
+ --cpu cortex-m55 \
+ --fpu VFPv5_D16 \
+
+else
+ $(error "TOOLCHAIN is not supported")
+endif
+
+FREERTOS_PORTABLE_SRC ?= $(FREERTOS_PORTABLE_PATH)/ARM_CM55_NTZ/non_secure
diff --git a/examples/build_system/make/make.mk b/examples/build_system/make/make.mk
index 3101b66b9..f70748d34 100644
--- a/examples/build_system/make/make.mk
+++ b/examples/build_system/make/make.mk
@@ -2,6 +2,9 @@
# Common make definition for all examples
# ---------------------------------------
+# upper helper function
+to_upper = $(subst a,A,$(subst b,B,$(subst c,C,$(subst d,D,$(subst e,E,$(subst f,F,$(subst g,G,$(subst h,H,$(subst i,I,$(subst j,J,$(subst k,K,$(subst l,L,$(subst m,M,$(subst n,N,$(subst o,O,$(subst p,P,$(subst q,Q,$(subst r,R,$(subst s,S,$(subst t,T,$(subst u,U,$(subst v,V,$(subst w,W,$(subst x,X,$(subst y,Y,$(subst z,Z,$(subst -,_,$(1))))))))))))))))))))))))))))
+
#-------------------------------------------------------------
# Toolchain
# Can be changed via TOOLCHAIN=gcc|iar or CC=arm-none-eabi-gcc|iccarm|clang
@@ -109,7 +112,7 @@ INC += \
$(TOP)/$(FAMILY_PATH) \
$(TOP)/src \
-BOARD_UPPER = $(subst a,A,$(subst b,B,$(subst c,C,$(subst d,D,$(subst e,E,$(subst f,F,$(subst g,G,$(subst h,H,$(subst i,I,$(subst j,J,$(subst k,K,$(subst l,L,$(subst m,M,$(subst n,N,$(subst o,O,$(subst p,P,$(subst q,Q,$(subst r,R,$(subst s,S,$(subst t,T,$(subst u,U,$(subst v,V,$(subst w,W,$(subst x,X,$(subst y,Y,$(subst z,Z,$(subst -,_,$(BOARD))))))))))))))))))))))))))))
+BOARD_UPPER = $(call to_upper,$(BOARD))
CFLAGS += -DBOARD_$(BOARD_UPPER)
ifdef CFLAGS_CLI
@@ -120,27 +123,24 @@ endif
ifeq (${MAX3421_HOST},1)
SRC_C += src/portable/analog/max3421/hcd_max3421.c
CFLAGS += -DCFG_TUH_MAX3421=1
- CMAKE_DEFSYM += -DMAX3421_HOST=1
endif
# Log level is mapped to TUSB DEBUG option
ifneq ($(LOG),)
- CMAKE_DEFSYM += -DLOG=$(LOG)
CFLAGS += -DCFG_TUSB_DEBUG=$(LOG)
endif
# Logger: default is uart, can be set to rtt or swo
-ifneq ($(LOGGER),)
- CMAKE_DEFSYM += -DLOGGER=$(LOGGER)
-endif
-
ifeq ($(LOGGER),rtt)
- CFLAGS += -DLOGGER_RTT -DSEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL
- RTT_SRC = lib/SEGGER_RTT
- INC += $(TOP)/$(RTT_SRC)/RTT
- SRC_C += $(RTT_SRC)/RTT/SEGGER_RTT.c
-else ifeq ($(LOGGER),swo)
+ CFLAGS += -DLOGGER_RTT
+ #CFLAGS += -DSEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL
+ INC += $(TOP)/$(lib/SEGGER_RTT)/RTT
+ SRC_C += $(lib/SEGGER_RTT)/RTT/SEGGER_RTT.c
+endif
+ifeq ($(LOGGER),swo)
CFLAGS += -DLOGGER_SWO
+else
+ CFLAGS += -DLOGGER_UART
endif
# CPU specific flags
diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c
index e8c40309e..f78e48f0c 100644
--- a/examples/device/audio_4_channel_mic/src/main.c
+++ b/examples/device/audio_4_channel_mic/src/main.c
@@ -69,13 +69,8 @@ uint8_t clkValid;
audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; // Volume range state
audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state
-#if CFG_TUD_AUDIO_ENABLE_ENCODING
-// Audio test data, each buffer contains 2 channels, buffer[0] for CH0-1, buffer[1] for CH1-2
-uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX*CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE/1000/CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
-#else
// Audio test data, 4 channels muxed together, buffer[0] for CH0, buffer[1] for CH1, buffer[2] for CH2, buffer[3] for CH3
uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX*CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE/1000];
-#endif
void led_blinking_task(void);
void audio_task(void);
@@ -106,27 +101,6 @@ int main(void)
sampleFreqRng.subrange[0].bRes = 0;
// Generate dummy data
-#if CFG_TUD_AUDIO_ENABLE_ENCODING
- uint16_t * p_buff = i2s_dummy_buffer[0];
- uint16_t dataVal = 0;
- for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++)
- {
- // CH0 saw wave
- *p_buff++ = dataVal;
- // CH1 inverted saw wave
- *p_buff++ = 3200 + AUDIO_SAMPLE_RATE/1000 - dataVal;
- dataVal+= 32;
- }
- p_buff = i2s_dummy_buffer[1];
- for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++)
- {
- // CH3 square wave
- *p_buff++ = cnt < (AUDIO_SAMPLE_RATE/1000/2) ? 3400:5000;
- // CH4 sinus wave
- float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000);
- *p_buff++ = (uint16_t)((int16_t)(sinf(t) * 750) + 6000);
- }
-#else
uint16_t * p_buff = i2s_dummy_buffer;
uint16_t dataVal = 0;
for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++)
@@ -142,7 +116,6 @@ int main(void)
float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000);
*p_buff++ = (uint16_t)((int16_t)(sinf(t) * 750) + 6000);
}
-#endif
while (1)
{
@@ -195,15 +168,7 @@ void audio_task(void)
uint32_t curr_ms = board_millis();
if ( start_ms == curr_ms ) return; // not enough time
start_ms = curr_ms;
-#if CFG_TUD_AUDIO_ENABLE_ENCODING
- // Write I2S buffer into FIFO
- for (uint8_t cnt=0; cnt < 2; cnt++)
- {
- tud_audio_write_support_ff(cnt, i2s_dummy_buffer[cnt], AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX);
- }
-#else
tud_audio_write(i2s_dummy_buffer, AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX);
-#endif
}
//--------------------------------------------------------------------+
diff --git a/examples/device/audio_4_channel_mic/src/tusb_config.h b/examples/device/audio_4_channel_mic/src/tusb_config.h
index 46484f847..446a7a32a 100644
--- a/examples/device/audio_4_channel_mic/src/tusb_config.h
+++ b/examples/device/audio_4_channel_mic/src/tusb_config.h
@@ -115,26 +115,11 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 4 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)
-#define CFG_TUD_AUDIO_ENABLE_ENCODING 1
#define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 1
-#if CFG_TUD_AUDIO_ENABLE_ENCODING
-
-#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN
-#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN
-
-#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 1
-#define CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX 2 // One I2S stream contains two channels, each stream is saved within one support FIFO - this value is currently fixed, the driver does not support a changing value
-#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX)
-#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO) // Example write FIFO every 1ms, so it should be 8 times larger for HS device
-
-#else
-
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_EP_SZ_IN // Example write FIFO every 1ms, so it should be 8 times larger for HS device
-#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/examples/device/audio_4_channel_mic_freertos/src/main.c b/examples/device/audio_4_channel_mic_freertos/src/main.c
index c9de4029a..d5a34b194 100644
--- a/examples/device/audio_4_channel_mic_freertos/src/main.c
+++ b/examples/device/audio_4_channel_mic_freertos/src/main.c
@@ -39,7 +39,7 @@
#include "bsp/board_api.h"
#include "tusb.h"
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
// ESP-IDF need "freertos/" prefix in include path.
// CFG_TUSB_OS_INC_PATH should be defined accordingly.
#include "freertos/FreeRTOS.h"
@@ -105,13 +105,8 @@ uint8_t clkValid;
audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; // Volume range state
audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state
-#if CFG_TUD_AUDIO_ENABLE_ENCODING
-// Audio test data, each buffer contains 2 channels, buffer[0] for CH0-1, buffer[1] for CH1-2
-uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX*CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE/1000/CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
-#else
// Audio test data, 4 channels muxed together, buffer[0] for CH0, buffer[1] for CH1, buffer[2] for CH2, buffer[3] for CH3
uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX*CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE/1000];
-#endif
void led_blinking_task(void* param);
void usb_device_task(void* param);
@@ -132,27 +127,6 @@ int main(void)
sampleFreqRng.subrange[0].bRes = 0;
// Generate dummy data
-#if CFG_TUD_AUDIO_ENABLE_ENCODING
- uint16_t * p_buff = i2s_dummy_buffer[0];
- uint16_t dataVal = 0;
- for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++)
- {
- // CH0 saw wave
- *p_buff++ = dataVal;
- // CH1 inverted saw wave
- *p_buff++ = 3200 + AUDIO_SAMPLE_RATE/1000 - dataVal;
- dataVal+= 32;
- }
- p_buff = i2s_dummy_buffer[1];
- for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++)
- {
- // CH3 square wave
- *p_buff++ = cnt < (AUDIO_SAMPLE_RATE/1000/2) ? 3400:5000;
- // CH4 sinus wave
- float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000);
- *p_buff++ = (uint16_t)((int16_t)(sinf(t) * 750) + 6000);
- }
-#else
uint16_t * p_buff = i2s_dummy_buffer;
uint16_t dataVal = 0;
for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++)
@@ -168,7 +142,6 @@ int main(void)
float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000);
*p_buff++ = (uint16_t)((int16_t)(sinf(t) * 750) + 6000);
}
-#endif
#if configSUPPORT_STATIC_ALLOCATION
// blinky task
@@ -185,17 +158,16 @@ int main(void)
xTaskCreate(audio_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL);
#endif
- // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
- #if !TUSB_MCU_VENDOR_ESPRESSIF
+ // only start scheduler for non-espressif mcu
+ #ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
return 0;
}
-#if TUSB_MCU_VENDOR_ESPRESSIF
-void app_main(void)
-{
+#ifdef ESP_PLATFORM
+void app_main(void) {
main();
}
#endif
@@ -269,15 +241,7 @@ void audio_task(void* param)
// Here we simulate a I2S receive callback every 1ms.
while (1) {
vTaskDelay(1);
-#if CFG_TUD_AUDIO_ENABLE_ENCODING
- // Write I2S buffer into FIFO
- for (uint8_t cnt=0; cnt < 2; cnt++)
- {
- tud_audio_write_support_ff(cnt, i2s_dummy_buffer[cnt], AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX);
- }
-#else
tud_audio_write(i2s_dummy_buffer, AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX);
-#endif
}
}
diff --git a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h b/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h
index 5cd93b0d6..f7c0efe08 100644
--- a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h
+++ b/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h
@@ -59,7 +59,7 @@ extern "C" {
#endif
// Espressif IDF requires "freertos/" prefix in include path
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
@@ -121,26 +121,11 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 4 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)
-#define CFG_TUD_AUDIO_ENABLE_ENCODING 1
#define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 1
-#if CFG_TUD_AUDIO_ENABLE_ENCODING
-
-#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN
-#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN
-
-#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 1
-#define CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX 2 // One I2S stream contains two channels, each stream is saved within one support FIFO - this value is currently fixed, the driver does not support a changing value
-#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX)
-#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO) // Example write FIFO every 1ms, so it should be 8 times larger for HS device
-
-#else
-
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_EP_SZ_IN // Example write FIFO every 1ms, so it should be 8 times larger for HS device
-#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/examples/device/audio_test_freertos/src/main.c b/examples/device/audio_test_freertos/src/main.c
index c5143c3fc..3831be87f 100644
--- a/examples/device/audio_test_freertos/src/main.c
+++ b/examples/device/audio_test_freertos/src/main.c
@@ -38,7 +38,7 @@
#include "bsp/board_api.h"
#include "tusb.h"
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
// ESP-IDF need "freertos/" prefix in include path.
// CFG_TUSB_OS_INC_PATH should be defined accordingly.
#include "freertos/FreeRTOS.h"
@@ -132,15 +132,15 @@ int main(void)
xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL);
#endif
- // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
- #if !TUSB_MCU_VENDOR_ESPRESSIF
+ // only start scheduler for non-espressif mcu
+ #ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
return 0;
}
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
void app_main(void) {
main();
}
diff --git a/examples/device/audio_test_freertos/src/tusb_config.h b/examples/device/audio_test_freertos/src/tusb_config.h
index 61c5cbb96..0fb2106e2 100644
--- a/examples/device/audio_test_freertos/src/tusb_config.h
+++ b/examples/device/audio_test_freertos/src/tusb_config.h
@@ -59,7 +59,7 @@ extern "C" {
#endif
// Espressif IDF requires "freertos/" prefix in include path
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
diff --git a/examples/device/board_test/src/main.c b/examples/device/board_test/src/main.c
index 2269d45f1..d91a8760e 100644
--- a/examples/device/board_test/src/main.c
+++ b/examples/device/board_test/src/main.c
@@ -49,25 +49,34 @@ int main(void) {
while (1) {
uint32_t interval_ms = board_button_read() ? BLINK_PRESSED : BLINK_UNPRESSED;
+ int ch = board_getchar();
+ if (ch > 0) {
+ board_putchar(ch);
+ #ifndef LOGGER_UART
+ board_uart_write(&ch, 1);
+ #endif
+ }
+
// Blink and print every interval ms
if (!(board_millis() - start_ms < interval_ms)) {
- board_uart_write(HELLO_STR, strlen(HELLO_STR));
-
start_ms = board_millis();
+ if (ch < 0) {
+ // skip if echoing
+ printf(HELLO_STR);
+
+ #ifndef LOGGER_UART
+ board_uart_write(HELLO_STR, strlen(HELLO_STR));
+ #endif
+ }
+
board_led_write(led_state);
led_state = 1 - led_state; // toggle
}
-
- // echo
- uint8_t ch;
- if (board_uart_read(&ch, 1) > 0) {
- board_uart_write(&ch, 1);
- }
}
}
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
void app_main(void) {
main();
}
diff --git a/examples/device/board_test/src/tusb_config.h b/examples/device/board_test/src/tusb_config.h
index 8ac3bc8de..81829d450 100644
--- a/examples/device/board_test/src/tusb_config.h
+++ b/examples/device/board_test/src/tusb_config.h
@@ -44,7 +44,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
diff --git a/examples/device/cdc_dual_ports/src/main.c b/examples/device/cdc_dual_ports/src/main.c
index 63ae8a8c9..5a3e18358 100644
--- a/examples/device/cdc_dual_ports/src/main.c
+++ b/examples/device/cdc_dual_ports/src/main.c
@@ -98,27 +98,33 @@ void tud_umount_cb(void) {
blink_interval_ms = BLINK_NOT_MOUNTED;
}
-
//--------------------------------------------------------------------+
// USB CDC
//--------------------------------------------------------------------+
static void cdc_task(void) {
- uint8_t itf;
-
- for (itf = 0; itf < CFG_TUD_CDC; itf++) {
+ for (uint8_t itf = 0; itf < CFG_TUD_CDC; itf++) {
// connected() check for DTR bit
// Most but not all terminal client set this when making connection
// if ( tud_cdc_n_connected(itf) )
{
if (tud_cdc_n_available(itf)) {
uint8_t buf[64];
-
uint32_t count = tud_cdc_n_read(itf, buf, sizeof(buf));
// echo back to both serial ports
echo_serial_port(0, buf, count);
echo_serial_port(1, buf, count);
}
+
+ // Press on-board button to send Uart status notification
+ static uint32_t btn_prev = 0;
+ static cdc_notify_uart_state_t uart_state = { .value = 0 };
+ const uint32_t btn = board_button_read();
+ if (!btn_prev && btn) {
+ uart_state.dsr ^= 1;
+ tud_cdc_notify_uart_state(&uart_state);
+ }
+ btn_prev = btn;
}
}
}
diff --git a/examples/device/cdc_dual_ports/src/tusb_config.h b/examples/device/cdc_dual_ports/src/tusb_config.h
index 070f08ed1..7f7df3909 100644
--- a/examples/device/cdc_dual_ports/src/tusb_config.h
+++ b/examples/device/cdc_dual_ports/src/tusb_config.h
@@ -97,6 +97,8 @@
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
+#define CFG_TUD_CDC_NOTIFY 1 // Enable use of notification endpoint
+
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
diff --git a/examples/device/cdc_dual_ports/src/usb_descriptors.c b/examples/device/cdc_dual_ports/src/usb_descriptors.c
index 7776eb958..bbcb479f5 100644
--- a/examples/device/cdc_dual_ports/src/usb_descriptors.c
+++ b/examples/device/cdc_dual_ports/src/usb_descriptors.c
@@ -42,8 +42,7 @@
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
-tusb_desc_device_t const desc_device =
-{
+tusb_desc_device_t const desc_device = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
@@ -68,16 +67,14 @@ tusb_desc_device_t const desc_device =
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
-uint8_t const * tud_descriptor_device_cb(void)
-{
+uint8_t const *tud_descriptor_device_cb(void) {
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
-enum
-{
+enum {
ITF_NUM_CDC_0 = 0,
ITF_NUM_CDC_0_DATA,
ITF_NUM_CDC_1,
@@ -130,36 +127,32 @@ enum
#define EPNUM_CDC_1_IN 0x84
#endif
-uint8_t const desc_fs_configuration[] =
-{
+uint8_t const desc_fs_configuration[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 16, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),
// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64),
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 16, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64),
};
#if TUD_OPT_HIGH_SPEED
// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration
-
-uint8_t const desc_hs_configuration[] =
-{
+uint8_t const desc_hs_configuration[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512),
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 16, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512),
// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512),
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 16, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512),
};
// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
-tusb_desc_device_qualifier_t const desc_device_qualifier =
-{
+tusb_desc_device_qualifier_t const desc_device_qualifier = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
@@ -177,34 +170,31 @@ tusb_desc_device_qualifier_t const desc_device_qualifier =
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
// device_qualifier descriptor describes information about a high-speed capable device that would
// change if the device were operating at the other speed. If not highspeed capable stall this request.
-uint8_t const* tud_descriptor_device_qualifier_cb(void)
-{
- return (uint8_t const*) &desc_device_qualifier;
+uint8_t const *tud_descriptor_device_qualifier_cb(void) {
+ return (uint8_t const *) &desc_device_qualifier;
}
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
-uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
-{
- (void) index; // for multiple configurations
+uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
+ (void) index;// for multiple configurations
// if link speed is high return fullspeed config, and vice versa
- return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration;
+ return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration;
}
-#endif // highspeed
+#endif// highspeed
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
-uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
-{
+uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
#if TUD_OPT_HIGH_SPEED
// Although we are highspeed, host may be fullspeed.
- return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
+ return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
#else
return desc_fs_configuration;
#endif
@@ -223,8 +213,7 @@ enum {
};
// array of pointer to string descriptors
-char const *string_desc_arr[] =
-{
+char const *string_desc_arr[] = {
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
@@ -254,14 +243,14 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
- if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) { return NULL; }
const char *str = string_desc_arr[index];
// Cap at max char
chr_count = strlen(str);
size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
- if ( chr_count > max_count ) chr_count = max_count;
+ if ( chr_count > max_count ) { chr_count = max_count; }
// Convert ASCII string into UTF-16
for ( size_t i = 0; i < chr_count; i++ ) {
@@ -272,6 +261,5 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
-
return _desc_str;
}
diff --git a/examples/device/cdc_msc/src/main.c b/examples/device/cdc_msc/src/main.c
index f36c910d7..5cd93e7dd 100644
--- a/examples/device/cdc_msc/src/main.c
+++ b/examples/device/cdc_msc/src/main.c
@@ -119,6 +119,16 @@ void cdc_task(void) {
tud_cdc_write(buf, count);
tud_cdc_write_flush();
}
+
+ // Press on-board button to send Uart status notification
+ static uint32_t btn_prev = 0;
+ static cdc_notify_uart_state_t uart_state = { .value = 0 };
+ const uint32_t btn = board_button_read();
+ if (!btn_prev && btn) {
+ uart_state.dsr ^= 1;
+ tud_cdc_notify_uart_state(&uart_state);
+ }
+ btn_prev = btn;
}
}
diff --git a/examples/device/cdc_msc/src/msc_disk.c b/examples/device/cdc_msc/src/msc_disk.c
index d325d77fa..458681f58 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 (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * 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/cdc_msc/src/tusb_config.h b/examples/device/cdc_msc/src/tusb_config.h
index 03e0e649c..811d464e9 100644
--- a/examples/device/cdc_msc/src/tusb_config.h
+++ b/examples/device/cdc_msc/src/tusb_config.h
@@ -87,7 +87,7 @@
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
-#define CFG_TUD_ENDPOINT0_SIZE 64
+#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
//------------- CLASS -------------//
@@ -97,6 +97,8 @@
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
+#define CFG_TUD_CDC_NOTIFY 1 // Enable use of notification endpoint
+
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
diff --git a/examples/device/cdc_msc/src/usb_descriptors.c b/examples/device/cdc_msc/src/usb_descriptors.c
index 4b6b88041..edcee0462 100644
--- a/examples/device/cdc_msc/src/usb_descriptors.c
+++ b/examples/device/cdc_msc/src/usb_descriptors.c
@@ -52,7 +52,6 @@ tusb_desc_device_t const desc_device = {
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
-
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_VID,
@@ -131,7 +130,7 @@ uint8_t const desc_fs_configuration[] = {
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
@@ -146,7 +145,7 @@ uint8_t const desc_hs_configuration[] = {
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
@@ -197,7 +196,6 @@ uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
#endif // highspeed
-
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
@@ -256,14 +254,14 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
- if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) { return NULL; }
const char *str = string_desc_arr[index];
// Cap at max char
chr_count = strlen(str);
size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
- if ( chr_count > max_count ) chr_count = max_count;
+ if ( chr_count > max_count ) { chr_count = max_count; }
// Convert ASCII string into UTF-16
for ( size_t i = 0; i < chr_count; i++ ) {
@@ -274,6 +272,5 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
-
return _desc_str;
}
diff --git a/examples/device/cdc_msc_freertos/src/main.c b/examples/device/cdc_msc_freertos/src/main.c
index c51e8ea81..09ccc9bf3 100644
--- a/examples/device/cdc_msc_freertos/src/main.c
+++ b/examples/device/cdc_msc_freertos/src/main.c
@@ -30,7 +30,7 @@
#include "bsp/board_api.h"
#include "tusb.h"
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define USBD_STACK_SIZE 4096
#else
// Increase stack size when debug log is enabled
@@ -72,7 +72,7 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
static void usb_device_task(void *param);
void led_blinking_task(void* param);
void cdc_task(void *params);
-
+extern void msc_disk_init(void);
//--------------------------------------------------------------------+
// Main
//--------------------------------------------------------------------+
@@ -91,15 +91,15 @@ int main(void) {
xTaskCreate(cdc_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES - 2, NULL);
#endif
-#if !TUSB_MCU_VENDOR_ESPRESSIF
- // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
+#ifndef ESP_PLATFORM
+ // only start scheduler for non-espressif mcu
vTaskStartScheduler();
#endif
return 0;
}
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
void app_main(void) {
main();
}
@@ -123,6 +123,7 @@ static void usb_device_task(void *param) {
board_init_after_tusb();
}
+ msc_disk_init();
// RTOS forever loop
while (1) {
// put this thread to waiting state until there is new events
@@ -188,6 +189,16 @@ void cdc_task(void *params) {
}
tud_cdc_write_flush();
+
+ // Press on-board button to send Uart status notification
+ static uint32_t btn_prev = 0;
+ static cdc_notify_uart_state_t uart_state = { .value = 0 };
+ const uint32_t btn = board_button_read();
+ if (!btn_prev && btn) {
+ uart_state.dsr ^= 1;
+ tud_cdc_notify_uart_state(&uart_state);
+ }
+ btn_prev = btn;
}
// For ESP32-Sx this delay is essential to allow idle how to run and reset watchdog
diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c
index d325d77fa..d1ff2f71b 100644
--- a/examples/device/cdc_msc_freertos/src/msc_disk.c
+++ b/examples/device/cdc_msc_freertos/src/msc_disk.c
@@ -28,6 +28,37 @@
#if CFG_TUD_MSC
+// Use async IO in example or not
+#define CFG_EXAMPLE_MSC_ASYNC_IO 1
+
+// Simulate read/write operation delay
+#define CFG_EXAMPLE_MSC_IO_DELAY_MS 0
+
+#if CFG_EXAMPLE_MSC_ASYNC_IO
+#define IO_STACK_SIZE configMINIMAL_STACK_SIZE
+
+typedef struct {
+ uint8_t lun;
+ bool is_read;
+ uint32_t lba;
+ uint32_t offset;
+ void* buffer;
+ uint32_t bufsize;
+} io_ops_t;
+
+QueueHandle_t io_queue;
+#if configSUPPORT_STATIC_ALLOCATION
+uint8_t io_queue_buf[sizeof(io_ops_t)];
+StaticQueue_t io_queue_static;
+StackType_t io_stack[IO_STACK_SIZE];
+StaticTask_t io_taskdef;
+#endif
+
+static void io_task(void *params);
+#endif
+
+void msc_disk_init(void);
+
// whether host does safe-eject
static bool ejected = false;
@@ -40,8 +71,7 @@ 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
-{
+enum {
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount
DISK_BLOCK_SIZE = 512
};
@@ -119,16 +149,52 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
README_CONTENTS
};
+#if CFG_EXAMPLE_MSC_ASYNC_IO
+void msc_disk_init() {
+
+#if configSUPPORT_STATIC_ALLOCATION
+ io_queue = xQueueCreateStatic(1, sizeof(io_ops_t), io_queue_buf, &io_queue_static);
+ xTaskCreateStatic(io_task, "io", IO_STACK_SIZE, NULL, 2, io_stack, &io_taskdef);
+#else
+ io_queue = xQueueCreate(1, sizeof(io_ops_t));
+ xTaskCreate(io_task, "io", IO_STACK_SIZE, NULL, 2, NULL);
+#endif
+}
+
+static void io_task(void *params) {
+ (void) params;
+ io_ops_t io_ops;
+ while (1) {
+ if (xQueueReceive(io_queue, &io_ops, portMAX_DELAY)) {
+ const uint8_t* addr = msc_disk[io_ops.lba] + io_ops.offset;
+ int32_t nbytes = io_ops.bufsize;
+ if (io_ops.is_read) {
+ memcpy(io_ops.buffer, addr, io_ops.bufsize);
+ } else {
+#ifndef CFG_EXAMPLE_MSC_READONLY
+ memcpy((uint8_t*) addr, io_ops.buffer, io_ops.bufsize);
+#else
+ nbytes = -1; // failed to write
+#endif
+ }
+
+ tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS);
+ tud_msc_async_io_done(nbytes, false);
+ }
+ }
+}
+
+#else
+void msc_disk_init() {}
+#endif
+
// 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(product_rev, rev, strlen(rev));
@@ -136,8 +202,7 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16
// 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,10 +217,8 @@ 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;
}
@@ -163,18 +226,14 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz
// 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,90 +244,107 @@ 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 ) {
- return -1;
+ if (lba >= DISK_BLOCK_NUM) {
+ return TUD_MSC_RET_ERROR;
}
// Check for overflow of offset + bufsize
- if ( offset + bufsize > DISK_BLOCK_SIZE ) {
- return -1;
+ if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) {
+ return TUD_MSC_RET_ERROR;
}
- uint8_t const* addr = msc_disk[lba] + offset;
- memcpy(buffer, addr, bufsize);
+ #if CFG_EXAMPLE_MSC_ASYNC_IO
+ io_ops_t io_ops = {.is_read = true, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize};
- return (int32_t) bufsize;
+ // Send IO operation to IO task
+ TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS);
+
+ return TUD_MSC_RET_ASYNC;
+ #else
+ uint8_t const *addr = msc_disk[lba] + offset;
+ memcpy(buffer, addr, bufsize);
+ return bufsize;
+ #endif
}
-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)
-{
- (void) lun;
-
+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 TUD_MSC_RET_ERROR;
+ }
-#ifndef CFG_EXAMPLE_MSC_READONLY
- uint8_t* addr = msc_disk[lba] + offset;
+ // Check for overflow of offset + bufsize
+ if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) {
+ return TUD_MSC_RET_ERROR;
+ }
+
+ #ifdef CFG_EXAMPLE_MSC_READONLY
+ (void) lun;
+ (void) buffer;
+ return bufsize;
+ #endif
+
+ #if CFG_EXAMPLE_MSC_ASYNC_IO
+ io_ops_t io_ops = {.is_read = false, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize};
+
+ // Send IO operation to IO task
+ TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS);
+
+ return TUD_MSC_RET_ASYNC;
+ #else
+ uint8_t *addr = msc_disk[lba] + offset;
memcpy(addr, buffer, bufsize);
-#else
- (void) lba; (void) offset; (void) buffer;
-#endif
+ tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS);
- return (int32_t) bufsize;
+ return bufsize;
+ #endif
}
// 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)
-{
+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
- void const* response = NULL;
+ 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;
+ break;
}
// return resplen must not larger than bufsize
- if ( resplen > bufsize ) resplen = bufsize;
+ if (resplen > bufsize) { resplen = bufsize; }
- if ( response && (resplen > 0) )
- {
- if(in_xfer)
- {
+ if (response && (resplen > 0)) {
+ if (in_xfer) {
memcpy(buffer, response, (size_t) resplen);
- }else
- {
+ } else {
// SCSI output
}
}
diff --git a/examples/device/cdc_msc_freertos/src/tusb_config.h b/examples/device/cdc_msc_freertos/src/tusb_config.h
index c3f2f7fb5..9cc3a18d1 100644
--- a/examples/device/cdc_msc_freertos/src/tusb_config.h
+++ b/examples/device/cdc_msc_freertos/src/tusb_config.h
@@ -59,7 +59,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
@@ -104,6 +104,8 @@
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
+#define CFG_TUD_CDC_NOTIFY 1 // Enable use of notification endpoint
+
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
diff --git a/examples/device/cdc_msc_freertos/src/usb_descriptors.c b/examples/device/cdc_msc_freertos/src/usb_descriptors.c
index 405a57fe4..a55fa3675 100644
--- a/examples/device/cdc_msc_freertos/src/usb_descriptors.c
+++ b/examples/device/cdc_msc_freertos/src/usb_descriptors.c
@@ -52,7 +52,6 @@ tusb_desc_device_t const desc_device = {
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
-
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_VID,
@@ -131,7 +130,7 @@ uint8_t const desc_fs_configuration[] =
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
@@ -147,7 +146,7 @@ uint8_t const desc_hs_configuration[] =
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
- TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
// Interface number, string index, EP Out & EP In address, EP size
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
@@ -176,16 +175,14 @@ tusb_desc_device_qualifier_t const desc_device_qualifier =
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
// device_qualifier descriptor describes information about a high-speed capable device that would
// change if the device were operating at the other speed. If not highspeed capable stall this request.
-uint8_t const* tud_descriptor_device_qualifier_cb(void)
-{
+uint8_t const* tud_descriptor_device_qualifier_cb(void) {
return (uint8_t const*) &desc_device_qualifier;
}
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
-uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
-{
+uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
@@ -204,13 +201,12 @@ uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
-uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
-{
+uint8_t const * tud_descriptor_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
#if TUD_OPT_HIGH_SPEED
// Although we are highspeed, host may be fullspeed.
- return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
+ return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
#else
return desc_fs_configuration;
#endif
@@ -229,8 +225,7 @@ enum {
};
// array of pointer to string descriptors
-char const *string_desc_arr[] =
-{
+char const *string_desc_arr[] = {
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
@@ -261,14 +256,14 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
- if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
+ if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) { return NULL; }
const char *str = string_desc_arr[index];
// Cap at max char
chr_count = strlen(str);
size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
- if ( chr_count > max_count ) chr_count = max_count;
+ if ( chr_count > max_count ) { chr_count = max_count; }
// Convert ASCII string into UTF-16
for ( size_t i = 0; i < chr_count; i++ ) {
@@ -279,6 +274,5 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
-
return _desc_str;
}
diff --git a/examples/device/hid_composite_freertos/src/main.c b/examples/device/hid_composite_freertos/src/main.c
index 30c0331ef..3f5e8a91c 100644
--- a/examples/device/hid_composite_freertos/src/main.c
+++ b/examples/device/hid_composite_freertos/src/main.c
@@ -31,7 +31,7 @@
#include "tusb.h"
#include "usb_descriptors.h"
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
// ESP-IDF need "freertos/" prefix in include path.
// CFG_TUSB_OS_INC_PATH should be defined accordingly.
#include "freertos/FreeRTOS.h"
@@ -112,17 +112,16 @@ int main(void)
xTimerStart(blinky_tm, 0);
- // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
-#if !TUSB_MCU_VENDOR_ESPRESSIF
+ // only start scheduler for non-espressif mcu
+#ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
return 0;
}
-#if TUSB_MCU_VENDOR_ESPRESSIF
-void app_main(void)
-{
+#ifdef ESP_PLATFORM
+void app_main(void) {
main();
}
#endif
diff --git a/examples/device/hid_composite_freertos/src/tusb_config.h b/examples/device/hid_composite_freertos/src/tusb_config.h
index 6ec38b95c..b28033a0c 100644
--- a/examples/device/hid_composite_freertos/src/tusb_config.h
+++ b/examples/device/hid_composite_freertos/src/tusb_config.h
@@ -59,7 +59,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
diff --git a/examples/device/midi_test_freertos/src/main.c b/examples/device/midi_test_freertos/src/main.c
index dbe89080c..3e406d38d 100644
--- a/examples/device/midi_test_freertos/src/main.c
+++ b/examples/device/midi_test_freertos/src/main.c
@@ -40,7 +40,7 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define USBD_STACK_SIZE 4096
#else
// Increase stack size when debug log is enabled
@@ -95,15 +95,15 @@ int main(void) {
xTaskCreate(midi_task, "midi", MIDI_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, NULL);
#endif
-#if !TUSB_MCU_VENDOR_ESPRESSIF
- // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
+#ifndef ESP_PLATFORM
+ // only start scheduler for non-espressif mcu
vTaskStartScheduler();
#endif
return 0;
}
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
void app_main(void) {
main();
}
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/device/net_lwip_webserver/Makefile b/examples/device/net_lwip_webserver/Makefile
index 141532466..4ad110dec 100644
--- a/examples/device/net_lwip_webserver/Makefile
+++ b/examples/device/net_lwip_webserver/Makefile
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += lib/lwip
-
include ../../build_system/make/make.mk
# suppress warning caused by lwip
diff --git a/examples/device/net_lwip_webserver/skip.txt b/examples/device/net_lwip_webserver/skip.txt
index 5ebe71612..20a264387 100644
--- a/examples/device/net_lwip_webserver/skip.txt
+++ b/examples/device/net_lwip_webserver/skip.txt
@@ -10,6 +10,8 @@ mcu:SAMD11
mcu:STM32L0
mcu:STM32F0
mcu:KINETIS_KL
+mcu:STM32H7RS
+mcu:STM32N6
family:broadcom_64bit
family:broadcom_32bit
family:espressif
diff --git a/examples/device/net_lwip_webserver/src/lwipopts.h b/examples/device/net_lwip_webserver/src/lwipopts.h
index 41e8f0d67..04949cef9 100644
--- a/examples/device/net_lwip_webserver/src/lwipopts.h
+++ b/examples/device/net_lwip_webserver/src/lwipopts.h
@@ -58,6 +58,7 @@
#define LWIP_HTTPD_SSI_INCLUDE_TAG 0
#define LWIP_SINGLE_NETIF 1
+#define LWIP_NETIF_LINK_CALLBACK 1
#define PBUF_POOL_SIZE 4
diff --git a/examples/device/net_lwip_webserver/src/main.c b/examples/device/net_lwip_webserver/src/main.c
index 36f402332..4bdddf6c5 100644
--- a/examples/device/net_lwip_webserver/src/main.c
+++ b/examples/device/net_lwip_webserver/src/main.c
@@ -31,6 +31,12 @@ this appears as either a RNDIS or CDC-ECM USB virtual network adapter; the OS pi
RNDIS should be valid on Linux and Windows hosts, and CDC-ECM should be valid on Linux and macOS hosts
The MCU appears to the host as IP address 192.168.7.1, and provides a DHCP server, DNS server, and web server.
+
+Link State Control:
+- Press the user button to toggle the network link state (UP/DOWN)
+- This simulates "ethernet cable unplugged/plugged" events
+- The host OS will see the network interface as disconnected/connected accordingly
+- Use this to test network error handling and recovery in host applications
*/
/*
Some smartphones *may* work with this implementation as well, but likely have limited (broken) drivers,
@@ -63,9 +69,6 @@ try changing the first byte of tud_network_mac_address[] below from 0x02 to 0x00
/* lwip context */
static struct netif netif_data;
-/* shared between tud_network_recv_cb() and service_traffic() */
-static struct pbuf *received_frame;
-
/* this is used by this code, ./class/net/net_driver.c, and usb_descriptors.c */
/* ideally speaking, this should be generated from the hardware's unique ID (if available) */
/* it is suggested that the first byte is 0x02 to indicate a link-local address */
@@ -137,6 +140,12 @@ static err_t netif_init_cb(struct netif *netif) {
return ERR_OK;
}
+/* notifies the USB host about the link state change. */
+static void usbnet_netif_link_callback(struct netif *netif) {
+ bool link_up = netif_is_link_up(netif);
+ tud_network_link_state(BOARD_TUD_RHPORT, link_up);
+}
+
static void init_lwip(void) {
struct netif *netif = &netif_data;
@@ -147,11 +156,19 @@ static void init_lwip(void) {
memcpy(netif->hwaddr, tud_network_mac_address, sizeof(tud_network_mac_address));
netif->hwaddr[5] ^= 0x01;
- netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, netif_init_cb, ip_input);
+ netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, netif_init_cb, ethernet_input);
#if LWIP_IPV6
netif_create_ip6_linklocal_address(netif, 1);
#endif
netif_set_default(netif);
+
+#if LWIP_NETIF_LINK_CALLBACK
+ // Set the link callback to notify USB host about link state changes
+ netif_set_link_callback(netif, usbnet_netif_link_callback);
+ netif_set_link_up(netif);
+#else
+ tud_network_link_state(BOARD_TUD_RHPORT, true);
+#endif
}
/* handle any DNS requests from dns-server */
@@ -164,20 +181,29 @@ bool dns_query_proc(const char *name, ip4_addr_t *addr) {
}
bool tud_network_recv_cb(const uint8_t *src, uint16_t size) {
- /* this shouldn't happen, but if we get another packet before
- parsing the previous, we must signal our inability to accept it */
- if (received_frame) return false;
+ struct netif *netif = &netif_data;
if (size) {
struct pbuf *p = pbuf_alloc(PBUF_RAW, size, PBUF_POOL);
- if (p) {
- /* pbuf_alloc() has already initialized struct; all we need to do is copy the data */
- memcpy(p->payload, src, size);
-
- /* store away the pointer for service_traffic() to later handle */
- received_frame = p;
+ if (p == NULL) {
+ printf("ERROR: Failed to allocate pbuf of size %d\n", size);
+ return false;
}
+
+ /* Copy buf to pbuf */
+ pbuf_take(p, src, size);
+
+ // Surrender ownership of our pbuf unless there was an error
+ // Only call pbuf_free if not Ok else it will panic with "pbuf_free: p->ref > 0"
+ // or steal it from whatever took ownership of it with undefined consequences.
+ // See: https://savannah.nongnu.org/patch/index.php?10121
+ if (netif->input(p, netif) != ERR_OK) {
+ printf("ERROR: netif input failed\n");
+ pbuf_free(p);
+ }
+ // Signal tinyusb that the current frame has been processed.
+ tud_network_recv_renew();
}
return true;
@@ -191,29 +217,26 @@ uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) {
return pbuf_copy_partial(p, dst, p->tot_len, 0);
}
-static void service_traffic(void) {
- /* handle any packet received by tud_network_recv_cb() */
- if (received_frame) {
- // Surrender ownership of our pbuf unless there was an error
- // Only call pbuf_free if not Ok else it will panic with "pbuf_free: p->ref > 0"
- // or steal it from whatever took ownership of it with undefined consequences.
- // See: https://savannah.nongnu.org/patch/index.php?10121
- if (ethernet_input(received_frame, &netif_data)!=ERR_OK) {
- pbuf_free(received_frame);
+static void handle_link_state_switch(void) {
+ /* Check for button press to toggle link state */
+ static bool last_link_state = true;
+ static bool last_button_state = false;
+ bool current_button_state = board_button_read();
+
+ if (current_button_state && !last_button_state) {
+ /* Button pressed - toggle link state */
+ last_link_state = !last_link_state;
+ if (last_link_state) {
+ printf("Link state: UP\n");
+ netif_set_link_up(&netif_data);
+ } else {
+ printf("Link state: DOWN\n");
+ netif_set_link_down(&netif_data);
}
- received_frame = NULL;
- tud_network_recv_renew();
+ /* LWIP callback will notify USB host about the change */
}
+ last_button_state = current_button_state;
- sys_check_timeouts();
-}
-
-void tud_network_init_cb(void) {
- /* if the network is re-initializing and we have a leftover packet, we must do a cleanup */
- if (received_frame) {
- pbuf_free(received_frame);
- received_frame = NULL;
- }
}
int main(void) {
@@ -243,15 +266,23 @@ int main(void) {
lwiperf_start_tcp_server_default(NULL, NULL);
#endif
+#if CFG_TUD_NCM
+ printf("USB NCM network interface initialized\n");
+#elif CFG_TUD_ECM_RNDIS
+ printf("USB RNDIS/ECM network interface initialized\n");
+#endif
+
while (1) {
tud_task();
- service_traffic();
+ sys_check_timeouts(); // service lwip
+ handle_link_state_switch();
}
return 0;
}
/* lwip has provision for using a mutex, when applicable */
+/* This implementation is for single-threaded use only */
sys_prot_t sys_arch_protect(void) {
return 0;
}
diff --git a/examples/device/net_lwip_webserver/src/tusb_config.h b/examples/device/net_lwip_webserver/src/tusb_config.h
index 22082fc81..c774f59ff 100644
--- a/examples/device/net_lwip_webserver/src/tusb_config.h
+++ b/examples/device/net_lwip_webserver/src/tusb_config.h
@@ -85,6 +85,7 @@ extern "C" {
#endif
// Use different configurations to test all net devices (also due to resource limitations)
+#ifndef USE_ECM
#if TU_CHECK_MCU(OPT_MCU_LPC15XX, OPT_MCU_LPC40XX, OPT_MCU_LPC51UXX, OPT_MCU_LPC54)
#define USE_ECM 1
#elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAML21, OPT_MCU_SAML22)
@@ -97,6 +98,7 @@ extern "C" {
#define USE_ECM 0
#define INCLUDE_IPERF
#endif
+#endif
//--------------------------------------------------------------------
// NCM CLASS CONFIGURATION, SEE "ncm.h" FOR PERFORMANCE TUNING
diff --git a/examples/device/video_capture/src/main.c b/examples/device/video_capture/src/main.c
index 04d4af4e5..0406279fd 100644
--- a/examples/device/video_capture/src/main.c
+++ b/examples/device/video_capture/src/main.c
@@ -292,7 +292,7 @@ void led_blinking_task(void* param) {
#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE
#define VIDEO_STACK_SIZE (configMINIMAL_STACK_SIZE*4)
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define USBD_STACK_SIZE 4096
int main(void);
void app_main(void) {
@@ -351,8 +351,8 @@ void freertos_init_task(void) {
xTaskCreate(video_task, "video", VIDEO_STACK_SZIE, NULL, configMAX_PRIORITIES - 2, NULL);
#endif
- // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
- #if !TUSB_MCU_VENDOR_ESPRESSIF
+ // only start scheduler for non-espressif mcu
+ #ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
}
diff --git a/examples/device/video_capture/src/tusb_config.h b/examples/device/video_capture/src/tusb_config.h
index 6dbd6f2a5..4ba86ca65 100644
--- a/examples/device/video_capture/src/tusb_config.h
+++ b/examples/device/video_capture/src/tusb_config.h
@@ -58,7 +58,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
diff --git a/examples/device/video_capture_2ch/src/main.c b/examples/device/video_capture_2ch/src/main.c
index 245e7abb8..dc616e3fa 100644
--- a/examples/device/video_capture_2ch/src/main.c
+++ b/examples/device/video_capture_2ch/src/main.c
@@ -300,7 +300,7 @@ void led_blinking_task(void* param) {
#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE
#define VIDEO_STACK_SIZE (configMINIMAL_STACK_SIZE*4)
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define USBD_STACK_SIZE 4096
int main(void);
void app_main(void) {
@@ -359,8 +359,8 @@ void freertos_init_task(void) {
xTaskCreate(video_task, "video", VIDEO_STACK_SZIE, NULL, configMAX_PRIORITIES - 2, NULL);
#endif
- // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
- #if !TUSB_MCU_VENDOR_ESPRESSIF
+ // only start scheduler for non-espressif mcu
+ #ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
}
diff --git a/examples/device/video_capture_2ch/src/tusb_config.h b/examples/device/video_capture_2ch/src/tusb_config.h
index 91775a327..e84e49879 100644
--- a/examples/device/video_capture_2ch/src/tusb_config.h
+++ b/examples/device/video_capture_2ch/src/tusb_config.h
@@ -58,7 +58,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#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 668808db2..a2a505952 100644
--- a/examples/dual/host_info_to_device_cdc/src/main.c
+++ b/examples/dual/host_info_to_device_cdc/src/main.c
@@ -70,11 +70,30 @@ enum {
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
static bool is_print[CFG_TUH_DEVICE_MAX+1] = { 0 };
+static tusb_desc_device_t descriptor_device[CFG_TUH_DEVICE_MAX+1];
static void print_utf16(uint16_t *temp_buf, size_t buf_len);
+static void print_device_info(uint8_t daddr, const tusb_desc_device_t* desc_device);
+
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();
@@ -135,84 +154,20 @@ void tud_resume_cb(void) {
blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
}
-#if 1
-#define cdc_printf(...) \
- do { \
- char _tempbuf[256]; \
- int count = sprintf(_tempbuf, __VA_ARGS__); \
- tud_cdc_write(_tempbuf, (uint32_t) count); \
- tud_cdc_write_flush(); \
- tud_task(); \
- } while(0)
-#endif
-
-//#define cdc_printf printf
-
-void print_device_info(uint8_t daddr) {
- tusb_desc_device_t desc_device;
- uint8_t xfer_result = tuh_descriptor_get_device_sync(daddr, &desc_device, 18);
- if (XFER_RESULT_SUCCESS != xfer_result) {
- tud_cdc_write_str("Failed to get device descriptor\r\n");
+void cdc_task(void) {
+ if (!tud_cdc_connected()) {
+ // delay a bit otherwise we can outpace host's terminal. Linux will set LineState (DTR) then Line Coding.
+ // If we send data before Linux's terminal set Line Coding, it can be ignored --> missing data with hardware test loop
+ board_delay(20);
return;
}
- // Get String descriptor using Sync API
- uint16_t serial[64];
- uint16_t buf[128];
-
- cdc_printf("Device %u: ID %04x:%04x SN ", daddr, desc_device.idVendor, desc_device.idProduct);
- xfer_result = tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, serial, sizeof(serial));
- if (XFER_RESULT_SUCCESS != xfer_result) {
- serial[0] = 'n';
- serial[1] = '/';
- serial[2] = 'a';
- serial[3] = 0;
- }
- print_utf16(serial, TU_ARRAY_SIZE(serial));
- tud_cdc_write_str("\r\n");
-
- cdc_printf("Device Descriptor:\r\n");
- cdc_printf(" bLength %u\r\n" , desc_device.bLength);
- cdc_printf(" bDescriptorType %u\r\n" , desc_device.bDescriptorType);
- cdc_printf(" bcdUSB %04x\r\n" , desc_device.bcdUSB);
- cdc_printf(" bDeviceClass %u\r\n" , desc_device.bDeviceClass);
- cdc_printf(" bDeviceSubClass %u\r\n" , desc_device.bDeviceSubClass);
- cdc_printf(" bDeviceProtocol %u\r\n" , desc_device.bDeviceProtocol);
- cdc_printf(" bMaxPacketSize0 %u\r\n" , desc_device.bMaxPacketSize0);
- cdc_printf(" idVendor 0x%04x\r\n" , desc_device.idVendor);
- cdc_printf(" idProduct 0x%04x\r\n" , desc_device.idProduct);
- cdc_printf(" bcdDevice %04x\r\n" , desc_device.bcdDevice);
-
- cdc_printf(" iManufacturer %u " , desc_device.iManufacturer);
- xfer_result = tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, buf, sizeof(buf));
- if (XFER_RESULT_SUCCESS == xfer_result ) {
- print_utf16(buf, TU_ARRAY_SIZE(buf));
- }
- tud_cdc_write_str("\r\n");
-
- cdc_printf(" iProduct %u " , desc_device.iProduct);
- xfer_result = tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, buf, sizeof(buf));
- if (XFER_RESULT_SUCCESS == xfer_result) {
- print_utf16(buf, TU_ARRAY_SIZE(buf));
- }
- tud_cdc_write_str("\r\n");
-
- cdc_printf(" iSerialNumber %u " , desc_device.iSerialNumber);
- tud_cdc_write_str((char*)serial); // serial is already to UTF-8
- tud_cdc_write_str("\r\n");
-
- cdc_printf(" bNumConfigurations %u\r\n" , desc_device.bNumConfigurations);
-}
-
-void cdc_task(void) {
- if (tud_cdc_connected()) {
- for (uint8_t daddr = 1; daddr <= CFG_TUH_DEVICE_MAX; daddr++) {
- if (tuh_mounted(daddr)) {
- if (is_print[daddr]) {
- is_print[daddr] = false;
- print_device_info(daddr);
- tud_cdc_write_flush();
- }
+ for (uint8_t daddr = 1; daddr <= CFG_TUH_DEVICE_MAX; daddr++) {
+ if (tuh_mounted(daddr)) {
+ if (is_print[daddr]) {
+ is_print[daddr] = false;
+ print_device_info(daddr, &descriptor_device[daddr]);
+ tud_cdc_write_flush();
}
}
}
@@ -221,13 +176,70 @@ void cdc_task(void) {
//--------------------------------------------------------------------+
// Host Get device information
//--------------------------------------------------------------------+
+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];
+ uint16_t buf[128];
+ (void) buf;
+
+ cdc_printf("Device %u: ID %04x:%04x SN ", daddr, desc_device->idVendor, desc_device->idProduct);
+ uint8_t xfer_result = tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, serial, sizeof(serial));
+ if (XFER_RESULT_SUCCESS != xfer_result) {
+ serial[0] = 'n';
+ serial[1] = '/';
+ serial[2] = 'a';
+ serial[3] = 0;
+ }
+ print_utf16(serial, TU_ARRAY_SIZE(serial));
+ cdc_printf("\r\n");
+
+ cdc_printf("Device Descriptor:\r\n");
+ cdc_printf(" bLength %u\r\n" , desc_device->bLength);
+ cdc_printf(" bDescriptorType %u\r\n" , desc_device->bDescriptorType);
+ cdc_printf(" bcdUSB %04x\r\n" , desc_device->bcdUSB);
+ cdc_printf(" bDeviceClass %u\r\n" , desc_device->bDeviceClass);
+ cdc_printf(" bDeviceSubClass %u\r\n" , desc_device->bDeviceSubClass);
+ cdc_printf(" bDeviceProtocol %u\r\n" , desc_device->bDeviceProtocol);
+ cdc_printf(" bMaxPacketSize0 %u\r\n" , desc_device->bMaxPacketSize0);
+ cdc_printf(" idVendor 0x%04x\r\n" , desc_device->idVendor);
+ cdc_printf(" idProduct 0x%04x\r\n" , desc_device->idProduct);
+ cdc_printf(" bcdDevice %04x\r\n" , desc_device->bcdDevice);
+
+ cdc_printf(" iManufacturer %u " , desc_device->iManufacturer);
+ xfer_result = tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, buf, sizeof(buf));
+ if (XFER_RESULT_SUCCESS == xfer_result) {
+ print_utf16(buf, TU_ARRAY_SIZE(buf));
+ }
+ cdc_printf("\r\n");
+
+ cdc_printf(" iProduct %u " , desc_device->iProduct);
+ xfer_result = tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, buf, sizeof(buf));
+ if (XFER_RESULT_SUCCESS == xfer_result) {
+ print_utf16(buf, TU_ARRAY_SIZE(buf));
+ }
+ cdc_printf("\r\n");
+
+ cdc_printf(" iSerialNumber %u " , desc_device->iSerialNumber);
+ cdc_printf((char*)serial); // serial is already to UTF-8
+ cdc_printf("\r\n");
+
+ cdc_printf(" bNumConfigurations %u\r\n" , desc_device->bNumConfigurations);
+}
+
+void tuh_enum_descriptor_device_cb(uint8_t daddr, tusb_desc_device_t const* desc_device) {
+ (void) daddr;
+ descriptor_device[daddr] = *desc_device; // save device descriptor
+}
+
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;
}
@@ -239,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);
@@ -290,13 +304,13 @@ 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);
((uint8_t*) temp_buf)[utf8_len] = '\0';
- tud_cdc_write(temp_buf, utf8_len);
- tud_cdc_write_flush();
- tud_task();
+ cdc_printf((char*) temp_buf);
}
diff --git a/examples/host/bare_api/only.txt b/examples/host/bare_api/only.txt
index 95f9f1d82..dcdaf41c7 100644
--- a/examples/host/bare_api/only.txt
+++ b/examples/host/bare_api/only.txt
@@ -15,3 +15,5 @@ mcu:MAX3421
mcu:STM32F4
mcu:STM32F7
mcu:STM32H7
+mcu:STM32H7RS
+mcu:STM32N6
diff --git a/examples/host/bare_api/src/main.c b/examples/host/bare_api/src/main.c
index f582f4f5a..0c76ff0c9 100644
--- a/examples/host/bare_api/src/main.c
+++ b/examples/host/bare_api/src/main.c
@@ -55,16 +55,15 @@ uint8_t* get_hid_buf(uint8_t daddr);
void free_hid_buf(uint8_t daddr);
/*------------- MAIN -------------*/
-int main(void)
-{
+int main(void) {
board_init();
printf("TinyUSB Bare API Example\r\n");
// init host stack on configured roothub port
tusb_rhport_init_t host_init = {
- .role = TUSB_ROLE_HOST,
- .speed = TUSB_SPEED_AUTO
+ .role = TUSB_ROLE_HOST,
+ .speed = TUSB_SPEED_AUTO
};
tusb_init(BOARD_TUH_RHPORT, &host_init);
@@ -72,8 +71,7 @@ int main(void)
board_init_after_tusb();
}
- while (1)
- {
+ while (1) {
// tinyusb host task
tuh_task();
led_blinking_task();
@@ -85,8 +83,7 @@ int main(void)
/*------------- TinyUSB Callbacks -------------*/
// Invoked when device is mounted (configured)
-void tuh_mount_cb (uint8_t daddr)
-{
+void tuh_mount_cb(uint8_t daddr) {
printf("Device attached, address = %d\r\n", daddr);
// Get Device Descriptor
@@ -95,8 +92,7 @@ void tuh_mount_cb (uint8_t daddr)
}
/// Invoked when device is unmounted (bus reset/unplugged)
-void tuh_umount_cb(uint8_t daddr)
-{
+void tuh_umount_cb(uint8_t daddr) {
printf("Device removed, address = %d\r\n", daddr);
free_hid_buf(daddr);
}
@@ -104,11 +100,8 @@ void tuh_umount_cb(uint8_t daddr)
//--------------------------------------------------------------------+
// Device Descriptor
//--------------------------------------------------------------------+
-
-void print_device_descriptor(tuh_xfer_t* xfer)
-{
- if ( XFER_RESULT_SUCCESS != xfer->result )
- {
+void print_device_descriptor(tuh_xfer_t *xfer) {
+ if (XFER_RESULT_SUCCESS != xfer->result) {
printf("Failed to get device descriptor\r\n");
return;
}
@@ -131,33 +124,29 @@ void print_device_descriptor(tuh_xfer_t* xfer)
// Get String descriptor using Sync API
uint16_t temp_buf[128];
- printf(" iManufacturer %u " , desc_device.iManufacturer);
- if (XFER_RESULT_SUCCESS == tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)) )
- {
+ printf(" iManufacturer %u ", desc_device.iManufacturer);
+ if (XFER_RESULT_SUCCESS == tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf))) {
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
}
printf("\r\n");
- printf(" iProduct %u " , desc_device.iProduct);
- if (XFER_RESULT_SUCCESS == tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
- {
+ printf(" iProduct %u ", desc_device.iProduct);
+ if (XFER_RESULT_SUCCESS == tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf))) {
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
}
printf("\r\n");
- printf(" iSerialNumber %u " , desc_device.iSerialNumber);
- if (XFER_RESULT_SUCCESS == tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
- {
+ printf(" iSerialNumber %u ", desc_device.iSerialNumber);
+ if (XFER_RESULT_SUCCESS == tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf))) {
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
}
printf("\r\n");
- printf(" bNumConfigurations %u\r\n" , desc_device.bNumConfigurations);
+ printf(" bNumConfigurations %u\r\n", desc_device.bNumConfigurations);
// Get configuration descriptor with sync API
- if (XFER_RESULT_SUCCESS == tuh_descriptor_get_configuration_sync(daddr, 0, temp_buf, sizeof(temp_buf)))
- {
- parse_config_descriptor(daddr, (tusb_desc_configuration_t*) temp_buf);
+ if (XFER_RESULT_SUCCESS == tuh_descriptor_get_configuration_sync(daddr, 0, temp_buf, sizeof(temp_buf))) {
+ parse_config_descriptor(daddr, (tusb_desc_configuration_t *) temp_buf);
}
}
@@ -171,37 +160,33 @@ uint16_t count_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_
void open_hid_interface(uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
// simple configuration parser to open and listen to HID Endpoint IN
-void parse_config_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg)
-{
- uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
- uint8_t const* p_desc = tu_desc_next(desc_cfg);
+void parse_config_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const *desc_cfg) {
+ uint8_t const *desc_end = ((uint8_t const *) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
+ uint8_t const *p_desc = tu_desc_next(desc_cfg);
// parse each interfaces
- while( p_desc < desc_end )
- {
+ while (p_desc < desc_end) {
uint8_t assoc_itf_count = 1;
// Class will always starts with Interface Association (if any) and then Interface descriptor
- if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
- {
- tusb_desc_interface_assoc_t const * desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
+ if (TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc)) {
+ tusb_desc_interface_assoc_t const *desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
assoc_itf_count = desc_iad->bInterfaceCount;
- p_desc = tu_desc_next(p_desc); // next to Interface
+ p_desc = tu_desc_next(p_desc);// next to Interface
}
// must be interface from now
- if( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) ) return;
- tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
+ if (TUSB_DESC_INTERFACE != tu_desc_type(p_desc)) { return; }
+ tusb_desc_interface_t const *desc_itf = (tusb_desc_interface_t const *) p_desc;
- uint16_t const drv_len = count_interface_total_len(desc_itf, assoc_itf_count, (uint16_t) (desc_end-p_desc));
+ uint16_t const drv_len = count_interface_total_len(desc_itf, assoc_itf_count, (uint16_t) (desc_end - p_desc));
// probably corrupted descriptor
- if(drv_len < sizeof(tusb_desc_interface_t)) return;
+ if (drv_len < sizeof(tusb_desc_interface_t)) { return; }
// only open and listen to HID endpoint IN
- if (desc_itf->bInterfaceClass == TUSB_CLASS_HID)
- {
+ if (desc_itf->bInterfaceClass == TUSB_CLASS_HID) {
open_hid_interface(dev_addr, desc_itf, drv_len);
}
@@ -210,25 +195,21 @@ void parse_config_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const*
}
}
-uint16_t count_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len)
-{
- uint8_t const* p_desc = (uint8_t const*) desc_itf;
+uint16_t count_interface_total_len(tusb_desc_interface_t const *desc_itf, uint8_t itf_count, uint16_t max_len) {
+ uint8_t const *p_desc = (uint8_t const *) desc_itf;
uint16_t len = 0;
- while (itf_count--)
- {
+ while (itf_count--) {
// Next on interface desc
len += tu_desc_len(desc_itf);
p_desc = tu_desc_next(p_desc);
- while (len < max_len)
- {
+ while (len < max_len) {
// return on IAD regardless of itf count
- if ( tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION ) return len;
+ if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION) { return len; }
- if ( (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) &&
- ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0 )
- {
+ if ((tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) &&
+ ((tusb_desc_interface_t const *) p_desc)->bAlternateSetting == 0) {
break;
}
@@ -246,46 +227,45 @@ uint16_t count_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_
void hid_report_received(tuh_xfer_t* xfer);
-void open_hid_interface(uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
-{
+void open_hid_interface(uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) {
// len = interface + hid + n*endpoints
uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) +
desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
// corrupted descriptor
- if (max_len < drv_len) return;
+ if (max_len < drv_len) { return; }
uint8_t const *p_desc = (uint8_t const *) desc_itf;
// HID descriptor
p_desc = tu_desc_next(p_desc);
tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc;
- if(HID_DESC_TYPE_HID != desc_hid->bDescriptorType) return;
+ if (HID_DESC_TYPE_HID != desc_hid->bDescriptorType) { return; }
// Endpoint descriptor
p_desc = tu_desc_next(p_desc);
- tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
+ tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
- for(int i = 0; i < desc_itf->bNumEndpoints; i++)
- {
- if (TUSB_DESC_ENDPOINT != desc_ep->bDescriptorType) return;
+ for (int i = 0; i < desc_itf->bNumEndpoints; i++) {
+ if (TUSB_DESC_ENDPOINT != desc_ep->bDescriptorType) { return; }
- if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN)
- {
- // skip if failed to open endpoint
- if ( ! tuh_edpt_open(daddr, desc_ep) ) return;
+ if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
+ if (!tuh_edpt_open(daddr, desc_ep)) {
+ return; // skip if failed to open endpoint
+ }
- uint8_t* buf = get_hid_buf(daddr);
- if (!buf) return; // out of memory
+ uint8_t *buf = get_hid_buf(daddr);
+ if (!buf) {
+ return;// out of memory
+ }
- tuh_xfer_t xfer =
- {
- .daddr = daddr,
- .ep_addr = desc_ep->bEndpointAddress,
- .buflen = 64,
- .buffer = buf,
- .complete_cb = hid_report_received,
- .user_data = (uintptr_t) buf, // since buffer is not available in callback, use user data to store the buffer
+ tuh_xfer_t xfer = {
+ .daddr = daddr,
+ .ep_addr = desc_ep->bEndpointAddress,
+ .buflen = 64,
+ .buffer = buf,
+ .complete_cb = hid_report_received,
+ .user_data = (uintptr_t) buf,// since buffer is not available in callback, use user data to store the buffer
};
// submit transfer for this EP
@@ -299,18 +279,17 @@ void open_hid_interface(uint8_t daddr, tusb_desc_interface_t const *desc_itf, ui
}
}
-void hid_report_received(tuh_xfer_t* xfer)
-{
+void hid_report_received(tuh_xfer_t *xfer) {
// Note: not all field in xfer is available for use (i.e filled by tinyusb stack) in callback to save sram
// For instance, xfer->buffer is NULL. We have used user_data to store buffer when submitted callback
- uint8_t* buf = (uint8_t*) xfer->user_data;
+ uint8_t *buf = (uint8_t *) xfer->user_data;
- if (xfer->result == XFER_RESULT_SUCCESS)
- {
+ if (xfer->result == XFER_RESULT_SUCCESS) {
printf("[dev %u: ep %02x] HID Report:", xfer->daddr, xfer->ep_addr);
- for(uint32_t i=0; iactual_len; i++)
- {
- if (i%16 == 0) printf("\r\n ");
+ for (uint32_t i = 0; i < xfer->actual_len; i++) {
+ if (i % 16 == 0) {
+ printf("\r\n ");
+ }
printf("%02X ", buf[i]);
}
printf("\r\n");
@@ -329,12 +308,9 @@ void hid_report_received(tuh_xfer_t* xfer)
//--------------------------------------------------------------------+
// get an buffer from pool
-uint8_t* get_hid_buf(uint8_t daddr)
-{
- for(size_t i=0; i> 6 & 0x1F));
- *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
- } else {
- // TODO: Verify surrogate.
- *utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F));
- *utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
- *utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
- }
- // TODO: Handle UTF-16 code points that take two entries.
+ for (size_t i = 0; i < utf16_len; i++) {
+ uint16_t chr = utf16[i];
+ if (chr < 0x80) {
+ *utf8++ = chr & 0xffu;
+ } else if (chr < 0x800) {
+ *utf8++ = (uint8_t) (0xC0 | (chr >> 6 & 0x1F));
+ *utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
+ } else {
+ // TODO: Verify surrogate.
+ *utf8++ = (uint8_t) (0xE0 | (chr >> 12 & 0x0F));
+ *utf8++ = (uint8_t) (0x80 | (chr >> 6 & 0x3F));
+ *utf8++ = (uint8_t) (0x80 | (chr >> 0 & 0x3F));
}
+ // TODO: Handle UTF-16 code points that take two entries.
+ }
}
// Count how many bytes a utf-16-le encoded string will take in utf-8.
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
- size_t total_bytes = 0;
- for (size_t i = 0; i < len; i++) {
- uint16_t chr = buf[i];
- if (chr < 0x80) {
- total_bytes += 1;
- } else if (chr < 0x800) {
- total_bytes += 2;
- } else {
- total_bytes += 3;
- }
- // TODO: Handle UTF-16 code points that take two entries.
+ size_t total_bytes = 0;
+ for (size_t i = 0; i < len; i++) {
+ uint16_t chr = buf[i];
+ if (chr < 0x80) {
+ total_bytes += 1;
+ } else if (chr < 0x800) {
+ total_bytes += 2;
+ } else {
+ total_bytes += 3;
}
- return (int) total_bytes;
+ // TODO: Handle UTF-16 code points that take two entries.
+ }
+ return (int) total_bytes;
}
static void print_utf16(uint16_t *temp_buf, size_t buf_len) {
- if ((temp_buf[0] & 0xff) == 0) return; // empty
- size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
- size_t utf8_len = (size_t) _count_utf8_bytes(temp_buf + 1, utf16_len);
- _convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len);
- ((uint8_t*) temp_buf)[utf8_len] = '\0';
+ 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);
+ ((uint8_t *) temp_buf)[utf8_len] = '\0';
- printf("%s", (char*)temp_buf);
+ printf("%s", (char *) temp_buf);
}
diff --git a/examples/host/cdc_msc_hid/only.txt b/examples/host/cdc_msc_hid/only.txt
index 95f9f1d82..dcdaf41c7 100644
--- a/examples/host/cdc_msc_hid/only.txt
+++ b/examples/host/cdc_msc_hid/only.txt
@@ -15,3 +15,5 @@ mcu:MAX3421
mcu:STM32F4
mcu:STM32F7
mcu:STM32H7
+mcu:STM32H7RS
+mcu:STM32N6
diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c
index 4a13f8b27..97f1a96d6 100644
--- a/examples/host/cdc_msc_hid/src/cdc_app.c
+++ b/examples/host/cdc_msc_hid/src/cdc_app.c
@@ -27,12 +27,11 @@
#include "tusb.h"
#include "bsp/board_api.h"
-size_t get_console_inputs(uint8_t* buf, size_t bufsize) {
+static size_t get_console_inputs(uint8_t* buf, size_t bufsize) {
size_t count = 0;
while (count < bufsize) {
int ch = board_getchar();
- if (ch <= 0) break;
-
+ if (ch <= 0) { break; }
buf[count] = (uint8_t) ch;
count++;
}
@@ -69,10 +68,15 @@ void tuh_cdc_rx_cb(uint8_t idx) {
uint32_t const bufsize = sizeof(buf) - 1;
// forward cdc interfaces -> console
- uint32_t count = tuh_cdc_read(idx, buf, bufsize);
- buf[count] = 0;
+ const uint32_t count = tuh_cdc_read(idx, buf, bufsize);
+ if (count) {
+ buf[count] = 0;
+ printf("%s", (char*) buf);
- printf("%s", (char*) buf);
+ #ifndef __ICCARM__ // TODO IAR doesn't support stream control ?
+ fflush(stdout);// flush right away, else nanolib will wait for newline
+ #endif
+ }
}
// Invoked when a device with CDC interface is mounted
@@ -88,7 +92,7 @@ void tuh_cdc_mount_cb(uint8_t idx) {
// If CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined, line coding will be set by tinyusb stack
// while eneumerating new cdc device
cdc_line_coding_t line_coding = {0};
- if (tuh_cdc_get_local_line_coding(idx, &line_coding)) {
+ if (tuh_cdc_get_line_coding_local(idx, &line_coding)) {
printf(" Baudrate: %" PRIu32 ", Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits);
printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity, line_coding.data_bits);
}
diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c
index 5bae250cf..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
}
}
@@ -165,57 +157,23 @@ static void process_kbd_report(hid_keyboard_report_t const *report)
// Mouse
//--------------------------------------------------------------------+
-void cursor_movement(int8_t x, int8_t y, int8_t wheel)
-{
-#if USE_ANSI_ESCAPE
- // Move X using ansi escape
- if ( x < 0)
- {
- printf(ANSI_CURSOR_BACKWARD(%d), (-x)); // move left
- }else if ( x > 0)
- {
- printf(ANSI_CURSOR_FORWARD(%d), x); // move right
- }
-
- // Move Y using ansi escape
- if ( y < 0)
- {
- printf(ANSI_CURSOR_UP(%d), (-y)); // move up
- }else if ( y > 0)
- {
- printf(ANSI_CURSOR_DOWN(%d), y); // move down
- }
-
- // Scroll using ansi escape
- if (wheel < 0)
- {
- printf(ANSI_SCROLL_UP(%d), (-wheel)); // scroll up
- }else if (wheel > 0)
- {
- printf(ANSI_SCROLL_DOWN(%d), wheel); // scroll down
- }
-
- printf("\r\n");
-#else
+static void cursor_movement(int8_t x, int8_t y, int8_t wheel) {
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);
}
@@ -264,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/main.c b/examples/host/cdc_msc_hid/src/main.c
index 2d5df23f9..7b02e238e 100644
--- a/examples/host/cdc_msc_hid/src/main.c
+++ b/examples/host/cdc_msc_hid/src/main.c
@@ -31,18 +31,12 @@
#include "tusb.h"
//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF PROTYPES
+// MACRO CONSTANT TYPEDEF PROTOTYPES
//--------------------------------------------------------------------+
void led_blinking_task(void);
extern void cdc_app_task(void);
extern void hid_app_task(void);
-#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
-// API to read/rite MAX3421's register. Implemented by TinyUSB
-extern uint8_t tuh_max3421_reg_read(uint8_t rhport, uint8_t reg, bool in_isr);
-extern bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr);
-#endif
-
/*------------- MAIN -------------*/
int main(void) {
board_init();
@@ -101,7 +95,9 @@ void led_blinking_task(void) {
static bool led_state = false;
// Blink every interval ms
- if (board_millis() - start_ms < interval_ms) return; // not enough time
+ if (board_millis() - start_ms < interval_ms) {
+ return;// not enough time
+ }
start_ms += interval_ms;
board_led_write(led_state);
diff --git a/examples/host/cdc_msc_hid/src/msc_app.c b/examples/host/cdc_msc_hid/src/msc_app.c
index 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/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h
index cc8d6e5c4..2f8cb5e03 100644
--- a/examples/host/cdc_msc_hid/src/tusb_config.h
+++ b/examples/host/cdc_msc_hid/src/tusb_config.h
@@ -103,10 +103,11 @@
#define CFG_TUH_ENUMERATION_BUFSIZE 256
#define CFG_TUH_HUB 1 // number of supported hubs
-#define CFG_TUH_CDC 1 // CDC ACM
+#define CFG_TUH_CDC 2 // number of supported CDC devices. also activates CDC ACM
#define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API
+#define CFG_TUH_CDC_PL2303 1 // PL2303 Serial. PL2303 is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
#define CFG_TUH_MSC 1
#define CFG_TUH_VENDOR 0
@@ -122,7 +123,7 @@
// Set Line Control state on enumeration/mounted:
// DTR ( bit 0), RTS (bit 1)
-#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
+#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS)
// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
// bit rate = 115200, 1 stop bit, no parity, 8 bit data width
diff --git a/examples/host/cdc_msc_hid_freertos/only.txt b/examples/host/cdc_msc_hid_freertos/only.txt
index e3ae25260..d939d4e7b 100644
--- a/examples/host/cdc_msc_hid_freertos/only.txt
+++ b/examples/host/cdc_msc_hid_freertos/only.txt
@@ -13,3 +13,5 @@ mcu:MAX3421
mcu:STM32F4
mcu:STM32F7
mcu:STM32H7
+mcu:STM32H7RS
+mcu:STM32N6
diff --git a/examples/host/cdc_msc_hid_freertos/src/cdc_app.c b/examples/host/cdc_msc_hid_freertos/src/cdc_app.c
index 7cbe1e03a..d99760a02 100644
--- a/examples/host/cdc_msc_hid_freertos/src/cdc_app.c
+++ b/examples/host/cdc_msc_hid_freertos/src/cdc_app.c
@@ -27,7 +27,7 @@
#include "tusb.h"
#include "bsp/board_api.h"
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define CDC_STACK_SZIE 2048
#else
#define CDC_STACK_SZIE (3*configMINIMAL_STACK_SIZE/2)
@@ -52,7 +52,7 @@ void cdc_app_init(void) {
}
// helper
-size_t get_console_inputs(uint8_t *buf, size_t bufsize) {
+static size_t get_console_inputs(uint8_t *buf, size_t bufsize) {
size_t count = 0;
while (count < bufsize) {
int ch = board_getchar();
diff --git a/examples/host/cdc_msc_hid_freertos/src/main.c b/examples/host/cdc_msc_hid_freertos/src/main.c
index 10d1b120b..0bcb355ec 100644
--- a/examples/host/cdc_msc_hid_freertos/src/main.c
+++ b/examples/host/cdc_msc_hid_freertos/src/main.c
@@ -30,7 +30,7 @@
#include "bsp/board_api.h"
#include "tusb.h"
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define USBH_STACK_SIZE 4096
#else
// Increase stack size when debug log is enabled
@@ -69,12 +69,6 @@ extern void cdc_app_init(void);
extern void hid_app_init(void);
extern void msc_app_init(void);
-#if CFG_TUH_ENABLED && CFG_TUH_MAX3421
-// API to read/rite MAX3421's register. Implemented by TinyUSB
-extern uint8_t tuh_max3421_reg_read(uint8_t rhport, uint8_t reg, bool in_isr);
-extern bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr);
-#endif
-
/*------------- MAIN -------------*/
int main(void) {
board_init();
@@ -92,15 +86,15 @@ int main(void) {
xTimerStart(blinky_tm, 0);
- // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
-#if !TUSB_MCU_VENDOR_ESPRESSIF
+ // only start scheduler for non-espressif mcu
+#ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
return 0;
}
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
void app_main(void) {
main();
}
diff --git a/examples/host/cdc_msc_hid_freertos/src/msc_app.c b/examples/host/cdc_msc_hid_freertos/src/msc_app.c
index 6b9cdab85..6439495a8 100644
--- a/examples/host/cdc_msc_hid_freertos/src/msc_app.c
+++ b/examples/host/cdc_msc_hid_freertos/src/msc_app.c
@@ -34,7 +34,7 @@ void msc_app_init(void) {
// nothing to do
}
-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;
diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h
index 682265f59..3cdb227e2 100644
--- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h
+++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h
@@ -44,7 +44,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
@@ -108,10 +108,11 @@
#define CFG_TUH_ENUMERATION_BUFSIZE 256
#define CFG_TUH_HUB 1 // number of supported hubs
-#define CFG_TUH_CDC 1 // CDC ACM
+#define CFG_TUH_CDC 1 // number of supported CDC devices. also activates CDC ACM
#define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API
+#define CFG_TUH_CDC_PL2303 1 // PL2303 Serial. PL2303 is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
#define CFG_TUH_MSC 1
#define CFG_TUH_VENDOR 0
@@ -127,7 +128,7 @@
// Set Line Control state on enumeration/mounted:
// DTR ( bit 0), RTS (bit 1)
-#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
+#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS)
// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
// bit rate = 115200, 1 stop bit, no parity, 8 bit data width
diff --git a/examples/host/device_info/only.txt b/examples/host/device_info/only.txt
index b6f87f423..b5a4b6739 100644
--- a/examples/host/device_info/only.txt
+++ b/examples/host/device_info/only.txt
@@ -18,3 +18,5 @@ mcu:RAXXX
mcu:STM32F4
mcu:STM32F7
mcu:STM32H7
+mcu:STM32H7RS
+mcu:STM32N6
diff --git a/examples/host/device_info/src/main.c b/examples/host/device_info/src/main.c
index 775968c16..7189972d6 100644
--- a/examples/host/device_info/src/main.c
+++ b/examples/host/device_info/src/main.c
@@ -81,7 +81,7 @@ void init_freertos_task(void);
//--------------------------------------------------------------------
// Main
//--------------------------------------------------------------------
-void init_tinyusb(void) {
+static void init_tinyusb(void) {
// init host stack on configured roothub port
tusb_rhport_init_t host_init = {
.role = TUSB_ROLE_HOST,
@@ -124,13 +124,18 @@ void tuh_mount_cb(uint8_t daddr) {
}
printf("Device %u: ID %04x:%04x SN ", daddr, desc.device.idVendor, desc.device.idProduct);
- xfer_result = tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, desc.serial, sizeof(desc.serial));
+
+ xfer_result = XFER_RESULT_FAILED;
+ if (desc.device.iSerialNumber != 0) {
+ xfer_result = tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, desc.serial, sizeof(desc.serial));
+ }
if (XFER_RESULT_SUCCESS != xfer_result) {
uint16_t* serial = (uint16_t*)(uintptr_t) desc.serial;
- serial[0] = 'n';
- serial[1] = '/';
- serial[2] = 'a';
- serial[3] = 0;
+ serial[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * 3 + 2));
+ serial[1] = 'n';
+ serial[2] = '/';
+ serial[3] = 'a';
+ serial[4] = 0;
}
print_utf16((uint16_t*)(uintptr_t) desc.serial, sizeof(desc.serial)/2);
printf("\r\n");
@@ -150,16 +155,20 @@ void tuh_mount_cb(uint8_t daddr) {
// Get String descriptor using Sync API
printf(" iManufacturer %u ", desc.device.iManufacturer);
- xfer_result = tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, desc.buf, sizeof(desc.buf));
- if (XFER_RESULT_SUCCESS == xfer_result) {
- print_utf16((uint16_t*)(uintptr_t) desc.buf, sizeof(desc.buf)/2);
+ if (desc.device.iManufacturer != 0) {
+ xfer_result = tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, desc.buf, sizeof(desc.buf));
+ if (XFER_RESULT_SUCCESS == xfer_result) {
+ print_utf16((uint16_t*)(uintptr_t) desc.buf, sizeof(desc.buf)/2);
+ }
}
printf("\r\n");
printf(" iProduct %u ", desc.device.iProduct);
- xfer_result = tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, desc.buf, sizeof(desc.buf));
- if (XFER_RESULT_SUCCESS == xfer_result) {
- print_utf16((uint16_t*)(uintptr_t) desc.buf, sizeof(desc.buf)/2);
+ if (desc.device.iProduct != 0) {
+ xfer_result = tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, desc.buf, sizeof(desc.buf));
+ if (XFER_RESULT_SUCCESS == xfer_result) {
+ print_utf16((uint16_t*)(uintptr_t) desc.buf, sizeof(desc.buf)/2);
+ }
}
printf("\r\n");
@@ -259,7 +268,7 @@ void led_blinking_task(void* param) {
#define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define USB_STACK_SIZE 4096
#else
// Increase stack size when debug log is enabled
@@ -276,7 +285,7 @@ StackType_t usb_stack[USB_STACK_SIZE];
StaticTask_t usb_taskdef;
#endif
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
void app_main(void) {
main();
}
@@ -299,8 +308,8 @@ void init_freertos_task(void) {
xTaskCreate(usb_host_task, "usbh", USB_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL);
#endif
- // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
-#if !TUSB_MCU_VENDOR_ESPRESSIF
+ // only start scheduler for non-espressif mcu
+#ifndef ESP_PLATFORM
vTaskStartScheduler();
#endif
}
diff --git a/examples/host/device_info/src/tusb_config.h b/examples/host/device_info/src/tusb_config.h
index e12970c12..e4ca2528e 100644
--- a/examples/host/device_info/src/tusb_config.h
+++ b/examples/host/device_info/src/tusb_config.h
@@ -40,7 +40,7 @@
#endif
// Espressif IDF requires "freertos/" prefix in include path
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
diff --git a/examples/host/hid_controller/only.txt b/examples/host/hid_controller/only.txt
index 95f9f1d82..dcdaf41c7 100644
--- a/examples/host/hid_controller/only.txt
+++ b/examples/host/hid_controller/only.txt
@@ -15,3 +15,5 @@ mcu:MAX3421
mcu:STM32F4
mcu:STM32F7
mcu:STM32H7
+mcu:STM32H7RS
+mcu:STM32N6
diff --git a/examples/host/hid_controller/src/hid_app.c b/examples/host/hid_controller/src/hid_app.c
index 6ffe0b6d4..1d6ca8b07 100644
--- a/examples/host/hid_controller/src/hid_app.c
+++ b/examples/host/hid_controller/src/hid_app.c
@@ -231,14 +231,12 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
}
// check if different than 2
-bool diff_than_2(uint8_t x, uint8_t y)
-{
+static inline bool diff_than_2(uint8_t x, uint8_t y) {
return (x - y > 2) || (y - x > 2);
}
// check if 2 reports are different enough
-bool diff_report(sony_ds4_report_t const* rpt1, sony_ds4_report_t const* rpt2)
-{
+static bool diff_report(sony_ds4_report_t const* rpt1, sony_ds4_report_t const* rpt2) {
bool result;
// x, y, z, rz must different than 2 to be counted
@@ -251,7 +249,7 @@ bool diff_report(sony_ds4_report_t const* rpt1, sony_ds4_report_t const* rpt2)
return result;
}
-void process_sony_ds4(uint8_t const* report, uint16_t len)
+static void process_sony_ds4(uint8_t const* report, uint16_t len)
{
(void)len;
const char* dpad_str[] = { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "none" };
@@ -310,16 +308,13 @@ void process_sony_ds4(uint8_t const* report, uint16_t len)
}
// Invoked when received report from device via interrupt endpoint
-void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
-{
- if ( is_sony_ds4(dev_addr) )
- {
+void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
+ if (is_sony_ds4(dev_addr)) {
process_sony_ds4(report, len);
}
// continue to request to receive report
- if ( !tuh_hid_receive_report(dev_addr, instance) )
- {
+ if (!tuh_hid_receive_report(dev_addr, instance)) {
printf("Error: cannot request to receive report\r\n");
}
}
diff --git a/examples/host/midi_rx/only.txt b/examples/host/midi_rx/only.txt
index b6f87f423..b5a4b6739 100644
--- a/examples/host/midi_rx/only.txt
+++ b/examples/host/midi_rx/only.txt
@@ -18,3 +18,5 @@ mcu:RAXXX
mcu:STM32F4
mcu:STM32F7
mcu:STM32H7
+mcu:STM32H7RS
+mcu:STM32N6
diff --git a/examples/host/midi_rx/src/tusb_config.h b/examples/host/midi_rx/src/tusb_config.h
index c9b430388..76bdf87f3 100644
--- a/examples/host/midi_rx/src/tusb_config.h
+++ b/examples/host/midi_rx/src/tusb_config.h
@@ -40,7 +40,7 @@ extern "C" {
#endif
// Espressif IDF requires "freertos/" prefix in include path
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
#define CFG_TUSB_OS_INC_PATH freertos/
#endif
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/examples/host/msc_file_explorer/only.txt b/examples/host/msc_file_explorer/only.txt
index 95f9f1d82..dcdaf41c7 100644
--- a/examples/host/msc_file_explorer/only.txt
+++ b/examples/host/msc_file_explorer/only.txt
@@ -15,3 +15,5 @@ mcu:MAX3421
mcu:STM32F4
mcu:STM32F7
mcu:STM32H7
+mcu:STM32H7RS
+mcu:STM32N6
diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c
index 226c870ea..40a9ef57e 100644
--- a/examples/host/msc_file_explorer/src/msc_app.c
+++ b/examples/host/msc_file_explorer/src/msc_app.c
@@ -34,6 +34,8 @@
#define EMBEDDED_CLI_IMPL
#include "embedded_cli.h"
+#include "msc_app.h"
+
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
diff --git a/examples/typec/power_delivery/src/main.c b/examples/typec/power_delivery/src/main.c
index 068dbbeb1..de0db4721 100644
--- a/examples/typec/power_delivery/src/main.c
+++ b/examples/typec/power_delivery/src/main.c
@@ -71,9 +71,8 @@ int main(void)
}
}
-#if TUSB_MCU_VENDOR_ESPRESSIF
-void app_main(void)
-{
+#ifdef ESP_PLATFORM
+void app_main(void) {
main();
}
#endif
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/board.c b/hw/bsp/board.c
index 0e0fa4ac6..1ba5a1b9d 100644
--- a/hw/bsp/board.c
+++ b/hw/bsp/board.c
@@ -60,17 +60,29 @@ int sys_read(int fhdl, char *buf, size_t count) {
int rd = (int) SEGGER_RTT_Read(0, buf, count);
return (rd > 0) ? rd : -1;
}
-
#endif
#elif defined(LOGGER_SWO)
+
+#define ITM_BASE 0xE0000000
+#define ITM_STIM0 (*((volatile uint8_t*)(ITM_BASE + 0)))
+#define ITM_TER *((volatile uint32_t*)(ITM_BASE + 0xE00))
+#define ITM_TCR *((volatile uint32_t*)(ITM_BASE + 0xE80))
+
+#define ITM_TCR_ITMENA (1 << 0)
+
// Logging with SWO for ARM Cortex-M
int sys_write (int fhdl, const char *buf, size_t count) {
(void) fhdl;
uint8_t const* buf8 = (uint8_t const*) buf;
- for(size_t i=0; i 0) ? (int) c : (-1);
}
+void board_putchar(int c) {
+ sys_write(0, (const char*)&c, 1);
+}
uint32_t tusb_time_millis_api(void) {
return board_millis();
@@ -144,7 +159,7 @@ uint32_t tusb_time_millis_api(void) {
//--------------------------------------------------------------------
// FreeRTOS hooks
//--------------------------------------------------------------------
-#if CFG_TUSB_OS == OPT_OS_FREERTOS && !TUSB_MCU_VENDOR_ESPRESSIF
+#if CFG_TUSB_OS == OPT_OS_FREERTOS && !defined(ESP_PLATFORM)
#include "FreeRTOS.h"
#include "task.h"
@@ -226,5 +241,4 @@ void vApplicationSetupTimerInterrupt(void) {
}
#endif
-
#endif
diff --git a/hw/bsp/board_api.h b/hw/bsp/board_api.h
index 9cdbbf0d3..328fe9363 100644
--- a/hw/bsp/board_api.h
+++ b/hw/bsp/board_api.h
@@ -41,7 +41,7 @@ extern "C" {
#if CFG_TUSB_OS == OPT_OS_ZEPHYR
#include
#elif CFG_TUSB_OS == OPT_OS_FREERTOS
- #if TUSB_MCU_VENDOR_ESPRESSIF
+ #ifdef ESP_PLATFORM
// ESP-IDF need "freertos/" prefix in include path.
// CFG_TUSB_OS_INC_PATH should be defined accordingly.
#include "freertos/FreeRTOS.h"
@@ -195,6 +195,7 @@ static inline void board_delay(uint32_t ms) {
// stdio getchar() is blocking, this is non-blocking version
int board_getchar(void);
+void board_putchar(int c);
#ifdef __cplusplus
}
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/brtmm90x/family.mk b/hw/bsp/brtmm90x/family.mk
index 6df0bfdfe..2de4dc760 100644
--- a/hw/bsp/brtmm90x/family.mk
+++ b/hw/bsp/brtmm90x/family.mk
@@ -13,7 +13,6 @@ else
# The submodule BRTSG-FOSS/ft90x-sdk contains header files and source
# code for the Bridgetek SDK. This can be used instead of the prebuilt
# library.
-DEPS_SUBMODULES += hw/mcu/bridgetek/ft9xx/ft90x-sdk
# The SDK can be used to load specific files from the Bridgetek SDK.
FT9XX_SDK = hw/mcu/bridgetek/ft9xx/ft90x-sdk/Source
INC += "$(TOP)/$(FT9XX_SDK)/include"
diff --git a/hw/bsp/ch32f20x/family.mk b/hw/bsp/ch32f20x/family.mk
index c08451b9c..2ff9f79e3 100644
--- a/hw/bsp/ch32f20x/family.mk
+++ b/hw/bsp/ch32f20x/family.mk
@@ -1,6 +1,5 @@
# Submodules
CH32F20X_SDK = hw/mcu/wch/ch32f20x
-DEPS_SUBMODULES += $(CH32F20X_SDK)
# WCH-SDK paths
CH32F20X_SDK_SRC = $(CH32F20X_SDK)/EVT/EXAM/SRC
diff --git a/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.h b/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.h
index 256958088..56f49205c 100644
--- a/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.h
+++ b/hw/bsp/ch32v20x/boards/ch32v203c_r0_1v0/board.h
@@ -13,6 +13,8 @@ extern "C" {
#define LED_PORT GPIOA
#define LED_PIN GPIO_Pin_0
#define LED_STATE_ON 0
+#define LED_CLOCK_EN() RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE)
+#define LED_MODE GPIO_Mode_Out_OD
#define UART_DEV USART1
#define UART_CLOCK_EN() RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE)
diff --git a/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.h b/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.h
index 827226d80..4a040e0df 100644
--- a/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.h
+++ b/hw/bsp/ch32v20x/boards/ch32v203g_r0_1v0/board.h
@@ -13,6 +13,8 @@ extern "C" {
#define LED_PORT GPIOA
#define LED_PIN GPIO_Pin_0
#define LED_STATE_ON 0
+#define LED_CLOCK_EN() RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE)
+#define LED_MODE GPIO_Mode_Out_OD
#define UART_DEV USART2
#define UART_CLOCK_EN() RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE)
diff --git a/hw/bsp/ch32v20x/boards/nanoch32v203/board.h b/hw/bsp/ch32v20x/boards/nanoch32v203/board.h
index f02fceced..63237861c 100644
--- a/hw/bsp/ch32v20x/boards/nanoch32v203/board.h
+++ b/hw/bsp/ch32v20x/boards/nanoch32v203/board.h
@@ -13,6 +13,8 @@ extern "C" {
#define LED_PORT GPIOA
#define LED_PIN GPIO_Pin_15
#define LED_STATE_ON 0
+#define LED_CLOCK_EN() RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE)
+#define LED_MODE GPIO_Mode_Out_OD
#define UART_DEV USART1
#define UART_CLOCK_EN() RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE)
diff --git a/hw/bsp/ch32v20x/family.c b/hw/bsp/ch32v20x/family.c
index d674ccd6f..2c212a82b 100644
--- a/hw/bsp/ch32v20x/family.c
+++ b/hw/bsp/ch32v20x/family.c
@@ -99,11 +99,11 @@ void board_init(void) {
SysTick_Config(SystemCoreClock / 1000);
#endif
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
+ LED_CLOCK_EN();
GPIO_InitTypeDef GPIO_InitStructure = {
.GPIO_Pin = LED_PIN,
- .GPIO_Mode = GPIO_Mode_Out_OD,
+ .GPIO_Mode = LED_MODE,
.GPIO_Speed = GPIO_Speed_10MHz,
};
GPIO_Init(LED_PORT, &GPIO_InitStructure);
diff --git a/hw/bsp/espressif/boards/adafruit_feather_esp32c6/board.cmake b/hw/bsp/espressif/boards/adafruit_feather_esp32c6/board.cmake
new file mode 100644
index 000000000..9adaefb17
--- /dev/null
+++ b/hw/bsp/espressif/boards/adafruit_feather_esp32c6/board.cmake
@@ -0,0 +1,3 @@
+# Apply board specific content here
+set(IDF_TARGET "esp32c6")
+set(MAX3421_HOST 1)
diff --git a/hw/bsp/espressif/boards/adafruit_feather_esp32c6/board.h b/hw/bsp/espressif/boards/adafruit_feather_esp32c6/board.h
new file mode 100644
index 000000000..18b51410d
--- /dev/null
+++ b/hw/bsp/espressif/boards/adafruit_feather_esp32c6/board.h
@@ -0,0 +1,56 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ name: Adafruit Feather EPS32-C6
+ url: https://www.adafruit.com/product/5933
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define NEOPIXEL_PIN 15
+
+#define BUTTON_PIN 9
+#define BUTTON_STATE_ACTIVE 0
+
+// SPI for USB host shield
+#define MAX3421_SPI_HOST SPI2_HOST
+#define MAX3421_SCK_PIN 21
+#define MAX3421_MOSI_PIN 22
+#define MAX3421_MISO_PIN 23
+#define MAX3421_CS_PIN 8
+#define MAX3421_INTR_PIN 7
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* BOARD_H_ */
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..2a5deed26 100644
--- a/hw/bsp/espressif/boards/family.c
+++ b/hw/bsp/espressif/boards/family.c
@@ -49,7 +49,9 @@ static led_strip_handle_t led_strip;
static void max3421_init(void);
#endif
+#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3, OPT_MCU_ESP32P4)
static bool usb_init(void);
+#endif
//--------------------------------------------------------------------+
// Implementation
@@ -92,10 +94,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
@@ -154,6 +156,10 @@ int board_getchar(void) {
return getchar();
}
+void board_putchar(int c) {
+ putchar(c);
+}
+
//--------------------------------------------------------------------
// PHY Init
//--------------------------------------------------------------------
diff --git a/hw/bsp/espressif/family.cmake b/hw/bsp/espressif/family.cmake
index daa12cdb4..ca9eadaf6 100644
--- a/hw/bsp/espressif/family.cmake
+++ b/hw/bsp/espressif/family.cmake
@@ -1,5 +1,3 @@
-cmake_minimum_required(VERSION 3.5)
-
# Apply board specific content i.e IDF_TARGET must be set before project.cmake is included
include("${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake")
string(TOUPPER ${IDF_TARGET} FAMILY_MCUS)
@@ -32,8 +30,6 @@ endif ()
# Add example src and bsp directories
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/espressif/family.mk b/hw/bsp/espressif/family.mk
deleted file mode 100644
index 0dc21b8eb..000000000
--- a/hw/bsp/espressif/family.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-#DEPS_SUBMODULES +=
-
-UF2_FAMILY_ID_esp32s2 = 0xbfdd4eee
-UF2_FAMILY_ID_esp32s3 = 0xc47e5767
-
-BOARD_CMAKE := $(file < $(TOP)/$(BOARD_PATH)/board.cmake)
-ifneq ($(findstring esp32s2,$(BOARD_CMAKE)),)
- IDF_TARGET = esp32s2
-else
-ifneq ($(findstring esp32s3,$(BOARD_CMAKE)),)
- IDF_TARGET = esp32s3
-endif
-endif
-
-.PHONY: all clean flash bootloader-flash app-flash erase monitor dfu-flash dfu
-
-all:
- idf.py -B$(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) $(CMAKE_DEFSYM) build
-
-build: all
-
-fullclean:
- if test -f sdkconfig; then $(RM) -f sdkconfig ; fi
- if test -d $(BUILD); then $(RM) -rf $(BUILD) ; fi
- idf.py -B$(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) $(CMAKE_DEFSYM) $@
-
-clean flash bootloader-flash app-flash erase monitor dfu-flash dfu size size-components size-files:
- idf.py -B$(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) $(CMAKE_DEFSYM) $@
-
-uf2: $(BUILD)/$(PROJECT).uf2
-
-$(BUILD)/$(PROJECT).uf2: $(BUILD)/$(PROJECT).bin
- @echo CREATE $@
- $(PYTHON) $(TOP)/tools/uf2/utils/uf2conv.py -f $(UF2_FAMILY_ID_$(IDF_TARGET)) -b 0x0 -c -o $@ $^
diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake
index e7161eba3..9ec80df91 100644
--- a/hw/bsp/family_support.cmake
+++ b/hw/bsp/family_support.cmake
@@ -38,6 +38,11 @@ if (NOT DEFINED TOOLCHAIN)
set(TOOLCHAIN gcc)
endif ()
+# Optimization
+if (NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
+ set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Build type" FORCE)
+endif ()
+
#-------------------------------------------------------------
# FAMILY and BOARD
#-------------------------------------------------------------
@@ -208,13 +213,16 @@ function(family_configure_common TARGET RTOS)
# LOGGER option
if (DEFINED LOGGER)
+ string(TOUPPER ${LOGGER} LOGGER)
target_compile_definitions(${TARGET} PUBLIC LOGGER_${LOGGER})
# Add segger rtt to example
- if(LOGGER STREQUAL "RTT" OR LOGGER STREQUAL "rtt")
+ if(LOGGER STREQUAL "RTT")
target_sources(${TARGET} PUBLIC ${TOP}/lib/SEGGER_RTT/RTT/SEGGER_RTT.c)
target_include_directories(${TARGET} PUBLIC ${TOP}/lib/SEGGER_RTT/RTT)
# target_compile_definitions(${TARGET} PUBLIC SEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL)
endif ()
+ else ()
+ target_compile_definitions(${TARGET} PUBLIC LOGGER_UART)
endif ()
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
@@ -270,10 +278,6 @@ function(family_add_tinyusb TARGET OPT_MCU)
# Add TinyUSB sources, include and common define
tinyusb_target_add(${TARGET})
-
- # path to tusb_config.h
- target_include_directories(${TARGET} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
-
target_compile_definitions(${TARGET} PUBLIC CFG_TUSB_MCU=${OPT_MCU})
if (DEFINED LOG)
target_compile_definitions(${TARGET} PUBLIC CFG_TUSB_DEBUG=${LOG})
@@ -486,7 +490,7 @@ function(family_flash_openocd TARGET)
# note skip verify since it has issue with rp2040
add_custom_target(${TARGET}-openocd
DEPENDS ${TARGET}
- COMMAND ${OPENOCD} -c "tcl_port disabled" -c "gdb_port disabled" ${OPTION_LIST} -c init -c halt -c "program $" -c reset ${OPTION_LIST2} -c exit
+ COMMAND ${OPENOCD} -c "tcl_port disabled; gdb_port disabled" ${OPTION_LIST} -c "init; halt; program $" -c reset ${OPTION_LIST2} -c exit
VERBATIM
)
endfunction()
@@ -506,10 +510,16 @@ endfunction()
# Add flash openocd adi (Analog Devices) target
# included with msdk or compiled from release branch of https://github.com/analogdevicesinc/openocd
function(family_flash_openocd_adi TARGET)
- if (DEFINED $ENV{MAXIM_PATH})
- # use openocd from msdk
- set(OPENOCD ENV{MAXIM_PATH}/Tools/OpenOCD/openocd)
- set(OPENOCD_OPTION2 "-s ENV{MAXIM_PATH}/Tools/OpenOCD/scripts")
+ if (DEFINED MAXIM_PATH)
+ # use openocd from msdk with MAXIM_PATH cmake variable first if the user specified it
+ set(OPENOCD ${MAXIM_PATH}/Tools/OpenOCD/openocd)
+ set(OPENOCD_OPTION2 "-s ${MAXIM_PATH}/Tools/OpenOCD/scripts")
+ elseif (DEFINED ENV{MAXIM_PATH})
+ # use openocd from msdk with MAXIM_PATH environment variable. Normalize
+ # since msdk can be Windows (MinGW) or Linux
+ file(TO_CMAKE_PATH "$ENV{MAXIM_PATH}" MAXIM_PATH_NORM)
+ set(OPENOCD ${MAXIM_PATH_NORM}/Tools/OpenOCD/openocd)
+ set(OPENOCD_OPTION2 "-s ${MAXIM_PATH_NORM}/Tools/OpenOCD/scripts")
else()
# compiled from source
if (NOT DEFINED OPENOCD_ADI_PATH)
diff --git a/hw/bsp/imxrt/boards/mimxrt1015_evk/board/clock_config.c b/hw/bsp/imxrt/boards/mimxrt1015_evk/board/clock_config.c
index ae1aa7fb1..b9e4851bf 100644
--- a/hw/bsp/imxrt/boards/mimxrt1015_evk/board/clock_config.c
+++ b/hw/bsp/imxrt/boards/mimxrt1015_evk/board/clock_config.c
@@ -15,11 +15,11 @@
/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
!!GlobalInfo
-product: Clocks v11.0
+product: Clocks v15.0
processor: MIMXRT1015xxxxx
package_id: MIMXRT1015DAF5A
mcu_data: ksdk2_0
-processor_version: 13.0.2
+processor_version: 24.12.10
board: MIMXRT1015-EVK
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
diff --git a/hw/bsp/imxrt/boards/mimxrt1015_evk/board/clock_config.h b/hw/bsp/imxrt/boards/mimxrt1015_evk/board/clock_config.h
index 2acdb16a7..cccbe487a 100644
--- a/hw/bsp/imxrt/boards/mimxrt1015_evk/board/clock_config.h
+++ b/hw/bsp/imxrt/boards/mimxrt1015_evk/board/clock_config.h
@@ -36,39 +36,39 @@ void BOARD_InitBootClocks(void);
#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 500000000U /*!< Core clock frequency: 500000000Hz */
/* Clock outputs (values are in Hz): */
-#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 500000000UL
-#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL
-#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL
-#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL
-#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL
-#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL
-#define BOARD_BOOTCLOCKRUN_ENET_500M_REF_CLK 500000000UL
-#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL
-#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 196363636UL
-#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 62500000UL
-#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 62500000UL
-#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 125000000UL
-#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL
-#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL
-#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL
-#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 62500000UL
-#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL
-#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL
-#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL
-#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL
-#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL
-#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL
-#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL
-#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL
-#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL
-#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 480000000UL
+#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 500000000UL /* Clock consumers of AHB_CLK_ROOT output : AIPSTZ1, AIPSTZ2, AIPSTZ3, AIPSTZ4, ARM, FLEXSPI */
+#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL /* Clock consumers of CKIL_SYNC_CLK_ROOT output : CSU, EWM, GPT1, GPT2, KPP, PIT, RTWDOG, SNVS, SPDIF, TEMPMON, USB, WDOG1, WDOG2 */
+#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL /* Clock consumers of CLKO1_CLK output : N/A */
+#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL /* Clock consumers of CLKO2_CLK output : N/A */
+#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL /* Clock consumers of CLK_1M output : EWM, RTWDOG */
+#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL /* Clock consumers of CLK_24M output : GPT1, GPT2 */
+#define BOARD_BOOTCLOCKRUN_ENET_500M_REF_CLK 500000000UL /* Clock consumers of ENET_500M_REF_CLK output : N/A */
+#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL /* Clock consumers of FLEXIO1_CLK_ROOT output : FLEXIO1 */
+#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 196363636UL /* Clock consumers of FLEXSPI_CLK_ROOT output : FLEXSPI */
+#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 62500000UL /* Clock consumers of GPT1_ipg_clk_highfreq output : GPT1 */
+#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 62500000UL /* Clock consumers of GPT2_ipg_clk_highfreq output : GPT2 */
+#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 125000000UL /* Clock consumers of IPG_CLK_ROOT output : ADC1, ADC_ETC, AOI, ARM, BEE, CCM, CSU, DCDC, DCP, DMA0, DMAMUX, ENC1, EWM, FLEXIO1, FLEXRAM, FLEXSPI, GPC, GPIO1, GPIO2, GPIO3, GPIO5, IOMUXC, KPP, LPI2C1, LPI2C2, LPSPI1, LPSPI2, LPUART1, LPUART2, LPUART3, LPUART4, NVIC, OCOTP, PWM1, RTWDOG, SAI1, SAI2, SAI3, SNVS, SPDIF, SRC, TEMPMON, TMR1, TRNG, USB, WDOG1, WDOG2, XBARA, XBARB */
+#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL /* Clock consumers of LPI2C_CLK_ROOT output : LPI2C1, LPI2C2 */
+#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL /* Clock consumers of LPSPI_CLK_ROOT output : LPSPI1, LPSPI2 */
+#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL /* Clock consumers of MQS_MCLK output : N/A */
+#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 62500000UL /* Clock consumers of PERCLK_CLK_ROOT output : GPT1, GPT2, PIT */
+#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL /* Clock consumers of SAI1_CLK_ROOT output : N/A */
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL /* Clock consumers of SAI1_MCLK1 output : SAI1 */
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL /* Clock consumers of SAI1_MCLK2 output : SAI1 */
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL /* Clock consumers of SAI1_MCLK3 output : SAI1 */
+#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL /* Clock consumers of SAI2_CLK_ROOT output : N/A */
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL /* Clock consumers of SAI2_MCLK1 output : SAI2 */
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL /* Clock consumers of SAI2_MCLK2 output : SAI2 */
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL /* Clock consumers of SAI2_MCLK3 output : SAI2 */
+#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL /* Clock consumers of SAI3_CLK_ROOT output : N/A */
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL /* Clock consumers of SAI3_MCLK1 output : SAI3 */
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL /* Clock consumers of SAI3_MCLK2 output : SAI3 */
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL /* Clock consumers of SAI3_MCLK3 output : SAI3 */
+#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL /* Clock consumers of SPDIF0_CLK_ROOT output : SPDIF */
+#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL /* Clock consumers of SPDIF0_EXTCLK_OUT output : SPDIF */
+#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 117333333UL /* Clock consumers of TRACE_CLK_ROOT output : ARM */
+#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL /* Clock consumers of UART_CLK_ROOT output : LPUART1, LPUART2, LPUART3, LPUART4 */
+#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 480000000UL /* Clock consumers of USBPHY1_CLK output : TEMPMON, USB */
/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration.
*/
diff --git a/hw/bsp/imxrt/boards/mimxrt1015_evk/board/pin_mux.c b/hw/bsp/imxrt/boards/mimxrt1015_evk/board/pin_mux.c
index 97224a332..76c1dae70 100644
--- a/hw/bsp/imxrt/boards/mimxrt1015_evk/board/pin_mux.c
+++ b/hw/bsp/imxrt/boards/mimxrt1015_evk/board/pin_mux.c
@@ -6,11 +6,11 @@
/*
* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
!!GlobalInfo
-product: Pins v13.1
+product: Pins v17.0
processor: MIMXRT1015xxxxx
package_id: MIMXRT1015DAF5A
mcu_data: ksdk2_0
-processor_version: 13.0.2
+processor_version: 24.12.10
board: MIMXRT1015-EVK
external_user_signals: {}
pin_labels:
@@ -32,6 +32,7 @@ power_domains: {NVCC_GPIO: '3.3'}
* END ****************************************************************************************************************/
void BOARD_InitBootPins(void) {
BOARD_InitPins();
+ BOARD_InitDEBUG_UARTPins();
}
/*
@@ -40,8 +41,6 @@ BOARD_InitPins:
- options: {callFromInitBoot: 'true', coreID: core0, enableClock: 'true'}
- pin_list:
- {pin_num: '1', peripheral: GPIO2, signal: 'gpio_io, 09', pin_signal: GPIO_EMC_09, direction: INPUT, pull_keeper_select: Pull, pull_up_down_config: Pull_Up_47K_Ohm}
- - {pin_num: '68', peripheral: LPUART1, signal: RX, pin_signal: GPIO_AD_B0_07, pull_up_down_config: Pull_Down_100K_Ohm}
- - {pin_num: '72', peripheral: LPUART1, signal: TX, pin_signal: GPIO_AD_B0_06}
- {pin_num: '21', peripheral: GPIO3, signal: 'gpio_io, 21', pin_signal: GPIO_SD_B1_01, direction: OUTPUT}
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
*/
@@ -73,15 +72,11 @@ void BOARD_InitPins(void) {
/* Initialize GPIO functionality on GPIO_SD_B1_01 (pin 21) */
GPIO_PinInit(GPIO3, 21U, &USER_LED_config);
- IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_06_LPUART1_TX, 0U);
- IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_07_LPUART1_RX, 0U);
IOMUXC_SetPinMux(IOMUXC_GPIO_EMC_09_GPIO2_IO09, 0U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_01_GPIO3_IO21, 0U);
- IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_07_LPUART1_RX, 0x10B0U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_EMC_09_GPIO2_IO09, 0x70B0U);
}
-
/*
* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
BOARD_InitQSPIPins:
@@ -113,6 +108,30 @@ void BOARD_InitQSPIPins(void) {
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_11_FLEXSPI_A_SS0_B, 0U);
}
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+BOARD_InitDEBUG_UARTPins:
+- options: {callFromInitBoot: 'true', coreID: core0, enableClock: 'true'}
+- pin_list:
+ - {pin_num: '68', peripheral: LPUART1, signal: RX, pin_signal: GPIO_AD_B0_07, slew_rate: Slow}
+ - {pin_num: '72', peripheral: LPUART1, signal: TX, pin_signal: GPIO_AD_B0_06, slew_rate: Slow}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitDEBUG_UARTPins
+ * Description : Configures pin routing and optionally pin electrical features.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitDEBUG_UARTPins(void) {
+ CLOCK_EnableClock(kCLOCK_Iomuxc);
+
+ IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_06_LPUART1_TX, 0U);
+ IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_07_LPUART1_RX, 0U);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_06_LPUART1_TX, 0x10B0U);
+ IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_07_LPUART1_RX, 0x10B0U);
+}
/***********************************************************************************************************************
* EOF
**********************************************************************************************************************/
diff --git a/hw/bsp/imxrt/boards/mimxrt1015_evk/board/pin_mux.h b/hw/bsp/imxrt/boards/mimxrt1015_evk/board/pin_mux.h
index c9cbe3b72..2f3bf2c4c 100644
--- a/hw/bsp/imxrt/boards/mimxrt1015_evk/board/pin_mux.h
+++ b/hw/bsp/imxrt/boards/mimxrt1015_evk/board/pin_mux.h
@@ -37,7 +37,7 @@ extern "C" {
*/
void BOARD_InitBootPins(void);
-/* GPIO_EMC_09 (number 1), USER_BUTTON */
+/* GPIO_EMC_09 (number 1), USER_BUTTON/SW4 */
/* Routed pin properties */
#define BOARD_INITPINS_USER_BUTTON_PERIPHERAL GPIO2 /*!< Peripheral name */
#define BOARD_INITPINS_USER_BUTTON_SIGNAL gpio_io /*!< Signal name */
@@ -51,16 +51,6 @@ void BOARD_InitBootPins(void);
#define BOARD_INITPINS_USER_BUTTON_PIN 9U /*!< PORT pin number */
#define BOARD_INITPINS_USER_BUTTON_PIN_MASK (1U << 9U) /*!< PORT pin mask */
-/* GPIO_AD_B0_07 (number 68), LPUART1_RXD */
-/* Routed pin properties */
-#define BOARD_INITPINS_UART1_RXD_PERIPHERAL LPUART1 /*!< Peripheral name */
-#define BOARD_INITPINS_UART1_RXD_SIGNAL RX /*!< Signal name */
-
-/* GPIO_AD_B0_06 (number 72), LPUART1_TXD */
-/* Routed pin properties */
-#define BOARD_INITPINS_UART1_TXD_PERIPHERAL LPUART1 /*!< Peripheral name */
-#define BOARD_INITPINS_UART1_TXD_SIGNAL TX /*!< Signal name */
-
/* GPIO_SD_B1_01 (number 21), GPIO SD_B1_01 */
/* Routed pin properties */
#define BOARD_INITPINS_USER_LED_PERIPHERAL GPIO3 /*!< Peripheral name */
@@ -69,6 +59,7 @@ void BOARD_InitBootPins(void);
/* Symbols to be used with GPIO driver */
#define BOARD_INITPINS_USER_LED_GPIO GPIO3 /*!< GPIO peripheral base pointer */
+#define BOARD_INITPINS_USER_LED_INIT_GPIO_VALUE 0U /*!< GPIO output initial state */
#define BOARD_INITPINS_USER_LED_GPIO_PIN 21U /*!< GPIO pin number */
#define BOARD_INITPINS_USER_LED_GPIO_PIN_MASK (1U << 21U) /*!< GPIO pin mask */
#define BOARD_INITPINS_USER_LED_PORT GPIO3 /*!< PORT peripheral base pointer */
@@ -119,6 +110,23 @@ void BOARD_InitPins(void);
*/
void BOARD_InitQSPIPins(void);
+/* GPIO_AD_B0_07 (number 68), LPUART1_RXD */
+/* Routed pin properties */
+#define BOARD_INITDEBUG_UARTPINS_UART1_RXD_PERIPHERAL LPUART1 /*!< Peripheral name */
+#define BOARD_INITDEBUG_UARTPINS_UART1_RXD_SIGNAL RX /*!< Signal name */
+
+/* GPIO_AD_B0_06 (number 72), LPUART1_TXD */
+/* Routed pin properties */
+#define BOARD_INITDEBUG_UARTPINS_UART1_TXD_PERIPHERAL LPUART1 /*!< Peripheral name */
+#define BOARD_INITDEBUG_UARTPINS_UART1_TXD_SIGNAL TX /*!< Signal name */
+
+
+/*!
+ * @brief Configures pin routing and optionally pin electrical features.
+ *
+ */
+void BOARD_InitDEBUG_UARTPins(void);
+
#if defined(__cplusplus)
}
#endif
diff --git a/hw/bsp/imxrt/boards/mimxrt1015_evk/mimxrt1015_evk.mex b/hw/bsp/imxrt/boards/mimxrt1015_evk/mimxrt1015_evk.mex
index 88265d32e..917bed375 100644
--- a/hw/bsp/imxrt/boards/mimxrt1015_evk/mimxrt1015_evk.mex
+++ b/hw/bsp/imxrt/boards/mimxrt1015_evk/mimxrt1015_evk.mex
@@ -1,5 +1,5 @@
-
+
MIMXRT1015xxxxx
MIMXRT1015DAF5A
@@ -13,19 +13,18 @@
true
- false
false
true
false
-
+
- 13.0.2
+ 24.12.10
@@ -45,12 +44,7 @@
true
-
-
- true
-
-
-
+
true
@@ -79,12 +73,6 @@
-
-
-
-
-
-
@@ -100,7 +88,7 @@
true
-
+
true
@@ -125,15 +113,52 @@
+
+ Configures pin routing and optionally pin electrical features.
+
+ true
+ core0
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
- 13.0.2
+ 24.12.10
diff --git a/hw/bsp/imxrt/boards/mimxrt1064_evk/board/clock_config.c b/hw/bsp/imxrt/boards/mimxrt1064_evk/board/clock_config.c
index 778ab02f2..be684faee 100644
--- a/hw/bsp/imxrt/boards/mimxrt1064_evk/board/clock_config.c
+++ b/hw/bsp/imxrt/boards/mimxrt1064_evk/board/clock_config.c
@@ -15,11 +15,11 @@
/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
!!GlobalInfo
-product: Clocks v11.0
+product: Clocks v15.0
processor: MIMXRT1064xxxxA
package_id: MIMXRT1064DVL6A
mcu_data: ksdk2_0
-processor_version: 13.0.2
+processor_version: 24.12.10
board: MIMXRT1064-EVK
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
diff --git a/hw/bsp/imxrt/boards/mimxrt1064_evk/board/clock_config.h b/hw/bsp/imxrt/boards/mimxrt1064_evk/board/clock_config.h
index 7ce24b6f4..2fa713c0d 100644
--- a/hw/bsp/imxrt/boards/mimxrt1064_evk/board/clock_config.h
+++ b/hw/bsp/imxrt/boards/mimxrt1064_evk/board/clock_config.h
@@ -36,56 +36,56 @@ void BOARD_InitBootClocks(void);
#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */
/* Clock outputs (values are in Hz): */
-#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL
-#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL
-#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL
-#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL
-#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL
-#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL
-#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL
-#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL
-#define BOARD_BOOTCLOCKRUN_ENET2_125M_CLK 1200000UL
-#define BOARD_BOOTCLOCKRUN_ENET2_REF_CLK 0UL
-#define BOARD_BOOTCLOCKRUN_ENET2_TX_CLK 0UL
-#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL
-#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL
-#define BOARD_BOOTCLOCKRUN_ENET_REF_CLK 0UL
-#define BOARD_BOOTCLOCKRUN_ENET_TX_CLK 0UL
-#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL
-#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL
-#define BOARD_BOOTCLOCKRUN_FLEXSPI2_CLK_ROOT 130909090UL
-#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 130909090UL
-#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL
-#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL
-#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL
-#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 67500000UL
-#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL
-#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL
-#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL
-#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL
-#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL
-#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 480000000UL
-#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL
-#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL
-#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL
-#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL
-#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL
-#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL
-#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL
-#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL
-#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL
-#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 132000000UL
-#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL
-#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 480000000UL
-#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 480000000UL
-#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL
-#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL
+#define BOARD_BOOTCLOCKRUN_AHB_CLK_ROOT 600000000UL /* Clock consumers of AHB_CLK_ROOT output : AIPSTZ1, AIPSTZ2, AIPSTZ3, AIPSTZ4, ARM, FLEXIO3, FLEXSPI, FLEXSPI2, GPIO6, GPIO7, GPIO8, GPIO9 */
+#define BOARD_BOOTCLOCKRUN_CAN_CLK_ROOT 40000000UL /* Clock consumers of CAN_CLK_ROOT output : CAN1, CAN2, CAN3 */
+#define BOARD_BOOTCLOCKRUN_CKIL_SYNC_CLK_ROOT 32768UL /* Clock consumers of CKIL_SYNC_CLK_ROOT output : CSU, EWM, GPT1, GPT2, KPP, PIT, RTWDOG, SNVS, SPDIF, TEMPMON, TSC, USB1, USB2, WDOG1, WDOG2 */
+#define BOARD_BOOTCLOCKRUN_CLKO1_CLK 0UL /* Clock consumers of CLKO1_CLK output : N/A */
+#define BOARD_BOOTCLOCKRUN_CLKO2_CLK 0UL /* Clock consumers of CLKO2_CLK output : N/A */
+#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL /* Clock consumers of CLK_1M output : EWM, RTWDOG */
+#define BOARD_BOOTCLOCKRUN_CLK_24M 24000000UL /* Clock consumers of CLK_24M output : GPT1, GPT2 */
+#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 12000000UL /* Clock consumers of CSI_CLK_ROOT output : CSI */
+#define BOARD_BOOTCLOCKRUN_ENET2_125M_CLK 1200000UL /* Clock consumers of ENET2_125M_CLK output : N/A */
+#define BOARD_BOOTCLOCKRUN_ENET2_REF_CLK 0UL /* Clock consumers of ENET2_REF_CLK output : ENET2 */
+#define BOARD_BOOTCLOCKRUN_ENET2_TX_CLK 0UL /* Clock consumers of ENET2_TX_CLK output : ENET2 */
+#define BOARD_BOOTCLOCKRUN_ENET_125M_CLK 2400000UL /* Clock consumers of ENET_125M_CLK output : N/A */
+#define BOARD_BOOTCLOCKRUN_ENET_25M_REF_CLK 1200000UL /* Clock consumers of ENET_25M_REF_CLK output : ENET, ENET2 */
+#define BOARD_BOOTCLOCKRUN_ENET_REF_CLK 0UL /* Clock consumers of ENET_REF_CLK output : ENET */
+#define BOARD_BOOTCLOCKRUN_ENET_TX_CLK 0UL /* Clock consumers of ENET_TX_CLK output : ENET */
+#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 30000000UL /* Clock consumers of FLEXIO1_CLK_ROOT output : FLEXIO1 */
+#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 30000000UL /* Clock consumers of FLEXIO2_CLK_ROOT output : FLEXIO2, FLEXIO3 */
+#define BOARD_BOOTCLOCKRUN_FLEXSPI2_CLK_ROOT 130909090UL /* Clock consumers of FLEXSPI2_CLK_ROOT output : FLEXSPI2 */
+#define BOARD_BOOTCLOCKRUN_FLEXSPI_CLK_ROOT 130909090UL /* Clock consumers of FLEXSPI_CLK_ROOT output : FLEXSPI */
+#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 75000000UL /* Clock consumers of GPT1_ipg_clk_highfreq output : GPT1 */
+#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 75000000UL /* Clock consumers of GPT2_ipg_clk_highfreq output : GPT2 */
+#define BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT 150000000UL /* Clock consumers of IPG_CLK_ROOT output : ADC1, ADC2, ADC_ETC, AOI1, AOI2, ARM, BEE, CAN1, CAN2, CAN3, CCM, CMP1, CMP2, CMP3, CMP4, CSI, CSU, DCDC, DCP, DMA0, DMAMUX, ENC1, ENC2, ENC3, ENC4, ENET, ENET2, EWM, FLEXIO1, FLEXIO2, FLEXIO3, FLEXRAM, FLEXSPI, FLEXSPI2, GPC, GPIO1, GPIO10, GPIO2, GPIO3, GPIO4, GPIO5, IOMUXC, KPP, LCDIF, LPI2C1, LPI2C2, LPI2C3, LPI2C4, LPSPI1, LPSPI2, LPSPI3, LPSPI4, LPUART1, LPUART2, LPUART3, LPUART4, LPUART5, LPUART6, LPUART7, LPUART8, NVIC, OCOTP, PMU, PWM1, PWM2, PWM3, PWM4, PXP, ROMC, RTWDOG, SAI1, SAI2, SAI3, SNVS, SPDIF, SRC, TEMPMON, TMR1, TMR2, TMR3, TMR4, TRNG, TSC, USB1, USB2, USDHC1, USDHC2, WDOG1, WDOG2, XBARA1, XBARB2, XBARB3 */
+#define BOARD_BOOTCLOCKRUN_LCDIF_CLK_ROOT 67500000UL /* Clock consumers of LCDIF_CLK_ROOT output : LCDIF */
+#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL /* Clock consumers of LPI2C_CLK_ROOT output : LPI2C1, LPI2C2, LPI2C3, LPI2C4 */
+#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 105600000UL /* Clock consumers of LPSPI_CLK_ROOT output : LPSPI1, LPSPI2, LPSPI3, LPSPI4 */
+#define BOARD_BOOTCLOCKRUN_LVDS1_CLK 1200000000UL /* Clock consumers of LVDS1_CLK output : N/A */
+#define BOARD_BOOTCLOCKRUN_MQS_MCLK 63529411UL /* Clock consumers of MQS_MCLK output : N/A */
+#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 75000000UL /* Clock consumers of PERCLK_CLK_ROOT output : GPT1, GPT2, PIT */
+#define BOARD_BOOTCLOCKRUN_PLL7_MAIN_CLK 480000000UL /* Clock consumers of PLL7_MAIN_CLK output : N/A */
+#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 63529411UL /* Clock consumers of SAI1_CLK_ROOT output : N/A */
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 63529411UL /* Clock consumers of SAI1_MCLK1 output : SAI1 */
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 63529411UL /* Clock consumers of SAI1_MCLK2 output : SAI1 */
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 30000000UL /* Clock consumers of SAI1_MCLK3 output : SAI1 */
+#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 63529411UL /* Clock consumers of SAI2_CLK_ROOT output : N/A */
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 63529411UL /* Clock consumers of SAI2_MCLK1 output : SAI2 */
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL /* Clock consumers of SAI2_MCLK2 output : SAI2 */
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 30000000UL /* Clock consumers of SAI2_MCLK3 output : SAI2 */
+#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 63529411UL /* Clock consumers of SAI3_CLK_ROOT output : N/A */
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 63529411UL /* Clock consumers of SAI3_MCLK1 output : SAI3 */
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL /* Clock consumers of SAI3_MCLK2 output : SAI3 */
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 30000000UL /* Clock consumers of SAI3_MCLK3 output : SAI3 */
+#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 75000000UL /* Clock consumers of SEMC_CLK_ROOT output : SEMC */
+#define BOARD_BOOTCLOCKRUN_SPDIF0_CLK_ROOT 30000000UL /* Clock consumers of SPDIF0_CLK_ROOT output : SPDIF */
+#define BOARD_BOOTCLOCKRUN_SPDIF0_EXTCLK_OUT 0UL /* Clock consumers of SPDIF0_EXTCLK_OUT output : SPDIF */
+#define BOARD_BOOTCLOCKRUN_TRACE_CLK_ROOT 132000000UL /* Clock consumers of TRACE_CLK_ROOT output : ARM */
+#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 80000000UL /* Clock consumers of UART_CLK_ROOT output : LPUART1, LPUART2, LPUART3, LPUART4, LPUART5, LPUART6, LPUART7, LPUART8 */
+#define BOARD_BOOTCLOCKRUN_USBPHY1_CLK 480000000UL /* Clock consumers of USBPHY1_CLK output : TEMPMON, USB1 */
+#define BOARD_BOOTCLOCKRUN_USBPHY2_CLK 480000000UL /* Clock consumers of USBPHY2_CLK output : USB2 */
+#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 198000000UL /* Clock consumers of USDHC1_CLK_ROOT output : USDHC1 */
+#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 198000000UL /* Clock consumers of USDHC2_CLK_ROOT output : USDHC2 */
/*! @brief Arm PLL set for BOARD_BootClockRUN configuration.
*/
diff --git a/hw/bsp/imxrt/boards/mimxrt1064_evk/board/pin_mux.c b/hw/bsp/imxrt/boards/mimxrt1064_evk/board/pin_mux.c
index 8e975dc72..60c4bab37 100644
--- a/hw/bsp/imxrt/boards/mimxrt1064_evk/board/pin_mux.c
+++ b/hw/bsp/imxrt/boards/mimxrt1064_evk/board/pin_mux.c
@@ -6,11 +6,11 @@
/*
* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
!!GlobalInfo
-product: Pins v13.1
+product: Pins v17.0
processor: MIMXRT1064xxxxA
package_id: MIMXRT1064DVL6A
mcu_data: ksdk2_0
-processor_version: 13.0.2
+processor_version: 24.12.10
board: MIMXRT1064-EVK
pin_labels:
- {pin_num: F14, pin_signal: GPIO_AD_B0_09, label: 'JTAG_TDI/J21[5]/ENET_RST/J22[5]', identifier: USER_LED}
@@ -81,7 +81,6 @@ void BOARD_InitPins(void) {
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_09_GPIO1_IO09, 0x50A0U);
}
-
/*
* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
BOARD_InitDEBUG_UARTPins:
@@ -109,7 +108,6 @@ void BOARD_InitDEBUG_UARTPins(void) {
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_13_LPUART1_RX, 0x10B0U);
}
-
/*
* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
BOARD_InitSDRAMPins:
@@ -209,7 +207,6 @@ void BOARD_InitSDRAMPins(void) {
IOMUXC_SetPinMux(IOMUXC_GPIO_EMC_39_SEMC_DQS, 0U);
}
-
/*
* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
BOARD_InitCSIPins:
@@ -267,7 +264,6 @@ void BOARD_InitCSIPins(void) {
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 0xD8B0U);
}
-
/*
* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
BOARD_InitLCDPins:
@@ -360,7 +356,6 @@ void BOARD_InitLCDPins(void) {
IOMUXC_SetPinConfig(IOMUXC_GPIO_B1_15_GPIO2_IO31, 0x10B0U);
}
-
/*
* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
BOARD_InitCANPins:
@@ -384,7 +379,6 @@ void BOARD_InitCANPins(void) {
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_15_FLEXCAN2_RX, 0U);
}
-
/*
* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
BOARD_InitENETPins:
@@ -424,7 +418,6 @@ void BOARD_InitENETPins(void) {
IOMUXC_SetPinMux(IOMUXC_GPIO_EMC_41_ENET_MDIO, 0U);
}
-
/*
* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
BOARD_InitUSDHCPins:
@@ -458,7 +451,6 @@ void BOARD_InitUSDHCPins(void) {
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B0_05_USDHC1_DATA3, 0U);
}
-
/*
* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
BOARD_InitQSPIPins:
@@ -491,7 +483,6 @@ void BOARD_InitQSPIPins(void) {
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_10_FLEXSPIA_DATA02, 0U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_11_FLEXSPIA_DATA03, 0U);
}
-
/***********************************************************************************************************************
* EOF
**********************************************************************************************************************/
diff --git a/hw/bsp/imxrt/boards/mimxrt1064_evk/board/pin_mux.h b/hw/bsp/imxrt/boards/mimxrt1064_evk/board/pin_mux.h
index bf494b6f6..be1461f16 100644
--- a/hw/bsp/imxrt/boards/mimxrt1064_evk/board/pin_mux.h
+++ b/hw/bsp/imxrt/boards/mimxrt1064_evk/board/pin_mux.h
@@ -47,6 +47,7 @@ void BOARD_InitBootPins(void);
/* Symbols to be used with GPIO driver */
#define BOARD_INITPINS_USER_LED_GPIO GPIO1 /*!< GPIO peripheral base pointer */
+#define BOARD_INITPINS_USER_LED_INIT_GPIO_VALUE 0U /*!< GPIO output initial state */
#define BOARD_INITPINS_USER_LED_GPIO_PIN 9U /*!< GPIO pin number */
#define BOARD_INITPINS_USER_LED_GPIO_PIN_MASK (1U << 9U) /*!< GPIO pin mask */
#define BOARD_INITPINS_USER_LED_PORT GPIO1 /*!< PORT peripheral base pointer */
diff --git a/hw/bsp/imxrt/boards/mimxrt1064_evk/mimxrt1064_evk.mex b/hw/bsp/imxrt/boards/mimxrt1064_evk/mimxrt1064_evk.mex
index 3f0948101..58247fa5b 100644
--- a/hw/bsp/imxrt/boards/mimxrt1064_evk/mimxrt1064_evk.mex
+++ b/hw/bsp/imxrt/boards/mimxrt1064_evk/mimxrt1064_evk.mex
@@ -1,5 +1,5 @@
-
+
MIMXRT1064xxxxA
MIMXRT1064DVL6A
@@ -13,19 +13,18 @@
true
- false
false
true
false
-
+
- 13.0.2
+ 24.12.10
@@ -41,7 +40,7 @@
true
-
+
true
@@ -84,7 +83,7 @@
true
-
+
true
@@ -137,7 +136,7 @@
true
-
+
true
@@ -204,12 +203,12 @@
true
-
+
true
-
+
true
@@ -277,7 +276,7 @@
true
-
+
true
@@ -450,7 +449,7 @@
true
-
+
true
@@ -479,7 +478,7 @@
true
-
+
true
@@ -516,7 +515,7 @@
true
-
+
true
@@ -550,7 +549,7 @@
true
-
+
true
@@ -578,13 +577,13 @@
-
+
- 13.0.2
+ 24.12.10
@@ -751,10 +750,7 @@
-
-
-
-
+
13.0.2
diff --git a/hw/bsp/imxrt/boards/mimxrt1170_evkb/board/clock_config.c b/hw/bsp/imxrt/boards/mimxrt1170_evkb/board/clock_config.c
index 66f1f983a..4f06299de 100644
--- a/hw/bsp/imxrt/boards/mimxrt1170_evkb/board/clock_config.c
+++ b/hw/bsp/imxrt/boards/mimxrt1170_evkb/board/clock_config.c
@@ -11,11 +11,11 @@
/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
!!GlobalInfo
-product: Clocks v14.0
+product: Clocks v15.0
processor: MIMXRT1176xxxxx
package_id: MIMXRT1176DVMAA
mcu_data: ksdk2_0
-processor_version: 16.3.0
+processor_version: 24.12.10
board: MIMXRT1170-EVKB
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
diff --git a/hw/bsp/imxrt/boards/mimxrt1170_evkb/board/pin_mux.c b/hw/bsp/imxrt/boards/mimxrt1170_evkb/board/pin_mux.c
index 2c83fb55e..5e8cb91c1 100644
--- a/hw/bsp/imxrt/boards/mimxrt1170_evkb/board/pin_mux.c
+++ b/hw/bsp/imxrt/boards/mimxrt1170_evkb/board/pin_mux.c
@@ -6,11 +6,11 @@
/*
* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
!!GlobalInfo
-product: Pins v16.0
+product: Pins v17.0
processor: MIMXRT1176xxxxx
package_id: MIMXRT1176DVMAA
mcu_data: ksdk2_0
-processor_version: 16.3.0
+processor_version: 24.12.10
board: MIMXRT1170-EVKB
external_user_signals: {}
pin_labels:
@@ -31,6 +31,7 @@ pin_labels:
* END ****************************************************************************************************************/
void BOARD_InitBootPins(void) {
BOARD_InitPins();
+ BOARD_InitDEBUG_UARTPins();
}
/*
@@ -38,10 +39,6 @@ void BOARD_InitBootPins(void) {
BOARD_InitPins:
- options: {callFromInitBoot: 'true', coreID: cm7, enableClock: 'true'}
- pin_list:
- - {pin_num: M15, peripheral: LPUART1, signal: RXD, pin_signal: GPIO_AD_25, software_input_on: Disable, pull_up_down_config: Pull_Down, pull_keeper_select: Keeper,
- open_drain: Disable, drive_strength: High, slew_rate: Slow}
- - {pin_num: L13, peripheral: LPUART1, signal: TXD, pin_signal: GPIO_AD_24, software_input_on: Disable, pull_up_down_config: Pull_Down, pull_keeper_select: Keeper,
- open_drain: Disable, drive_strength: High, slew_rate: Slow}
- {pin_num: M13, peripheral: GPIO9, signal: 'gpio_io, 03', pin_signal: GPIO_AD_04, identifier: USER_LED, direction: OUTPUT, pull_up_down_config: Pull_Down, pull_keeper_select: Keeper}
- {pin_num: T8, peripheral: GPIO13, signal: 'gpio_io, 00', pin_signal: WAKEUP, direction: INPUT, pull_up_down_config: Pull_Up}
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
@@ -77,12 +74,6 @@ void BOARD_InitPins(void) {
IOMUXC_SetPinMux(
IOMUXC_GPIO_AD_04_GPIO9_IO03, /* GPIO_AD_04 is configured as GPIO9_IO03 */
0U); /* Software Input On Field: Input Path is determined by functionality */
- IOMUXC_SetPinMux(
- IOMUXC_GPIO_AD_24_LPUART1_TXD, /* GPIO_AD_24 is configured as LPUART1_TXD */
- 0U); /* Software Input On Field: Input Path is determined by functionality */
- IOMUXC_SetPinMux(
- IOMUXC_GPIO_AD_25_LPUART1_RXD, /* GPIO_AD_25 is configured as LPUART1_RXD */
- 0U); /* Software Input On Field: Input Path is determined by functionality */
IOMUXC_SetPinMux(
IOMUXC_WAKEUP_DIG_GPIO13_IO00, /* WAKEUP_DIG is configured as GPIO13_IO00 */
0U); /* Software Input On Field: Input Path is determined by functionality */
@@ -95,6 +86,40 @@ void BOARD_InitPins(void) {
Open Drain Field: Disabled
Domain write protection: Both cores are allowed
Domain write protection lock: Neither of DWP bits is locked */
+ IOMUXC_SetPinConfig(
+ IOMUXC_WAKEUP_DIG_GPIO13_IO00, /* WAKEUP_DIG PAD functional properties : */
+ 0x0EU); /* Pull / Keep Select Field: Pull Enable
+ Pull Up / Down Config. Field: Weak pull up
+ Open Drain SNVS Field: Disabled
+ Domain write protection: Both cores are allowed
+ Domain write protection lock: Neither of DWP bits is locked */
+}
+
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+BOARD_InitDEBUG_UARTPins:
+- options: {callFromInitBoot: 'true', coreID: cm7, enableClock: 'true'}
+- pin_list:
+ - {pin_num: L13, peripheral: LPUART1, signal: TXD, pin_signal: GPIO_AD_24, pull_keeper_select: Keeper, slew_rate: Slow}
+ - {pin_num: M15, peripheral: LPUART1, signal: RXD, pin_signal: GPIO_AD_25, pull_keeper_select: Keeper, slew_rate: Slow}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitDEBUG_UARTPins, assigned for the Cortex-M7F core.
+ * Description : Configures pin routing and optionally pin electrical features.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitDEBUG_UARTPins(void) {
+ CLOCK_EnableClock(kCLOCK_Iomuxc); /* LPCG on: LPCG is ON. */
+
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_24_LPUART1_TXD, /* GPIO_AD_24 is configured as LPUART1_TXD */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_25_LPUART1_RXD, /* GPIO_AD_25 is configured as LPUART1_RXD */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
IOMUXC_SetPinConfig(
IOMUXC_GPIO_AD_24_LPUART1_TXD, /* GPIO_AD_24 PAD functional properties : */
0x02U); /* Slew Rate Field: Slow Slew Rate
@@ -113,13 +138,6 @@ void BOARD_InitPins(void) {
Open Drain Field: Disabled
Domain write protection: Both cores are allowed
Domain write protection lock: Neither of DWP bits is locked */
- IOMUXC_SetPinConfig(
- IOMUXC_WAKEUP_DIG_GPIO13_IO00, /* WAKEUP_DIG PAD functional properties : */
- 0x0EU); /* Pull / Keep Select Field: Pull Enable
- Pull Up / Down Config. Field: Weak pull up
- Open Drain SNVS Field: Disabled
- Domain write protection: Both cores are allowed
- Domain write protection lock: Neither of DWP bits is locked */
}
/***********************************************************************************************************************
* EOF
diff --git a/hw/bsp/imxrt/boards/mimxrt1170_evkb/board/pin_mux.h b/hw/bsp/imxrt/boards/mimxrt1170_evkb/board/pin_mux.h
index a5b621476..0e0368ef6 100644
--- a/hw/bsp/imxrt/boards/mimxrt1170_evkb/board/pin_mux.h
+++ b/hw/bsp/imxrt/boards/mimxrt1170_evkb/board/pin_mux.h
@@ -25,16 +25,6 @@ extern "C" {
*/
void BOARD_InitBootPins(void);
-/* GPIO_AD_25 (coord M15), LPUART1_RXD */
-/* Routed pin properties */
-#define BOARD_INITPINS_LPUART1_RXD_PERIPHERAL LPUART1 /*!< Peripheral name */
-#define BOARD_INITPINS_LPUART1_RXD_SIGNAL RXD /*!< Signal name */
-
-/* GPIO_AD_24 (coord L13), LPUART1_TXD */
-/* Routed pin properties */
-#define BOARD_INITPINS_LPUART1_TXD_PERIPHERAL LPUART1 /*!< Peripheral name */
-#define BOARD_INITPINS_LPUART1_TXD_SIGNAL TXD /*!< Signal name */
-
/* GPIO_AD_04 (coord M13), SIM1_PD/J44[C8]/USER_LED_CTL1/J9[8]/J25[7] */
/* Routed pin properties */
#define BOARD_INITPINS_USER_LED_PERIPHERAL GPIO9 /*!< Peripheral name */
@@ -43,6 +33,7 @@ void BOARD_InitBootPins(void);
/* Symbols to be used with GPIO driver */
#define BOARD_INITPINS_USER_LED_GPIO GPIO9 /*!< GPIO peripheral base pointer */
+#define BOARD_INITPINS_USER_LED_INIT_GPIO_VALUE 0U /*!< GPIO output initial state */
#define BOARD_INITPINS_USER_LED_GPIO_PIN 3U /*!< GPIO pin number */
#define BOARD_INITPINS_USER_LED_GPIO_PIN_MASK (1U << 3U) /*!< GPIO pin mask */
@@ -63,6 +54,22 @@ void BOARD_InitBootPins(void);
*/
void BOARD_InitPins(void); /* Function assigned for the Cortex-M7F */
+/* GPIO_AD_24 (coord L13), LPUART1_TXD */
+/* Routed pin properties */
+#define BOARD_INITDEBUG_UARTPINS_LPUART1_TXD_PERIPHERAL LPUART1 /*!< Peripheral name */
+#define BOARD_INITDEBUG_UARTPINS_LPUART1_TXD_SIGNAL TXD /*!< Signal name */
+
+/* GPIO_AD_25 (coord M15), LPUART1_RXD */
+/* Routed pin properties */
+#define BOARD_INITDEBUG_UARTPINS_LPUART1_RXD_PERIPHERAL LPUART1 /*!< Peripheral name */
+#define BOARD_INITDEBUG_UARTPINS_LPUART1_RXD_SIGNAL RXD /*!< Signal name */
+
+/*!
+ * @brief Configures pin routing and optionally pin electrical features.
+ *
+ */
+void BOARD_InitDEBUG_UARTPins(void); /* Function assigned for the Cortex-M7F */
+
#if defined(__cplusplus)
}
#endif
diff --git a/hw/bsp/imxrt/boards/mimxrt1170_evkb/mimxrt1170_evkb.mex b/hw/bsp/imxrt/boards/mimxrt1170_evkb/mimxrt1170_evkb.mex
index a4c8917f7..de6b12394 100644
--- a/hw/bsp/imxrt/boards/mimxrt1170_evkb/mimxrt1170_evkb.mex
+++ b/hw/bsp/imxrt/boards/mimxrt1170_evkb/mimxrt1170_evkb.mex
@@ -1,5 +1,5 @@
-
+
MIMXRT1176xxxxx
MIMXRT1176DVMAA
@@ -13,19 +13,18 @@
true
- false
false
true
false
-
+
- 16.3.0
+ 24.12.10
@@ -43,11 +42,6 @@
true
-
-
- true
-
-
true
@@ -65,26 +59,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -101,15 +75,54 @@
+
+ Configures pin routing and optionally pin electrical features.
+
+ true
+ cm7
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
- 16.3.0
+ 24.12.10
diff --git a/hw/bsp/imxrt/family.c b/hw/bsp/imxrt/family.c
index ad529a227..7e4734a66 100644
--- a/hw/bsp/imxrt/family.c
+++ b/hw/bsp/imxrt/family.c
@@ -61,7 +61,7 @@
- Define CFG_TUSB_MEM_SECTION=__attribute__((section("NonCacheable")))
*/
-static void BOARD_ConfigMPU(void);
+// static void BOARD_ConfigMPU(void);
// needed by fsl_flexspi_nor_boot
TU_ATTR_USED const uint8_t dcd_data[] = {0x00};
@@ -109,8 +109,8 @@ static void init_usb_phy(uint8_t usb_id) {
}
void board_init(void) {
- BOARD_ConfigMPU();
- BOARD_InitPins();
+ // BOARD_ConfigMPU();
+ BOARD_InitBootPins();
BOARD_BootClockRUN();
SystemCoreClockUpdate();
@@ -258,6 +258,7 @@ void _exit(int __status) {
//--------------------------------------------------------------------
// MPU configuration
//--------------------------------------------------------------------
+#if 0 // TODO move to per board specific
#if __CORTEX_M == 7
static void BOARD_ConfigMPU(void) {
#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
@@ -455,7 +456,7 @@ static void BOARD_ConfigMPU(void) {
#elif __CORTEX_M == 4
-void BOARD_ConfigMPU(void) {
+static void BOARD_ConfigMPU(void) {
#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
extern uint32_t Image$$RW_m_ncache$$Base[];
/* RW_m_ncache_unused is a auxiliary region which is used to get the whole size of noncache section */
@@ -636,3 +637,4 @@ void BOARD_ConfigMPU(void) {
LMEM->PCCCR |= LMEM_PCCCR_ENCACHE_MASK;
}
#endif
+#endif
diff --git a/hw/bsp/imxrt/family.cmake b/hw/bsp/imxrt/family.cmake
index f08ccb3e5..6224b63a4 100644
--- a/hw/bsp/imxrt/family.cmake
+++ b/hw/bsp/imxrt/family.cmake
@@ -123,8 +123,6 @@ function(family_configure_example TARGET RTOS)
# Board target
add_board_target(board_${BOARD})
- #---------- Port Specific ----------
- # These files are built for each example since it depends on example's tusb_config.h
target_sources(${TARGET} PUBLIC
# BSP
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
@@ -146,8 +144,6 @@ function(family_configure_example TARGET RTOS)
)
target_link_libraries(${TARGET} PUBLIC board_${BOARD})
-
-
# Flashing
family_add_bin_hex(${TARGET})
family_flash_jlink(${TARGET})
diff --git a/hw/bsp/imxrt/family.mk b/hw/bsp/imxrt/family.mk
index 0cf84a4ae..9a2c37121 100644
--- a/hw/bsp/imxrt/family.mk
+++ b/hw/bsp/imxrt/family.mk
@@ -1,6 +1,5 @@
UF2_FAMILY_ID = 0x4fb2d5bd
SDK_DIR = hw/mcu/nxp/mcux-sdk
-DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5
include $(TOP)/$(BOARD_PATH)/board.mk
diff --git a/hw/bsp/kinetis_k/family.mk b/hw/bsp/kinetis_k/family.mk
index 844ce332e..e95cdb717 100644
--- a/hw/bsp/kinetis_k/family.mk
+++ b/hw/bsp/kinetis_k/family.mk
@@ -1,5 +1,4 @@
SDK_DIR = hw/mcu/nxp/mcux-sdk
-DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5
MCU_DIR = $(SDK_DIR)/devices/${MCU_VARIANT}
include $(TOP)/$(BOARD_PATH)/board.mk
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/kinetis_kl/family.mk b/hw/bsp/kinetis_kl/family.mk
index 1fdce981a..8d113aecf 100644
--- a/hw/bsp/kinetis_kl/family.mk
+++ b/hw/bsp/kinetis_kl/family.mk
@@ -1,5 +1,4 @@
SDK_DIR = hw/mcu/nxp/mcux-sdk
-DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5
MCU_DIR = $(SDK_DIR)/devices/$(MCU)
include $(TOP)/$(BOARD_PATH)/board.mk
diff --git a/hw/bsp/lpc13/boards/lpcxpresso1347/board.mk b/hw/bsp/lpc13/boards/lpcxpresso1347/board.mk
index 31eb2f28f..8513c24ca 100644
--- a/hw/bsp/lpc13/boards/lpcxpresso1347/board.mk
+++ b/hw/bsp/lpc13/boards/lpcxpresso1347/board.mk
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
-
CFLAGS += \
-DCFG_TUSB_MEM_SECTION='__attribute__((section(".data.$$RAM2")))'
diff --git a/hw/bsp/lpc13/family.mk b/hw/bsp/lpc13/family.mk
index 4f8b48c4b..7ff2c058a 100644
--- a/hw/bsp/lpc13/family.mk
+++ b/hw/bsp/lpc13/family.mk
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
-
MCU_DIR = hw/mcu/nxp/lpcopen/lpc13xx/lpc_chip_13xx
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m3
diff --git a/hw/bsp/lpc15/family.mk b/hw/bsp/lpc15/family.mk
index b83e008e8..3267e973a 100644
--- a/hw/bsp/lpc15/family.mk
+++ b/hw/bsp/lpc15/family.mk
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
-
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m3
@@ -15,7 +13,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..e8d707ea5 100644
--- a/hw/bsp/lpc17/family.mk
+++ b/hw/bsp/lpc17/family.mk
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
-
MCU_DIR = hw/mcu/nxp/lpcopen/lpc175x_6x/lpc_chip_175x_6x
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m3
@@ -13,7 +11,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..3bbafed11 100644
--- a/hw/bsp/lpc18/family.mk
+++ b/hw/bsp/lpc18/family.mk
@@ -1,4 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
MCU_DIR = hw/mcu/nxp/lpcopen/lpc18xx/lpc_chip_18xx
include $(TOP)/$(BOARD_PATH)/board.mk
@@ -12,7 +11,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..c72631235 100644
--- a/hw/bsp/lpc40/family.mk
+++ b/hw/bsp/lpc40/family.mk
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
-
MCU_DIR = hw/mcu/nxp/lpcopen/lpc40xx/lpc_chip_40xx
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m4
@@ -13,7 +11,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..39be867d1 100644
--- a/hw/bsp/lpc43/family.mk
+++ b/hw/bsp/lpc43/family.mk
@@ -1,18 +1,17 @@
-DEPS_SUBMODULES += hw/mcu/nxp/lpcopen
SDK_DIR = hw/mcu/nxp/lpcopen/lpc43xx/lpc_chip_43xx
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/lpc51/family.cmake b/hw/bsp/lpc51/family.cmake
index 2146c29f7..09d97d256 100644
--- a/hw/bsp/lpc51/family.cmake
+++ b/hw/bsp/lpc51/family.cmake
@@ -36,7 +36,7 @@ function(add_board_target BOARD_TARGET)
# driver
${SDK_DIR}/drivers/lpc_gpio/fsl_gpio.c
${SDK_DIR}/drivers/flexcomm/fsl_flexcomm.c
- ${SDK_DIR}/drivers/flexcomm/fsl_usart.c
+ ${SDK_DIR}/drivers/flexcomm/usart/fsl_usart.c
# mcu
${SDK_DIR}/devices/${MCU_VARIANT}/system_${MCU_VARIANT}.c
${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_clock.c
diff --git a/hw/bsp/lpc51/family.mk b/hw/bsp/lpc51/family.mk
index b41b5438e..91d1261cb 100644
--- a/hw/bsp/lpc51/family.mk
+++ b/hw/bsp/lpc51/family.mk
@@ -28,15 +28,16 @@ SRC_C += \
$(MCU_DIR)/drivers/fsl_reset.c \
$(SDK_DIR)/drivers/lpc_gpio/fsl_gpio.c \
$(SDK_DIR)/drivers/flexcomm/fsl_flexcomm.c \
- $(SDK_DIR)/drivers/flexcomm/fsl_usart.c
+ $(SDK_DIR)/drivers/flexcomm/usart/fsl_usart.c
INC += \
- $(TOP)/$(BOARD_PATH) \
- $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
+ $(TOP)/$(BOARD_PATH) \
+ $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
$(TOP)/$(MCU_DIR) \
$(TOP)/$(MCU_DIR)/drivers \
$(TOP)/$(SDK_DIR)/drivers/common \
$(TOP)/$(SDK_DIR)/drivers/flexcomm \
+ $(TOP)/$(SDK_DIR)/drivers/flexcomm/usart \
$(TOP)/$(SDK_DIR)/drivers/lpc_iocon \
$(TOP)/$(SDK_DIR)/drivers/lpc_gpio
diff --git a/hw/bsp/lpc54/family.cmake b/hw/bsp/lpc54/family.cmake
index 90497b9fb..66320870a 100644
--- a/hw/bsp/lpc54/family.cmake
+++ b/hw/bsp/lpc54/family.cmake
@@ -44,7 +44,7 @@ function(add_board_target BOARD_TARGET)
${SDK_DIR}/drivers/lpc_gpio/fsl_gpio.c
${SDK_DIR}/drivers/common/fsl_common_arm.c
${SDK_DIR}/drivers/flexcomm/fsl_flexcomm.c
- ${SDK_DIR}/drivers/flexcomm/fsl_usart.c
+ ${SDK_DIR}/drivers/flexcomm/usart/fsl_usart.c
# mcu
${SDK_DIR}/devices/${MCU_VARIANT}/system_${MCU_CORE}.c
${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_clock.c
@@ -56,6 +56,7 @@ function(add_board_target BOARD_TARGET)
# driver
${SDK_DIR}/drivers/common
${SDK_DIR}/drivers/flexcomm
+ ${SDK_DIR}/drivers/flexcomm/usart
${SDK_DIR}/drivers/lpc_iocon
${SDK_DIR}/drivers/lpc_gpio
${SDK_DIR}/drivers/lpuart
diff --git a/hw/bsp/lpc54/family.mk b/hw/bsp/lpc54/family.mk
index ea4c9c39c..94168f6b2 100644
--- a/hw/bsp/lpc54/family.mk
+++ b/hw/bsp/lpc54/family.mk
@@ -1,5 +1,4 @@
SDK_DIR = hw/mcu/nxp/mcux-sdk
-DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m4
@@ -36,7 +35,7 @@ SRC_C += \
$(MCU_DIR)/drivers/fsl_reset.c \
$(SDK_DIR)/drivers/lpc_gpio/fsl_gpio.c \
$(SDK_DIR)/drivers/flexcomm/fsl_flexcomm.c \
- $(SDK_DIR)/drivers/flexcomm/fsl_usart.c \
+ $(SDK_DIR)/drivers/flexcomm/usart/fsl_usart.c \
$(SDK_DIR)/drivers/common/fsl_common_arm.c
INC += \
@@ -46,6 +45,7 @@ INC += \
$(TOP)/$(MCU_DIR)/drivers \
$(TOP)/$(SDK_DIR)/drivers/common \
$(TOP)/$(SDK_DIR)/drivers/flexcomm \
+ $(TOP)/$(SDK_DIR)/drivers/flexcomm/usart \
$(TOP)/$(SDK_DIR)/drivers/lpc_iocon \
$(TOP)/$(SDK_DIR)/drivers/lpc_gpio
diff --git a/hw/bsp/lpc55/family.cmake b/hw/bsp/lpc55/family.cmake
index cd1eb5f78..a89548635 100644
--- a/hw/bsp/lpc55/family.cmake
+++ b/hw/bsp/lpc55/family.cmake
@@ -44,7 +44,7 @@ function(add_board_target BOARD_TARGET)
${SDK_DIR}/drivers/lpc_gpio/fsl_gpio.c
${SDK_DIR}/drivers/common/fsl_common_arm.c
${SDK_DIR}/drivers/flexcomm/fsl_flexcomm.c
- ${SDK_DIR}/drivers/flexcomm/fsl_usart.c
+ ${SDK_DIR}/drivers/flexcomm/usart/fsl_usart.c
# mcu
${SDK_DIR}/devices/${MCU_VARIANT}/system_${MCU_CORE}.c
${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_clock.c
@@ -56,9 +56,9 @@ function(add_board_target BOARD_TARGET)
# driver
${SDK_DIR}/drivers/common
${SDK_DIR}/drivers/flexcomm
+ ${SDK_DIR}/drivers/flexcomm/usart
${SDK_DIR}/drivers/lpc_iocon
${SDK_DIR}/drivers/lpc_gpio
- ${SDK_DIR}/drivers/lpuart
${SDK_DIR}/drivers/sctimer
# mcu
${SDK_DIR}/devices/${MCU_VARIANT}
diff --git a/hw/bsp/lpc55/family.mk b/hw/bsp/lpc55/family.mk
index d82e85904..fadf852cd 100644
--- a/hw/bsp/lpc55/family.mk
+++ b/hw/bsp/lpc55/family.mk
@@ -1,6 +1,5 @@
UF2_FAMILY_ID = 0x2abc77ec
SDK_DIR = hw/mcu/nxp/mcux-sdk
-DEPS_SUBMODULES += lib/CMSIS_5 lib/sct_neopixel $(SDK_DIR)
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m33
@@ -45,7 +44,7 @@ SRC_C += \
$(SDK_DIR)/drivers/lpc_gpio/fsl_gpio.c \
$(SDK_DIR)/drivers/common/fsl_common_arm.c \
$(SDK_DIR)/drivers/flexcomm/fsl_flexcomm.c \
- $(SDK_DIR)/drivers/flexcomm/fsl_usart.c \
+ $(SDK_DIR)/drivers/flexcomm/usart/fsl_usart.c \
lib/sct_neopixel/sct_neopixel.c
INC += \
@@ -55,11 +54,10 @@ INC += \
$(TOP)/$(MCU_DIR) \
$(TOP)/$(MCU_DIR)/drivers \
$(TOP)/$(SDK_DIR)/drivers/common \
- $(TOP)/$(SDK_DIR)/drivers/flexcomm \
+ $(TOP)/$(SDK_DIR)/drivers/flexcomm/usart \
+ $(TOP)/$(SDK_DIR)/drivers/flexcomm/ \
$(TOP)/$(SDK_DIR)/drivers/lpc_iocon \
$(TOP)/$(SDK_DIR)/drivers/lpc_gpio \
$(TOP)/$(SDK_DIR)/drivers/sctimer
SRC_S += $(MCU_DIR)/gcc/startup_$(MCU_CORE).S
-
-LIBS += $(TOP)/$(MCU_DIR)/gcc/libpower_hardabi.a
diff --git a/hw/bsp/max32650/README.md b/hw/bsp/max32650/README.md
deleted file mode 100644
index ca66a1ac4..000000000
--- a/hw/bsp/max32650/README.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Analog Devices MAX32650/1/2
-
-This BSP is for working with the Analog Devices
-[MAX32650](https://www.analog.com/en/products/max32650.html),
-[MAX32651](https://www.analog.com/en/products/max32651.html) and
-[MAX32652](https://www.analog.com/en/products/max32652.html)
-microcontrollers. The following boards are supported:
- * [MAX32650EVKIT](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32650-evkit.html)
- * [MAX32650FTHR](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32650fthr.html)
- * [MAX32651EVKIT](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32651-evkit.html) (Secure Bootloader)
-
-This part family leverages the Maxim Microcontrollers SDK (MSDK) for the device
-interfaces and hardware abstraction layers. This source code package is fetched
-as part of the get-deps script.
-
-The microcontrollers utilize the standard GNU ARM toolchain. If this toolchain
-is not already available on your build machine, it can be installed by using the
-bundled MSDK installation. Details on downloading and installing can be found
-in the [User's Guide](https://analogdevicesinc.github.io/msdk//USERGUIDE/).
-
-## Flashing
-
-### MAX32650 and MAX32652
-
-The default flashing behavior in this BSP for the MAX32650 and MAX32652 is to
-utilize JLink. This can be done by running the `flash` or `flash-jlink` rule
-for Makefiles, or the `-jlink` target for CMake.
-
-Both the Evaluation Kit and Feather boards are shipped with a CMSIS-DAP
-compatible debug probe. However, at the time of writing, the necessary flashing
-algorithms for OpenOCD have not yet been incorporated into the OpenOCD master
-branch. To utilize the provided debug probes, please install the bundled MSDK
-package which includes the appropriate OpenOCD modifications. To leverage this
-OpenOCD instance, run the `flash-msdk` Makefile rule, or `-msdk` CMake
-target.
-
-### MAX32651
-
-The MAX32651 features an integrated secure bootloader which requires the
-application image be signed prior to flashing. Both the Makefile and CMake
-scripts account for this signing automatically when building for the
-MAX32651EVKIT.
-
-To flash the signed image, the MSDK's OpenOCD variant must be used. To flash
-the MAX32651EVKIT please install the bundled MSDK, and utilize the `flash-msdk`
-and `-msdk` rule and target.
diff --git a/hw/bsp/max32650/boards/max32650evkit/board.cmake b/hw/bsp/max32650/boards/max32650evkit/board.cmake
deleted file mode 100644
index fffdcc9fb..000000000
--- a/hw/bsp/max32650/boards/max32650evkit/board.cmake
+++ /dev/null
@@ -1,10 +0,0 @@
-# Use the standard, non-secure linker file
-set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/max32650.ld)
-
-function(update_board_extras TARGET)
- #No extra arguments
-endfunction()
-
-function(prepare_image TARGET_IN)
- #No signing required
-endfunction()
diff --git a/hw/bsp/max32650/boards/max32650evkit/board.mk b/hw/bsp/max32650/boards/max32650evkit/board.mk
deleted file mode 100644
index 0bc210e11..000000000
--- a/hw/bsp/max32650/boards/max32650evkit/board.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-# Use the standard, non-secure linker file
-LD_FILE = $(BOARD_PATH)/max32650.ld
diff --git a/hw/bsp/max32650/boards/max32650fthr/board.cmake b/hw/bsp/max32650/boards/max32650fthr/board.cmake
deleted file mode 100644
index fffdcc9fb..000000000
--- a/hw/bsp/max32650/boards/max32650fthr/board.cmake
+++ /dev/null
@@ -1,10 +0,0 @@
-# Use the standard, non-secure linker file
-set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/max32650.ld)
-
-function(update_board_extras TARGET)
- #No extra arguments
-endfunction()
-
-function(prepare_image TARGET_IN)
- #No signing required
-endfunction()
diff --git a/hw/bsp/max32650/boards/max32650fthr/board.mk b/hw/bsp/max32650/boards/max32650fthr/board.mk
deleted file mode 100644
index 0bc210e11..000000000
--- a/hw/bsp/max32650/boards/max32650fthr/board.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-# Use the standard, non-secure linker file
-LD_FILE = $(BOARD_PATH)/max32650.ld
diff --git a/hw/bsp/max32650/boards/max32650fthr/max32650.ld b/hw/bsp/max32650/boards/max32650fthr/max32650.ld
deleted file mode 100644
index 0e56a91ec..000000000
--- a/hw/bsp/max32650/boards/max32650fthr/max32650.ld
+++ /dev/null
@@ -1,119 +0,0 @@
-MEMORY {
- ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x00010000 /* 64kB ROM */
- FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 0x00300000 /* 3MB flash */
- SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00100000 /* 1MB SRAM */
-}
-
-SECTIONS {
- .text :
- {
- _text = .;
- KEEP(*(.isr_vector))
- *(.text*) /* program code */
- *(.rodata*) /* read-only data: "const" */
-
- KEEP(*(.init))
- KEEP(*(.fini))
-
- /* .ctors */
- *crtbegin.o(.ctors)
- *crtbegin?.o(.ctors)
- *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
- *(SORT(.ctors.*))
- *(.ctors)
-
- /* .dtors */
- *crtbegin.o(.dtors)
- *crtbegin?.o(.dtors)
- *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
- *(SORT(.dtors.*))
- *(.dtors)
-
- /* C++ Exception handling */
- KEEP(*(.eh_frame*))
- _etext = .;
- } > FLASH
-
- .ARM.extab :
- {
- *(.ARM.extab* .gnu.linkonce.armextab.*)
- } > FLASH
-
- /* it's used for C++ exception handling */
- /* we need to keep this to avoid overlapping */
- .ARM.exidx :
- {
- __exidx_start = .;
- *(.ARM.exidx* .gnu.linkonce.armexidx.*)
- __exidx_end = .;
- } > FLASH
-
- .data :
- {
- _data = ALIGN(., 4);
- *(vtable)
- *(.data*) /*read-write initialized data: initialized global variable*/
- *(.spix_config*) /* SPIX configuration functions need to be run from SRAM */
- *(.flashprog*) /* Flash program */
-
-
- /* These array sections are used by __libc_init_array to call static C++ constructors */
- . = ALIGN(4);
- /* preinit data */
- PROVIDE_HIDDEN (__preinit_array_start = .);
- KEEP(*(.preinit_array))
- PROVIDE_HIDDEN (__preinit_array_end = .);
-
- . = ALIGN(4);
- /* init data */
- PROVIDE_HIDDEN (__init_array_start = .);
- KEEP(*(SORT(.init_array.*)))
- KEEP(*(.init_array))
- PROVIDE_HIDDEN (__init_array_end = .);
-
- . = ALIGN(4);
- /* finit data */
- PROVIDE_HIDDEN (__fini_array_start = .);
- KEEP(*(SORT(.fini_array.*)))
- KEEP(*(.fini_array))
- PROVIDE_HIDDEN (__fini_array_end = .);
-
- _edata = ALIGN(., 4);
- } > SRAM AT>FLASH
- __load_data = LOADADDR(.data);
- .bss :
- {
- . = ALIGN(4);
- _bss = .;
- *(.bss*) /*read-write zero initialized data: uninitialized global variable*/
- *(COMMON)
- _ebss = ALIGN(., 4);
- } > SRAM
-
- /* Set stack top to end of RAM, and stack limit move down by
- * size of stack_dummy section */
- __StackTop = ORIGIN(SRAM) + LENGTH(SRAM);
- __StackLimit = __StackTop - SIZEOF(.stack_dummy);
-
- /* .stack_dummy section doesn't contains any symbols. It is only
- * used for linker to calculate size of stack sections, and assign
- * values to stack symbols later */
- .stack_dummy (COPY):
- {
- *(.stack*)
- } > SRAM
-
- .heap (COPY):
- {
- . = ALIGN(4);
- PROVIDE ( end = . );
- PROVIDE ( _end = . );
- *(.heap*)
- __HeapLimit = ABSOLUTE(__StackLimit);
- } > SRAM
-
- PROVIDE(__stack = __StackTop);
-
- /* Check if data + heap + stack exceeds RAM limit */
- ASSERT(__StackLimit >= _ebss, "region RAM overflowed with stack")
-}
diff --git a/hw/bsp/max32650/family.c b/hw/bsp/max32650/family.c
deleted file mode 100644
index 8f0e56734..000000000
--- a/hw/bsp/max32650/family.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2024 Brent Kowal (Analog Devices, Inc)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-/* metadata:
- manufacturer: Analog Devices
-*/
-
-#ifdef __GNUC__
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstrict-prototypes" // _mxc_crit_get_state()
-#endif
-
-#include "gpio.h"
-#include "mxc_sys.h"
-#include "mxc_device.h"
-#include "uart.h"
-
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
-
-#include "board.h"
-#include "bsp/board_api.h"
-
-
-//--------------------------------------------------------------------+
-// Forward USB interrupt events to TinyUSB IRQ Handler
-//--------------------------------------------------------------------+
-void USB_IRQHandler(void) {
- tud_int_handler(0);
-}
-
-//--------------------------------------------------------------------+
-// MACRO TYPEDEF CONSTANT ENUM
-//--------------------------------------------------------------------+
-mxc_uart_regs_t *ConsoleUart = MXC_UART_GET_UART(UART_NUM);
-
-void board_init(void) {
-#if CFG_TUSB_OS == OPT_OS_NONE
- // 1ms tick timer
- SysTick_Config(SystemCoreClock / 1000);
-#elif CFG_TUSB_OS == OPT_OS_FREERTOS
- // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
- NVIC_SetPriority(USB_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
-#endif
- mxc_gpio_cfg_t gpioConfig;
-
- // LED
- gpioConfig.drvstr = MXC_GPIO_DRVSTR_0;
- gpioConfig.func = MXC_GPIO_FUNC_OUT;
- gpioConfig.mask = LED_PIN;
- gpioConfig.pad = MXC_GPIO_PAD_NONE;
- gpioConfig.port = LED_PORT;
- gpioConfig.vssel = LED_VDDIO;
- MXC_GPIO_Config(&gpioConfig);
- board_led_write(false);
-
- // Button
- gpioConfig.drvstr = MXC_GPIO_DRVSTR_0;
- gpioConfig.func = MXC_GPIO_FUNC_IN;
- gpioConfig.mask = BUTTON_PIN;
- gpioConfig.pad = BUTTON_PULL;
- gpioConfig.port = BUTTON_PORT;
- gpioConfig.vssel = MXC_GPIO_VSSEL_VDDIO;
- MXC_GPIO_Config(&gpioConfig);
-
- // UART
- MXC_UART_Init(ConsoleUart, CFG_BOARD_UART_BAUDRATE);
-
- //USB
- // Startup the HIRC96M clock if it's not on already
- if (!(MXC_GCR->clk_ctrl & MXC_F_GCR_CLK_CTRL_HIRC96_EN)) {
- MXC_GCR->clk_ctrl |= MXC_F_GCR_CLK_CTRL_HIRC96_EN;
- MXC_SYS_Clock_Timeout(MXC_F_GCR_CLK_CTRL_HIRC96_RDY);
- }
-
- MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_USB);
- MXC_SYS_Reset_Periph(MXC_SYS_RESET_USB);
-}
-
-//--------------------------------------------------------------------+
-// Board porting API
-//--------------------------------------------------------------------+
-
-void board_led_write(bool state) {
-#if LED_STATE_ON
- state = !state;
-#endif
- if (state) {
- MXC_GPIO_OutClr(LED_PORT, LED_PIN);
- } else {
- MXC_GPIO_OutSet(LED_PORT, LED_PIN);
- }
-}
-
-uint32_t board_button_read(void) {
- uint32_t state = MXC_GPIO_InGet(BUTTON_PORT, BUTTON_PIN) ? 1 : 0;
- return BUTTON_STATE_ACTIVE == state;
-}
-
-size_t board_get_unique_id(uint8_t id[], size_t max_len) {
- uint8_t hw_id[13];//USN Buffer
- MXC_SYS_GetUSN(hw_id, 13);
-
- size_t act_len = TU_MIN(max_len, 13);
- memcpy(id, hw_id, act_len);
- return act_len;
-}
-
-int board_uart_read(uint8_t *buf, int len) {
- int uart_val;
- int act_len = 0;
-
- while (act_len < len) {
- if ((uart_val = MXC_UART_ReadCharacterRaw(ConsoleUart)) == E_UNDERFLOW) {
- break;
- } else {
- *buf++ = (uint8_t) uart_val;
- act_len++;
- }
- }
- return act_len;
-}
-
-int board_uart_write(void const *buf, int len) {
- int act_len = 0;
- const uint8_t *ch_ptr = (const uint8_t *) buf;
- while (act_len < len) {
- MXC_UART_WriteCharacter(ConsoleUart, *ch_ptr++);
- act_len++;
- }
- return len;
-}
-
-#if CFG_TUSB_OS == OPT_OS_NONE
-volatile uint32_t system_ticks = 0;
-
-void SysTick_Handler(void) {
- system_ticks++;
-}
-
-uint32_t board_millis(void) {
- return system_ticks;
-}
-#endif
-
-void HardFault_Handler(void) {
- __asm("BKPT #0\n");
-}
-
-// Required by __libc_init_array in startup code if we are compiling using
-// -nostdlib/-nostartfiles.
-void _init(void) {
-}
diff --git a/hw/bsp/max32650/family.cmake b/hw/bsp/max32650/family.cmake
deleted file mode 100644
index b1d5dded7..000000000
--- a/hw/bsp/max32650/family.cmake
+++ /dev/null
@@ -1,169 +0,0 @@
-include_guard()
-
-set(MAX32_PERIPH ${TOP}/hw/mcu/analog/max32/Libraries/PeriphDrivers)
-set(MAX32_CMSIS ${TOP}/hw/mcu/analog/max32/Libraries/CMSIS)
-set(CMSIS_5 ${TOP}/lib/CMSIS_5)
-
-# include board specific information and functions
-include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
-
-# Get the linker file
-set(LD_FILE_Clang ${LD_FILE_GNU})
-
-# toolchain set up
-set(CMAKE_SYSTEM_CPU cortex-m4 CACHE INTERNAL "System Processor")
-set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
-set(JLINK_DEVICE max32650)
-set(OPENOCD_OPTION "-f interface/cmsis-dap.cfg -f target/max32650.cfg")
-
-set(FAMILY_MCUS MAX32650 CACHE INTERNAL "")
-
-function(update_board TARGET)
- target_compile_definitions(${TARGET} PUBLIC
- TARGET=MAX32650
- TARGET_REV=0x4131
- MXC_ASSERT_ENABLE
- MAX32650
- IAR_PRAGMAS=0
- CFG_TUSB_MCU=OPT_MCU_MAX32650
- BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
- )
-
- # Run any board specific updates
- update_board_extras(${TARGET})
-endfunction()
-
-#------------------------------------
-# BOARD_TARGET
-#------------------------------------
-# only need to be built ONCE for all examples
-function(add_board_target BOARD_TARGET)
- if (TARGET ${BOARD_TARGET})
- return()
- endif ()
-
- # Startup & Linker script
- set(STARTUP_FILE_GNU ${MAX32_CMSIS}/Device/Maxim/MAX32650/Source/GCC/startup_max32650.S)
- set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
-
- set(PERIPH_SRC ${MAX32_PERIPH}/Source)
- add_library(${BOARD_TARGET} STATIC
- ${MAX32_CMSIS}/Device/Maxim/MAX32650/Source/heap.c
- ${MAX32_CMSIS}/Device/Maxim/MAX32650/Source/header_MAX32650.c
- ${MAX32_CMSIS}/Device/Maxim/MAX32650/Source/system_max32650.c
- ${PERIPH_SRC}/SYS/mxc_assert.c
- ${PERIPH_SRC}/SYS/mxc_delay.c
- ${PERIPH_SRC}/SYS/mxc_lock.c
- ${PERIPH_SRC}/SYS/nvic_table.c
- ${PERIPH_SRC}/SYS/pins_me10.c
- ${PERIPH_SRC}/SYS/sys_me10.c
- ${PERIPH_SRC}/TPU/tpu_me10.c
- ${PERIPH_SRC}/TPU/tpu_reva.c
- ${PERIPH_SRC}/FLC/flc_common.c
- ${PERIPH_SRC}/FLC/flc_me10.c
- ${PERIPH_SRC}/FLC/flc_reva.c
- ${PERIPH_SRC}/GPIO/gpio_common.c
- ${PERIPH_SRC}/GPIO/gpio_me10.c
- ${PERIPH_SRC}/GPIO/gpio_reva.c
- ${PERIPH_SRC}/ICC/icc_me10.c
- ${PERIPH_SRC}/ICC/icc_reva.c
- ${PERIPH_SRC}/ICC/icc_common.c
- ${PERIPH_SRC}/UART/uart_common.c
- ${PERIPH_SRC}/UART/uart_me10.c
- ${PERIPH_SRC}/UART/uart_reva.c
- ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
- )
- target_include_directories(${BOARD_TARGET} PUBLIC
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
- ${MAX32_CMSIS}/Include
- ${MAX32_CMSIS}/Device/Maxim/MAX32650/Include
- ${MAX32_PERIPH}/Include/MAX32650
- ${PERIPH_SRC}/SYS
- ${PERIPH_SRC}/GPIO
- ${PERIPH_SRC}/TPU
- ${PERIPH_SRC}/ICC
- ${PERIPH_SRC}/FLC
- ${PERIPH_SRC}/UART
- )
-
- target_compile_options(${BOARD_TARGET} PRIVATE
- -Wno-error=strict-prototypes
- )
- update_board(${BOARD_TARGET})
-
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
- target_link_options(${BOARD_TARGET} PUBLIC
- "LINKER:--script=${LD_FILE_GNU}"
- -nostartfiles
- --specs=nosys.specs --specs=nano.specs
- -u sb_header #Needed when linking libraries to not lose the Signing header
- )
- elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
- target_link_options(${BOARD_TARGET} PUBLIC
- "LINKER:--script=${LD_FILE_Clang}"
- )
- endif ()
-endfunction()
-
-
-#------------------------------------
-# Functions
-#------------------------------------
-function(family_configure_example TARGET RTOS)
- family_configure_common(${TARGET} ${RTOS})
-
- # Board target
- add_board_target(board_${BOARD})
-
- #---------- Port Specific ----------
- # These files are built for each example since it depends on example's tusb_config.h
- target_sources(${TARGET} PUBLIC
- # BSP
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
- )
- target_include_directories(${TARGET} PUBLIC
- # family, hw, board
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
- )
-
- # Add TinyUSB target and port source
- family_add_tinyusb(${TARGET} OPT_MCU_MAX32650)
- target_sources(${TARGET} PUBLIC
- ${TOP}/src/portable/mentor/musb/dcd_musb.c
- )
- target_compile_options(${TARGET} PRIVATE
- -Wno-error=strict-prototypes
- )
-
- target_link_libraries(${TARGET} PUBLIC board_${BOARD})
- target_compile_options(${TARGET} PRIVATE
- -Wno-error=strict-prototypes
- )
-
-
-
- # Flashing
- family_add_bin_hex(${TARGET})
- family_flash_jlink(${TARGET})
- family_flash_openocd_adi(${TARGET})
-
- # Add the optional MSDK OpenOCD flashing
- family_flash_msdk(${TARGET})
-endfunction()
-
-function(family_flash_msdk TARGET)
- # Prepare the image (signed) if the board requires it
- prepare_image(${TARGET})
-
- set(MAXIM_PATH "$ENV{MAXIM_PATH}")
- add_custom_target(${TARGET}-msdk
- DEPENDS ${TARGET}
- COMMAND ${MAXIM_PATH}/Tools/OpenOCD/openocd -s ${MAXIM_PATH}/Tools/OpenOCD/scripts
- -f interface/cmsis-dap.cfg -f target/max32650.cfg
- -c "program $ verify; init; reset; exit"
- VERBATIM
- )
-endfunction()
diff --git a/hw/bsp/max32650/family.mk b/hw/bsp/max32650/family.mk
deleted file mode 100644
index d2fc293e4..000000000
--- a/hw/bsp/max32650/family.mk
+++ /dev/null
@@ -1,140 +0,0 @@
-DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/analog/max32
-
-# Important locations in the hw support for MCU
-MAX32_CMSIS = hw/mcu/analog/max32/Libraries/CMSIS
-MAX32_PERIPH = hw/mcu/analog/max32/Libraries/PeriphDrivers
-
-# Add any board specific make rules
-include $(TOP)/$(BOARD_PATH)/board.mk
-
-CPU_CORE ?= cortex-m4
-PORT ?= 0
-
-# GCC
-SRC_S_GCC += $(MAX32_CMSIS)/Device/Maxim/MAX32650/Source/GCC/startup_max32650.S
-
-# --------------
-# Compiler Flags
-# --------------
-# Flags for the MAX32650/1/2 SDK
-CFLAGS += -DTARGET=MAX32650 \
- -DTARGET_REV=0x4131 \
- -DMXC_ASSERT_ENABLE \
- -DMAX32650 \
- -DIAR_PRAGMAS=0
-
-# Flags for TUSB features
-CFLAGS += \
- -DCFG_TUSB_MCU=OPT_MCU_MAX32650 \
- -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
-
-# mcu driver cause following warnings
-CFLAGS += -Wno-error=strict-prototypes \
- -Wno-error=unused-parameter \
- -Wno-error=cast-align \
- -Wno-error=cast-qual \
- -Wno-error=sign-compare
-
-LDFLAGS_GCC += -nostartfiles --specs=nosys.specs --specs=nano.specs
-
-# Configure the flash rule. By default, use JLink.
-SIGNED_BUILD ?= 0
-DEFAULT_FLASH = flash-jlink
-
-# If the applications needs to be signed (for the MAX32651), sign it first and
-# then need to use MSDK's OpenOCD to flash it
-# Also need to include the __SLA_FWK__ define to enable the signed header into
-# memory
-ifeq ($(SIGNED_BUILD), 1)
-# Extra definitions to build for the secure part
-CFLAGS += -D__SLA_FWK__
-DEFAULT_FLASH := sign-build flash-msdk
-endif
-
-# For flash-jlink target
-JLINK_DEVICE = max32650
-
-# Configure the flash rule
-flash: $(DEFAULT_FLASH)
-
-# -----------------
-# Sources & Include
-# -----------------
-PERIPH_SRC = $(TOP)/$(MAX32_PERIPH)/Source
-SRC_C += \
- src/portable/mentor/musb/dcd_musb.c \
- $(MAX32_CMSIS)/Device/Maxim/MAX32650/Source/heap.c \
- $(MAX32_CMSIS)/Device/Maxim/MAX32650/Source/system_max32650.c \
- $(MAX32_CMSIS)/Device/Maxim/MAX32650/Source/header_MAX32650.c \
- $(PERIPH_SRC)/SYS/mxc_assert.c \
- $(PERIPH_SRC)/SYS/mxc_delay.c \
- $(PERIPH_SRC)/SYS/mxc_lock.c \
- $(PERIPH_SRC)/SYS/nvic_table.c \
- $(PERIPH_SRC)/SYS/pins_me10.c \
- $(PERIPH_SRC)/SYS/sys_me10.c \
- $(PERIPH_SRC)/FLC/flc_common.c \
- $(PERIPH_SRC)/FLC/flc_me10.c \
- $(PERIPH_SRC)/FLC/flc_reva.c \
- $(PERIPH_SRC)/GPIO/gpio_common.c \
- $(PERIPH_SRC)/GPIO/gpio_me10.c \
- $(PERIPH_SRC)/GPIO/gpio_reva.c \
- $(PERIPH_SRC)/ICC/icc_me10.c \
- $(PERIPH_SRC)/ICC/icc_reva.c \
- $(PERIPH_SRC)/ICC/icc_common.c \
- $(PERIPH_SRC)/TPU/tpu_me10.c \
- $(PERIPH_SRC)/TPU/tpu_reva.c \
- $(PERIPH_SRC)/UART/uart_common.c \
- $(PERIPH_SRC)/UART/uart_me10.c \
- $(PERIPH_SRC)/UART/uart_reva.c \
-
-INC += \
- $(TOP)/$(BOARD_PATH) \
- $(TOP)/$(MAX32_CMSIS)/Include \
- $(TOP)/$(MAX32_CMSIS)/Device/Maxim/MAX32650/Include \
- $(TOP)/$(MAX32_PERIPH)/Include/MAX32650 \
- $(PERIPH_SRC)/SYS \
- $(PERIPH_SRC)/GPIO \
- $(PERIPH_SRC)/ICC \
- $(PERIPH_SRC)/FLC \
- $(PERIPH_SRC)/TPU \
- $(PERIPH_SRC)/UART
-
-
-# The MAX32651EVKIT is pin for pin identical to the MAX32650EVKIT, however the
-# MAX32651 has a secure bootloader which requires the image to be signed before
-# loading into flash. All MAX32651EVKIT's have the same key for evaluation
-# purposes, so create a special flash rule to sign the binary and flash using
-# the MSDK.
-MCU_PATH = $(TOP)/hw/mcu/analog/max32/
-# Assume no extension for sign utility
-SIGN_EXE = sign_app
-ifeq ($(OS), Windows_NT)
-# Must use .exe extension on Windows, since the binaries
-# for Linux may live in the same place.
-SIGN_EXE := sign_app.exe
-else
-UNAME = $(shell uname -s)
-ifneq ($(findstring MSYS_NT,$(UNAME)),)
-# Must also use .exe extension for MSYS2
-SIGN_EXE := sign_app.exe
-endif
-endif
-
-# Rule to sign the build. This will in-place modify the existing .elf file
-# an populate the .sig section with the signature value
-sign-build: $(BUILD)/$(PROJECT).elf
- $(OBJCOPY) $(BUILD)/$(PROJECT).elf -R .sig -O binary $(BUILD)/$(PROJECT).bin
- $(MCU_PATH)/Tools/SBT/bin/$(SIGN_EXE) -c MAX32651 \
- key_file="$(MCU_PATH)/Tools/SBT/devices/MAX32651/keys/maximtestcrk.key" \
- ca=$(BUILD)/$(PROJECT).bin sca=$(BUILD)/$(PROJECT).sbin
- $(OBJCOPY) $(BUILD)/$(PROJECT).elf --update-section .sig=$(BUILD)/$(PROJECT).sig
-
-# Optional flash option when running within an installed MSDK to use OpenOCD
-# Mainline OpenOCD does not yet have the MAX32's flash algorithm integrated.
-# If the MSDK is installed, flash-msdk can be run to utilize the the modified
-# openocd with the algorithms
-MAXIM_PATH := $(subst \,/,$(MAXIM_PATH))
-flash-msdk: $(BUILD)/$(PROJECT).elf
- $(MAXIM_PATH)/Tools/OpenOCD/openocd -s $(MAXIM_PATH)/Tools/OpenOCD/scripts \
- -f interface/cmsis-dap.cfg -f target/max32650.cfg \
- -c "program $(BUILD)/$(PROJECT).elf verify; init; reset; exit"
diff --git a/hw/bsp/max32666/README.md b/hw/bsp/max32666/README.md
deleted file mode 100644
index 902d82e25..000000000
--- a/hw/bsp/max32666/README.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# Analog Devices MAX32665/6
-
-This BSP is for working with the Analog Devices
-[MAX32665](https://www.analog.com/en/products/max32665.html) and
-[MAX32666](https://www.analog.com/en/products/max32666.html) microcontrollers.
-The following boards are supported:
- * [MAX32666EVKIT](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32666evkit.html)
- * [MAX32666FTHR](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32666fthr.html)
-
-
-This part family leverages the Maxim Microcontrollers SDK (MSDK) for the device
-interfaces and hardware abstraction layers. This source code package is fetched
-as part of the get-deps script.
-
-The microcontrollers utilize the standard GNU ARM toolchain. If this toolchain
-is not already available on your build machine, it can be installed by using the
-bundled MSDK installation. Details on downloading and installing can be found
-in the [User's Guide](https://analogdevicesinc.github.io/msdk//USERGUIDE/).
-
-## Flashing
-
-The default flashing behavior in this BSP is to utilize JLink. This can be done
-by running the `flash` or `flash-jlink` rule for Makefiles, or the
-`-jlink` target for CMake.
-
-Both the Evaluation Kit and Feather boards are shipped with a CMSIS-DAP
-compatible debug probe. However, at the time of writing, the necessary flashing
-algorithms for OpenOCD have not yet been incorporated into the OpenOCD master
-branch. To utilize the provided debug probes, please install the bundled MSDK
-package which includes the appropriate OpenOCD modifications. To leverage this
-OpenOCD instance, run the `flash-msdk` Makefile rule, or `-msdk` CMake
-target.
diff --git a/hw/bsp/max32666/boards/max32666evkit/board.cmake b/hw/bsp/max32666/boards/max32666evkit/board.cmake
deleted file mode 100644
index 9dc6962eb..000000000
--- a/hw/bsp/max32666/boards/max32666evkit/board.cmake
+++ /dev/null
@@ -1 +0,0 @@
-# Nothing to be done at the board level
diff --git a/hw/bsp/max32666/boards/max32666evkit/board.mk b/hw/bsp/max32666/boards/max32666evkit/board.mk
deleted file mode 100644
index a813a5327..000000000
--- a/hw/bsp/max32666/boards/max32666evkit/board.mk
+++ /dev/null
@@ -1 +0,0 @@
-# No specific build requirements for the board.
diff --git a/hw/bsp/max32666/boards/max32666fthr/board.cmake b/hw/bsp/max32666/boards/max32666fthr/board.cmake
deleted file mode 100644
index 9dc6962eb..000000000
--- a/hw/bsp/max32666/boards/max32666fthr/board.cmake
+++ /dev/null
@@ -1 +0,0 @@
-# Nothing to be done at the board level
diff --git a/hw/bsp/max32666/boards/max32666fthr/board.mk b/hw/bsp/max32666/boards/max32666fthr/board.mk
deleted file mode 100644
index a813a5327..000000000
--- a/hw/bsp/max32666/boards/max32666fthr/board.mk
+++ /dev/null
@@ -1 +0,0 @@
-# No specific build requirements for the board.
diff --git a/hw/bsp/max32666/family.cmake b/hw/bsp/max32666/family.cmake
deleted file mode 100644
index 49798729a..000000000
--- a/hw/bsp/max32666/family.cmake
+++ /dev/null
@@ -1,147 +0,0 @@
-include_guard()
-
-set(MAX32_PERIPH ${TOP}/hw/mcu/analog/max32/Libraries/PeriphDrivers)
-set(MAX32_CMSIS ${TOP}/hw/mcu/analog/max32/Libraries/CMSIS)
-set(CMSIS_5 ${TOP}/lib/CMSIS_5)
-
-# include board specific
-include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
-
-# Get the linker file from current location (family)
-set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/max32666.ld)
-set(LD_FILE_Clang ${LD_FILE_GNU})
-
-# toolchain set up
-set(CMAKE_SYSTEM_CPU cortex-m4 CACHE INTERNAL "System Processor")
-set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
-set(JLINK_DEVICE max32666)
-set(OPENOCD_OPTION "-f interface/cmsis-dap.cfg -f target/max32665.cfg")
-
-set(FAMILY_MCUS MAX32666 CACHE INTERNAL "")
-
-function(update_board TARGET)
- target_compile_definitions(${TARGET} PUBLIC
- TARGET=MAX32665
- TARGET_REV=0x4131
- MXC_ASSERT_ENABLE
- MAX32665
- IAR_PRAGMAS=0
- CFG_TUSB_MCU=OPT_MCU_MAX32666
- BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
- )
-endfunction()
-
-#------------------------------------
-# BOARD_TARGET
-#------------------------------------
-# only need to be built ONCE for all examples
-function(add_board_target BOARD_TARGET)
- if (TARGET ${BOARD_TARGET})
- return()
- endif ()
-
- # Startup & Linker script
- set(STARTUP_FILE_GNU ${MAX32_CMSIS}/Device/Maxim/MAX32665/Source/GCC/startup_max32665.S)
- set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
-
- set(PERIPH_SRC ${MAX32_PERIPH}/Source)
- add_library(${BOARD_TARGET} STATIC
- ${MAX32_CMSIS}/Device/Maxim/MAX32665/Source/heap.c
- ${MAX32_CMSIS}/Device/Maxim/MAX32665/Source/system_max32665.c
- ${PERIPH_SRC}/SYS/mxc_assert.c
- ${PERIPH_SRC}/SYS/mxc_delay.c
- ${PERIPH_SRC}/SYS/mxc_lock.c
- ${PERIPH_SRC}/SYS/nvic_table.c
- ${PERIPH_SRC}/SYS/pins_me14.c
- ${PERIPH_SRC}/SYS/sys_me14.c
- ${PERIPH_SRC}/TPU/tpu_me14.c
- ${PERIPH_SRC}/TPU/tpu_reva.c
- ${PERIPH_SRC}/FLC/flc_common.c
- ${PERIPH_SRC}/FLC/flc_me14.c
- ${PERIPH_SRC}/FLC/flc_reva.c
- ${PERIPH_SRC}/GPIO/gpio_common.c
- ${PERIPH_SRC}/GPIO/gpio_me14.c
- ${PERIPH_SRC}/GPIO/gpio_reva.c
- ${PERIPH_SRC}/ICC/icc_me14.c
- ${PERIPH_SRC}/ICC/icc_reva.c
- ${PERIPH_SRC}/UART/uart_common.c
- ${PERIPH_SRC}/UART/uart_me14.c
- ${PERIPH_SRC}/UART/uart_reva.c
- ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
- )
- target_include_directories(${BOARD_TARGET} PUBLIC
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
- ${MAX32_CMSIS}/Include
- ${MAX32_CMSIS}/Device/Maxim/MAX32665/Include
- ${MAX32_PERIPH}/Include/MAX32665
- ${PERIPH_SRC}/SYS
- ${PERIPH_SRC}/GPIO
- ${PERIPH_SRC}/TPU
- ${PERIPH_SRC}/ICC
- ${PERIPH_SRC}/FLC
- ${PERIPH_SRC}/UART
- )
-
- target_compile_options(${BOARD_TARGET} PRIVATE
- -Wno-error=strict-prototypes
- )
- update_board(${BOARD_TARGET})
-
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
- target_link_options(${BOARD_TARGET} PUBLIC
- "LINKER:--script=${LD_FILE_GNU}"
- -nostartfiles
- --specs=nosys.specs --specs=nano.specs
- )
- elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
- target_link_options(${BOARD_TARGET} PUBLIC
- "LINKER:--script=${LD_FILE_Clang}"
- )
- endif ()
-endfunction()
-
-
-#------------------------------------
-# Functions
-#------------------------------------
-function(family_configure_example TARGET RTOS)
- family_configure_common(${TARGET} ${RTOS})
-
- # Board target
- add_board_target(board_${BOARD})
-
- #---------- Port Specific ----------
- # These files are built for each example since it depends on example's tusb_config.h
- target_sources(${TARGET} PUBLIC
- # BSP
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
- )
- target_include_directories(${TARGET} PUBLIC
- # family, hw, board
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
- )
-
- # Add TinyUSB target and port source
- family_add_tinyusb(${TARGET} OPT_MCU_MAX32666)
- target_sources(${TARGET} PUBLIC
- ${TOP}/src/portable/mentor/musb/dcd_musb.c
- )
- target_compile_options(${TARGET} PRIVATE
- -Wno-error=strict-prototypes
- )
-
- target_link_libraries(${TARGET} PUBLIC board_${BOARD})
- target_compile_options(${TARGET} PRIVATE
- -Wno-error=strict-prototypes
- )
-
-
-
- # Flashing
- family_add_bin_hex(${TARGET})
- family_flash_jlink(${TARGET})
- family_flash_openocd_adi(${TARGET})
-endfunction()
diff --git a/hw/bsp/max32666/family.mk b/hw/bsp/max32666/family.mk
deleted file mode 100644
index b4f7d1e57..000000000
--- a/hw/bsp/max32666/family.mk
+++ /dev/null
@@ -1,93 +0,0 @@
-DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/analog/max32
-
-# Important locations in the hw support for MCU
-MAX32_CMSIS = hw/mcu/analog/max32/Libraries/CMSIS
-MAX32_PERIPH = hw/mcu/analog/max32/Libraries/PeriphDrivers
-
-# Add any board specific make rules
-include $(TOP)/$(BOARD_PATH)/board.mk
-
-CPU_CORE ?= cortex-m4
-PORT ?= 0
-
-# GCC
-SRC_S_GCC += $(MAX32_CMSIS)/Device/Maxim/MAX32665/Source/GCC/startup_max32665.S
-LD_FILE = $(FAMILY_PATH)/max32666.ld
-
-# --------------
-# Compiler Flags
-# --------------
-# Flags for the MAX32665/6 SDK
-CFLAGS += -DTARGET=MAX32665 \
- -DTARGET_REV=0x4131 \
- -DMXC_ASSERT_ENABLE \
- -DMAX32665 \
- -DIAR_PRAGMAS=0
-
-# Flags for TUSB features
-CFLAGS += \
- -DCFG_TUSB_MCU=OPT_MCU_MAX32666 \
- -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
-
-# mcu driver cause following warnings
-CFLAGS += -Wno-error=strict-prototypes \
- -Wno-error=unused-parameter \
- -Wno-error=cast-align \
- -Wno-error=cast-qual
-LDFLAGS_GCC += -nostartfiles --specs=nosys.specs --specs=nano.specs
-
-# For flash-jlink target
-JLINK_DEVICE = max32666
-
-# flash target using Jlink by default
-flash: flash-jlink
-
-# Optional flash option when running within an installed MSDK to use OpenOCD
-# Mainline OpenOCD does not yet have the MAX32's flash algorithm integrated.
-# If the MSDK is installed, flash-msdk can be run to utilize the the modified
-# openocd with the algorithms
-MAXIM_PATH := $(subst \,/,$(MAXIM_PATH))
-flash-msdk: $(BUILD)/$(PROJECT).elf
- $(MAXIM_PATH)/Tools/OpenOCD/openocd -s $(MAXIM_PATH)/Tools/OpenOCD/scripts \
- -f interface/cmsis-dap.cfg -f target/max32665.cfg \
- -c "program $(BUILD)/$(PROJECT).elf verify; init; reset; exit"
-
-# -----------------
-# Sources & Include
-# -----------------
-PERIPH_SRC = $(TOP)/$(MAX32_PERIPH)/Source
-SRC_C += \
- src/portable/mentor/musb/dcd_musb.c \
- $(MAX32_CMSIS)/Device/Maxim/MAX32665/Source/heap.c \
- $(MAX32_CMSIS)/Device/Maxim/MAX32665/Source/system_max32665.c \
- $(PERIPH_SRC)/SYS/mxc_assert.c \
- $(PERIPH_SRC)/SYS/mxc_delay.c \
- $(PERIPH_SRC)/SYS/mxc_lock.c \
- $(PERIPH_SRC)/SYS/nvic_table.c \
- $(PERIPH_SRC)/SYS/pins_me14.c \
- $(PERIPH_SRC)/SYS/sys_me14.c \
- $(PERIPH_SRC)/FLC/flc_common.c \
- $(PERIPH_SRC)/FLC/flc_me14.c \
- $(PERIPH_SRC)/FLC/flc_reva.c \
- $(PERIPH_SRC)/GPIO/gpio_common.c \
- $(PERIPH_SRC)/GPIO/gpio_me14.c \
- $(PERIPH_SRC)/GPIO/gpio_reva.c \
- $(PERIPH_SRC)/ICC/icc_me14.c \
- $(PERIPH_SRC)/ICC/icc_reva.c \
- $(PERIPH_SRC)/TPU/tpu_me14.c \
- $(PERIPH_SRC)/TPU/tpu_reva.c \
- $(PERIPH_SRC)/UART/uart_common.c \
- $(PERIPH_SRC)/UART/uart_me14.c \
- $(PERIPH_SRC)/UART/uart_reva.c \
-
-INC += \
- $(TOP)/$(BOARD_PATH) \
- $(TOP)/$(MAX32_CMSIS)/Include \
- $(TOP)/$(MAX32_CMSIS)/Device/Maxim/MAX32665/Include \
- $(TOP)/$(MAX32_PERIPH)/Include/MAX32665 \
- $(PERIPH_SRC)/SYS \
- $(PERIPH_SRC)/GPIO \
- $(PERIPH_SRC)/ICC \
- $(PERIPH_SRC)/FLC \
- $(PERIPH_SRC)/TPU \
- $(PERIPH_SRC)/UART
diff --git a/hw/bsp/max32690/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/max32690/FreeRTOSConfig/FreeRTOSConfig.h
deleted file mode 100644
index e5a76af85..000000000
--- a/hw/bsp/max32690/FreeRTOSConfig/FreeRTOSConfig.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * FreeRTOS Kernel V10.0.0
- * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software. If you wish to use our Amazon
- * FreeRTOS name, please do so in a fair use way that does not cause confusion.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * http://www.FreeRTOS.org
- * http://aws.amazon.com/freertos
- *
- * 1 tab == 4 spaces!
- */
-
-
-#ifndef FREERTOS_CONFIG_H
-#define FREERTOS_CONFIG_H
-
-/*-----------------------------------------------------------
- * Application specific definitions.
- *
- * These definitions should be adjusted for your particular hardware and
- * application requirements.
- *
- * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
- * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
- *
- * See http://www.freertos.org/a00110.html.
- *----------------------------------------------------------*/
-
-// skip if included from IAR assembler
-#ifndef __IASMARM__
- #include "mxc_device.h"
-#endif
-
-/* Cortex M23/M33 port configuration. */
-#define configENABLE_MPU 0
-#define configENABLE_FPU 1
-#define configENABLE_TRUSTZONE 0
-#define configMINIMAL_SECURE_STACK_SIZE (1024)
-
-#define configUSE_PREEMPTION 1
-#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
-#define configCPU_CLOCK_HZ SystemCoreClock
-#define configTICK_RATE_HZ ( 1000 )
-#define configMAX_PRIORITIES ( 5 )
-#define configMINIMAL_STACK_SIZE ( 128 )
-#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 )
-#define configMAX_TASK_NAME_LEN 16
-#define configUSE_16_BIT_TICKS 0
-#define configIDLE_SHOULD_YIELD 1
-#define configUSE_MUTEXES 1
-#define configUSE_RECURSIVE_MUTEXES 1
-#define configUSE_COUNTING_SEMAPHORES 1
-#define configQUEUE_REGISTRY_SIZE 4
-#define configUSE_QUEUE_SETS 0
-#define configUSE_TIME_SLICING 0
-#define configUSE_NEWLIB_REENTRANT 0
-#define configENABLE_BACKWARD_COMPATIBILITY 1
-#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
-
-#define configSUPPORT_STATIC_ALLOCATION 1
-#define configSUPPORT_DYNAMIC_ALLOCATION 0
-
-/* Hook function related definitions. */
-#define configUSE_IDLE_HOOK 0
-#define configUSE_TICK_HOOK 0
-#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning
-#define configCHECK_FOR_STACK_OVERFLOW 2
-#define configCHECK_HANDLER_INSTALLATION 0
-
-/* Run time and task stats gathering related definitions. */
-#define configGENERATE_RUN_TIME_STATS 0
-#define configRECORD_STACK_HIGH_ADDRESS 1
-#define configUSE_TRACE_FACILITY 1 // legacy trace
-#define configUSE_STATS_FORMATTING_FUNCTIONS 0
-
-/* Co-routine definitions. */
-#define configUSE_CO_ROUTINES 0
-#define configMAX_CO_ROUTINE_PRIORITIES 2
-
-/* Software timer related definitions. */
-#define configUSE_TIMERS 1
-#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2)
-#define configTIMER_QUEUE_LENGTH 32
-#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
-
-/* Optional functions - most linkers will remove unused functions anyway. */
-#define INCLUDE_vTaskPrioritySet 0
-#define INCLUDE_uxTaskPriorityGet 0
-#define INCLUDE_vTaskDelete 0
-#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY
-#define INCLUDE_xResumeFromISR 0
-#define INCLUDE_vTaskDelayUntil 1
-#define INCLUDE_vTaskDelay 1
-#define INCLUDE_xTaskGetSchedulerState 0
-#define INCLUDE_xTaskGetCurrentTaskHandle 1
-#define INCLUDE_uxTaskGetStackHighWaterMark 0
-#define INCLUDE_xTaskGetIdleTaskHandle 0
-#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
-#define INCLUDE_pcTaskGetTaskName 0
-#define INCLUDE_eTaskGetState 0
-#define INCLUDE_xEventGroupSetBitFromISR 0
-#define INCLUDE_xTimerPendFunctionCall 0
-
-/* FreeRTOS hooks to NVIC vectors */
-#define xPortPendSVHandler PendSV_Handler
-#define xPortSysTickHandler SysTick_Handler
-#define vPortSVCHandler SVC_Handler
-
-//--------------------------------------------------------------------+
-// Interrupt nesting behavior configuration.
-//--------------------------------------------------------------------+
-
-// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header
-#define configPRIO_BITS __NVIC_PRIO_BITS
-
-/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
-#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<-jlink` target for CMake.
-
-Both the Evaluation Kit and APARD boards are shipped with a CMSIS-DAP
-compatible debug probe. However, at the time of writing, the necessary flashing
-algorithms for OpenOCD have not yet been incorporated into the OpenOCD master
-branch. To utilize the provided debug probes, please install the bundled MSDK
-package which includes the appropriate OpenOCD modifications. To leverage this
-OpenOCD instance, run the `flash-msdk` Makefile rule, or `-msdk` CMake
-target.
diff --git a/hw/bsp/max32690/boards/apard32690/board.cmake b/hw/bsp/max32690/boards/apard32690/board.cmake
deleted file mode 100644
index 9dc6962eb..000000000
--- a/hw/bsp/max32690/boards/apard32690/board.cmake
+++ /dev/null
@@ -1 +0,0 @@
-# Nothing to be done at the board level
diff --git a/hw/bsp/max32690/boards/apard32690/board.mk b/hw/bsp/max32690/boards/apard32690/board.mk
deleted file mode 100644
index a813a5327..000000000
--- a/hw/bsp/max32690/boards/apard32690/board.mk
+++ /dev/null
@@ -1 +0,0 @@
-# No specific build requirements for the board.
diff --git a/hw/bsp/max32690/boards/max32690evkit/board.cmake b/hw/bsp/max32690/boards/max32690evkit/board.cmake
deleted file mode 100644
index 9dc6962eb..000000000
--- a/hw/bsp/max32690/boards/max32690evkit/board.cmake
+++ /dev/null
@@ -1 +0,0 @@
-# Nothing to be done at the board level
diff --git a/hw/bsp/max32690/boards/max32690evkit/board.mk b/hw/bsp/max32690/boards/max32690evkit/board.mk
deleted file mode 100644
index a813a5327..000000000
--- a/hw/bsp/max32690/boards/max32690evkit/board.mk
+++ /dev/null
@@ -1 +0,0 @@
-# No specific build requirements for the board.
diff --git a/hw/bsp/max32690/family.c b/hw/bsp/max32690/family.c
deleted file mode 100644
index 7ba5fbef3..000000000
--- a/hw/bsp/max32690/family.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2024 Brent Kowal (Analog Devices, Inc)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-/* metadata:
- manufacturer: Analog Devices
-*/
-
-#ifdef __GNUC__
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstrict-prototypes" // _mxc_crit_get_state()
-#endif
-
-#include "gpio.h"
-#include "mxc_sys.h"
-#include "mcr_regs.h"
-#include "mxc_device.h"
-#include "uart.h"
-
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
-
-#include "board.h"
-#include "bsp/board_api.h"
-
-
-//--------------------------------------------------------------------+
-// Forward USB interrupt events to TinyUSB IRQ Handler
-//--------------------------------------------------------------------+
-void USB_IRQHandler(void) {
- tud_int_handler(0);
-}
-
-//--------------------------------------------------------------------+
-// MACRO TYPEDEF CONSTANT ENUM
-//--------------------------------------------------------------------+
-mxc_uart_regs_t *ConsoleUart = MXC_UART_GET_UART(UART_NUM);
-
-void board_init(void) {
-#if CFG_TUSB_OS == OPT_OS_NONE
- // 1ms tick timer
- SysTick_Config(SystemCoreClock / 1000);
-#elif CFG_TUSB_OS == OPT_OS_FREERTOS
- // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
- NVIC_SetPriority(USB_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
-#endif
- mxc_gpio_cfg_t gpioConfig;
-
- // LED
- gpioConfig.drvstr = MXC_GPIO_DRVSTR_0;
- gpioConfig.func = MXC_GPIO_FUNC_OUT;
- gpioConfig.mask = LED_PIN;
- gpioConfig.pad = MXC_GPIO_PAD_NONE;
- gpioConfig.port = LED_PORT;
- gpioConfig.vssel = LED_VDDIO;
- MXC_GPIO_Config(&gpioConfig);
- board_led_write(false);
-
- // Button
- gpioConfig.drvstr = MXC_GPIO_DRVSTR_0;
- gpioConfig.func = MXC_GPIO_FUNC_IN;
- gpioConfig.mask = BUTTON_PIN;
- gpioConfig.pad = BUTTON_PULL;
- gpioConfig.port = BUTTON_PORT;
- gpioConfig.vssel = MXC_GPIO_VSSEL_VDDIO;
- MXC_GPIO_Config(&gpioConfig);
-
- // UART
- MXC_UART_Init(ConsoleUart, CFG_BOARD_UART_BAUDRATE, MXC_UART_IBRO_CLK);
-
- //USB
- MXC_SYS_ClockSourceEnable(MXC_SYS_CLOCK_IPO);
- MXC_MCR->ldoctrl |= MXC_F_MCR_LDOCTRL_0P9EN;
- MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_USB);
- MXC_SYS_Reset_Periph(MXC_SYS_RESET0_USB);
-}
-
-//--------------------------------------------------------------------+
-// Board porting API
-//--------------------------------------------------------------------+
-
-void board_led_write(bool state) {
-#if LED_STATE_ON
- state = !state;
-#endif
- if (state) {
- MXC_GPIO_OutClr(LED_PORT, LED_PIN);
- } else {
- MXC_GPIO_OutSet(LED_PORT, LED_PIN);
- }
-}
-
-uint32_t board_button_read(void) {
- uint32_t state = MXC_GPIO_InGet(BUTTON_PORT, BUTTON_PIN) ? 1 : 0;
- return BUTTON_STATE_ACTIVE == state;
-}
-
-size_t board_get_unique_id(uint8_t id[], size_t max_len) {
- uint8_t hw_id[MXC_SYS_USN_CHECKSUM_LEN];//USN Buffer
- /* All other 2nd parameter is optional checksum buffer */
- MXC_SYS_GetUSN(hw_id, NULL);
-
- size_t act_len = TU_MIN(max_len, MXC_SYS_USN_LEN);
- memcpy(id, hw_id, act_len);
- return act_len;
-}
-
-int board_uart_read(uint8_t *buf, int len) {
- int uart_val;
- int act_len = 0;
-
- while (act_len < len) {
- if ((uart_val = MXC_UART_ReadCharacterRaw(ConsoleUart)) == E_UNDERFLOW) {
- break;
- } else {
- *buf++ = (uint8_t) uart_val;
- act_len++;
- }
- }
- return act_len;
-}
-
-int board_uart_write(void const *buf, int len) {
- int act_len = 0;
- const uint8_t *ch_ptr = (const uint8_t *) buf;
- while (act_len < len) {
- MXC_UART_WriteCharacter(ConsoleUart, *ch_ptr++);
- act_len++;
- }
- return len;
-}
-
-#if CFG_TUSB_OS == OPT_OS_NONE
-volatile uint32_t system_ticks = 0;
-
-void SysTick_Handler(void) {
- system_ticks++;
-}
-
-uint32_t board_millis(void) {
- return system_ticks;
-}
-#endif
-
-void HardFault_Handler(void) {
- __asm("BKPT #0\n");
-}
-
-// Required by __libc_init_array in startup code if we are compiling using
-// -nostdlib/-nostartfiles.
-void _init(void) {
-}
diff --git a/hw/bsp/max32690/family.cmake b/hw/bsp/max32690/family.cmake
deleted file mode 100644
index 0d544d9e6..000000000
--- a/hw/bsp/max32690/family.cmake
+++ /dev/null
@@ -1,152 +0,0 @@
-include_guard()
-
-set(MAX32_PERIPH ${TOP}/hw/mcu/analog/max32/Libraries/PeriphDrivers)
-set(MAX32_CMSIS ${TOP}/hw/mcu/analog/max32/Libraries/CMSIS)
-set(CMSIS_5 ${TOP}/lib/CMSIS_5)
-
-# include board specific
-include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
-
-# Get the linker file from current location (family)
-set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/max32690.ld)
-set(LD_FILE_Clang ${LD_FILE_GNU})
-
-# toolchain set up
-set(CMAKE_SYSTEM_CPU cortex-m4 CACHE INTERNAL "System Processor")
-set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
-set(JLINK_DEVICE max32690)
-set(OPENOCD_OPTION "-f interface/cmsis-dap.cfg -f target/max32690.cfg")
-
-set(FAMILY_MCUS MAX32690 CACHE INTERNAL "")
-
-function(update_board TARGET)
- target_compile_definitions(${TARGET} PUBLIC
- TARGET=MAX32690
- TARGET_REV=0x4131
- MXC_ASSERT_ENABLE
- MAX32690
- FLASH_ORIGIN=0x10000000
- FLASH_SIZE=0x340000
- SRAM_ORIGIN=0x20000000
- SRAM_SIZE=0x100000
- IAR_PRAGMAS=0
- CFG_TUSB_MCU=OPT_MCU_MAX32690
- BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
- )
-endfunction()
-
-#------------------------------------
-# BOARD_TARGET
-#------------------------------------
-# only need to be built ONCE for all examples
-function(add_board_target BOARD_TARGET)
- if (TARGET ${BOARD_TARGET})
- return()
- endif ()
-
- # Startup & Linker script
- set(STARTUP_FILE_GNU ${MAX32_CMSIS}/Device/Maxim/MAX32690/Source/GCC/startup_max32690.S)
- set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
-
- set(PERIPH_SRC ${MAX32_PERIPH}/Source)
- add_library(${BOARD_TARGET} STATIC
- ${MAX32_CMSIS}/Device/Maxim/MAX32690/Source/heap.c
- ${MAX32_CMSIS}/Device/Maxim/MAX32690/Source/system_max32690.c
- ${PERIPH_SRC}/SYS/mxc_assert.c
- ${PERIPH_SRC}/SYS/mxc_delay.c
- ${PERIPH_SRC}/SYS/mxc_lock.c
- ${PERIPH_SRC}/SYS/nvic_table.c
- ${PERIPH_SRC}/SYS/pins_me18.c
- ${PERIPH_SRC}/SYS/sys_me18.c
- ${PERIPH_SRC}/CTB/ctb_me18.c
- ${PERIPH_SRC}/CTB/ctb_reva.c
- ${PERIPH_SRC}/CTB/ctb_common.c
- ${PERIPH_SRC}/FLC/flc_common.c
- ${PERIPH_SRC}/FLC/flc_me18.c
- ${PERIPH_SRC}/FLC/flc_reva.c
- ${PERIPH_SRC}/GPIO/gpio_common.c
- ${PERIPH_SRC}/GPIO/gpio_me18.c
- ${PERIPH_SRC}/GPIO/gpio_reva.c
- ${PERIPH_SRC}/ICC/icc_me18.c
- ${PERIPH_SRC}/ICC/icc_reva.c
- ${PERIPH_SRC}/UART/uart_common.c
- ${PERIPH_SRC}/UART/uart_me18.c
- ${PERIPH_SRC}/UART/uart_revb.c
- ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
- )
- target_include_directories(${BOARD_TARGET} PUBLIC
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
- ${MAX32_CMSIS}/Include
- ${MAX32_CMSIS}/Device/Maxim/MAX32690/Include
- ${MAX32_PERIPH}/Include/MAX32690
- ${PERIPH_SRC}/SYS
- ${PERIPH_SRC}/GPIO
- ${PERIPH_SRC}/CTB
- ${PERIPH_SRC}/ICC
- ${PERIPH_SRC}/FLC
- ${PERIPH_SRC}/UART
- )
-
- target_compile_options(${BOARD_TARGET} PRIVATE
- -Wno-error=strict-prototypes
- )
- update_board(${BOARD_TARGET})
-
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
- target_link_options(${BOARD_TARGET} PUBLIC
- "LINKER:--script=${LD_FILE_GNU}"
- -nostartfiles
- --specs=nosys.specs --specs=nano.specs
- )
- elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
- target_link_options(${BOARD_TARGET} PUBLIC
- "LINKER:--script=${LD_FILE_Clang}"
- )
- endif ()
-endfunction()
-
-
-#------------------------------------
-# Functions
-#------------------------------------
-function(family_configure_example TARGET RTOS)
- family_configure_common(${TARGET} ${RTOS})
-
- # Board target
- add_board_target(board_${BOARD})
-
- #---------- Port Specific ----------
- # These files are built for each example since it depends on example's tusb_config.h
- target_sources(${TARGET} PUBLIC
- # BSP
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
- )
- target_include_directories(${TARGET} PUBLIC
- # family, hw, board
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
- )
-
- # Add TinyUSB target and port source
- family_add_tinyusb(${TARGET} OPT_MCU_MAX32690)
- target_sources(${TARGET} PUBLIC
- ${TOP}/src/portable/mentor/musb/dcd_musb.c
- )
- target_compile_options(${TARGET} PRIVATE
- -Wno-error=strict-prototypes
- )
-
- target_link_libraries(${TARGET} PUBLIC board_${BOARD})
- target_compile_options(${TARGET} PRIVATE
- -Wno-error=strict-prototypes
- )
-
-
-
- # Flashing
- family_add_bin_hex(${TARGET})
- family_flash_jlink(${TARGET})
- family_flash_openocd_adi(${TARGET})
-endfunction()
diff --git a/hw/bsp/max32690/family.mk b/hw/bsp/max32690/family.mk
deleted file mode 100644
index d4df8ef2f..000000000
--- a/hw/bsp/max32690/family.mk
+++ /dev/null
@@ -1,101 +0,0 @@
-DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/analog/max32
-
-# Important locations in the hw support for MCU
-MAX32_CMSIS = hw/mcu/analog/max32/Libraries/CMSIS
-MAX32_PERIPH = hw/mcu/analog/max32/Libraries/PeriphDrivers
-
-# Add any board specific make rules
-include $(TOP)/$(BOARD_PATH)/board.mk
-
-CPU_CORE ?= cortex-m4
-PORT ?= 0
-
-# GCC
-SRC_S_GCC += $(MAX32_CMSIS)/Device/Maxim/MAX32690/Source/GCC/startup_max32690.S
-LD_FILE = $(FAMILY_PATH)/max32690.ld
-
-# --------------
-# Compiler Flags
-# --------------
-# Flags for the MAX32690 SDK
-CFLAGS += -DTARGET=MAX32690 \
- -DTARGET_REV=0x4131 \
- -DMXC_ASSERT_ENABLE \
- -DMAX32690 \
- -DFLASH_ORIGIN=0x10000000 \
- -DFLASH_SIZE=0x340000 \
- -DSRAM_ORIGIN=0x20000000 \
- -DSRAM_SIZE=0x100000 \
- -DIAR_PRAGMAS=0
-
-# Flags for TUSB features
-CFLAGS += \
- -DCFG_TUSB_MCU=OPT_MCU_MAX32690 \
- -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
-
-# mcu driver cause following warnings
-CFLAGS += -Wno-error=unused-parameter \
- -Wno-error=strict-prototypes \
- -Wno-error=old-style-declaration \
- -Wno-error=sign-compare \
- -Wno-error=cast-qual \
- -Wno-lto-type-mismatch
-
-LDFLAGS_GCC += -nostartfiles --specs=nosys.specs --specs=nano.specs
-
-# For flash-jlink target
-JLINK_DEVICE = max32690
-
-# flash target using Jlink by default
-flash: flash-jlink
-
-# Optional flash option when running within an installed MSDK to use OpenOCD
-# Mainline OpenOCD does not yet have the MAX32's flash algorithm integrated.
-# If the MSDK is installed, flash-msdk can be run to utilize the the modified
-# openocd with the algorithms
-MAXIM_PATH := $(subst \,/,$(MAXIM_PATH))
-flash-msdk: $(BUILD)/$(PROJECT).elf
- $(MAXIM_PATH)/Tools/OpenOCD/openocd -s $(MAXIM_PATH)/Tools/OpenOCD/scripts \
- -f interface/cmsis-dap.cfg -f target/max32690.cfg \
- -c "program $(BUILD)/$(PROJECT).elf verify; init; reset; exit"
-
-# -----------------
-# Sources & Include
-# -----------------
-PERIPH_SRC = $(TOP)/$(MAX32_PERIPH)/Source
-SRC_C += \
- src/portable/mentor/musb/dcd_musb.c \
- $(MAX32_CMSIS)/Device/Maxim/MAX32690/Source/heap.c \
- $(MAX32_CMSIS)/Device/Maxim/MAX32690/Source/system_max32690.c \
- $(PERIPH_SRC)/SYS/mxc_assert.c \
- $(PERIPH_SRC)/SYS/mxc_delay.c \
- $(PERIPH_SRC)/SYS/mxc_lock.c \
- $(PERIPH_SRC)/SYS/nvic_table.c \
- $(PERIPH_SRC)/SYS/pins_me18.c \
- $(PERIPH_SRC)/SYS/sys_me18.c \
- $(PERIPH_SRC)/CTB/ctb_me18.c \
- $(PERIPH_SRC)/CTB/ctb_reva.c \
- $(PERIPH_SRC)/CTB/ctb_common.c \
- $(PERIPH_SRC)/FLC/flc_common.c \
- $(PERIPH_SRC)/FLC/flc_me18.c \
- $(PERIPH_SRC)/FLC/flc_reva.c \
- $(PERIPH_SRC)/GPIO/gpio_common.c \
- $(PERIPH_SRC)/GPIO/gpio_me18.c \
- $(PERIPH_SRC)/GPIO/gpio_reva.c \
- $(PERIPH_SRC)/ICC/icc_me18.c \
- $(PERIPH_SRC)/ICC/icc_reva.c \
- $(PERIPH_SRC)/UART/uart_common.c \
- $(PERIPH_SRC)/UART/uart_me18.c \
- $(PERIPH_SRC)/UART/uart_revb.c \
-
-INC += \
- $(TOP)/$(BOARD_PATH) \
- $(TOP)/$(MAX32_CMSIS)/Include \
- $(TOP)/$(MAX32_CMSIS)/Device/Maxim/MAX32690/Include \
- $(TOP)/$(MAX32_PERIPH)/Include/MAX32690 \
- $(PERIPH_SRC)/SYS \
- $(PERIPH_SRC)/GPIO \
- $(PERIPH_SRC)/CTB \
- $(PERIPH_SRC)/ICC \
- $(PERIPH_SRC)/FLC \
- $(PERIPH_SRC)/UART
diff --git a/hw/bsp/max78002/README.md b/hw/bsp/max78002/README.md
deleted file mode 100644
index 4fb1bede4..000000000
--- a/hw/bsp/max78002/README.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Analog Devices MAX78002
-
-This BSP is for working with the Analog Devices
-[MAX78002](https://www.analog.com/en/products/max78002.html) AI microcontroller.
-The following boards are supported:
- * [MAX78002EVKIT](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max78002evkit.html)
-
-This part family leverages the Maxim Microcontrollers SDK (MSDK) for the device
-interfaces and hardware abstraction layers. This source code package is fetched
-as part of the get-deps script.
-
-The microcontroller utilizes the standard GNU ARM toolchain. If this toolchain
-is not already available on your build machine, it can be installed by using the
-bundled MSDK installation. Details on downloading and installing can be found
-in the [User's Guide](https://analogdevicesinc.github.io/msdk//USERGUIDE/).
-
-## Flashing
-
-The default flashing behavior in this BSP is to utilize JLink. This can be done
-by running the `flash` or `flash-jlink` rule for Makefiles, or the
-`-jlink` target for CMake.
-
-The Evaluation Kit is shipped with a CMSIS-DAP compatible debug probe. However,
-at the time of writing, the necessary flashing algorithms for OpenOCD have not
-yet been incorporated into the OpenOCD master branch. To utilize the provided
-debug probes, please install the bundled MSDK package which includes the
-appropriate OpenOCD modifications. To leverage this OpenOCD instance, run the
-`flash-msdk` Makefile rule, or `-msdk` CMake target.
diff --git a/hw/bsp/max78002/boards/max78002evkit/board.cmake b/hw/bsp/max78002/boards/max78002evkit/board.cmake
deleted file mode 100644
index 9dc6962eb..000000000
--- a/hw/bsp/max78002/boards/max78002evkit/board.cmake
+++ /dev/null
@@ -1 +0,0 @@
-# Nothing to be done at the board level
diff --git a/hw/bsp/max78002/boards/max78002evkit/board.mk b/hw/bsp/max78002/boards/max78002evkit/board.mk
deleted file mode 100644
index a813a5327..000000000
--- a/hw/bsp/max78002/boards/max78002evkit/board.mk
+++ /dev/null
@@ -1 +0,0 @@
-# No specific build requirements for the board.
diff --git a/hw/bsp/max78002/family.c b/hw/bsp/max78002/family.c
deleted file mode 100644
index 5c23f40f9..000000000
--- a/hw/bsp/max78002/family.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2024 Brent Kowal (Analog Devices, Inc)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-/* metadata:
- manufacturer: Analog Devices
-*/
-
-#ifdef __GNUC__
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstrict-prototypes" // _mxc_crit_get_state()
-#endif
-
-#include "gpio.h"
-#include "mxc_sys.h"
-#include "mcr_regs.h"
-#include "mxc_device.h"
-#include "uart.h"
-
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
-
-#include "board.h"
-#include "bsp/board_api.h"
-
-//--------------------------------------------------------------------+
-// Forward USB interrupt events to TinyUSB IRQ Handler
-//--------------------------------------------------------------------+
-void USB_IRQHandler(void) {
- tud_int_handler(0);
-}
-
-//--------------------------------------------------------------------+
-// MACRO TYPEDEF CONSTANT ENUM
-//--------------------------------------------------------------------+
-mxc_uart_regs_t *ConsoleUart = MXC_UART_GET_UART(UART_NUM);
-
-void board_init(void) {
-#if CFG_TUSB_OS == OPT_OS_NONE
- // 1ms tick timer
- SysTick_Config(SystemCoreClock / 1000);
-#elif CFG_TUSB_OS == OPT_OS_FREERTOS
- // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
- NVIC_SetPriority(USB_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
-#endif
- mxc_gpio_cfg_t gpioConfig;
-
- // LED
- gpioConfig.drvstr = MXC_GPIO_DRVSTR_0;
- gpioConfig.func = MXC_GPIO_FUNC_OUT;
- gpioConfig.mask = LED_PIN;
- gpioConfig.pad = MXC_GPIO_PAD_NONE;
- gpioConfig.port = LED_PORT;
- gpioConfig.vssel = LED_VDDIO;
- MXC_GPIO_Config(&gpioConfig);
- board_led_write(false);
-
- // Button
- gpioConfig.drvstr = MXC_GPIO_DRVSTR_0;
- gpioConfig.func = MXC_GPIO_FUNC_IN;
- gpioConfig.mask = BUTTON_PIN;
- gpioConfig.pad = BUTTON_PULL;
- gpioConfig.port = BUTTON_PORT;
- gpioConfig.vssel = MXC_GPIO_VSSEL_VDDIO;
- MXC_GPIO_Config(&gpioConfig);
-
- // UART
- MXC_UART_Init(ConsoleUart, CFG_BOARD_UART_BAUDRATE, MXC_UART_IBRO_CLK);
- UART_PORT->vssel |= UART_VDDIO_BITS; //Set necessary bits to 3.3V
-
- //USB
- MXC_MCR->ldoctrl |= MXC_F_MCR_LDOCTRL_0P9EN;
- MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_USB);
-}
-
-//--------------------------------------------------------------------+
-// Board porting API
-//--------------------------------------------------------------------+
-
-void board_led_write(bool state) {
-#if LED_STATE_ON
- state = !state;
-#endif
- if (state) {
- MXC_GPIO_OutClr(LED_PORT, LED_PIN);
- } else {
- MXC_GPIO_OutSet(LED_PORT, LED_PIN);
- }
-}
-
-uint32_t board_button_read(void) {
- uint32_t state = MXC_GPIO_InGet(BUTTON_PORT, BUTTON_PIN) ? 1 : 0;
- return BUTTON_STATE_ACTIVE == state;
-}
-
-size_t board_get_unique_id(uint8_t id[], size_t max_len) {
- uint8_t hw_id[MXC_SYS_USN_CHECKSUM_LEN];//USN Buffer
- /* All other 2nd parameter is optional checksum buffer */
- MXC_SYS_GetUSN(hw_id, NULL);
-
- size_t act_len = TU_MIN(max_len, MXC_SYS_USN_LEN);
- memcpy(id, hw_id, act_len);
- return act_len;
-}
-
-int board_uart_read(uint8_t *buf, int len) {
- int uart_val;
- int act_len = 0;
-
- while (act_len < len) {
- if ((uart_val = MXC_UART_ReadCharacterRaw(ConsoleUart)) == E_UNDERFLOW) {
- break;
- } else {
- *buf++ = (uint8_t) uart_val;
- act_len++;
- }
- }
- return act_len;
-}
-
-int board_uart_write(void const *buf, int len) {
- int act_len = 0;
- const uint8_t *ch_ptr = (const uint8_t *) buf;
- while (act_len < len) {
- MXC_UART_WriteCharacter(ConsoleUart, *ch_ptr++);
- act_len++;
- }
- return len;
-}
-
-#if CFG_TUSB_OS == OPT_OS_NONE
-volatile uint32_t system_ticks = 0;
-
-void SysTick_Handler(void) {
- system_ticks++;
-}
-
-uint32_t board_millis(void) {
- return system_ticks;
-}
-#endif
-
-void HardFault_Handler(void) {
- __asm("BKPT #0\n");
-}
-
-// Required by __libc_init_array in startup code if we are compiling using
-// -nostdlib/-nostartfiles.
-void _init(void) {
-}
diff --git a/hw/bsp/max78002/family.cmake b/hw/bsp/max78002/family.cmake
deleted file mode 100644
index ce0fcfa08..000000000
--- a/hw/bsp/max78002/family.cmake
+++ /dev/null
@@ -1,166 +0,0 @@
-include_guard()
-
-set(MAX32_PERIPH ${TOP}/hw/mcu/analog/max32/Libraries/PeriphDrivers)
-set(MAX32_CMSIS ${TOP}/hw/mcu/analog/max32/Libraries/CMSIS)
-set(CMSIS_5 ${TOP}/lib/CMSIS_5)
-
-# include board specific
-include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
-
-# Get the linker file from current location (family)
-set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/max78002.ld)
-set(LD_FILE_Clang ${LD_FILE_GNU})
-
-# toolchain set up
-set(CMAKE_SYSTEM_CPU cortex-m4 CACHE INTERNAL "System Processor")
-set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
-set(JLINK_DEVICE max78000)
-
-set(FAMILY_MCUS MAX78002 CACHE INTERNAL "")
-
-function(update_board TARGET)
- target_compile_definitions(${TARGET} PUBLIC
- TARGET=MAX78002
- TARGET_REV=0x4131
- MXC_ASSERT_ENABLE
- MAX78002
- IAR_PRAGMAS=0
- CFG_TUSB_MCU=OPT_MCU_MAX78002
- BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
- )
-endfunction()
-
-#------------------------------------
-# BOARD_TARGET
-#------------------------------------
-# only need to be built ONCE for all examples
-function(add_board_target BOARD_TARGET)
- if (TARGET ${BOARD_TARGET})
- return()
- endif ()
-
- # Startup & Linker script
- set(STARTUP_FILE_GNU ${MAX32_CMSIS}/Device/Maxim/MAX78002/Source/GCC/startup_max78002.S)
- set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
-
- set(PERIPH_SRC ${MAX32_PERIPH}/Source)
- add_library(${BOARD_TARGET} STATIC
- ${MAX32_CMSIS}/Device/Maxim/MAX78002/Source/heap.c
- ${MAX32_CMSIS}/Device/Maxim/MAX78002/Source/system_max78002.c
- ${PERIPH_SRC}/SYS/mxc_assert.c
- ${PERIPH_SRC}/SYS/mxc_delay.c
- ${PERIPH_SRC}/SYS/mxc_lock.c
- ${PERIPH_SRC}/SYS/nvic_table.c
- ${PERIPH_SRC}/SYS/pins_ai87.c
- ${PERIPH_SRC}/SYS/sys_ai87.c
- ${PERIPH_SRC}/AES/aes_ai87.c
- ${PERIPH_SRC}/AES/aes_revb.c
- ${PERIPH_SRC}/FLC/flc_common.c
- ${PERIPH_SRC}/FLC/flc_ai87.c
- ${PERIPH_SRC}/FLC/flc_reva.c
- ${PERIPH_SRC}/GPIO/gpio_common.c
- ${PERIPH_SRC}/GPIO/gpio_ai87.c
- ${PERIPH_SRC}/GPIO/gpio_reva.c
- ${PERIPH_SRC}/ICC/icc_ai87.c
- ${PERIPH_SRC}/ICC/icc_reva.c
- ${PERIPH_SRC}/TRNG/trng_ai87.c
- ${PERIPH_SRC}/TRNG/trng_revb.c
- ${PERIPH_SRC}/UART/uart_common.c
- ${PERIPH_SRC}/UART/uart_ai87.c
- ${PERIPH_SRC}/UART/uart_revb.c
- ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
- )
- target_include_directories(${BOARD_TARGET} PUBLIC
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
- ${MAX32_CMSIS}/Include
- ${MAX32_CMSIS}/Device/Maxim/MAX78002/Include
- ${MAX32_PERIPH}/Include/MAX78002
- ${PERIPH_SRC}/SYS
- ${PERIPH_SRC}/GPIO
- ${PERIPH_SRC}/AES
- ${PERIPH_SRC}/TRNG
- ${PERIPH_SRC}/ICC
- ${PERIPH_SRC}/FLC
- ${PERIPH_SRC}/UART
- )
-
- target_compile_options(${BOARD_TARGET} PRIVATE
- -Wno-error=strict-prototypes
- -Wno-error=redundant-decls
- )
- update_board(${BOARD_TARGET})
-
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
- target_link_options(${BOARD_TARGET} PUBLIC
- "LINKER:--script=${LD_FILE_GNU}"
- -nostartfiles
- --specs=nosys.specs --specs=nano.specs
- )
- elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
- target_link_options(${BOARD_TARGET} PUBLIC
- "LINKER:--script=${LD_FILE_Clang}"
- )
- endif ()
-endfunction()
-
-
-#------------------------------------
-# Functions
-#------------------------------------
-function(family_configure_example TARGET RTOS)
- family_configure_common(${TARGET} ${RTOS})
-
- # Board target
- add_board_target(board_${BOARD})
-
- #---------- Port Specific ----------
- # These files are built for each example since it depends on example's tusb_config.h
- target_sources(${TARGET} PUBLIC
- # BSP
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
- )
- target_include_directories(${TARGET} PUBLIC
- # family, hw, board
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
- )
-
- target_compile_options(${TARGET} PRIVATE
- -Wno-error=strict-prototypes
- -Wno-error=redundant-decls
- )
-
-
- # Add TinyUSB target and port source
- family_add_tinyusb(${TARGET} OPT_MCU_MAX78002)
- target_sources(${TARGET} PUBLIC
- ${TOP}/src/portable/mentor/musb/dcd_musb.c
- )
- target_link_libraries(${TARGET} PUBLIC board_${BOARD})
- target_compile_options(${TARGET} PRIVATE
- -Wno-error=strict-prototypes
- -Wno-error=redundant-decls
- )
-
-
-
- # Flashing
- family_add_bin_hex(${TARGET})
- family_flash_jlink(${TARGET})
- family_flash_msdk(${TARGET})
-endfunction()
-
-# Add flash msdk target
-function(family_flash_msdk TARGET)
- set(MAXIM_PATH "$ENV{MAXIM_PATH}")
-
- add_custom_target(${TARGET}-msdk
- DEPENDS ${TARGET}
- COMMAND ${MAXIM_PATH}/Tools/OpenOCD/openocd -s ${MAXIM_PATH}/Tools/OpenOCD/scripts
- -f interface/cmsis-dap.cfg -f target/max78002.cfg
- -c "program $ verify; init; reset; exit"
- VERBATIM
- )
-endfunction()
diff --git a/hw/bsp/max78002/family.mk b/hw/bsp/max78002/family.mk
deleted file mode 100644
index 997816261..000000000
--- a/hw/bsp/max78002/family.mk
+++ /dev/null
@@ -1,99 +0,0 @@
-DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/analog/max32
-
-# Important locations in the hw support for MCU
-MAX32_CMSIS = hw/mcu/analog/max32/Libraries/CMSIS
-MAX32_PERIPH = hw/mcu/analog/max32/Libraries/PeriphDrivers
-
-# Add any board specific make rules
-include $(TOP)/$(BOARD_PATH)/board.mk
-
-CPU_CORE ?= cortex-m4
-PORT ?= 0
-
-# GCC
-SRC_S_GCC += $(MAX32_CMSIS)/Device/Maxim/MAX78002/Source/GCC/startup_max78002.S
-LD_FILE = $(FAMILY_PATH)/max78002.ld
-
-# --------------
-# Compiler Flags
-# --------------
-# Flags for the MAX78002 SDK
-CFLAGS += -DTARGET=MAX78002 \
- -DTARGET_REV=0x4131 \
- -DMXC_ASSERT_ENABLE \
- -DMAX78002 \
- -DIAR_PRAGMAS=0
-
-# Flags for TUSB features
-CFLAGS += \
- -DCFG_TUSB_MCU=OPT_MCU_MAX78002 \
- -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
-
-# mcu driver cause following warnings
-CFLAGS += -Wno-error=redundant-decls \
- -Wno-error=strict-prototypes \
- -Wno-error=unused-parameter \
- -Wno-error=enum-conversion \
- -Wno-error=sign-compare \
- -Wno-error=cast-qual
-
-LDFLAGS_GCC += -nostartfiles --specs=nosys.specs --specs=nano.specs
-
-# For flash-jlink target
-JLINK_DEVICE = max78000
-
-# flash target using Jlink by default
-flash: flash-jlink
-
-# Optional flash option when running within an installed MSDK to use OpenOCD
-# Mainline OpenOCD does not yet have the MAX32's flash algorithm integrated.
-# If the MSDK is installed, flash-msdk can be run to utilize the the modified
-# openocd with the algorithms
-MAXIM_PATH := $(subst \,/,$(MAXIM_PATH))
-flash-msdk: $(BUILD)/$(PROJECT).elf
- $(MAXIM_PATH)/Tools/OpenOCD/openocd -s $(MAXIM_PATH)/Tools/OpenOCD/scripts \
- -f interface/cmsis-dap.cfg -f target/max78002.cfg \
- -c "program $(BUILD)/$(PROJECT).elf verify; init; reset; exit"
-
-# -----------------
-# Sources & Include
-# -----------------
-PERIPH_SRC = $(TOP)/$(MAX32_PERIPH)/Source
-SRC_C += \
- src/portable/mentor/musb/dcd_musb.c \
- $(MAX32_CMSIS)/Device/Maxim/MAX78002/Source/heap.c \
- $(MAX32_CMSIS)/Device/Maxim/MAX78002/Source/system_max78002.c \
- $(PERIPH_SRC)/SYS/mxc_assert.c \
- $(PERIPH_SRC)/SYS/mxc_delay.c \
- $(PERIPH_SRC)/SYS/mxc_lock.c \
- $(PERIPH_SRC)/SYS/nvic_table.c \
- $(PERIPH_SRC)/SYS/pins_ai87.c \
- $(PERIPH_SRC)/SYS/sys_ai87.c \
- $(PERIPH_SRC)/AES/aes_ai87.c \
- $(PERIPH_SRC)/AES/aes_revb.c \
- $(PERIPH_SRC)/FLC/flc_common.c \
- $(PERIPH_SRC)/FLC/flc_ai87.c \
- $(PERIPH_SRC)/FLC/flc_reva.c \
- $(PERIPH_SRC)/GPIO/gpio_common.c \
- $(PERIPH_SRC)/GPIO/gpio_ai87.c \
- $(PERIPH_SRC)/GPIO/gpio_reva.c \
- $(PERIPH_SRC)/ICC/icc_ai87.c \
- $(PERIPH_SRC)/ICC/icc_reva.c \
- $(PERIPH_SRC)/TRNG/trng_ai87.c \
- $(PERIPH_SRC)/TRNG/trng_revb.c \
- $(PERIPH_SRC)/UART/uart_common.c \
- $(PERIPH_SRC)/UART/uart_ai87.c \
- $(PERIPH_SRC)/UART/uart_revb.c \
-
-INC += \
- $(TOP)/$(BOARD_PATH) \
- $(TOP)/$(MAX32_CMSIS)/Include \
- $(TOP)/$(MAX32_CMSIS)/Device/Maxim/MAX78002/Include \
- $(TOP)/$(MAX32_PERIPH)/Include/MAX78002 \
- $(PERIPH_SRC)/SYS \
- $(PERIPH_SRC)/GPIO \
- $(PERIPH_SRC)/AES \
- $(PERIPH_SRC)/ICC \
- $(PERIPH_SRC)/FLC \
- $(PERIPH_SRC)/TRNG \
- $(PERIPH_SRC)/UART
diff --git a/hw/bsp/max32650/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/maxim/FreeRTOSConfig/FreeRTOSConfig.h
similarity index 100%
rename from hw/bsp/max32650/FreeRTOSConfig/FreeRTOSConfig.h
rename to hw/bsp/maxim/FreeRTOSConfig/FreeRTOSConfig.h
diff --git a/hw/bsp/maxim/README.md b/hw/bsp/maxim/README.md
new file mode 100644
index 000000000..e2983e899
--- /dev/null
+++ b/hw/bsp/maxim/README.md
@@ -0,0 +1,43 @@
+# Analog Devices MAXIM
+
+This BSP is for working with the Analog microcontrollers
+ - [MAX32650](https://www.analog.com/en/products/max32650.html),
+ - [MAX32651](https://www.analog.com/en/products/max32651.html)
+ - [MAX32652](https://www.analog.com/en/products/max32652.html)
+ - [MAX32665](https://www.analog.com/en/products/max32665.html)
+ - [MAX32666](https://www.analog.com/en/products/max32666.html)
+ - [MAX32690](https://www.analog.com/en/products/max32690.html)
+ - [MAX78002](https://www.analog.com/en/products/max78002.html) AI microcontroller.
+
+The following boards are supported:
+ * [MAX32650EVKIT](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32650-evkit.html)
+ * [MAX32650FTHR](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32650fthr.html)
+ * [MAX32651EVKIT](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32651-evkit.html) (Secure Bootloader)
+ * [MAX32666EVKIT](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32666evkit.html)
+ * [MAX32666FTHR](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32666fthr.html)
+ * [MAX32690EVKIT](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32690evkit.html)
+ * [AD-APARD32690-SL](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/ad-apard32690-sl.html)
+ * [MAX78002EVKIT](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max78002evkit.html)
+
+This part family leverages the Maxim Microcontrollers SDK (MSDK) for the device
+interfaces and hardware abstraction layers. This source code package is fetched
+as part of the get-deps script.
+
+The microcontroller utilizes the standard GNU ARM toolchain. If this toolchain
+is not already available on your build machine, it can be installed by using the
+bundled MSDK installation. Details on downloading and installing can be found
+in the [User's Guide](https://analogdevicesinc.github.io/msdk//USERGUIDE/).
+
+## Flashing
+
+The default flashing behavior in this BSP is to utilize JLink. This can be done
+by running the `flash` or `flash-jlink` rule for Makefiles, or the
+`-jlink` target for CMake.
+
+Most the Evaluation Kit and boards are shipped with a CMSIS-DAP
+compatible debug probe. However, at the time of writing, the necessary flashing
+algorithms for OpenOCD have not yet been incorporated into the OpenOCD master
+branch. To utilize the provided debug probes, please install the bundled MSDK
+package which includes the appropriate OpenOCD modifications. To leverage this
+OpenOCD instance, run the `flash-msdk` Makefile rule, or `-openocd` CMake
+target.
diff --git a/hw/bsp/maxim/boards/apard32690/board.cmake b/hw/bsp/maxim/boards/apard32690/board.cmake
new file mode 100644
index 000000000..a03d05f8d
--- /dev/null
+++ b/hw/bsp/maxim/boards/apard32690/board.cmake
@@ -0,0 +1,4 @@
+set(MAX_DEVICE max32690)
+
+function(update_board TARGET)
+endfunction()
diff --git a/hw/bsp/max32690/boards/apard32690/board.h b/hw/bsp/maxim/boards/apard32690/board.h
similarity index 97%
rename from hw/bsp/max32690/boards/apard32690/board.h
rename to hw/bsp/maxim/boards/apard32690/board.h
index 87b9c4e88..19f74bf56 100644
--- a/hw/bsp/max32690/boards/apard32690/board.h
+++ b/hw/bsp/maxim/boards/apard32690/board.h
@@ -32,8 +32,7 @@
#ifndef BOARD_H_
#define BOARD_H_
-#include "gpio.h"
-#include "mxc_sys.h"
+#include "max32690.h"
#ifdef __cplusplus
extern "C" {
diff --git a/hw/bsp/maxim/boards/apard32690/board.mk b/hw/bsp/maxim/boards/apard32690/board.mk
new file mode 100644
index 000000000..d8a0c9cae
--- /dev/null
+++ b/hw/bsp/maxim/boards/apard32690/board.mk
@@ -0,0 +1 @@
+MAX_DEVICE = max32690
diff --git a/hw/bsp/maxim/boards/max32650evkit/board.cmake b/hw/bsp/maxim/boards/max32650evkit/board.cmake
new file mode 100644
index 000000000..59721e756
--- /dev/null
+++ b/hw/bsp/maxim/boards/max32650evkit/board.cmake
@@ -0,0 +1,8 @@
+set(MAX_DEVICE max32650)
+
+function(update_board TARGET)
+endfunction()
+
+function(prepare_image TARGET_IN)
+ #No signing required
+endfunction()
diff --git a/hw/bsp/max32650/boards/max32650evkit/board.h b/hw/bsp/maxim/boards/max32650evkit/board.h
similarity index 94%
rename from hw/bsp/max32650/boards/max32650evkit/board.h
rename to hw/bsp/maxim/boards/max32650evkit/board.h
index 65ed2659e..0dfc074fa 100644
--- a/hw/bsp/max32650/boards/max32650evkit/board.h
+++ b/hw/bsp/maxim/boards/max32650evkit/board.h
@@ -26,14 +26,13 @@
/* metadata:
name: MAX32650 EVKIT
- url: https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32650-evkit.html#eb-overview
+ url: https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max32650-evkit.html
*/
#ifndef BOARD_H_
#define BOARD_H_
-#include "gpio.h"
-#include "mxc_sys.h"
+#include "max32650.h"
#ifdef __cplusplus
extern "C" {
diff --git a/hw/bsp/maxim/boards/max32650evkit/board.mk b/hw/bsp/maxim/boards/max32650evkit/board.mk
new file mode 100644
index 000000000..3a4108005
--- /dev/null
+++ b/hw/bsp/maxim/boards/max32650evkit/board.mk
@@ -0,0 +1 @@
+MAX_DEVICE = max32650
diff --git a/hw/bsp/maxim/boards/max32650fthr/board.cmake b/hw/bsp/maxim/boards/max32650fthr/board.cmake
new file mode 100644
index 000000000..59721e756
--- /dev/null
+++ b/hw/bsp/maxim/boards/max32650fthr/board.cmake
@@ -0,0 +1,8 @@
+set(MAX_DEVICE max32650)
+
+function(update_board TARGET)
+endfunction()
+
+function(prepare_image TARGET_IN)
+ #No signing required
+endfunction()
diff --git a/hw/bsp/max32650/boards/max32650fthr/board.h b/hw/bsp/maxim/boards/max32650fthr/board.h
similarity index 98%
rename from hw/bsp/max32650/boards/max32650fthr/board.h
rename to hw/bsp/maxim/boards/max32650fthr/board.h
index 755fa15b5..af0fa1c39 100644
--- a/hw/bsp/max32650/boards/max32650fthr/board.h
+++ b/hw/bsp/maxim/boards/max32650fthr/board.h
@@ -32,8 +32,7 @@
#ifndef BOARD_H_
#define BOARD_H_
-#include "gpio.h"
-#include "mxc_sys.h"
+#include "max32650.h"
#ifdef __cplusplus
extern "C" {
diff --git a/hw/bsp/maxim/boards/max32650fthr/board.mk b/hw/bsp/maxim/boards/max32650fthr/board.mk
new file mode 100644
index 000000000..3a4108005
--- /dev/null
+++ b/hw/bsp/maxim/boards/max32650fthr/board.mk
@@ -0,0 +1 @@
+MAX_DEVICE = max32650
diff --git a/hw/bsp/max32650/boards/max32651evkit/board.cmake b/hw/bsp/maxim/boards/max32651evkit/board.cmake
similarity index 81%
rename from hw/bsp/max32650/boards/max32651evkit/board.cmake
rename to hw/bsp/maxim/boards/max32651evkit/board.cmake
index bd8077a42..773989126 100644
--- a/hw/bsp/max32650/boards/max32651evkit/board.cmake
+++ b/hw/bsp/maxim/boards/max32651evkit/board.cmake
@@ -1,22 +1,23 @@
-# Use the secure linker file
-set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/max32651.ld)
+set(MAX_DEVICE max32650)
-function(update_board_extras TARGET)
+# Use the secure linker file
+set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/../../linker/max32651.ld)
+
+function(update_board TARGET)
# for the signed target, need to add the __SLA_FWK__ define
target_compile_definitions(${TARGET} PUBLIC
__SLA_FWK__
)
endfunction()
-function(prepare_image TARGET_IN)
- #For the signed target, set up a POST_BUILD command to sign the elf file once
- #created
+function(sign_image TARGET_IN)
+ #For the signed target, set up a POST_BUILD command to sign the elf file once created
if((WIN32) OR (MINGW) OR (MSYS))
set(SIGN_EXE "sign_app.exe")
else()
set(SIGN_EXE "sign_app")
endif()
- set(MCU_PATH "${TOP}/hw/mcu/analog/max32/")
+ set(MCU_PATH "${TOP}/hw/mcu/analog/msdk/")
# Custom POST_BUILD command
add_custom_command(
diff --git a/hw/bsp/max32650/boards/max32651evkit/board.h b/hw/bsp/maxim/boards/max32651evkit/board.h
similarity index 98%
rename from hw/bsp/max32650/boards/max32651evkit/board.h
rename to hw/bsp/maxim/boards/max32651evkit/board.h
index 0b49ff309..dbf2a4b7c 100644
--- a/hw/bsp/max32650/boards/max32651evkit/board.h
+++ b/hw/bsp/maxim/boards/max32651evkit/board.h
@@ -32,8 +32,7 @@
#ifndef BOARD_H_
#define BOARD_H_
-#include "gpio.h"
-#include "mxc_sys.h"
+#include "max32650.h"
#ifdef __cplusplus
extern "C" {
diff --git a/hw/bsp/max32650/boards/max32651evkit/board.mk b/hw/bsp/maxim/boards/max32651evkit/board.mk
similarity index 61%
rename from hw/bsp/max32650/boards/max32651evkit/board.mk
rename to hw/bsp/maxim/boards/max32651evkit/board.mk
index b609598c1..5d4971148 100644
--- a/hw/bsp/max32650/boards/max32651evkit/board.mk
+++ b/hw/bsp/maxim/boards/max32651evkit/board.mk
@@ -1,5 +1,7 @@
+MAX_DEVICE = max32650
+
# Use the secure linker file
-LD_FILE = $(BOARD_PATH)/max32651.ld
+LD_FILE = $(FAMILY_PATH)/linker/max32651.ld
# Let the family script know the build needs to be signed
SIGNED_BUILD := 1
diff --git a/hw/bsp/maxim/boards/max32666evkit/board.cmake b/hw/bsp/maxim/boards/max32666evkit/board.cmake
new file mode 100644
index 000000000..e7116b603
--- /dev/null
+++ b/hw/bsp/maxim/boards/max32666evkit/board.cmake
@@ -0,0 +1,4 @@
+set(MAX_DEVICE max32665)
+
+function(update_board TARGET)
+endfunction()
diff --git a/hw/bsp/max32666/boards/max32666evkit/board.h b/hw/bsp/maxim/boards/max32666evkit/board.h
similarity index 98%
rename from hw/bsp/max32666/boards/max32666evkit/board.h
rename to hw/bsp/maxim/boards/max32666evkit/board.h
index 54589444d..42965d3c5 100644
--- a/hw/bsp/max32666/boards/max32666evkit/board.h
+++ b/hw/bsp/maxim/boards/max32666evkit/board.h
@@ -32,8 +32,7 @@
#ifndef BOARD_H_
#define BOARD_H_
-#include "gpio.h"
-#include "mxc_sys.h"
+#include "max32665.h"
#ifdef __cplusplus
extern "C" {
diff --git a/hw/bsp/maxim/boards/max32666evkit/board.mk b/hw/bsp/maxim/boards/max32666evkit/board.mk
new file mode 100644
index 000000000..a1cf3045d
--- /dev/null
+++ b/hw/bsp/maxim/boards/max32666evkit/board.mk
@@ -0,0 +1 @@
+MAX_DEVICE = max32665
diff --git a/hw/bsp/maxim/boards/max32666fthr/board.cmake b/hw/bsp/maxim/boards/max32666fthr/board.cmake
new file mode 100644
index 000000000..e7116b603
--- /dev/null
+++ b/hw/bsp/maxim/boards/max32666fthr/board.cmake
@@ -0,0 +1,4 @@
+set(MAX_DEVICE max32665)
+
+function(update_board TARGET)
+endfunction()
diff --git a/hw/bsp/max32666/boards/max32666fthr/board.h b/hw/bsp/maxim/boards/max32666fthr/board.h
similarity index 98%
rename from hw/bsp/max32666/boards/max32666fthr/board.h
rename to hw/bsp/maxim/boards/max32666fthr/board.h
index 0caea5934..fbb217949 100644
--- a/hw/bsp/max32666/boards/max32666fthr/board.h
+++ b/hw/bsp/maxim/boards/max32666fthr/board.h
@@ -32,8 +32,7 @@
#ifndef BOARD_H_
#define BOARD_H_
-#include "gpio.h"
-#include "mxc_sys.h"
+#include "max32665.h"
#ifdef __cplusplus
extern "C" {
diff --git a/hw/bsp/maxim/boards/max32666fthr/board.mk b/hw/bsp/maxim/boards/max32666fthr/board.mk
new file mode 100644
index 000000000..a1cf3045d
--- /dev/null
+++ b/hw/bsp/maxim/boards/max32666fthr/board.mk
@@ -0,0 +1 @@
+MAX_DEVICE = max32665
diff --git a/hw/bsp/maxim/boards/max32690evkit/board.cmake b/hw/bsp/maxim/boards/max32690evkit/board.cmake
new file mode 100644
index 000000000..a03d05f8d
--- /dev/null
+++ b/hw/bsp/maxim/boards/max32690evkit/board.cmake
@@ -0,0 +1,4 @@
+set(MAX_DEVICE max32690)
+
+function(update_board TARGET)
+endfunction()
diff --git a/hw/bsp/max32690/boards/max32690evkit/board.h b/hw/bsp/maxim/boards/max32690evkit/board.h
similarity index 98%
rename from hw/bsp/max32690/boards/max32690evkit/board.h
rename to hw/bsp/maxim/boards/max32690evkit/board.h
index aa8dbb1de..41c73621f 100644
--- a/hw/bsp/max32690/boards/max32690evkit/board.h
+++ b/hw/bsp/maxim/boards/max32690evkit/board.h
@@ -32,13 +32,12 @@
#ifndef BOARD_H_
#define BOARD_H_
-#include "gpio.h"
-#include "mxc_sys.h"
-
#ifdef __cplusplus
extern "C" {
#endif
+#include "max32690.h"
+
// LED
#define LED_PORT MXC_GPIO0
#define LED_PIN MXC_GPIO_PIN_14
diff --git a/hw/bsp/maxim/boards/max32690evkit/board.mk b/hw/bsp/maxim/boards/max32690evkit/board.mk
new file mode 100644
index 000000000..d8a0c9cae
--- /dev/null
+++ b/hw/bsp/maxim/boards/max32690evkit/board.mk
@@ -0,0 +1 @@
+MAX_DEVICE = max32690
diff --git a/hw/bsp/maxim/boards/max78002evkit/board.cmake b/hw/bsp/maxim/boards/max78002evkit/board.cmake
new file mode 100644
index 000000000..dd4c3c215
--- /dev/null
+++ b/hw/bsp/maxim/boards/max78002evkit/board.cmake
@@ -0,0 +1,4 @@
+set(MAX_DEVICE max78002)
+
+function(update_board TARGET)
+endfunction()
diff --git a/hw/bsp/max78002/boards/max78002evkit/board.h b/hw/bsp/maxim/boards/max78002evkit/board.h
similarity index 98%
rename from hw/bsp/max78002/boards/max78002evkit/board.h
rename to hw/bsp/maxim/boards/max78002evkit/board.h
index 85d55d7de..8c1fc13d4 100644
--- a/hw/bsp/max78002/boards/max78002evkit/board.h
+++ b/hw/bsp/maxim/boards/max78002evkit/board.h
@@ -32,8 +32,7 @@
#ifndef BOARD_H_
#define BOARD_H_
-#include "gpio.h"
-#include "mxc_sys.h"
+#include "max78002.h"
#ifdef __cplusplus
extern "C" {
diff --git a/hw/bsp/maxim/boards/max78002evkit/board.mk b/hw/bsp/maxim/boards/max78002evkit/board.mk
new file mode 100644
index 000000000..b19e95187
--- /dev/null
+++ b/hw/bsp/maxim/boards/max78002evkit/board.mk
@@ -0,0 +1 @@
+MAX_DEVICE = max78002
diff --git a/hw/bsp/max32666/family.c b/hw/bsp/maxim/family.c
similarity index 77%
rename from hw/bsp/max32666/family.c
rename to hw/bsp/maxim/family.c
index 05306c6c9..0ef6b8c4d 100644
--- a/hw/bsp/max32666/family.c
+++ b/hw/bsp/maxim/family.c
@@ -35,7 +35,9 @@
#include "gpio.h"
#include "mxc_sys.h"
+#if __has_include("mcr_regs.h")
#include "mcr_regs.h"
+#endif
#include "mxc_device.h"
#include "uart.h"
@@ -88,16 +90,45 @@ void board_init(void) {
MXC_GPIO_Config(&gpioConfig);
// UART
+#if MAX_PERIPH_ID == 14
MXC_UART_Init(ConsoleUart, CFG_BOARD_UART_BAUDRATE, UART_MAP);
+#elif MAX_PERIPH_ID == 18 || MAX_PERIPH_ID == 87
+ MXC_UART_Init(ConsoleUart, CFG_BOARD_UART_BAUDRATE, MXC_UART_IBRO_CLK);
+ #if MAX_PERIPH_ID == 87
+ UART_PORT->vssel |= UART_VDDIO_BITS; // Set necessary bits to 3.3V
+ #endif
+#endif
//USB
+#if defined(MAX32650)
// Startup the HIRC96M clock if it's not on already
- if (!(MXC_GCR->clkcn & MXC_F_GCR_CLKCN_HIRC96M_EN)) {
- MXC_GCR->clkcn |= MXC_F_GCR_CLKCN_HIRC96M_EN;
+ if (!(MXC_GCR->clk_ctrl & MXC_F_GCR_CLK_CTRL_HIRC96_EN)) {
+ MXC_GCR->clk_ctrl |= MXC_F_GCR_CLK_CTRL_HIRC96_EN;
+ MXC_SYS_Clock_Timeout(MXC_F_GCR_CLK_CTRL_HIRC96_RDY);
}
-
MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_USB);
MXC_SYS_Reset_Periph(MXC_SYS_RESET_USB);
+
+#elif defined(MAX32665) || defined(MAX32666)
+ // Startup the HIRC96M clock if it's not on already
+ if (!(MXC_GCR->clkcn & MXC_F_GCR_CLKCN_HIRC96M_EN)) {
+ MXC_GCR->clkcn |= MXC_F_GCR_CLKCN_HIRC96M_EN;
+ }
+ MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_USB);
+ MXC_SYS_Reset_Periph(MXC_SYS_RESET_USB);
+
+#elif defined(MAX32690)
+ MXC_SYS_ClockSourceEnable(MXC_SYS_CLOCK_IPO);
+ MXC_MCR->ldoctrl |= MXC_F_MCR_LDOCTRL_0P9EN;
+ MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_USB);
+ MXC_SYS_Reset_Periph(MXC_SYS_RESET0_USB);
+
+# elif defined(MAX78002)
+ MXC_MCR->ldoctrl |= MXC_F_MCR_LDOCTRL_0P9EN;
+ MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_USB);
+#else
+ #error "Unsupported MAXIM MCU for board_dfu_init"
+#endif
}
//--------------------------------------------------------------------+
@@ -121,13 +152,18 @@ uint32_t board_button_read(void) {
}
size_t board_get_unique_id(uint8_t id[], size_t max_len) {
- uint8_t hw_id[MXC_SYS_USN_CHECKSUM_LEN];//USN Buffer
- /* All other 2nd parameter is optional checksum buffer */
- MXC_SYS_GetUSN(hw_id, NULL);
+#if defined(MAX32650)
+ // USN is 13 bytes on this device
+ MXC_SYS_GetUSN(id, 13);
+ return 13;
+#else
+ uint8_t hw_id[MXC_SYS_USN_CHECKSUM_LEN]; //USN Buffer
+ MXC_SYS_GetUSN(hw_id, NULL); // 2nd parameter is optional checksum buffer
size_t act_len = TU_MIN(max_len, MXC_SYS_USN_LEN);
memcpy(id, hw_id, act_len);
return act_len;
+#endif
}
int board_uart_read(uint8_t *buf, int len) {
diff --git a/hw/bsp/maxim/family.cmake b/hw/bsp/maxim/family.cmake
new file mode 100644
index 000000000..75daec753
--- /dev/null
+++ b/hw/bsp/maxim/family.cmake
@@ -0,0 +1,196 @@
+include_guard()
+
+# stub: overridden by board.cmake if needed
+function(sign_image TARGET_IN)
+endfunction()
+
+set(MSDK_LIB ${TOP}/hw/mcu/analog/msdk/Libraries)
+
+# include board specific
+include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
+
+# toolchain set up
+set(CMAKE_SYSTEM_CPU cortex-m4 CACHE INTERNAL "System Processor")
+set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
+
+string(TOUPPER ${MAX_DEVICE} MAX_DEVICE_UPPER)
+cmake_print_variables(MAX_DEVICE MAX_DEVICE_UPPER)
+
+set(JLINK_DEVICE ${MAX_DEVICE})
+set(OPENOCD_OPTION "-f interface/cmsis-dap.cfg -f target/${MAX_DEVICE}.cfg")
+
+set(FAMILY_MCUS ${MAX_DEVICE_UPPER} CACHE INTERNAL "")
+
+if (${MAX_DEVICE} STREQUAL "max32650")
+ set(PERIPH_ID 10)
+ set(PERIPH_SUFFIX "me")
+elseif (${MAX_DEVICE} STREQUAL "max32665" OR ${MAX_DEVICE} STREQUAL "max32666")
+ set(PERIPH_ID 14)
+ set(PERIPH_SUFFIX "me")
+elseif (${MAX_DEVICE} STREQUAL "max32690")
+ set(PERIPH_ID 18)
+ set(PERIPH_SUFFIX "me")
+elseif (${MAX_DEVICE} STREQUAL "max78002")
+ set(PERIPH_ID 87)
+ set(PERIPH_SUFFIX "ai")
+else()
+ message(FATAL_ERROR "Unsupported MAX device: ${MAX_DEVICE}")
+endif()
+
+#------------------------------------
+# BOARD_TARGET
+#------------------------------------
+# only need to be built ONCE for all examples
+function(add_board_target BOARD_TARGET)
+ if (TARGET ${BOARD_TARGET})
+ return()
+ endif ()
+
+ # Startup & Linker script
+ set(STARTUP_FILE_GNU ${MSDK_LIB}/CMSIS/Device/Maxim/${MAX_DEVICE_UPPER}/Source/GCC/startup_${MAX_DEVICE}.S)
+ set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
+
+ if (NOT DEFINED LD_FILE_GNU)
+ set(LD_FILE_GNU ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/linker/${MAX_DEVICE}.ld)
+ endif ()
+ set(LD_FILE_Clang ${LD_FILE_GNU})
+
+ # Common
+ add_library(${BOARD_TARGET} STATIC
+ ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
+ ${MSDK_LIB}/CMSIS/Device/Maxim/${MAX_DEVICE_UPPER}/Source/heap.c
+ ${MSDK_LIB}/CMSIS/Device/Maxim/${MAX_DEVICE_UPPER}/Source/system_${MAX_DEVICE}.c
+ ${MSDK_LIB}/PeriphDrivers/Source/SYS/mxc_assert.c
+ ${MSDK_LIB}/PeriphDrivers/Source/SYS/mxc_delay.c
+ ${MSDK_LIB}/PeriphDrivers/Source/SYS/mxc_lock.c
+ ${MSDK_LIB}/PeriphDrivers/Source/SYS/nvic_table.c
+ ${MSDK_LIB}/PeriphDrivers/Source/SYS/pins_${PERIPH_SUFFIX}${PERIPH_ID}.c
+ ${MSDK_LIB}/PeriphDrivers/Source/SYS/sys_${PERIPH_SUFFIX}${PERIPH_ID}.c
+ ${MSDK_LIB}/PeriphDrivers/Source/FLC/flc_common.c
+ ${MSDK_LIB}/PeriphDrivers/Source/FLC/flc_${PERIPH_SUFFIX}${PERIPH_ID}.c
+ ${MSDK_LIB}/PeriphDrivers/Source/FLC/flc_reva.c
+ ${MSDK_LIB}/PeriphDrivers/Source/GPIO/gpio_common.c
+ ${MSDK_LIB}/PeriphDrivers/Source/GPIO/gpio_${PERIPH_SUFFIX}${PERIPH_ID}.c
+ ${MSDK_LIB}/PeriphDrivers/Source/GPIO/gpio_reva.c
+ ${MSDK_LIB}/PeriphDrivers/Source/ICC/icc_${PERIPH_SUFFIX}${PERIPH_ID}.c
+ ${MSDK_LIB}/PeriphDrivers/Source/ICC/icc_reva.c
+ ${MSDK_LIB}/PeriphDrivers/Source/UART/uart_common.c
+ ${MSDK_LIB}/PeriphDrivers/Source/UART/uart_${PERIPH_SUFFIX}${PERIPH_ID}.c
+ )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${MSDK_LIB}/CMSIS/5.9.0/Core/Include
+ ${MSDK_LIB}/CMSIS/Device/Maxim/${MAX_DEVICE_UPPER}/Include
+ ${MSDK_LIB}/PeriphDrivers/Include/${MAX_DEVICE_UPPER}
+ ${MSDK_LIB}/PeriphDrivers/Source/SYS
+ ${MSDK_LIB}/PeriphDrivers/Source/GPIO
+ ${MSDK_LIB}/PeriphDrivers/Source/ICC
+ ${MSDK_LIB}/PeriphDrivers/Source/FLC
+ ${MSDK_LIB}/PeriphDrivers/Source/UART
+ )
+
+ # device specific
+ if (${MAX_DEVICE} STREQUAL "max32650" OR
+ ${MAX_DEVICE} STREQUAL "max32665" OR ${MAX_DEVICE} STREQUAL "max32666")
+ target_sources(${BOARD_TARGET} PRIVATE
+ ${MSDK_LIB}/PeriphDrivers/Source/ICC/icc_common.c
+ ${MSDK_LIB}/PeriphDrivers/Source/TPU/tpu_${PERIPH_SUFFIX}${PERIPH_ID}.c
+ ${MSDK_LIB}/PeriphDrivers/Source/TPU/tpu_reva.c
+ ${MSDK_LIB}/PeriphDrivers/Source/UART/uart_reva.c
+ )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${MSDK_LIB}/PeriphDrivers/Source/TPU
+ )
+ elseif (${MAX_DEVICE} STREQUAL "max32690")
+ target_sources(${BOARD_TARGET} PRIVATE
+ ${MSDK_LIB}/PeriphDrivers/Source/CTB/ctb_${PERIPH_SUFFIX}${PERIPH_ID}.c
+ ${MSDK_LIB}/PeriphDrivers/Source/CTB/ctb_reva.c
+ ${MSDK_LIB}/PeriphDrivers/Source/CTB/ctb_common.c
+ ${MSDK_LIB}/PeriphDrivers/Source/UART/uart_revb.c
+ )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${MSDK_LIB}/PeriphDrivers/Source/CTB
+ )
+ elseif (${MAX_DEVICE} STREQUAL "max78002")
+ target_sources(${BOARD_TARGET} PRIVATE
+ ${MSDK_LIB}/PeriphDrivers/Source/AES/aes_${PERIPH_SUFFIX}${PERIPH_ID}.c
+ ${MSDK_LIB}/PeriphDrivers/Source/AES/aes_revb.c
+ ${MSDK_LIB}/PeriphDrivers/Source/TRNG/trng_${PERIPH_SUFFIX}${PERIPH_ID}.c
+ ${MSDK_LIB}/PeriphDrivers/Source/TRNG/trng_revb.c
+ ${MSDK_LIB}/PeriphDrivers/Source/UART/uart_revb.c
+ )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${MSDK_LIB}/PeriphDrivers/Source/AES
+ ${MSDK_LIB}/PeriphDrivers/Source/TRNG
+ )
+ else()
+ message(FATAL_ERROR "Unsupported MAX device: ${MAX_DEVICE}")
+ endif()
+
+ target_compile_definitions(${BOARD_TARGET} PUBLIC
+ TARGET=${MAX_DEVICE_UPPER}
+ TARGET_REV=0x4131
+ MXC_ASSERT_ENABLE
+ ${MAX_DEVICE_UPPER}
+ IAR_PRAGMAS=0
+ MAX_PERIPH_ID=${PERIPH_ID}
+ BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
+ )
+ target_compile_options(${BOARD_TARGET} PRIVATE
+ -Wno-error=strict-prototypes
+ )
+ update_board(${BOARD_TARGET})
+
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--script=${LD_FILE_GNU}"
+ -nostartfiles
+ --specs=nosys.specs --specs=nano.specs
+ )
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--script=${LD_FILE_Clang}"
+ )
+ endif ()
+endfunction()
+
+
+#------------------------------------
+# Functions
+#------------------------------------
+function(family_configure_example TARGET RTOS)
+ family_configure_common(${TARGET} ${RTOS})
+
+ # Board target
+ add_board_target(board_${BOARD})
+
+ #---------- Port Specific ----------
+ # These files are built for each example since it depends on example's tusb_config.h
+ target_sources(${TARGET} PUBLIC
+ # BSP
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
+ )
+ target_include_directories(${TARGET} PUBLIC
+ # family, hw, board
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
+ )
+
+ # Add TinyUSB target and port source
+ family_add_tinyusb(${TARGET} OPT_MCU_${MAX_DEVICE_UPPER})
+ target_sources(${TARGET} PUBLIC
+ ${TOP}/src/portable/mentor/musb/dcd_musb.c
+ )
+ target_compile_options(${TARGET} PRIVATE
+ -Wno-error=strict-prototypes
+ )
+ target_link_libraries(${TARGET} PUBLIC board_${BOARD})
+
+ # Flashing
+ family_add_bin_hex(${TARGET})
+ family_flash_jlink(${TARGET})
+
+ sign_image(${TARGET}) # for secured device such as max32651
+ family_flash_openocd_adi(${TARGET})
+endfunction()
diff --git a/hw/bsp/maxim/family.mk b/hw/bsp/maxim/family.mk
new file mode 100644
index 000000000..3ddf8cf39
--- /dev/null
+++ b/hw/bsp/maxim/family.mk
@@ -0,0 +1,190 @@
+MSDK_LIB = hw/mcu/analog/msdk/Libraries
+
+# Add any board specific make rules
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+CPU_CORE ?= cortex-m4
+PORT ?= 0
+JLINK_DEVICE = ${MAX_DEVICE}
+MAX_DEVICE_UPPER = $(call to_upper,${MAX_DEVICE})
+
+ifeq ($(MAX_DEVICE),max32650)
+ PERIPH_ID = 10
+ PERIPH_SUFFIX = me
+endif
+
+ifneq ($(filter $(MAX_DEVICE),max32665 max32666),)
+ PERIPH_ID = 14
+ PERIPH_SUFFIX = me
+endif
+
+ifeq ($(MAX_DEVICE),max32690)
+ PERIPH_ID = 18
+ PERIPH_SUFFIX = me
+endif
+
+ifeq ($(MAX_DEVICE),max78002)
+ PERIPH_ID = 87
+ PERIPH_SUFFIX = ai
+endif
+
+ifndef PERIPH_ID
+ $(error Unsupported MAX device: ${MAX_DEVICE})
+endif
+
+# Configure the flash rule. By default, use JLink.
+SIGNED_BUILD ?= 0
+DEFAULT_FLASH = flash-jlink
+
+# --------------
+# Compiler Flags
+# --------------
+CFLAGS += \
+ -DTARGET=${MAX_DEVICE_UPPER}\
+ -DTARGET_REV=0x4131 \
+ -DMXC_ASSERT_ENABLE \
+ -D${MAX_DEVICE_UPPER} \
+ -DIAR_PRAGMAS=0 \
+ -DMAX_PERIPH_ID=${PERIPH_ID} \
+ -DCFG_TUSB_MCU=OPT_MCU_${MAX_DEVICE_UPPER} \
+ -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED
+
+# mcu driver cause following warnings
+CFLAGS += \
+ -Wno-error=old-style-declaration \
+ -Wno-error=redundant-decls \
+ -Wno-error=strict-prototypes \
+ -Wno-error=unused-parameter \
+ -Wno-error=cast-align \
+ -Wno-error=cast-qual \
+ -Wno-error=sign-compare \
+ -Wno-error=enum-conversion \
+
+LDFLAGS_GCC += -nostartfiles --specs=nosys.specs --specs=nano.specs
+LD_FILE_GCC ?= $(FAMILY_PATH)/linker/${MAX_DEVICE}.ld
+
+# If the applications needs to be signed (for the MAX32651), sign it first and
+# then need to use MSDK's OpenOCD to flash it
+# Also need to include the __SLA_FWK__ define to enable the signed header into
+# memory
+ifeq ($(SIGNED_BUILD), 1)
+# Extra definitions to build for the secure part
+CFLAGS += -D__SLA_FWK__
+DEFAULT_FLASH := sign-build flash-msdk
+endif
+
+# -----------------
+# Sources & Include
+# -----------------
+
+# common
+SRC_C += \
+ src/portable/mentor/musb/dcd_musb.c \
+ ${MSDK_LIB}/CMSIS/Device/Maxim/${MAX_DEVICE_UPPER}/Source/heap.c \
+ ${MSDK_LIB}/CMSIS/Device/Maxim/${MAX_DEVICE_UPPER}/Source/system_${MAX_DEVICE}.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/SYS/mxc_assert.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/SYS/mxc_delay.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/SYS/mxc_lock.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/SYS/nvic_table.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/SYS/pins_${PERIPH_SUFFIX}${PERIPH_ID}.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/SYS/sys_${PERIPH_SUFFIX}${PERIPH_ID}.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/FLC/flc_common.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/FLC/flc_${PERIPH_SUFFIX}${PERIPH_ID}.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/FLC/flc_reva.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/GPIO/gpio_common.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/GPIO/gpio_${PERIPH_SUFFIX}${PERIPH_ID}.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/GPIO/gpio_reva.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/ICC/icc_${PERIPH_SUFFIX}${PERIPH_ID}.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/ICC/icc_reva.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/UART/uart_common.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/UART/uart_${PERIPH_SUFFIX}${PERIPH_ID}.c \
+
+SRC_S_GCC += ${MSDK_LIB}/CMSIS/Device/Maxim/${MAX_DEVICE_UPPER}/Source/GCC/startup_${MAX_DEVICE}.S
+
+INC += \
+ $(TOP)/$(BOARD_PATH) \
+ $(TOP)/${MSDK_LIB}/CMSIS/5.9.0/Core/Include \
+ $(TOP)/${MSDK_LIB}/CMSIS/Device/Maxim/${MAX_DEVICE_UPPER}/Include \
+ $(TOP)/${MSDK_LIB}/PeriphDrivers/Include/${MAX_DEVICE_UPPER} \
+ $(TOP)/${MSDK_LIB}/PeriphDrivers/Source/SYS \
+ $(TOP)/${MSDK_LIB}/PeriphDrivers/Source/GPIO \
+ $(TOP)/${MSDK_LIB}/PeriphDrivers/Source/ICC \
+ $(TOP)/${MSDK_LIB}/PeriphDrivers/Source/FLC \
+ $(TOP)/${MSDK_LIB}/PeriphDrivers/Source/UART \
+
+# device specific
+ifneq ($(filter $(MAX_DEVICE),max32650 max32665 max32666),)
+ SRC_C += \
+ ${MSDK_LIB}/PeriphDrivers/Source/ICC/icc_common.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/TPU/tpu_${PERIPH_SUFFIX}${PERIPH_ID}.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/TPU/tpu_reva.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/UART/uart_reva.c \
+
+ INC += $(TOP)/${MSDK_LIB}/PeriphDrivers/Source/TPU
+endif
+
+ifeq (${MAX_DEVICE},max32690)
+ SRC_C += \
+ ${MSDK_LIB}/PeriphDrivers/Source/CTB/ctb_${PERIPH_SUFFIX}${PERIPH_ID}.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/CTB/ctb_reva.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/CTB/ctb_common.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/UART/uart_revb.c \
+
+ INC += ${TOP}/${MSDK_LIB}/PeriphDrivers/Source/CTB
+endif
+
+ifeq (${MAX_DEVICE},max78002)
+ SRC_C += \
+ ${MSDK_LIB}/PeriphDrivers/Source/AES/aes_${PERIPH_SUFFIX}${PERIPH_ID}.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/AES/aes_revb.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/TRNG/trng_${PERIPH_SUFFIX}${PERIPH_ID}.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/TRNG/trng_revb.c \
+ ${MSDK_LIB}/PeriphDrivers/Source/UART/uart_revb.c \
+
+ INC += \
+ ${TOP}/${MSDK_LIB}/PeriphDrivers/Source/AES \
+ ${TOP}/${MSDK_LIB}/PeriphDrivers/Source/TRNG
+endif
+
+
+# The MAX32651EVKIT is pin for pin identical to the MAX32650EVKIT, however the
+# MAX32651 has a secure bootloader which requires the image to be signed before
+# loading into flash. All MAX32651EVKIT's have the same key for evaluation
+# purposes, so create a special flash rule to sign the binary and flash using
+# the MSDK.
+MCU_PATH = $(TOP)/hw/mcu/analog/msdk/
+# Assume no extension for sign utility
+SIGN_EXE = sign_app
+ifeq ($(OS), Windows_NT)
+# Must use .exe extension on Windows, since the binaries
+# for Linux may live in the same place.
+SIGN_EXE := sign_app.exe
+else
+UNAME = $(shell uname -s)
+ifneq ($(findstring MSYS_NT,$(UNAME)),)
+# Must also use .exe extension for MSYS2
+SIGN_EXE := sign_app.exe
+endif
+endif
+
+# Rule to sign the build. This will in-place modify the existing .elf file
+# an populate the .sig section with the signature value
+sign-build: $(BUILD)/$(PROJECT).elf
+ $(OBJCOPY) $(BUILD)/$(PROJECT).elf -R .sig -O binary $(BUILD)/$(PROJECT).bin
+ $(MCU_PATH)/Tools/SBT/bin/$(SIGN_EXE) -c MAX32651 \
+ key_file="$(MCU_PATH)/Tools/SBT/devices/MAX32651/keys/maximtestcrk.key" \
+ ca=$(BUILD)/$(PROJECT).bin sca=$(BUILD)/$(PROJECT).sbin
+ $(OBJCOPY) $(BUILD)/$(PROJECT).elf --update-section .sig=$(BUILD)/$(PROJECT).sig
+
+# Optional flash option when running within an installed MSDK to use OpenOCD
+# Mainline OpenOCD does not yet have the MAX32's flash algorithm integrated.
+# If the MSDK is installed, flash-msdk can be run to utilize the the modified
+# openocd with the algorithms
+MAXIM_PATH := $(subst \,/,$(MAXIM_PATH))
+flash-msdk: $(BUILD)/$(PROJECT).elf
+ $(MAXIM_PATH)/Tools/OpenOCD/openocd -s $(MAXIM_PATH)/Tools/OpenOCD/scripts \
+ -f interface/cmsis-dap.cfg -f target/max32650.cfg \
+ -c "program $(BUILD)/$(PROJECT).elf verify; init; reset; exit"
+
+# Configure the flash rule
+flash: $(DEFAULT_FLASH)
diff --git a/hw/bsp/max32650/boards/max32650evkit/max32650.ld b/hw/bsp/maxim/linker/max32650.ld
similarity index 100%
rename from hw/bsp/max32650/boards/max32650evkit/max32650.ld
rename to hw/bsp/maxim/linker/max32650.ld
diff --git a/hw/bsp/max32650/boards/max32651evkit/max32651.ld b/hw/bsp/maxim/linker/max32651.ld
similarity index 100%
rename from hw/bsp/max32650/boards/max32651evkit/max32651.ld
rename to hw/bsp/maxim/linker/max32651.ld
diff --git a/hw/bsp/max32666/max32666.ld b/hw/bsp/maxim/linker/max32665.ld
similarity index 100%
rename from hw/bsp/max32666/max32666.ld
rename to hw/bsp/maxim/linker/max32665.ld
diff --git a/hw/bsp/max32690/max32690.ld b/hw/bsp/maxim/linker/max32690.ld
similarity index 100%
rename from hw/bsp/max32690/max32690.ld
rename to hw/bsp/maxim/linker/max32690.ld
diff --git a/hw/bsp/max78002/max78002.ld b/hw/bsp/maxim/linker/max78002.ld
similarity index 100%
rename from hw/bsp/max78002/max78002.ld
rename to hw/bsp/maxim/linker/max78002.ld
diff --git a/hw/bsp/mcx/boards/frdm_mcxa153/board.h b/hw/bsp/mcx/boards/frdm_mcxa153/board.h
index fb1290088..86f987de9 100644
--- a/hw/bsp/mcx/boards/frdm_mcxa153/board.h
+++ b/hw/bsp/mcx/boards/frdm_mcxa153/board.h
@@ -39,10 +39,10 @@ extern "C" {
// LED
#define LED_GPIO GPIO3
#define LED_CLK kCLOCK_GateGPIO3
-#define LED_PIN 12 // red
+#define LED_PIN 12 //red
#define LED_STATE_ON 0
-// ISP button (Dummy, use unused pin
+// ISP button
#define BUTTON_GPIO GPIO3
#define BUTTON_CLK kCLOCK_GateGPIO3
#define BUTTON_PIN 29 //sw2
diff --git a/hw/bsp/mcx/boards/frdm_mcxa153/clock_config.c b/hw/bsp/mcx/boards/frdm_mcxa153/clock_config.c
index f16bc51f6..5a132dc67 100644
--- a/hw/bsp/mcx/boards/frdm_mcxa153/clock_config.c
+++ b/hw/bsp/mcx/boards/frdm_mcxa153/clock_config.c
@@ -45,14 +45,13 @@ processor_version: 0.13.0
* Variables
******************************************************************************/
/* System clock frequency. */
-//uint32_t SystemCoreClock;
+//extern uint32_t SystemCoreClock;
/*******************************************************************************
************************ BOARD_InitBootClocks function ************************
******************************************************************************/
void BOARD_InitBootClocks(void)
{
- BOARD_BootClockFRO96M();
}
/*******************************************************************************
@@ -386,7 +385,6 @@ void BOARD_BootClockFRO64M(void)
/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
!!Configuration
name: BOARD_BootClockFRO96M
-called_from_default_init: true
outputs:
- {id: CLK_1M_clock.outFreq, value: 1 MHz}
- {id: CLK_48M_clock.outFreq, value: 48 MHz}
diff --git a/hw/bsp/mcx/boards/frdm_mcxa153/pin_mux.c b/hw/bsp/mcx/boards/frdm_mcxa153/pin_mux.c
index cc8f56e63..47709951b 100644
--- a/hw/bsp/mcx/boards/frdm_mcxa153/pin_mux.c
+++ b/hw/bsp/mcx/boards/frdm_mcxa153/pin_mux.c
@@ -4,7 +4,6 @@
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-
/***********************************************************************************************************************
* This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file
* will be overwritten if the respective MCUXpresso Config Tools is used to update this file.
@@ -18,16 +17,13 @@ product: Pins v14.0
processor: MCXA153
package_id: MCXA153VLH
mcu_data: ksdk2_0
-processor_version: 0.14.3
-pin_labels:
-- {pin_num: '38', pin_signal: P3_12/LPUART2_RTS_B/CT1_MAT2/PWM0_X0, label: LED_RED, identifier: LED_RED}
+processor_version: 0.14.4
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
*/
/* clang-format on */
#include "fsl_common.h"
#include "fsl_port.h"
-#include "fsl_gpio.h"
#include "pin_mux.h"
/* FUNCTION ************************************************************************************************************
@@ -47,8 +43,10 @@ void BOARD_InitBootPins(void)
BOARD_InitPins:
- options: {callFromInitBoot: 'true', coreID: cm33_core0, enableClock: 'true'}
- pin_list:
- - {pin_num: '38', peripheral: GPIO3, signal: 'GPIO, 12', pin_signal: P3_12/LPUART2_RTS_B/CT1_MAT2/PWM0_X0, direction: OUTPUT, gpio_init_state: 'false', slew_rate: fast,
- open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal}
+ - {pin_num: '51', peripheral: LPUART0, signal: RX, pin_signal: P0_2/TDO/SWO/LPUART0_RXD/LPSPI0_SCK/CT0_MAT0/UTICK_CAP0/I3C0_PUR, slew_rate: fast, open_drain: disable,
+ drive_strength: low, pull_select: up, pull_enable: enable, input_buffer: enable, invert_input: normal}
+ - {pin_num: '52', peripheral: LPUART0, signal: TX, pin_signal: P0_3/TDI/LPUART0_TXD/LPSPI0_SDO/CT0_MAT1/UTICK_CAP1/CMP0_OUT/CMP1_IN1, slew_rate: fast, open_drain: disable,
+ drive_strength: low, pull_select: up, pull_enable: enable, input_buffer: enable, invert_input: normal}
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
*/
/* clang-format on */
@@ -61,15 +59,6 @@ BOARD_InitPins:
* END ****************************************************************************************************************/
void BOARD_InitPins(void)
{
- RESET_PeripheralReset(kLPUART0_RST_SHIFT_RSTn);
- RESET_PeripheralReset(kPORT0_RST_SHIFT_RSTn);
- CLOCK_SetClockDiv(kCLOCK_DivLPUART0, 1u);
- CLOCK_AttachClk(kFRO12M_to_LPUART0);
-
- /* write to PORT0: Peripheral clock is enabled */
- CLOCK_EnableClock(kCLOCK_GatePORT0);
-
- /* Write to GPIO3: Peripheral clock is enabled */
CLOCK_EnableClock(kCLOCK_GateGPIO3);
/* Write to PORT3: Peripheral clock is enabled */
CLOCK_EnableClock(kCLOCK_GatePORT3);
@@ -78,30 +67,13 @@ void BOARD_InitPins(void)
/* PORT3 peripheral is released from reset */
RESET_ReleasePeripheralReset(kPORT3_RST_SHIFT_RSTn);
- const port_pin_config_t port3_12_pin38_config = {/* Internal pull-up/down resistor is disabled */
- kPORT_PullDisable,
- /* Low internal pull resistor value is selected. */
- kPORT_LowPullResistor,
- /* Fast slew rate is configured */
- kPORT_FastSlewRate,
- /* Passive input filter is disabled */
- kPORT_PassiveFilterDisable,
- /* Open drain output is disabled */
- kPORT_OpenDrainDisable,
- /* Low drive strength is configured */
- kPORT_LowDriveStrength,
- /* Normal drive strength is configured */
- kPORT_NormalDriveStrength,
- /* Pin is configured as P3_12 */
- kPORT_MuxAlt0,
- /* Digital input enabled */
- kPORT_InputBufferEnable,
- /* Digital input is not inverted */
- kPORT_InputNormal,
- /* Pin Control Register fields [15:0] are not locked */
- kPORT_UnlockRegister};
- /* PORT3_12 (pin 38) is configured as P3_12 */
- PORT_SetPinConfig(PORT3, 12U, &port3_12_pin38_config);
+
+ /* Write to PORT0: Peripheral clock is enabled */
+ CLOCK_EnableClock(kCLOCK_GatePORT0);
+ /* LPUART0 peripheral is released from reset */
+ RESET_ReleasePeripheralReset(kLPUART0_RST_SHIFT_RSTn);
+ /* PORT0 peripheral is released from reset */
+ RESET_ReleasePeripheralReset(kPORT0_RST_SHIFT_RSTn);
const port_pin_config_t port0_2_pin51_config = {/* Internal pull-up resistor is enabled */
kPORT_PullUp,
@@ -152,7 +124,6 @@ void BOARD_InitPins(void)
kPORT_UnlockRegister};
/* PORT0_3 (pin 52) is configured as LPUART0_TXD */
PORT_SetPinConfig(PORT0, 3U, &port0_3_pin52_config);
-
}
/***********************************************************************************************************************
* EOF
diff --git a/hw/bsp/mcx/boards/frdm_mcxa153/pin_mux.h b/hw/bsp/mcx/boards/frdm_mcxa153/pin_mux.h
index 06b6fdee9..2c0e617a5 100644
--- a/hw/bsp/mcx/boards/frdm_mcxa153/pin_mux.h
+++ b/hw/bsp/mcx/boards/frdm_mcxa153/pin_mux.h
@@ -1,9 +1,13 @@
/*
- * Copyright 2022 NXP
+ * Copyright 2023 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+/***********************************************************************************************************************
+ * This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file
+ * will be overwritten if the respective MCUXpresso Config Tools is used to update this file.
+ **********************************************************************************************************************/
#ifndef _PIN_MUX_H_
#define _PIN_MUX_H_
diff --git a/hw/bsp/mcx/boards/frdm_mcxa156/board.cmake b/hw/bsp/mcx/boards/frdm_mcxa156/board.cmake
new file mode 100644
index 000000000..a6aa6c2e4
--- /dev/null
+++ b/hw/bsp/mcx/boards/frdm_mcxa156/board.cmake
@@ -0,0 +1,21 @@
+set(MCU_VARIANT MCXA156)
+set(MCU_CORE MCXA156)
+
+set(JLINK_DEVICE MCXA156_M33)
+set(PYOCD_TARGET MCXA156)
+set(NXPLINK_DEVICE MCXA156:MCXA156)
+
+set(PORT 0)
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC
+ CPU_MCXA156VLH
+ BOARD_TUD_RHPORT=0
+ BOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED
+ CFG_EXAMPLE_VIDEO_READONLY
+ )
+ target_sources(${TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/clock_config.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/pin_mux.c
+ )
+endfunction()
diff --git a/hw/bsp/mcx/boards/frdm_mcxa156/board.h b/hw/bsp/mcx/boards/frdm_mcxa156/board.h
new file mode 100644
index 000000000..6c19797c6
--- /dev/null
+++ b/hw/bsp/mcx/boards/frdm_mcxa156/board.h
@@ -0,0 +1,69 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ name: Freedom MCXA156
+ url: https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-MCXA156
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// LED
+#define LED_GPIO GPIO3
+#define LED_CLK kCLOCK_GateGPIO3
+#define LED_PIN 12 // red
+#define LED_STATE_ON 0
+
+// ISP button
+#define BUTTON_GPIO GPIO0
+#define BUTTON_CLK kCLOCK_GateGPIO0
+#define BUTTON_PIN 6 //SW3
+#define BUTTON_STATE_ACTIVE 0
+
+// UART
+#define UART_DEV LPUART0
+
+static inline void board_uart_init_clock(void) {
+ /* attach 12 MHz clock to LPUART0 (debug console) */
+ CLOCK_SetClockDiv(kCLOCK_DivLPUART0, 1u);
+ CLOCK_AttachClk(kFRO12M_to_LPUART0);
+
+ RESET_PeripheralReset(kLPUART0_RST_SHIFT_RSTn);
+}
+
+// XTAL
+#define XTAL0_CLK_HZ (24 * 1000 * 1000U)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/bsp/mcx/boards/frdm_mcxa156/board.mk b/hw/bsp/mcx/boards/frdm_mcxa156/board.mk
new file mode 100644
index 000000000..d4a59b32a
--- /dev/null
+++ b/hw/bsp/mcx/boards/frdm_mcxa156/board.mk
@@ -0,0 +1,14 @@
+MCU_VARIANT = MCXA156
+MCU_CORE = MCXA156
+PORT = 0
+
+CPU_CORE = cortex-m33-nodsp-nofp
+CFLAGS += \
+ -DCPU_MCXA156VLH \
+ -DCFG_TUSB_MCU=OPT_MCU_MCXA15 \
+
+JLINK_DEVICE = MCXA156
+PYOCD_TARGET = MCXA156
+
+# flash using pyocd
+flash: flash-jlink
diff --git a/hw/bsp/mcx/boards/frdm_mcxa156/clock_config.c b/hw/bsp/mcx/boards/frdm_mcxa156/clock_config.c
new file mode 100644
index 000000000..f549af243
--- /dev/null
+++ b/hw/bsp/mcx/boards/frdm_mcxa156/clock_config.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/***********************************************************************************************************************
+ * This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file
+ * will be overwritten if the respective MCUXpresso Config Tools is used to update this file.
+ **********************************************************************************************************************/
+/*
+ * How to setup clock using clock driver functions:
+ *
+ * 1. Setup clock sources.
+ *
+ * 2. Set up wait states of the flash.
+ *
+ * 3. Set up all dividers.
+ *
+ * 4. Set up all selectors to provide selected clocks.
+ *
+ */
+
+/* clang-format off */
+/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+!!GlobalInfo
+product: Clocks v13.0
+processor: MCXA156
+package_id: MCXA156VLL
+mcu_data: ksdk2_0
+processor_version: 0.15.0
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
+/* clang-format on */
+
+#include "fsl_clock.h"
+#include "clock_config.h"
+#include "fsl_spc.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* System clock frequency. */
+//extern uint32_t SystemCoreClock;
+
+/*******************************************************************************
+ ************************ BOARD_InitBootClocks function ************************
+ ******************************************************************************/
+void BOARD_InitBootClocks(void)
+{
+ BOARD_BootClockFRO96M();
+}
+
+/*******************************************************************************
+ ******************** Configuration BOARD_BootClockFRO12M **********************
+ ******************************************************************************/
+/* clang-format off */
+/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+!!Configuration
+name: BOARD_BootClockFRO12M
+outputs:
+- {id: CLK_1M_clock.outFreq, value: 1 MHz}
+- {id: CPU_clock.outFreq, value: 12 MHz}
+- {id: FRO_12M_clock.outFreq, value: 12 MHz}
+- {id: MAIN_clock.outFreq, value: 12 MHz}
+- {id: Slow_clock.outFreq, value: 3 MHz}
+- {id: System_clock.outFreq, value: 12 MHz}
+- {id: UTICK_clock.outFreq, value: 1 MHz}
+settings:
+- {id: SCGMode, value: SIRC}
+- {id: FRO_HF_PERIPHERALS_EN_CFG, value: Disabled}
+- {id: MRCC.FREQMEREFCLKSEL.sel, value: MRCC.aoi0_out0}
+- {id: MRCC.FREQMETARGETCLKSEL.sel, value: MRCC.aoi0_out0}
+- {id: MRCC.OSTIMERCLKSEL.sel, value: VBAT.CLK16K_1}
+- {id: SCG.SCSSEL.sel, value: SCG.SIRC}
+- {id: SCG_FIRCCSR_FIRCEN_CFG, value: Disabled}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
+/* clang-format on */
+
+/*******************************************************************************
+ * Variables for BOARD_BootClockFRO12M configuration
+ ******************************************************************************/
+/*******************************************************************************
+ * Code for BOARD_BootClockFRO12M configuration
+ ******************************************************************************/
+void BOARD_BootClockFRO12M(void)
+{
+ uint32_t coreFreq;
+ spc_active_mode_core_ldo_option_t ldoOption;
+ spc_sram_voltage_config_t sramOption;
+
+ /* Get the CPU Core frequency */
+ coreFreq = CLOCK_GetCoreSysClkFreq();
+
+ /* The flow of increasing voltage and frequency */
+ if (coreFreq <= BOARD_BOOTCLOCKFRO12M_CORE_CLOCK) {
+ /* Set the LDO_CORE VDD regulator level */
+ ldoOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage;
+ ldoOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
+ (void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOption);
+ /* Configure Flash to support different voltage level and frequency */
+ FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x0U));
+ /* Specifies the operating voltage for the SRAM's read/write timing margin */
+ sramOption.operateVoltage = kSPC_sramOperateAt1P0V;
+ sramOption.requestVoltageUpdate = true;
+ (void)SPC_SetSRAMOperateVoltage(SPC0, &sramOption);
+ }
+
+ CLOCK_SetupFRO12MClocking(); /*!< Setup FRO12M clock */
+
+ CLOCK_AttachClk(kFRO12M_to_MAIN_CLK); /* !< Switch MAIN_CLK to FRO12M */
+
+ /* The flow of decreasing voltage and frequency */
+ if (coreFreq > BOARD_BOOTCLOCKFRO12M_CORE_CLOCK) {
+ /* Configure Flash to support different voltage level and frequency */
+ FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x0U));
+ /* Specifies the operating voltage for the SRAM's read/write timing margin */
+ sramOption.operateVoltage = kSPC_sramOperateAt1P0V;
+ sramOption.requestVoltageUpdate = true;
+ (void)SPC_SetSRAMOperateVoltage(SPC0, &sramOption);
+ /* Set the LDO_CORE VDD regulator level */
+ ldoOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage;
+ ldoOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
+ (void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOption);
+ }
+
+ /*!< Set up clock selectors - Attach clocks to the peripheries */
+
+ /*!< Set up dividers */
+ CLOCK_SetClockDiv(kCLOCK_DivAHBCLK, 1U); /* !< Set AHBCLKDIV divider to value 1 */
+
+ /* Set SystemCoreClock variable */
+ SystemCoreClock = BOARD_BOOTCLOCKFRO12M_CORE_CLOCK;
+}
+/*******************************************************************************
+ ******************** Configuration BOARD_BootClockFRO24M **********************
+ ******************************************************************************/
+/* clang-format off */
+/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+!!Configuration
+name: BOARD_BootClockFRO24M
+outputs:
+- {id: CLK_1M_clock.outFreq, value: 1 MHz}
+- {id: CLK_48M_clock.outFreq, value: 48 MHz}
+- {id: CPU_clock.outFreq, value: 24 MHz}
+- {id: FRO_12M_clock.outFreq, value: 12 MHz}
+- {id: FRO_HF_DIV_clock.outFreq, value: 48 MHz}
+- {id: FRO_HF_clock.outFreq, value: 48 MHz}
+- {id: MAIN_clock.outFreq, value: 48 MHz}
+- {id: Slow_clock.outFreq, value: 6 MHz}
+- {id: System_clock.outFreq, value: 24 MHz}
+- {id: UTICK_clock.outFreq, value: 1 MHz}
+settings:
+- {id: MRCC.FREQMEREFCLKSEL.sel, value: MRCC.aoi0_out0}
+- {id: MRCC.FREQMETARGETCLKSEL.sel, value: MRCC.aoi0_out0}
+- {id: MRCC.OSTIMERCLKSEL.sel, value: VBAT.CLK16K_1}
+- {id: SYSCON.AHBCLKDIV.scale, value: '2', locked: true}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
+/* clang-format on */
+
+/*******************************************************************************
+ * Variables for BOARD_BootClockFRO24M configuration
+ ******************************************************************************/
+/*******************************************************************************
+ * Code for BOARD_BootClockFRO24M configuration
+ ******************************************************************************/
+void BOARD_BootClockFRO24M(void)
+{
+ uint32_t coreFreq;
+ spc_active_mode_core_ldo_option_t ldoOption;
+ spc_sram_voltage_config_t sramOption;
+
+ /* Get the CPU Core frequency */
+ coreFreq = CLOCK_GetCoreSysClkFreq();
+
+ /* The flow of increasing voltage and frequency */
+ if (coreFreq <= BOARD_BOOTCLOCKFRO24M_CORE_CLOCK) {
+ /* Set the LDO_CORE VDD regulator level */
+ ldoOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage;
+ ldoOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
+ (void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOption);
+ /* Configure Flash to support different voltage level and frequency */
+ FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x0U));
+ /* Specifies the operating voltage for the SRAM's read/write timing margin */
+ sramOption.operateVoltage = kSPC_sramOperateAt1P0V;
+ sramOption.requestVoltageUpdate = true;
+ (void)SPC_SetSRAMOperateVoltage(SPC0, &sramOption);
+ }
+
+ CLOCK_SetupFROHFClocking(48000000U); /*!< Enable FRO HF(48MHz) output */
+
+ CLOCK_SetupFRO12MClocking(); /*!< Setup FRO12M clock */
+
+ CLOCK_AttachClk(kFRO_HF_to_MAIN_CLK); /* !< Switch MAIN_CLK to FRO_HF */
+
+ /* The flow of decreasing voltage and frequency */
+ if (coreFreq > BOARD_BOOTCLOCKFRO24M_CORE_CLOCK) {
+ /* Configure Flash to support different voltage level and frequency */
+ FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x0U));
+ /* Specifies the operating voltage for the SRAM's read/write timing margin */
+ sramOption.operateVoltage = kSPC_sramOperateAt1P0V;
+ sramOption.requestVoltageUpdate = true;
+ (void)SPC_SetSRAMOperateVoltage(SPC0, &sramOption);
+ /* Set the LDO_CORE VDD regulator level */
+ ldoOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage;
+ ldoOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
+ (void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOption);
+ }
+
+ /*!< Set up clock selectors - Attach clocks to the peripheries */
+
+ /*!< Set up dividers */
+ CLOCK_SetClockDiv(kCLOCK_DivAHBCLK, 2U); /* !< Set AHBCLKDIV divider to value 2 */
+ CLOCK_SetClockDiv(kCLOCK_DivFRO_HF_DIV, 1U); /* !< Set FROHFDIV divider to value 1 */
+
+ /* Set SystemCoreClock variable */
+ SystemCoreClock = BOARD_BOOTCLOCKFRO24M_CORE_CLOCK;
+}
+/*******************************************************************************
+ ******************** Configuration BOARD_BootClockFRO48M **********************
+ ******************************************************************************/
+/* clang-format off */
+/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+!!Configuration
+name: BOARD_BootClockFRO48M
+outputs:
+- {id: CLK_1M_clock.outFreq, value: 1 MHz}
+- {id: CLK_48M_clock.outFreq, value: 48 MHz}
+- {id: CPU_clock.outFreq, value: 48 MHz}
+- {id: FRO_12M_clock.outFreq, value: 12 MHz}
+- {id: FRO_HF_DIV_clock.outFreq, value: 48 MHz}
+- {id: FRO_HF_clock.outFreq, value: 48 MHz}
+- {id: MAIN_clock.outFreq, value: 48 MHz}
+- {id: Slow_clock.outFreq, value: 12 MHz}
+- {id: System_clock.outFreq, value: 48 MHz}
+- {id: UTICK_clock.outFreq, value: 1 MHz}
+settings:
+- {id: MRCC.FREQMEREFCLKSEL.sel, value: MRCC.aoi0_out0}
+- {id: MRCC.FREQMETARGETCLKSEL.sel, value: MRCC.aoi0_out0}
+- {id: MRCC.OSTIMERCLKSEL.sel, value: VBAT.CLK16K_1}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
+/* clang-format on */
+
+/*******************************************************************************
+ * Variables for BOARD_BootClockFRO48M configuration
+ ******************************************************************************/
+/*******************************************************************************
+ * Code for BOARD_BootClockFRO48M configuration
+ ******************************************************************************/
+void BOARD_BootClockFRO48M(void)
+{
+ uint32_t coreFreq;
+ spc_active_mode_core_ldo_option_t ldoOption;
+ spc_sram_voltage_config_t sramOption;
+
+ /* Get the CPU Core frequency */
+ coreFreq = CLOCK_GetCoreSysClkFreq();
+
+ /* The flow of increasing voltage and frequency */
+ if (coreFreq <= BOARD_BOOTCLOCKFRO48M_CORE_CLOCK) {
+ /* Set the LDO_CORE VDD regulator level */
+ ldoOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage;
+ ldoOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
+ (void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOption);
+ /* Configure Flash to support different voltage level and frequency */
+ FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x1U));
+ /* Specifies the operating voltage for the SRAM's read/write timing margin */
+ sramOption.operateVoltage = kSPC_sramOperateAt1P0V;
+ sramOption.requestVoltageUpdate = true;
+ (void)SPC_SetSRAMOperateVoltage(SPC0, &sramOption);
+ }
+
+ CLOCK_SetupFROHFClocking(48000000U); /*!< Enable FRO HF(48MHz) output */
+
+ CLOCK_SetupFRO12MClocking(); /*!< Setup FRO12M clock */
+
+ CLOCK_AttachClk(kFRO_HF_to_MAIN_CLK); /* !< Switch MAIN_CLK to FRO_HF */
+
+ /* The flow of decreasing voltage and frequency */
+ if (coreFreq > BOARD_BOOTCLOCKFRO48M_CORE_CLOCK) {
+ /* Configure Flash to support different voltage level and frequency */
+ FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x1U));
+ /* Specifies the operating voltage for the SRAM's read/write timing margin */
+ sramOption.operateVoltage = kSPC_sramOperateAt1P0V;
+ sramOption.requestVoltageUpdate = true;
+ (void)SPC_SetSRAMOperateVoltage(SPC0, &sramOption);
+ /* Set the LDO_CORE VDD regulator level */
+ ldoOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage;
+ ldoOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
+ (void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOption);
+ }
+
+ /*!< Set up clock selectors - Attach clocks to the peripheries */
+
+ /*!< Set up dividers */
+ CLOCK_SetClockDiv(kCLOCK_DivAHBCLK, 1U); /* !< Set AHBCLKDIV divider to value 1 */
+ CLOCK_SetClockDiv(kCLOCK_DivFRO_HF_DIV, 1U); /* !< Set FROHFDIV divider to value 1 */
+
+ /* Set SystemCoreClock variable */
+ SystemCoreClock = BOARD_BOOTCLOCKFRO48M_CORE_CLOCK;
+}
+/*******************************************************************************
+ ******************** Configuration BOARD_BootClockFRO64M **********************
+ ******************************************************************************/
+/* clang-format off */
+/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+!!Configuration
+name: BOARD_BootClockFRO64M
+outputs:
+- {id: CLK_1M_clock.outFreq, value: 1 MHz}
+- {id: CLK_48M_clock.outFreq, value: 48 MHz}
+- {id: CPU_clock.outFreq, value: 64 MHz}
+- {id: FRO_12M_clock.outFreq, value: 12 MHz}
+- {id: FRO_HF_DIV_clock.outFreq, value: 64 MHz}
+- {id: FRO_HF_clock.outFreq, value: 64 MHz}
+- {id: MAIN_clock.outFreq, value: 64 MHz}
+- {id: Slow_clock.outFreq, value: 16 MHz}
+- {id: System_clock.outFreq, value: 64 MHz}
+- {id: UTICK_clock.outFreq, value: 1 MHz}
+settings:
+- {id: VDD_CORE, value: voltage_1v1}
+- {id: MRCC.FREQMEREFCLKSEL.sel, value: MRCC.aoi0_out0}
+- {id: MRCC.FREQMETARGETCLKSEL.sel, value: MRCC.aoi0_out0}
+- {id: MRCC.FROHFDIV.scale, value: '1', locked: true}
+- {id: MRCC.OSTIMERCLKSEL.sel, value: VBAT.CLK16K_1}
+- {id: SYSCON.AHBCLKDIV.scale, value: '1', locked: true}
+sources:
+- {id: SCG.FIRC.outFreq, value: 64 MHz}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
+/* clang-format on */
+
+/*******************************************************************************
+ * Variables for BOARD_BootClockFRO64M configuration
+ ******************************************************************************/
+/*******************************************************************************
+ * Code for BOARD_BootClockFRO64M configuration
+ ******************************************************************************/
+void BOARD_BootClockFRO64M(void)
+{
+ uint32_t coreFreq;
+ spc_active_mode_core_ldo_option_t ldoOption;
+ spc_sram_voltage_config_t sramOption;
+
+ /* Get the CPU Core frequency */
+ coreFreq = CLOCK_GetCoreSysClkFreq();
+
+ /* The flow of increasing voltage and frequency */
+ if (coreFreq <= BOARD_BOOTCLOCKFRO64M_CORE_CLOCK) {
+ /* Set the LDO_CORE VDD regulator level */
+ ldoOption.CoreLDOVoltage = kSPC_CoreLDO_NormalVoltage;
+ ldoOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
+ (void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOption);
+ /* Configure Flash to support different voltage level and frequency */
+ FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x1U));
+ /* Specifies the operating voltage for the SRAM's read/write timing margin */
+ sramOption.operateVoltage = kSPC_sramOperateAt1P1V;
+ sramOption.requestVoltageUpdate = true;
+ (void)SPC_SetSRAMOperateVoltage(SPC0, &sramOption);
+ }
+
+ CLOCK_SetupFROHFClocking(64000000U); /*!< Enable FRO HF(64MHz) output */
+
+ CLOCK_SetupFRO12MClocking(); /*!< Setup FRO12M clock */
+
+ CLOCK_AttachClk(kFRO_HF_to_MAIN_CLK); /* !< Switch MAIN_CLK to FRO_HF */
+
+ /* The flow of decreasing voltage and frequency */
+ if (coreFreq > BOARD_BOOTCLOCKFRO64M_CORE_CLOCK) {
+ /* Configure Flash to support different voltage level and frequency */
+ FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x1U));
+ /* Specifies the operating voltage for the SRAM's read/write timing margin */
+ sramOption.operateVoltage = kSPC_sramOperateAt1P1V;
+ sramOption.requestVoltageUpdate = true;
+ (void)SPC_SetSRAMOperateVoltage(SPC0, &sramOption);
+ /* Set the LDO_CORE VDD regulator level */
+ ldoOption.CoreLDOVoltage = kSPC_CoreLDO_NormalVoltage;
+ ldoOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
+ (void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOption);
+ }
+
+ /*!< Set up clock selectors - Attach clocks to the peripheries */
+
+ /*!< Set up dividers */
+ CLOCK_SetClockDiv(kCLOCK_DivAHBCLK, 1U); /* !< Set AHBCLKDIV divider to value 1 */
+ CLOCK_SetClockDiv(kCLOCK_DivFRO_HF_DIV, 1U); /* !< Set FROHFDIV divider to value 1 */
+
+ /* Set SystemCoreClock variable */
+ SystemCoreClock = BOARD_BOOTCLOCKFRO64M_CORE_CLOCK;
+}
+/*******************************************************************************
+ ******************** Configuration BOARD_BootClockFRO96M **********************
+ ******************************************************************************/
+/* clang-format off */
+/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+!!Configuration
+name: BOARD_BootClockFRO96M
+called_from_default_init: true
+outputs:
+- {id: CLK_1M_clock.outFreq, value: 1 MHz}
+- {id: CLK_48M_clock.outFreq, value: 48 MHz}
+- {id: CPU_clock.outFreq, value: 96 MHz}
+- {id: FRO_12M_clock.outFreq, value: 12 MHz}
+- {id: FRO_HF_DIV_clock.outFreq, value: 96 MHz}
+- {id: FRO_HF_clock.outFreq, value: 96 MHz}
+- {id: MAIN_clock.outFreq, value: 96 MHz}
+- {id: Slow_clock.outFreq, value: 24 MHz}
+- {id: System_clock.outFreq, value: 96 MHz}
+- {id: UTICK_clock.outFreq, value: 1 MHz}
+settings:
+- {id: VDD_CORE, value: voltage_1v1}
+- {id: CLKOUTDIV_HALT, value: Enable}
+- {id: MRCC.FREQMEREFCLKSEL.sel, value: MRCC.aoi0_out0}
+- {id: MRCC.FREQMETARGETCLKSEL.sel, value: MRCC.aoi0_out0}
+- {id: MRCC.FROHFDIV.scale, value: '1', locked: true}
+- {id: MRCC.OSTIMERCLKSEL.sel, value: VBAT.CLK16K_1}
+- {id: SYSCON.AHBCLKDIV.scale, value: '1', locked: true}
+sources:
+- {id: SCG.FIRC.outFreq, value: 96 MHz}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
+/* clang-format on */
+
+/*******************************************************************************
+ * Variables for BOARD_BootClockFRO96M configuration
+ ******************************************************************************/
+/*******************************************************************************
+ * Code for BOARD_BootClockFRO96M configuration
+ ******************************************************************************/
+void BOARD_BootClockFRO96M(void)
+{
+ uint32_t coreFreq;
+ spc_active_mode_core_ldo_option_t ldoOption;
+ spc_sram_voltage_config_t sramOption;
+
+ /* Get the CPU Core frequency */
+ coreFreq = CLOCK_GetCoreSysClkFreq();
+
+ /* The flow of increasing voltage and frequency */
+ if (coreFreq <= BOARD_BOOTCLOCKFRO96M_CORE_CLOCK) {
+ /* Set the LDO_CORE VDD regulator level */
+ ldoOption.CoreLDOVoltage = kSPC_CoreLDO_NormalVoltage;
+ ldoOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
+ (void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOption);
+ /* Configure Flash to support different voltage level and frequency */
+ FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x2U));
+ /* Specifies the operating voltage for the SRAM's read/write timing margin */
+ sramOption.operateVoltage = kSPC_sramOperateAt1P1V;
+ sramOption.requestVoltageUpdate = true;
+ (void)SPC_SetSRAMOperateVoltage(SPC0, &sramOption);
+ }
+
+ CLOCK_SetupFROHFClocking(96000000U); /*!< Enable FRO HF(96MHz) output */
+
+ CLOCK_SetupFRO12MClocking(); /*!< Setup FRO12M clock */
+
+ CLOCK_AttachClk(kFRO_HF_to_MAIN_CLK); /* !< Switch MAIN_CLK to FRO_HF */
+
+ /* The flow of decreasing voltage and frequency */
+ if (coreFreq > BOARD_BOOTCLOCKFRO96M_CORE_CLOCK) {
+ /* Configure Flash to support different voltage level and frequency */
+ FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x2U));
+ /* Specifies the operating voltage for the SRAM's read/write timing margin */
+ sramOption.operateVoltage = kSPC_sramOperateAt1P1V;
+ sramOption.requestVoltageUpdate = true;
+ (void)SPC_SetSRAMOperateVoltage(SPC0, &sramOption);
+ /* Set the LDO_CORE VDD regulator level */
+ ldoOption.CoreLDOVoltage = kSPC_CoreLDO_NormalVoltage;
+ ldoOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
+ (void)SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOption);
+ }
+
+ /*!< Set up clock selectors - Attach clocks to the peripheries */
+
+ /*!< Set up dividers */
+ CLOCK_SetClockDiv(kCLOCK_DivAHBCLK, 1U); /* !< Set AHBCLKDIV divider to value 1 */
+ CLOCK_SetClockDiv(kCLOCK_DivFRO_HF_DIV, 1U); /* !< Set FROHFDIV divider to value 1 */
+
+ /* Set SystemCoreClock variable */
+ SystemCoreClock = BOARD_BOOTCLOCKFRO96M_CORE_CLOCK;
+}
diff --git a/hw/bsp/mcx/boards/frdm_mcxa156/clock_config.h b/hw/bsp/mcx/boards/frdm_mcxa156/clock_config.h
new file mode 100644
index 000000000..3f5dfefda
--- /dev/null
+++ b/hw/bsp/mcx/boards/frdm_mcxa156/clock_config.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/***********************************************************************************************************************
+ * This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file
+ * will be overwritten if the respective MCUXpresso Config Tools is used to update this file.
+ **********************************************************************************************************************/
+
+#ifndef _CLOCK_CONFIG_H_
+#define _CLOCK_CONFIG_H_
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*******************************************************************************
+ ************************ BOARD_InitBootClocks function ************************
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes default configuration of clocks.
+ *
+ */
+void BOARD_InitBootClocks(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ******************** Configuration BOARD_BootClockFRO12M **********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockFRO12M configuration
+ ******************************************************************************/
+#define BOARD_BOOTCLOCKFRO12M_CORE_CLOCK 12000000U /*!< Core clock frequency: 12000000Hz */
+
+
+/*******************************************************************************
+ * API for BOARD_BootClockFRO12M configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockFRO12M(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ******************** Configuration BOARD_BootClockFRO24M **********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockFRO24M configuration
+ ******************************************************************************/
+#define BOARD_BOOTCLOCKFRO24M_CORE_CLOCK 24000000U /*!< Core clock frequency: 24000000Hz */
+
+
+/*******************************************************************************
+ * API for BOARD_BootClockFRO24M configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockFRO24M(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ******************** Configuration BOARD_BootClockFRO48M **********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockFRO48M configuration
+ ******************************************************************************/
+#define BOARD_BOOTCLOCKFRO48M_CORE_CLOCK 48000000U /*!< Core clock frequency: 48000000Hz */
+
+
+/*******************************************************************************
+ * API for BOARD_BootClockFRO48M configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockFRO48M(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ******************** Configuration BOARD_BootClockFRO64M **********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockFRO64M configuration
+ ******************************************************************************/
+#define BOARD_BOOTCLOCKFRO64M_CORE_CLOCK 64000000U /*!< Core clock frequency: 64000000Hz */
+
+
+/*******************************************************************************
+ * API for BOARD_BootClockFRO64M configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockFRO64M(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ******************** Configuration BOARD_BootClockFRO96M **********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockFRO96M configuration
+ ******************************************************************************/
+#define BOARD_BOOTCLOCKFRO96M_CORE_CLOCK 96000000U /*!< Core clock frequency: 96000000Hz */
+
+
+/*******************************************************************************
+ * API for BOARD_BootClockFRO96M configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockFRO96M(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+#endif /* _CLOCK_CONFIG_H_ */
diff --git a/hw/bsp/mcx/boards/frdm_mcxa156/pin_mux.c b/hw/bsp/mcx/boards/frdm_mcxa156/pin_mux.c
new file mode 100644
index 000000000..de35103a6
--- /dev/null
+++ b/hw/bsp/mcx/boards/frdm_mcxa156/pin_mux.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/***********************************************************************************************************************
+ * This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file
+ * will be overwritten if the respective MCUXpresso Config Tools is used to update this file.
+ **********************************************************************************************************************/
+
+/* clang-format off */
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+!!GlobalInfo
+product: Pins v15.0
+processor: MCXA156
+package_id: MCXA156VLL
+mcu_data: ksdk2_0
+processor_version: 0.15.0
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+/* clang-format on */
+
+#include "fsl_common.h"
+#include "fsl_port.h"
+#include "pin_mux.h"
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitBootPins
+ * Description : Calls initialization functions.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitBootPins(void)
+{
+ BOARD_InitPins();
+}
+
+/* clang-format off */
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+BOARD_InitPins:
+- options: {callFromInitBoot: 'true', coreID: cm33_core0, enableClock: 'true'}
+- pin_list:
+ - {pin_num: '78', peripheral: LPUART0, signal: RX, pin_signal: P0_2/TDO/SWO/LPUART0_RXD/LPSPI0_SCK/CT0_MAT0/UTICK_CAP0/FLEXIO0_D2, slew_rate: fast, open_drain: disable,
+ drive_strength: low, pull_select: up, pull_enable: enable, input_buffer: enable, invert_input: normal}
+ - {pin_num: '79', peripheral: LPUART0, signal: TX, pin_signal: P0_3/TDI/LPUART0_TXD/LPSPI0_SDO/CT0_MAT1/UTICK_CAP1/FLEXIO0_D3/CMP0_OUT, slew_rate: fast, open_drain: disable,
+ drive_strength: low, pull_select: up, pull_enable: enable, input_buffer: enable, invert_input: normal}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+/* clang-format on */
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitPins
+ * Description : Configures pin routing and optionally pin electrical features.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitPins(void)
+{
+
+ RESET_PeripheralReset(kLPUART0_RST_SHIFT_RSTn);
+ CLOCK_SetClockDiv(kCLOCK_DivLPUART0, 1u);
+ CLOCK_AttachClk(kFRO12M_to_LPUART0);
+
+ /* GPIO3: Peripheral clock is enabled */
+ CLOCK_EnableClock(kCLOCK_GateGPIO3);
+ /* PORT3: Peripheral clock is enabled */
+ CLOCK_EnableClock(kCLOCK_GatePORT3);
+ /* GPIO3 peripheral is released from reset */
+ RESET_ReleasePeripheralReset(kGPIO3_RST_SHIFT_RSTn);
+ /* PORT3 peripheral is released from reset */
+ RESET_ReleasePeripheralReset(kPORT3_RST_SHIFT_RSTn);
+
+ /* GPIO3: Peripheral clock is enabled */
+ CLOCK_EnableClock(kCLOCK_GateGPIO0);
+ /* PORT3: Peripheral clock is enabled */
+ CLOCK_EnableClock(kCLOCK_GatePORT0);
+ /* GPIO3 peripheral is released from reset */
+ RESET_ReleasePeripheralReset(kGPIO0_RST_SHIFT_RSTn);
+ /* PORT3 peripheral is released from reset */
+ RESET_ReleasePeripheralReset(kPORT0_RST_SHIFT_RSTn);
+
+ /* PORT0: Peripheral clock is enabled */
+ CLOCK_EnableClock(kCLOCK_GatePORT0);
+ /* LPUART0 peripheral is released from reset */
+ RESET_ReleasePeripheralReset(kLPUART0_RST_SHIFT_RSTn);
+ /* PORT0 peripheral is released from reset */
+ RESET_ReleasePeripheralReset(kPORT0_RST_SHIFT_RSTn);
+
+ const port_pin_config_t port0_2_pin78_config = {/* Internal pull-up resistor is enabled */
+ kPORT_PullUp,
+ /* Low internal pull resistor value is selected. */
+ kPORT_LowPullResistor,
+ /* Fast slew rate is configured */
+ kPORT_FastSlewRate,
+ /* Passive input filter is disabled */
+ kPORT_PassiveFilterDisable,
+ /* Open drain output is disabled */
+ kPORT_OpenDrainDisable,
+ /* Low drive strength is configured */
+ kPORT_LowDriveStrength,
+ /* Normal drive strength is configured */
+ kPORT_NormalDriveStrength,
+ /* Pin is configured as LPUART0_RXD */
+ kPORT_MuxAlt2,
+ /* Digital input enabled */
+ kPORT_InputBufferEnable,
+ /* Digital input is not inverted */
+ kPORT_InputNormal,
+ /* Pin Control Register fields [15:0] are not locked */
+ kPORT_UnlockRegister};
+ /* PORT0_2 (pin 78) is configured as LPUART0_RXD */
+ PORT_SetPinConfig(PORT0, 2U, &port0_2_pin78_config);
+
+ const port_pin_config_t port0_3_pin79_config = {/* Internal pull-up resistor is enabled */
+ kPORT_PullUp,
+ /* Low internal pull resistor value is selected. */
+ kPORT_LowPullResistor,
+ /* Fast slew rate is configured */
+ kPORT_FastSlewRate,
+ /* Passive input filter is disabled */
+ kPORT_PassiveFilterDisable,
+ /* Open drain output is disabled */
+ kPORT_OpenDrainDisable,
+ /* Low drive strength is configured */
+ kPORT_LowDriveStrength,
+ /* Normal drive strength is configured */
+ kPORT_NormalDriveStrength,
+ /* Pin is configured as LPUART0_TXD */
+ kPORT_MuxAlt2,
+ /* Digital input enabled */
+ kPORT_InputBufferEnable,
+ /* Digital input is not inverted */
+ kPORT_InputNormal,
+ /* Pin Control Register fields [15:0] are not locked */
+ kPORT_UnlockRegister};
+ /* PORT0_3 (pin 79) is configured as LPUART0_TXD */
+ PORT_SetPinConfig(PORT0, 3U, &port0_3_pin79_config);
+}
+/***********************************************************************************************************************
+ * EOF
+ **********************************************************************************************************************/
diff --git a/hw/bsp/mcx/boards/frdm_mcxa156/pin_mux.h b/hw/bsp/mcx/boards/frdm_mcxa156/pin_mux.h
new file mode 100644
index 000000000..fb7d1fc04
--- /dev/null
+++ b/hw/bsp/mcx/boards/frdm_mcxa156/pin_mux.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/***********************************************************************************************************************
+ * This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file
+ * will be overwritten if the respective MCUXpresso Config Tools is used to update this file.
+ **********************************************************************************************************************/
+
+#ifndef _PIN_MUX_H_
+#define _PIN_MUX_H_
+
+/*!
+ * @addtogroup pin_mux
+ * @{
+ */
+
+/***********************************************************************************************************************
+ * API
+ **********************************************************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @brief Calls initialization functions.
+ *
+ */
+void BOARD_InitBootPins(void);
+
+/*!
+ * @brief Configures pin routing and optionally pin electrical features.
+ *
+ */
+void BOARD_InitPins(void);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif /* _PIN_MUX_H_ */
+
+/***********************************************************************************************************************
+ * EOF
+ **********************************************************************************************************************/
diff --git a/hw/bsp/mcx/boards/frdm_mcxn947/board.h b/hw/bsp/mcx/boards/frdm_mcxn947/board.h
index a35b6818a..bb15620ef 100644
--- a/hw/bsp/mcx/boards/frdm_mcxn947/board.h
+++ b/hw/bsp/mcx/boards/frdm_mcxn947/board.h
@@ -49,17 +49,22 @@
#define BUTTON_STATE_ACTIVE 0
// UART
-#define UART_DEV LPUART4
+#define UART_DEV LPUART4
+#define LP_FLEXCOMM_INST 4
+
+#include "fsl_lpflexcomm.h"
static inline void board_uart_init_clock(void) {
+
/* attach FRO 12M to FLEXCOMM4 */
+
+ LP_FLEXCOMM_Init(LP_FLEXCOMM_INST, LP_FLEXCOMM_PERIPH_LPUART);
+
CLOCK_SetClkDiv(kCLOCK_DivFlexcom4Clk, 1u);
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM4);
RESET_ClearPeripheralReset(kFC4_RST_SHIFT_RSTn);
-}
-//#define UART_RX_PINMUX 0, 24, IOCON_PIO_DIG_FUNC1_EN
-//#define UART_TX_PINMUX 0, 25, IOCON_PIO_DIG_FUNC1_EN
+}
// XTAL
#define XTAL0_CLK_HZ (24 * 1000 * 1000U)
diff --git a/hw/bsp/mcx/drivers/spc/fsl_spc.c b/hw/bsp/mcx/drivers/spc/fsl_spc.c
new file mode 100644
index 000000000..b16ca5fc5
--- /dev/null
+++ b/hw/bsp/mcx/drivers/spc/fsl_spc.c
@@ -0,0 +1,1680 @@
+/*
+ * Copyright 2022-2024 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_spc.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.mcx_spc"
+#endif
+
+/*
+ * $Coverage Justification Reference$
+ *
+ * $Justification spc_c_ref_1$
+ * The SPC busy status flag is too short to get coverage data.
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Gets selected power domain's requested low power mode.
+ *
+ * param base SPC peripheral base address.
+ * param powerDomainId Power Domain Id, please refer to spc_power_domain_id_t.
+ *
+ * return The selected power domain's requested low power mode, please refer to spc_power_domain_low_power_mode_t.
+ */
+spc_power_domain_low_power_mode_t SPC_GetPowerDomainLowPowerMode(SPC_Type *base, spc_power_domain_id_t powerDomainId)
+{
+ assert((uint8_t)powerDomainId < SPC_PD_STATUS_COUNT);
+
+ uint32_t val;
+
+ val = ((base->PD_STATUS[(uint8_t)powerDomainId] & SPC_PD_STATUS_LP_MODE_MASK) >> SPC_PD_STATUS_LP_MODE_SHIFT);
+ return (spc_power_domain_low_power_mode_t)val;
+}
+
+/*!
+ * brief Gets Isolation status for each power domains.
+ *
+ * This function gets the status which indicates whether certain
+ * peripheral and the IO pads are in a latched state as a result
+ * of having been in POWERDOWN mode.
+ *
+ * param base SPC peripheral base address.
+ * return Current isolation status for each power domains.
+ */
+uint8_t SPC_GetPeriphIOIsolationStatus(SPC_Type *base)
+{
+ uint32_t reg;
+
+ reg = base->SC;
+ return (uint8_t)((reg & SPC_SC_ISO_CLR_MASK) >> SPC_SC_ISO_CLR_SHIFT);
+}
+
+/*!
+ * brief Configs Low power request output pin.
+ *
+ * This function configs the low power request output pin
+ *
+ * param base SPC peripheral base address.
+ * param config Pointer the spc_LowPower_Request_config_t structure.
+ */
+void SPC_SetLowPowerRequestConfig(SPC_Type *base, const spc_lowpower_request_config_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t reg;
+
+ reg = base->LPREQ_CFG;
+ reg &= ~(SPC_LPREQ_CFG_LPREQOE_MASK | SPC_LPREQ_CFG_LPREQPOL_MASK | SPC_LPREQ_CFG_LPREQOV_MASK);
+
+ if (config->enable)
+ {
+ reg |= SPC_LPREQ_CFG_LPREQOE_MASK | SPC_LPREQ_CFG_LPREQPOL((uint8_t)(config->polarity)) |
+ SPC_LPREQ_CFG_LPREQOV((uint8_t)(config->override));
+ }
+ else
+ {
+ reg &= ~SPC_LPREQ_CFG_LPREQOE_MASK;
+ }
+
+ base->LPREQ_CFG = reg;
+}
+
+#if !(defined(FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) && FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT)
+/*!
+ * brief Configures VDD Core Glitch detector, including ripple counter selection, timeout value and so on.
+ *
+ * param base SPC peripheral base address.
+ * param config Pointer to the structure in type of spc_vdd_core_glitch_detector_config_t.
+ */
+void SPC_ConfigVddCoreGlitchDetector(SPC_Type *base, const spc_vdd_core_glitch_detector_config_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t reg;
+
+ reg = (base->VDD_CORE_GLITCH_DETECT_SC) &
+ ~(SPC_VDD_CORE_GLITCH_DETECT_SC_CNT_SELECT_MASK | SPC_VDD_CORE_GLITCH_DETECT_SC_TIMEOUT_MASK |
+ SPC_VDD_CORE_GLITCH_DETECT_SC_RE_MASK | SPC_VDD_CORE_GLITCH_DETECT_SC_IE_MASK);
+
+ reg |= SPC_VDD_CORE_GLITCH_DETECT_SC_CNT_SELECT(config->rippleCounterSelect) |
+ SPC_VDD_CORE_GLITCH_DETECT_SC_TIMEOUT(config->resetTimeoutValue) |
+ SPC_VDD_CORE_GLITCH_DETECT_SC_RE(config->enableReset) |
+ SPC_VDD_CORE_GLITCH_DETECT_SC_IE(config->enableInterrupt);
+
+ base->VDD_CORE_GLITCH_DETECT_SC = reg;
+}
+#endif
+
+/*!
+ * brief Set SRAM operate voltage.
+ *
+ * param base SPC peripheral base address.
+ * param config The pointer to spc_sram_voltage_config_t, specifies the configuration of sram voltage.
+ */
+void SPC_SetSRAMOperateVoltage(SPC_Type *base, const spc_sram_voltage_config_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t reg = 0UL;
+
+ reg |= SPC_SRAMCTL_VSM(config->operateVoltage);
+
+ base->SRAMCTL = reg;
+
+ if (config->requestVoltageUpdate)
+ {
+ base->SRAMCTL |= SPC_SRAMCTL_REQ_MASK;
+ while ((base->SRAMCTL & SPC_SRAMCTL_ACK_MASK) == 0UL)
+ {
+ /* Wait until acknowledged */
+ ;
+ }
+ base->SRAMCTL &= ~SPC_SRAMCTL_REQ_MASK;
+ }
+}
+
+/*!
+ * brief Configs Bandgap mode in Active mode.
+ *
+ * @note To disable bandgap in Active mode:
+ * 1. Disable all LVD's and HVD's in active mode;
+ * 2. Disable Glitch detect;
+ * 3. Configure LDO's and DCDC to low drive strength in active mode;
+ * 4. Invoke this function to disable bandgap in active mode;
+ * otherwise the error status will be reported.
+ *
+ * @note Some other system resources(such as PLL, CMP) require bandgap to be enabled, to disable bandgap please
+ * take care of other system resources.
+ *
+ * param base SPC peripheral base address.
+ * param mode The Bandgap mode be selected.
+ *
+ * retval kStatus_SPC_BandgapModeWrong The Bandgap can not be disabled in active mode.
+ * retval kStatus_Success Config Bandgap mode in Active power mode successful.
+ */
+status_t SPC_SetActiveModeBandgapModeConfig(SPC_Type *base, spc_bandgap_mode_t mode)
+{
+ uint32_t reg;
+ uint32_t state;
+
+ reg = base->ACTIVE_CFG;
+
+ if (mode == kSPC_BandgapDisabled)
+ {
+ state = SPC_GetActiveModeVoltageDetectStatus(base);
+
+ /* If any of the LVD/HVDs are kept enabled, bandgap mode must be enabled with buffer disabled. */
+ if (state != 0UL)
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+
+ /* The bandgap mode must be enabled if any regulators' drive strength set as Normal. */
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+ if ((base->ACTIVE_CFG & SPC_ACTIVE_CFG_SYSLDO_VDD_DS_MASK) ==
+ SPC_ACTIVE_CFG_SYSLDO_VDD_DS(kSPC_SysLDO_NormalDriveStrength))
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+ if ((base->ACTIVE_CFG & SPC_ACTIVE_CFG_DCDC_VDD_DS_MASK) == SPC_ACTIVE_CFG_DCDC_VDD_DS(kSPC_DCDC_NormalVoltage))
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+
+#if !(defined(FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) && FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT)
+ /* state of GLITCH_DETECT_DISABLE will be ignored if bandgap is disabled. */
+ if ((base->ACTIVE_CFG & SPC_ACTIVE_CFG_GLITCH_DETECT_DISABLE_MASK) == 0UL)
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+#endif
+#if defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS
+ if ((base->ACTIVE_CFG & SPC_ACTIVE_CFG_CORELDO_VDD_DS_MASK) ==
+ SPC_ACTIVE_CFG_CORELDO_VDD_DS(kSPC_CoreLDO_NormalDriveStrength))
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
+ }
+
+ reg &= ~SPC_ACTIVE_CFG_BGMODE_MASK;
+ reg |= SPC_ACTIVE_CFG_BGMODE(mode);
+
+ base->ACTIVE_CFG = reg;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configs Bandgap mode in Low Power mode.
+ *
+ * @note To disable Bandgap in Low-power mode:
+ * 1. Disable all LVD's ad HVD's in low power mode;
+ * 2. Disable Glitch detect in low power mode;
+ * 3. Configure LDO's and DCDC to low drive strength in low power mode;
+ * 4. Disable bandgap in low power mode;
+ * Otherwise, the error status will be reported.
+ *
+ * @note Some other system resources(such as PLL, CMP) require bandgap to be enabled, to disable bandgap please
+ * take care of other system resources.
+ *
+ * param base SPC peripheral base address.
+ * param mode The Bandgap mode be selected.
+ *
+ * retval kStatus_SPC_BandgapModeWrong The bandgap mode setting in Low Power mode is wrong.
+ * retval kStatus_Success Config Bandgap mode in Low Power power mode successful.
+ */
+status_t SPC_SetLowPowerModeBandgapmodeConfig(SPC_Type *base, spc_bandgap_mode_t mode)
+{
+ uint32_t reg;
+ uint32_t state;
+
+ reg = base->LP_CFG;
+
+ if (mode == kSPC_BandgapDisabled)
+ {
+ state = (uint32_t)SPC_GetLowPowerModeVoltageDetectStatus(base);
+
+ /* If any of the LVD/HVDs are kept enabled, bandgap mode must be enabled with buffer disabled. */
+ if (state != 0UL)
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+ if ((base->LP_CFG & SPC_LP_CFG_DCDC_VDD_DS_MASK) == SPC_LP_CFG_DCDC_VDD_DS(kSPC_DCDC_NormalDriveStrength))
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+ if ((base->LP_CFG & SPC_LP_CFG_SYSLDO_VDD_DS_MASK) == SPC_LP_CFG_SYSLDO_VDD_DS(kSPC_SysLDO_NormalDriveStrength))
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+ if ((base->LP_CFG & SPC_LP_CFG_CORELDO_VDD_DS_MASK) ==
+ SPC_LP_CFG_CORELDO_VDD_DS(kSPC_CoreLDO_NormalDriveStrength))
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+
+#if !(defined(FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) && FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT)
+ /* state of GLITCH_DETECT_DISABLE will be ignored if bandgap is disabled. */
+ if ((base->LP_CFG & SPC_LP_CFG_GLITCH_DETECT_DISABLE_MASK) == 0UL)
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+#endif
+ }
+
+ reg &= ~SPC_LP_CFG_BGMODE_MASK;
+ reg |= SPC_LP_CFG_BGMODE(mode);
+ base->LP_CFG = reg;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configs CORE voltage detect options.
+ *
+ * This function configs CORE voltage detect options.
+ * Note: Setting both the voltage detect interrupt and reset
+ * enable will cause interrupt to be generated on exit from reset.
+ * If those conditioned is not desired, interrupt/reset only one is enabled.
+ *
+ * param base SPC peripheral base address.
+ * param config Pointer to spc_core_voltage_detect_config_t structure.
+ */
+void SPC_SetCoreVoltageDetectConfig(SPC_Type *base, const spc_core_voltage_detect_config_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t reg = 0UL;
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD) && FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD)
+ reg |= (config->option.HVDInterruptEnable) ? SPC_VD_CORE_CFG_HVDIE(1U) : SPC_VD_CORE_CFG_HVDIE(0U);
+ reg |= (config->option.HVDResetEnable) ? SPC_VD_CORE_CFG_HVDRE(1U) : SPC_VD_CORE_CFG_HVDRE(0U);
+#endif /* FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD */
+ reg |= (config->option.LVDInterruptEnable) ? SPC_VD_CORE_CFG_LVDIE(1U) : SPC_VD_CORE_CFG_LVDIE(0U);
+ reg |= (config->option.LVDResetEnable) ? SPC_VD_CORE_CFG_LVDRE(1U) : SPC_VD_CORE_CFG_LVDRE(0U);
+
+ base->VD_CORE_CFG = reg;
+}
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD) && FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD)
+/*!
+ * brief Enables the Core High Voltage Detector in Active mode.
+ *
+ * note If the CORE_LDO high voltage detect is enabled in Active mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low.
+ *
+ * param base SPC peripheral base address.
+ * param enable Enable/Disable Core HVD.
+ * true - Enable Core High voltage detector in active mode.
+ * false - Disable Core High voltage detector in active mode.
+ *
+ * retval kStatus_Success Enable Core High Voltage Detect successfully.
+ */
+status_t SPC_EnableActiveModeCoreHighVoltageDetect(SPC_Type *base, bool enable)
+{
+ status_t status = kStatus_Success;
+
+ if (enable)
+ {
+ base->ACTIVE_CFG |= SPC_ACTIVE_CFG_CORE_HVDE_MASK;
+ }
+ else
+ {
+ base->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_CORE_HVDE_MASK;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Enables the Core High Voltage Detector in Low Power mode.
+ *
+ * note If the CORE_LDO high voltage detect is enabled in Low Power mode,
+ * please note that the bandgap must be enabled and the drive strength of each regulator
+ * must not set to low in low power mode.
+ *
+ * param base SPC peripheral base address.
+ * param enable Enable/Disable Core HVD.
+ * true - Enable Core High voltage detector in low power mode.
+ * false - Disable Core High voltage detector in low power mode.
+ *
+ * retval kStatus_Success Enable Core High Voltage Detect in low power mode successfully.
+ */
+status_t SPC_EnableLowPowerModeCoreHighVoltageDetect(SPC_Type *base, bool enable)
+{
+ status_t status = kStatus_Success;
+
+ if (enable)
+ {
+ base->LP_CFG |= SPC_LP_CFG_CORE_HVDE_MASK;
+ }
+ else
+ {
+ base->LP_CFG &= ~SPC_LP_CFG_CORE_HVDE_MASK;
+ }
+
+ return status;
+}
+#endif /* FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD */
+
+/*!
+ * brief Enables the Core VDD Low Voltage Detector in Active mode.
+ *
+ * note If the Core VDD high voltage detect is enabled in Active mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low.
+ *
+ * param base SPC peripheral base address.
+ * param enable Enable/Disable Core LVD.
+ * true - Enable Core Low voltage detector in active mode.
+ * false - Disable Core Low voltage detector in active mode.
+ *
+ * retval kStatus_Success Enable Core Low Voltage Detect successfully.
+ */
+status_t SPC_EnableActiveModeCoreLowVoltageDetect(SPC_Type *base, bool enable)
+{
+ status_t status = kStatus_Success;
+
+ if (enable)
+ {
+ base->ACTIVE_CFG |= SPC_ACTIVE_CFG_CORE_LVDE_MASK;
+ }
+ else
+ {
+ base->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_CORE_LVDE_MASK;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Enables the Core Low Voltage Detector in Low Power mode.
+ *
+ * note If the Core VDD low voltage detect is enabled in Low Power mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low in Low Power mode.
+ *
+ * param base SPC peripheral base address.
+ * param enable Enable/Disable Core HVD.
+ * true - Enable Core Low voltage detector in low power mode.
+ * false - Disable Core Low voltage detector in low power mode.
+ *
+ * retval kStatus_Success Enable Core Low Voltage Detect in low power mode successfully.
+ */
+status_t SPC_EnableLowPowerModeCoreLowVoltageDetect(SPC_Type *base, bool enable)
+{
+ status_t status = kStatus_Success;
+
+ if (enable)
+ {
+ base->LP_CFG |= SPC_LP_CFG_CORE_LVDE_MASK;
+ }
+ else
+ {
+ base->LP_CFG &= ~SPC_LP_CFG_CORE_LVDE_MASK;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Set system VDD Low-voltage level selection.
+ *
+ * This function selects the system VDD low-voltage level. Changing system VDD low-voltage level
+ * must be done after disabling the System VDD low voltage reset and interrupt.
+ *
+ * @deprecated In latest RM, reserved for all devices, will removed in next release.
+ *
+ * param base SPC peripheral base address.
+ * param level System VDD Low-Voltage level selection. See @ref spc_low_voltage_level_select_t for details.
+ */
+void SPC_SetSystemVDDLowVoltageLevel(SPC_Type *base, spc_low_voltage_level_select_t level)
+{
+ (void)level;
+ (void)base;
+
+ /*
+ uint32_t reg;
+
+ reg = base->VD_SYS_CFG;
+
+ base->VD_SYS_CFG &= ~(SPC_VD_SYS_CFG_LVDRE_MASK | SPC_VD_SYS_CFG_LVDIE_MASK);
+ reg |= SPC_VD_SYS_CFG_LVSEL(level);
+
+ base->VD_SYS_CFG = reg; */
+}
+
+/*!
+ * brief Configs SYS VDD voltage detect options.
+ *
+ * This function config SYS voltage detect options.
+ * Note: Setting both the voltage detect interrupt and reset
+ * enable will cause interrupt to be generated on exit from reset.
+ * If those conditioned is not desired, interrupt/reset only one is enabled.
+ *
+ * param base SPC peripheral base address.
+ * param config Pointer to spc_system_voltage_detect_config_t structure.
+ */
+void SPC_SetSystemVoltageDetectConfig(SPC_Type *base, const spc_system_voltage_detect_config_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t reg = 0UL;
+
+ reg |= (config->option.HVDInterruptEnable) ? SPC_VD_SYS_CFG_HVDIE(1U) : SPC_VD_SYS_CFG_HVDIE(0U);
+ reg |= (config->option.LVDInterruptEnable) ? SPC_VD_SYS_CFG_LVDIE(1U) : SPC_VD_SYS_CFG_LVDIE(0U);
+ reg |= (config->option.HVDResetEnable) ? SPC_VD_SYS_CFG_HVDRE(1U) : SPC_VD_SYS_CFG_HVDRE(0U);
+ reg |= (config->option.LVDResetEnable) ? SPC_VD_SYS_CFG_LVDRE(1U) : SPC_VD_SYS_CFG_LVDRE(0U);
+
+ base->VD_SYS_CFG = reg;
+
+ (void)(config->level);
+ /* SPC_SetSystemVDDLowVoltageLevel(base, config->level); */
+}
+
+/*!
+ * brief Enables the System VDD High Voltage Detector in Active mode.
+ *
+ * note If the System_LDO high voltage detect is enabled in Active mode,
+ * please note that the bandgap must be enabled and the drive strength of
+ * each regulator must not set to low in Active mode.
+ *
+ * param base SPC peripheral base address.
+ * param enable Enable/Disable System HVD.
+ * true - Enable System High voltage detector in active mode.
+ * false - Disable System High voltage detector in active mode.
+ *
+ * retval kStatus_Success Enable System High Voltage Detect successfully.
+ */
+status_t SPC_EnableActiveModeSystemHighVoltageDetect(SPC_Type *base, bool enable)
+{
+ status_t status = kStatus_Success;
+
+ if (enable)
+ {
+ base->ACTIVE_CFG |= SPC_ACTIVE_CFG_SYS_HVDE_MASK;
+ }
+ else
+ {
+ base->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_SYS_HVDE_MASK;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Enables the System VDD Low Voltage Detector in Active mode.
+ *
+ * note If the System_LDO low voltage detect is enabled in Active mode,
+ * please note that the bandgap must be enabled and the drive strength of each
+ * regulator must not set to low in Active mode.
+ *
+ * param base SPC peripheral base address.
+ * param enable Enable/Disable System LVD.
+ * true - Enable System Low voltage detector in active mode.
+ * false - Disable System Low voltage detector in active mode.
+ *
+ * retval kStatus_Success Enable the System Low Voltage Detect successfully.
+ */
+status_t SPC_EnableActiveModeSystemLowVoltageDetect(SPC_Type *base, bool enable)
+{
+ status_t status = kStatus_Success;
+
+ if (enable)
+ {
+ base->ACTIVE_CFG |= SPC_ACTIVE_CFG_SYS_LVDE_MASK;
+ }
+ else
+ {
+ base->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_SYS_LVDE_MASK;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Enables the System VDD High Voltage Detector in Low Power mode.
+ *
+ * note If the System_LDO high voltage detect is enabled in low power mode,
+ * please note that the bandgap must be enabled and the drive strength of each
+ * regulator must not set to low in low power mode.
+ *
+ * param base SPC peripheral base address.
+ * param enable Enable/Disable System HVD.
+ * true - Enable System High voltage detector in low power mode.
+ * false - Disable System High voltage detector in low power mode.
+ *
+ * retval kStatus_Success Enable System High Voltage Detect in low power mode successfully.
+ */
+status_t SPC_EnableLowPowerModeSystemHighVoltageDetect(SPC_Type *base, bool enable)
+{
+ status_t status = kStatus_Success;
+
+ if (enable)
+ {
+ base->LP_CFG |= SPC_LP_CFG_SYS_HVDE_MASK;
+ }
+ else
+ {
+ base->LP_CFG &= ~SPC_LP_CFG_SYS_HVDE_MASK;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Enables the System VDD Low Voltage Detector in Low Power mode.
+ *
+ * note If the System_LDO low voltage detect is enabled in Low Power mode,
+ * please note that the bandgap must be enabled and the drive strength of each
+ * regulator must not set to low in Low Power mode.
+ *
+ * param base SPC peripheral base address.
+ * param enable Enable/Disable System HVD.
+ * true - Enable System Low voltage detector in low power mode.
+ * false - Disable System Low voltage detector in low power mode.
+ *
+ * retval kStatus_Success Enable System Low Voltage Detect in low power mode successfully.
+ */
+status_t SPC_EnableLowPowerModeSystemLowVoltageDetect(SPC_Type *base, bool enable)
+{
+ status_t status = kStatus_Success;
+
+ if (enable)
+ {
+ base->LP_CFG |= SPC_LP_CFG_SYS_LVDE_MASK;
+ }
+ else
+ {
+ base->LP_CFG &= ~SPC_LP_CFG_SYS_LVDE_MASK;
+ }
+
+ return status;
+}
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD) && FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD)
+/*!
+ * brief Set IO VDD Low-Voltage level selection.
+ *
+ * This function selects the IO VDD Low-voltage level. Changing IO VDD low-voltage level
+ * must be done after disabling the IO VDD low voltage reset and interrupt.
+ *
+ * param base SPC peripheral base address.
+ * param level IO VDD Low-voltage level selection.
+ */
+void SPC_SetIOVDDLowVoltageLevel(SPC_Type *base, spc_low_voltage_level_select_t level)
+{
+ uint32_t reg;
+
+ reg = base->VD_IO_CFG;
+
+ base->VD_IO_CFG &= ~(SPC_VD_IO_CFG_LVDRE_MASK | SPC_VD_IO_CFG_LVDIE_MASK | SPC_VD_IO_CFG_LVSEL_MASK);
+ reg |= SPC_VD_IO_CFG_LVSEL(level);
+
+ base->VD_IO_CFG = reg;
+}
+
+/*!
+ * brief Configs IO VDD voltage detect options.
+ *
+ * This function config IO voltage detect options.
+ * Note: Setting both the voltage detect interrupt and reset
+ * enable will cause interrupt to be generated on exit from reset.
+ * If those conditioned is not desired, interrupt/reset so only one is enabled.
+ *
+ * param base SPC peripheral base address.
+ * param config Pointer to spc_IO_voltage_detect_config_t structure.
+ */
+void SPC_SetIOVoltageDetectConfig(SPC_Type *base, const spc_io_voltage_detect_config_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t reg = 0UL;
+
+ /* Set trip voltage level. */
+ SPC_SetIOVDDLowVoltageLevel(base, config->level);
+
+ reg = base->VD_IO_CFG;
+ reg &= ~(SPC_VD_IO_CFG_LVDRE_MASK | SPC_VD_IO_CFG_LVDIE_MASK | SPC_VD_IO_CFG_HVDRE_MASK | SPC_VD_IO_CFG_HVDIE_MASK);
+
+ reg |= (config->option.HVDInterruptEnable) ? SPC_VD_IO_CFG_HVDIE(1U) : SPC_VD_IO_CFG_HVDIE(0U);
+ reg |= (config->option.LVDInterruptEnable) ? SPC_VD_IO_CFG_LVDIE(1U) : SPC_VD_IO_CFG_LVDIE(0U);
+ reg |= (config->option.HVDResetEnable) ? SPC_VD_IO_CFG_HVDRE(1U) : SPC_VD_IO_CFG_HVDRE(0U);
+ reg |= (config->option.LVDResetEnable) ? SPC_VD_IO_CFG_LVDRE(1U) : SPC_VD_IO_CFG_LVDRE(0U);
+
+ base->VD_IO_CFG = reg;
+}
+
+/*!
+ * brief Enables the IO VDD High Voltage Detector in Active mode.
+ *
+ * note If the IO high voltage detect is enabled in Active mode,
+ * please note that the bandgap must be enabled and the drive strength
+ * of each regulator must not set to low in Active mode.
+ *
+ * param base SPC peripheral base address.
+ * param enable Enable/Disable IO HVD.
+ * true - Enable IO High voltage detector in active mode.
+ * false - Disable IO High voltage detector in active mode.
+ *
+ * retval kStatus_Success Enable IO High Voltage Detect successfully.
+ */
+status_t SPC_EnableActiveModeIOHighVoltageDetect(SPC_Type *base, bool enable)
+{
+ status_t status = kStatus_Success;
+
+ if (enable)
+ {
+ base->ACTIVE_CFG |= SPC_ACTIVE_CFG_IO_HVDE_MASK;
+ }
+ else
+ {
+ base->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_IO_HVDE_MASK;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Enables the IO VDD Low Voltage Detector in Active mode.
+ *
+ * note If the IO low voltage detect is enabled in Active mode,
+ * please note that the bandgap must be enabled and the drive strength
+ * of each regulator must not set to low in Active mode.
+ *
+ * param base SPC peripheral base address.
+ * param enable Enable/Disable IO LVD.
+ * true - Enable IO Low voltage detector in active mode.
+ * false - Disable IO Low voltage detector in active mode.
+ *
+ * retval kStatus_Success Enable IO Low Voltage Detect successfully.
+ */
+status_t SPC_EnableActiveModeIOLowVoltageDetect(SPC_Type *base, bool enable)
+{
+ status_t status = kStatus_Success;
+
+ if (enable)
+ {
+ base->ACTIVE_CFG |= SPC_ACTIVE_CFG_IO_LVDE_MASK;
+ }
+ else
+ {
+ base->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_IO_LVDE_MASK;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Enables the IO VDD High Voltage Detector in Low Power mode.
+ *
+ * note If the IO high voltage detect is enabled in Low Power mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low in Low Power mode.
+ *
+ * param base SPC peripheral base address.
+ * param enable Enable/Disable IO HVD.
+ * true - Enable IO High voltage detector in low power mode.
+ * false - Disable IO High voltage detector in low power mode.
+ *
+ * retval kStatus_Success Enable IO High Voltage Detect in low power mode successfully.
+ */
+status_t SPC_EnableLowPowerModeIOHighVoltageDetect(SPC_Type *base, bool enable)
+{
+ status_t status = kStatus_Success;
+
+ if (enable)
+ {
+ base->LP_CFG |= SPC_LP_CFG_IO_HVDE_MASK;
+ }
+ else
+ {
+ base->LP_CFG &= ~SPC_LP_CFG_IO_HVDE_MASK;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Enables the IO VDD Low Voltage Detector in Low Power mode.
+ *
+ * note If the IO low voltage detect is enabled in Low Power mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low in Low Power mode.
+ *
+ * param base SPC peripheral base address.
+ * param enable Enable/Disable IO HVD.
+ * true - Enable IO Low voltage detector in low power mode.
+ * false - Disable IO Low voltage detector in low power mode.
+ *
+ * retval kStatus_Success Enable IO Low Voltage Detect in low power mode successfully.
+ */
+status_t SPC_EnableLowPowerModeIOLowVoltageDetect(SPC_Type *base, bool enable)
+{
+ status_t status = kStatus_Success;
+
+ if (enable)
+ {
+ base->LP_CFG |= SPC_LP_CFG_IO_LVDE_MASK;
+ }
+ else
+ {
+ base->LP_CFG &= ~SPC_LP_CFG_IO_LVDE_MASK;
+ }
+
+ return status;
+}
+#endif /* FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD */
+
+/*!
+ * brief Configs external voltage domains
+ *
+ * This function configs external voltage domains isolation.
+ *
+ * param base SPC peripheral base address.
+ * param lowPowerIsoMask The mask of external domains isolate enable during low power mode.
+ * param IsoMask The mask of external domains isolate.
+ */
+void SPC_SetExternalVoltageDomainsConfig(SPC_Type *base, uint8_t lowPowerIsoMask, uint8_t IsoMask)
+{
+ uint32_t reg = 0UL;
+
+ reg |= SPC_EVD_CFG_REG_EVDISO(IsoMask) | SPC_EVD_CFG_REG_EVDLPISO(lowPowerIsoMask);
+ base->EVD_CFG = reg;
+}
+
+/*!
+ * brief Configs Core LDO Regulator in Active mode.
+ *
+ * @note The bandgap must be enabled before invoking this function.
+ * @note To set Core LDO as low drive strength, all HVDs/LVDs must be disabled previously.
+ *
+ * param base SPC peripheral base address.
+ * param option Pointer to the spc_active_mode_Core_LDO_option_t structure.
+ *
+ * retval kStatus_Success Config Core LDO regulator in Active power mode successful.
+ * retval kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * retval kStatus_SPC_BandgapModeWrong Bandgap should be enabled before invoking this function.
+ * retval kStatus_SPC_CORELDOLowDriveStrengthIgnore To set Core LDO as low drive strength,
+ * all LVDs/HVDs must be disabled before invoking this function.
+ */
+status_t SPC_SetActiveModeCoreLDORegulatorConfig(SPC_Type *base, const spc_active_mode_core_ldo_option_t *option)
+{
+ assert(option != NULL);
+
+ if ((base->SC & SPC_SC_BUSY_MASK) != 0UL)
+ {
+ return kStatus_SPC_Busy;
+ }
+
+ /* Check input parameters. */
+ /* 1. Bandgap must not be disabled. */
+ if (SPC_GetActiveModeBandgapMode(base) == kSPC_BandgapDisabled)
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+
+ /* 2. To set to low drive strength, all LVDs/HVDs must be disabled previously. */
+ if ((SPC_GetActiveModeVoltageDetectStatus(base) != 0UL) &&
+ (option->CoreLDODriveStrength == kSPC_CoreLDO_LowDriveStrength))
+ {
+ return kStatus_SPC_CORELDOLowDriveStrengthIgnore;
+ }
+
+ if ((uint8_t)SPC_GetActiveModeCoreLDOVDDVoltageLevel(base) != (uint8_t)(option->CoreLDOVoltage))
+ {
+#if defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS
+ (void)SPC_SetActiveModeCoreLDORegulatorDriveStrength(base, kSPC_CoreLDO_NormalDriveStrength);
+#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
+ (void)SPC_SetActiveModeCoreLDORegulatorVoltageLevel(base, option->CoreLDOVoltage);
+ }
+
+#if defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS
+ (void)SPC_SetActiveModeCoreLDORegulatorDriveStrength(base, option->CoreLDODriveStrength);
+#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Set Core LDO VDD Regulator Voltage level in Active mode.
+ *
+ * @note In active mode, the Core LDO voltage level should only be changed when the
+ * Core LDO is in normal drive strength.
+ *
+ * @note Update Core LDO voltage level will set Busy flag,
+ * this function return only when busy flag is cleared by hardware
+ *
+ * param base SPC peripheral base address.
+ * param voltageLevel Specify the voltage level of CORE LDO Regulator in Active mode, please
+ refer to @ref spc_core_ldo_voltage_level_t.
+ *
+ * retval kStatus_SPC_CORELDOVoltageSetFail Core LDO voltage level should only be
+ * changed when the CORE_LDO is in normal drive strength.
+ * retval kStatus_Success Set Core LDO regulator voltage level in Active power mode successful.
+ */
+status_t SPC_SetActiveModeCoreLDORegulatorVoltageLevel(SPC_Type *base, spc_core_ldo_voltage_level_t voltageLevel)
+{
+ if ((uint8_t)voltageLevel != (uint8_t)SPC_GetActiveModeCoreLDOVDDVoltageLevel(base))
+ {
+#if (defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS)
+ if (SPC_GetActiveModeCoreLDODriveStrength(base) != kSPC_CoreLDO_NormalDriveStrength)
+ {
+ return kStatus_SPC_CORELDOVoltageSetFail;
+ }
+#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
+
+ base->ACTIVE_CFG =
+ ((base->ACTIVE_CFG & ~SPC_ACTIVE_CFG_CORELDO_VDD_LVL_MASK) | SPC_ACTIVE_CFG_CORELDO_VDD_LVL(voltageLevel));
+
+ /*
+ * $Branch Coverage Justification$
+ * $ref spc_c_ref_1$.
+ */
+ while ((base->SC & SPC_SC_BUSY_MASK) != 0UL)
+ {
+ }
+ }
+ return kStatus_Success;
+}
+
+#if defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS
+/*!
+ * brief Set Core LDO VDD Regulator Drive Strength in Active mode.
+ *
+ * param base SPC peripheral base address.
+ * param driveStrength Specify the drive strength of CORE LDO Regulator in Active mode, please
+ refer to @ref spc_core_ldo_drive_strength_t.
+ *
+ * retval #kStatus_Success Set Core LDO regulator drive strength in Active power mode successful.
+ * retval #kStatus_SPC_CORELDOLowDriveStrengthIgnore If any voltage detect enabled,
+ core_ldo's drive strength can not set to low.
+ * retval #kStatus_SPC_BandgapModeWrong The selected bandgap mode is not allowed.
+ */
+status_t SPC_SetActiveModeCoreLDORegulatorDriveStrength(SPC_Type *base, spc_core_ldo_drive_strength_t driveStrength)
+{
+ if (driveStrength == kSPC_CoreLDO_LowDriveStrength)
+ {
+ /* If any voltage detect feature is enabled in Active mode, then CORE_LDO's drive strength must not set to low.
+ */
+ if (SPC_GetActiveModeVoltageDetectStatus(base) != 0UL)
+ {
+ return kStatus_SPC_CORELDOLowDriveStrengthIgnore;
+ }
+ }
+
+ if (driveStrength == kSPC_CoreLDO_NormalDriveStrength)
+ {
+ /* If specify normal drive strength, bandgap must not be disabled. */
+ if (SPC_GetActiveModeBandgapMode(base) == kSPC_BandgapDisabled)
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+ }
+
+ base->ACTIVE_CFG =
+ ((base->ACTIVE_CFG & ~SPC_ACTIVE_CFG_CORELDO_VDD_DS_MASK) | SPC_ACTIVE_CFG_CORELDO_VDD_DS(driveStrength));
+
+ return kStatus_Success;
+}
+#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
+
+/*!
+ * brief Configs CORE LDO Regulator in low power mode
+ *
+ * This function configs CORE LDO Regulator in Low Power mode.
+ * If CORE LDO VDD Drive Strength is set to Normal, the CORE LDO VDD regulator voltage
+ * level in Active mode must be equal to the voltage level in Low power mode. And the Bandgap
+ * must be programmed to select bandgap enabled.
+ * Core VDD voltage levels for the Core LDO low power regulator can only be changed when the CORE
+ * LDO Drive Strength is set as Normal.
+ *
+ * param base SPC peripheral base address.
+ * param option Pointer to the spc_lowpower_mode_Core_LDO_option_t structure.
+ * retval kStatus_Success Config Core LDO regulator in power mode successfully.
+ * retval kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * retval kStatus_SPC_CORELDOLowDriveStrengthIgnore HVDs/LVDs are not disabled before invoking this function.
+ * retval kStatus_SPC_BandgapModeWrong The bandgap is not enabled before invoking this function.
+ */
+status_t SPC_SetLowPowerModeCoreLDORegulatorConfig(SPC_Type *base, const spc_lowpower_mode_core_ldo_option_t *option)
+{
+ status_t status = kStatus_Success;
+
+ if ((base->SC & SPC_SC_BUSY_MASK) != 0UL)
+ {
+ /*
+ * $Line Coverage Justification$
+ * $ref spc_c_ref_1$.
+ */
+ return kStatus_SPC_Busy;
+ }
+
+ status = SPC_SetLowPowerModeCoreLDORegulatorDriveStrength(base, option->CoreLDODriveStrength);
+ if (status == kStatus_Success)
+ {
+ (void)SPC_SetLowPowerModeCoreLDORegulatorVoltageLevel(base, option->CoreLDOVoltage);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Set Core LDO VDD Regulator Voltage level in Low power mode.
+ *
+ * @note If Core LDO's drive strengths are same in active and low power mode, the Core LDO's voltage must be set to the
+ * same value in active and low power mode. Application should take care of this limitation.
+ *
+ * @note Some devices require Core LDO and DCDC have the same voltage level even if Core LDO is off. Application should
+ * take care of this limitation.
+ *
+ * param base SPC peripheral base address.
+ * param voltageLevel Voltage level of CORE LDO Regulator in Low power mode, please
+ refer to @ref spc_core_ldo_voltage_level_t.
+ *
+ * retval #kStatus_SPC_Busy The SPC instance is busy to execute other operation.
+ * retval #kStatus_Success Set Core LDO regulator voltage level in Low power mode successful.
+ */
+status_t SPC_SetLowPowerModeCoreLDORegulatorVoltageLevel(SPC_Type *base, spc_core_ldo_voltage_level_t voltageLevel)
+{
+ if ((base->SC & SPC_SC_BUSY_MASK) != 0UL)
+ {
+ /*
+ * $Line Coverage Justification$
+ * $ref spc_c_ref_1$.
+ */
+ return kStatus_SPC_Busy;
+ }
+
+ base->LP_CFG = ((base->LP_CFG & ~SPC_LP_CFG_CORELDO_VDD_LVL_MASK) | SPC_LP_CFG_CORELDO_VDD_LVL(voltageLevel));
+
+ /*
+ * $Branch Coverage Justification$
+ * $ref spc_c_ref_1$.
+ */
+ while ((base->SC & SPC_SC_BUSY_MASK) != 0UL)
+ {
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Set Core LDO VDD Regulator Drive Strength in Low power mode.
+ *
+ * param base SPC peripheral base address.
+ * param driveStrength Specify drive strength of CORE LDO in low power mode.
+ *
+ * retval #kStatus_SPC_CORELDOLowDriveStrengthIgnore Some voltage detect enabled, CORE LDO's drive strength can not set
+ * as low.
+ * retval #kStatus_Success Set Core LDO regulator drive strength in Low power mode successful.
+ * retval #kStatus_SPC_BandgapModeWrong Bandgap is disabled when attempt to set CORE LDO work as normal drive strength.
+ */
+status_t SPC_SetLowPowerModeCoreLDORegulatorDriveStrength(SPC_Type *base, spc_core_ldo_drive_strength_t driveStrength)
+{
+ if (driveStrength == kSPC_CoreLDO_LowDriveStrength)
+ {
+ /* If any voltage detect feature is enabled in Low Power mode, then CORE_LDO's drive strength must not set to
+ * low.
+ */
+ if (SPC_GetLowPowerModeVoltageDetectStatus(base) != 0UL)
+ {
+ return kStatus_SPC_CORELDOLowDriveStrengthIgnore;
+ }
+ }
+ else
+ {
+ /* To specify normal drive strength, the bandgap must be enabled in low power mode. */
+ if (SPC_GetLowPowerModeBandgapMode(base) == kSPC_BandgapDisabled)
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+ }
+
+ base->LP_CFG = ((base->LP_CFG & ~SPC_LP_CFG_CORELDO_VDD_DS_MASK) | SPC_LP_CFG_CORELDO_VDD_DS(driveStrength));
+
+ return kStatus_Success;
+}
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+/*!
+ * brief Configs System LDO VDD Regulator in Active mode.
+ *
+ * This function configs System LDO VDD Regulator in Active mode.
+ * If System LDO VDD Drive Strength is set to Normal, the Bandgap mode in Active mode must be programmed
+ * to a value that enable the bandgap.
+ * If any voltage detects are kept enabled, configuration to set System LDO VDD drive strength to low will
+ * be ignored.
+ * If select System LDO VDD Regulator voltage level to Over Drive Voltage, the Drive Strength of System LDO VDD
+ * Regulator must be set to Normal otherwise the regulator Drive Strength will be forced to Normal.
+ * If select System LDO VDD Regulator voltage level to Over Drive Voltage, the High voltage detect must be disabled.
+ * Otherwise it will be fail to regulator to Over Drive Voltage.
+ *
+ * param base SPC peripheral base address.
+ * param option Pointer to the spc_active_mode_Sys_LDO_option_t structure.
+ * retval kStatus_Success Config System LDO regulator in Active power mode successful.
+ * retval kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * retval kStatus_SPC_BandgapModeWrong The bandgap is not enabled before invoking this function.
+ * retval kStatus_SPC_SYSLDOOverDriveVoltageFail HVD of System VDD is not disable before setting to Over Drive voltage.
+ * retval kStatus_SPC_SYSLDOLowDriveStrengthIgnore Set System LDO VDD regulator's driver strength to Low will be
+ * ignored.
+ */
+status_t SPC_SetActiveModeSystemLDORegulatorConfig(SPC_Type *base, const spc_active_mode_sys_ldo_option_t *option)
+{
+ assert(option != NULL);
+
+ if ((base->SC & SPC_SC_BUSY_MASK) != 0UL)
+ {
+ /*
+ * $Line Coverage Justification$
+ * $ref spc_c_ref_1$.
+ */
+ return kStatus_SPC_Busy;
+ }
+
+ /* Check input parameters before setting registers. */
+ /* 1. To set to low DS, all LVDs/HVDs must be disabled previously. */
+ if ((SPC_GetActiveModeVoltageDetectStatus(base) != 0UL) &&
+ (option->SysLDODriveStrength == kSPC_SysLDO_LowDriveStrength))
+ {
+ return kStatus_SPC_SYSLDOLowDriveStrengthIgnore;
+ }
+ /* 2. If specify normal drive strength, bandgap must not be disabled. */
+ if ((SPC_GetActiveModeBandgapMode(base) == kSPC_BandgapDisabled) &&
+ (option->SysLDODriveStrength == kSPC_SysLDO_NormalDriveStrength))
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+
+ /* 3. Must disable system LDO high voltage detector before specifying overdrive voltage. */
+ if ((option->SysLDOVoltage == kSPC_SysLDO_OverDriveVoltage) &&
+ ((SPC_GetActiveModeVoltageDetectStatus(base) & SPC_ACTIVE_CFG_SYS_HVDE_MASK) != 0UL))
+ {
+ return kStatus_SPC_SYSLDOOverDriveVoltageFail;
+ }
+
+ (void)SPC_SetActiveModeSystemLDORegulatorDriveStrength(base, option->SysLDODriveStrength);
+ (void)SPC_SetActiveModeSystemLDORegulatorVoltageLevel(base, option->SysLDOVoltage);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Set System LDO Regulator voltage level in Active mode.
+ *
+ * @note The system LDO regulator can only operate at the overdrive voltage level for a limited amount of time for the
+ * life of chip.
+ *
+ * param base SPC peripheral base address.
+ * param voltageLevel Specify the voltage level of System LDO Regulator in Active mode.
+ *
+ * retval #kStatus_Success Set System LDO Regulator voltage level in Active mode successfully.
+ * retval #kStatus_SPC_SYSLDOOverDriveVoltageFail Must disable system LDO high voltage detector before specifying
+ * overdrive voltage.
+ */
+status_t SPC_SetActiveModeSystemLDORegulatorVoltageLevel(SPC_Type *base, spc_sys_ldo_voltage_level_t voltageLevel)
+{
+ if (voltageLevel == kSPC_SysLDO_OverDriveVoltage)
+ {
+ /* Must disable system LDO high voltage detector before specifying overdrive voltage. */
+ if ((SPC_GetActiveModeVoltageDetectStatus(base) & SPC_ACTIVE_CFG_SYS_HVDE_MASK) != 0UL)
+ {
+ return kStatus_SPC_SYSLDOOverDriveVoltageFail;
+ }
+ }
+
+ base->ACTIVE_CFG =
+ (base->ACTIVE_CFG & ~SPC_ACTIVE_CFG_SYSLDO_VDD_LVL_MASK) | SPC_ACTIVE_CFG_SYSLDO_VDD_LVL(voltageLevel);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Set System LDO Regulator Drive Strength in Active mode.
+ *
+ * param base SPC peripheral base address.
+ * param driveStrength Specify the drive strength of System LDO Regulator in Active mode.
+ *
+ * retval #kStatus_Success Set System LDO Regulator drive strength in Active mode successfully.
+ * retval #kStatus_SPC_SYSLDOLowDriveStrengthIgnore Attempt to specify low drive strength is ignored due to any
+ voltage detect feature is enabled in active mode.
+ * retval #kStatus_SPC_BandgapModeWrong Bandgap mode in Active mode must be programmed to a value that enables
+ the bandgap if attempt to specify normal drive strength.
+ */
+status_t SPC_SetActiveModeSystemLDORegulatorDriveStrength(SPC_Type *base, spc_sys_ldo_drive_strength_t driveStrength)
+{
+ if (driveStrength == kSPC_SysLDO_LowDriveStrength)
+ {
+ /* If enabled any LVDs or HVDs, SPC will ignore the attempt to specify low drive strength. */
+ if (SPC_GetActiveModeVoltageDetectStatus(base) != 0UL)
+ {
+ return kStatus_SPC_SYSLDOLowDriveStrengthIgnore;
+ }
+ }
+
+ if (driveStrength == kSPC_SysLDO_NormalDriveStrength)
+ {
+ /* If specify normal drive strength, bandgap must not be disabled. */
+ if (SPC_GetActiveModeBandgapMode(base) == kSPC_BandgapDisabled)
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+ }
+
+ base->ACTIVE_CFG =
+ (base->ACTIVE_CFG & ~SPC_ACTIVE_CFG_SYSLDO_VDD_DS_MASK) | SPC_ACTIVE_CFG_SYSLDO_VDD_DS(driveStrength);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configs System LDO regulator in low power modes.
+ *
+ * This function configs System LDO regulator in low power modes.
+ * If System LDO VDD Regulator Drive strength is set to normal, bandgap mode in low power
+ * mode must be programmed to a value that enables the Bandgap.
+ * If any High voltage detectors or Low Voltage detectors are kept enabled, configuration
+ * to set System LDO Regulator drive strength as Low will be ignored.
+ *
+ * param base SPC peripheral base address.
+ * param option Pointer to spc_lowpower_mode_Sys_LDO_option_t structure.
+ *
+ * retval kStatus_Success Config System LDO regulator in Low Power Mode successfully.
+ * retval kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * retval kStatus_SPC_BandgapModeWrong The bandgap mode setting in Low Power Mode is wrong.
+ * retval kStatus_SPC_SYSLDOLowDriveStrengthIgnore Set driver strength to low will be ignored.
+ */
+status_t SPC_SetLowPowerModeSystemLDORegulatorConfig(SPC_Type *base, const spc_lowpower_mode_sys_ldo_option_t *option)
+{
+ status_t status;
+
+ if ((base->SC & SPC_SC_BUSY_MASK) != 0UL)
+ {
+ /*
+ * $Line Coverage Justification$
+ * $ref spc_c_ref_1$.
+ */
+ return kStatus_SPC_Busy;
+ }
+
+ status = SPC_SetLowPowerModeSystemLDORegulatorDriveStrength(base, option->SysLDODriveStrength);
+
+ return status;
+}
+
+/*!
+ * brief Set System LDO Regulator drive strength in Low Power Mode.
+ *
+ * param base SPC peripheral base address.
+ * param driveStrength Specify the drive strength of System LDO Regulator in Low Power Mode.
+ *
+ * retval #kStatus_Success Set System LDO Regulator drive strength in Low Power Mode successfully.
+ * retval #kStatus_SPC_SYSLDOLowDriveStrengthIgnore Attempt to specify low drive strength is ignored due to any
+ voltage detect feature is enabled in low power mode.
+ * retval #kStatus_SPC_BandgapModeWrong Bandgap mode in low power mode must be programmed to a value that enables
+ the bandgap if attempt to specify normal drive strength.
+ */
+status_t SPC_SetLowPowerModeSystemLDORegulatorDriveStrength(SPC_Type *base, spc_sys_ldo_drive_strength_t driveStrength)
+{
+ if (driveStrength == kSPC_SysLDO_LowDriveStrength)
+ {
+ /* If enabled any LVDs or HVDs, SPC will ignore the attempt to specify low drive strength. */
+ if (SPC_GetLowPowerModeVoltageDetectStatus(base) != 0UL)
+ {
+ return kStatus_SPC_SYSLDOLowDriveStrengthIgnore;
+ }
+ }
+ else
+ {
+ /* If specify normal drive strength, bandgap must not be disabled. */
+ if (SPC_GetLowPowerModeBandgapMode(base) == kSPC_BandgapDisabled)
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+ }
+
+ base->LP_CFG = (base->LP_CFG & ~SPC_LP_CFG_SYSLDO_VDD_DS_MASK) | SPC_LP_CFG_SYSLDO_VDD_DS(driveStrength);
+
+ return kStatus_Success;
+}
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+/*!
+ * brief Configs DCDC VDD Regulator in Active mode.
+ *
+ * note When changing the DCDC output voltage level, take care to change the CORE LDO voltage level.
+ *
+ * param base SPC peripheral base address.
+ * param option Pointer to the spc_active_mode_DCDC_option_t structure.
+ *
+ * retval kStatus_Success Config DCDC regulator in Active power mode successful.
+ * retval kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * retval kStatus_SPC_BandgapModeWrong The bandgap mode setting in Active mode is wrong.
+ */
+status_t SPC_SetActiveModeDCDCRegulatorConfig(SPC_Type *base, const spc_active_mode_dcdc_option_t *option)
+{
+ assert(option != NULL);
+ status_t status = kStatus_Success;
+
+ if ((base->SC & SPC_SC_BUSY_MASK) != 0UL)
+ {
+ /*
+ * $Line Coverage Justification$
+ * $ref spc_c_ref_1$.
+ */
+ return kStatus_SPC_Busy;
+ }
+
+ status = SPC_SetActiveModeDCDCRegulatorDriveStrength(base, option->DCDCDriveStrength);
+
+ if (status == kStatus_Success)
+ {
+ SPC_SetActiveModeDCDCRegulatorVoltageLevel(base, option->DCDCVoltage);
+ }
+
+ /*
+ * $Branch Coverage Justification$
+ * $ref spc_c_ref_1$.
+ */
+ while ((base->SC & SPC_SC_BUSY_MASK) != 0UL)
+ {
+ }
+
+ return status;
+}
+
+/*!
+ * brief Set DCDC VDD Regulator drive strength in Active mode.
+ *
+ * note To set DCDC drive strength as Normal, the bandgap must be enabled.
+ *
+ * param base SPC peripheral base address.
+ * param driveStrength Specify the DCDC VDD regulator drive strength, please refer to @ref spc_dcdc_drive_strength_t.
+ *
+ * retval #kStatus_Success Set DCDC VDD Regulator drive strength in Active mode successfully.
+ * retval #kStatus_SPC_BandgapModeWrong Set DCDC VDD Regulator drive strength to Normal, the Bandgap must be enabled.
+ */
+status_t SPC_SetActiveModeDCDCRegulatorDriveStrength(SPC_Type *base, spc_dcdc_drive_strength_t driveStrength)
+{
+ if (driveStrength == kSPC_DCDC_NormalDriveStrength)
+ {
+ /* If specify normal drive strength, bandgap must not be disabled. */
+ if (SPC_GetActiveModeBandgapMode(base) == kSPC_BandgapDisabled)
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+ }
+
+ base->ACTIVE_CFG =
+ ((base->ACTIVE_CFG) & (~SPC_ACTIVE_CFG_DCDC_VDD_DS_MASK)) | SPC_ACTIVE_CFG_DCDC_VDD_DS(driveStrength);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configs DCDC VDD Regulator in Low power modes.
+ *
+ * If DCDC VDD Drive Strength is set to Normal, the Bandgap mode in Low Power mode must be programmed
+ * to a value that enables the Bandgap.
+ * In Deep Power Down mode, DCDC regulator is always turned off.
+ *
+ * param base SPC peripheral base address.
+ * param option Pointer to the spc_lowpower_mode_DCDC_option_t structure.
+ *
+ * retval kStatus_Success Config DCDC regulator in low power mode successfully.
+ * retval kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * retval kStatus_SPC_BandgapModeWrong The bandgap should be enabled before invoking this function.
+ */
+status_t SPC_SetLowPowerModeDCDCRegulatorConfig(SPC_Type *base, const spc_lowpower_mode_dcdc_option_t *option)
+{
+ if ((base->SC & SPC_SC_BUSY_MASK) != 0UL)
+ {
+ /*
+ * $Line Coverage Justification$
+ * $ref spc_c_ref_1$.
+ */
+ return kStatus_SPC_Busy;
+ }
+
+ /* Check input parameter before setting registers. */
+ if ((option->DCDCDriveStrength == kSPC_DCDC_NormalDriveStrength) &&
+ (SPC_GetLowPowerModeBandgapMode(base) == kSPC_BandgapDisabled))
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+
+ /*
+ 1. Configure to desired voltage level.
+ 2. Change to low drive strength.
+ 3. Configure same voltage level in active mode.
+ */
+ SPC_SetLowPowerModeDCDCRegulatorVoltageLevel(base, option->DCDCVoltage);
+
+ /* Change to desired drive strength. */
+ if (option->DCDCDriveStrength != kSPC_DCDC_LowDriveStrength)
+ {
+ (void)SPC_SetLowPowerModeDCDCRegulatorDriveStrength(base, option->DCDCDriveStrength);
+ }
+
+ /*
+ * $Branch Coverage Justification$
+ * $ref spc_c_ref_1$.
+ */
+ while ((base->SC & SPC_SC_BUSY_MASK) != 0UL)
+ {
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Set DCDC VDD Regulator drive strength in Low power mode.
+ *
+ * param base SPC peripheral base address.
+ * param driveStrength Specify the DCDC VDD Regulator drive strength, please refer to @ref spc_dcdc_drive_strength_t.
+ *
+ * retval #kStatus_Success Set DCDC VDD Regulator drive strength in Low power mode successfully.
+ * retval #kStatus_SPC_BandgapModeWrong Set DCDC VDD Regulator drive strength to Normal, the Bandgap must be enabled.
+ */
+status_t SPC_SetLowPowerModeDCDCRegulatorDriveStrength(SPC_Type *base, spc_dcdc_drive_strength_t driveStrength)
+{
+ if (driveStrength == kSPC_DCDC_NormalDriveStrength)
+ {
+ /* If specify normal drive strength, bandgap must not be disabled. */
+ if (SPC_GetLowPowerModeBandgapMode(base) == kSPC_BandgapDisabled)
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+ }
+
+ base->LP_CFG = ((base->LP_CFG) & (~SPC_LP_CFG_DCDC_VDD_DS_MASK)) | SPC_LP_CFG_DCDC_VDD_DS(driveStrength);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Config DCDC Burst options
+ *
+ * param base SPC peripheral base address.
+ * param config Pointer to spc_DCDC_burst_config_t structure.
+ */
+void SPC_SetDCDCBurstConfig(SPC_Type *base, spc_dcdc_burst_config_t *config)
+{
+ assert(config != NULL);
+ uint32_t reg;
+ reg = base->DCDC_CFG;
+ reg &= ~(SPC_DCDC_CFG_FREQ_CNTRL_MASK | SPC_DCDC_CFG_FREQ_CNTRL_ON_MASK);
+ reg |= SPC_DCDC_CFG_FREQ_CNTRL(config->freq);
+ reg |= config->stabilizeBurstFreq ? SPC_DCDC_CFG_FREQ_CNTRL_ON(1U) : SPC_DCDC_CFG_FREQ_CNTRL_ON(0U);
+ base->DCDC_CFG = reg;
+
+ /* Blocking until previous DCDC burst completed. */
+ while ((base->DCDC_BURST_CFG & SPC_DCDC_BURST_CFG_BURST_ACK_MASK) == 0UL)
+ {
+ }
+
+ if ((config->sofwareBurstRequest) || (config->externalBurstRequest))
+ {
+ /* Clear DCDC burst acknowledge flag. */
+ base->DCDC_BURST_CFG |= SPC_DCDC_BURST_CFG_BURST_ACK_MASK;
+ }
+ base->DCDC_BURST_CFG |= SPC_DCDC_BURST_CFG_EXT_BURST_EN(config->externalBurstRequest);
+
+ if (config->sofwareBurstRequest)
+ {
+ base->DCDC_BURST_CFG |= SPC_DCDC_BURST_CFG_BURST_REQ_MASK;
+ }
+}
+
+/*!
+ * brief Set the count value of the reference clock.
+ *
+ * This function set the count value of the reference clock to control the frequency
+ * of dcdc refresh when dcdc is configured in Pulse Refresh mode.
+ *
+ * param base SPC peripheral base address.
+ * param count The count value, 16 bit width.
+ */
+void SPC_SetDCDCRefreshCount(SPC_Type *base, uint16_t count)
+{
+ uint32_t reg;
+
+ reg = base->DCDC_BURST_CFG;
+ reg &= ~SPC_DCDC_BURST_CFG_PULSE_REFRESH_CNT_MASK;
+ reg |= SPC_DCDC_BURST_CFG_PULSE_REFRESH_CNT(count);
+
+ base->DCDC_BURST_CFG = reg;
+}
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+
+/*!
+ * brief Configs all settings of regulators in Active mode at a time.
+ *
+ * @note This function is used to overwrite all settings of regulators(including bandgap mode, regulators'
+ * drive strength and voltage level) in active mode at a time.
+ *
+ * @note Enable/disable LVDs/HVDs before invoking this function.
+ *
+ * @note This function will check input parameters based on hardware restrictions before setting registers, if input
+ * parameters do not satisfy hardware restrictions the specific error will be reported.
+ *
+ *
+ * @note Some hardware restrictions not covered, application should be aware of this and follow this hardware
+ * restrictions otherwise some unknown issue may occur:
+ * 1. If Core LDO's drive strength are set to same value in both Active mode and low power mode,
+ * the voltage level should also set to same value.
+ * 2. When switching Core LDO's drive strength from low to normal, ensure the LDO_CORE high voltage level is set
+ * to same level that was set prior to switching to the LDO_CORE drive strength. Otherwise, if the LVDs are
+ * enabled, an unexpected LVD can occur.
+ *
+ * @note If this function can not satisfy some tricky settings, please invoke other low-level functions.
+ *
+ * param base SPC peripheral base address.
+ * param config Pointer to spc_active_mode_regulators_config_t structure.
+ * retval kStatus_Success Config regulators in Active power mode successful.
+ * retval kStatus_SPC_BandgapModeWrong The bandgap mode setting in Active mode is wrong.
+ * retval kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * retval kStatus_SPC_CORELDOVoltageWrong The selected voltage level in active mode is not allowed.
+ * retval kStatus_SPC_SYSLDOOverDriveVoltageFail Fail to regulator to Over Drive Voltage.
+ * retval kStatus_SPC_SYSLDOLowDriveStrengthIgnore Set driver strength to Low will be ignored.
+ * retval kStatus_SPC_DCDCLowDriveStrengthIgnore Set driver strength to Low will be ignored.
+ */
+status_t SPC_SetActiveModeRegulatorsConfig(SPC_Type *base, const spc_active_mode_regulators_config_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t activeModeVDValue = SPC_GetActiveModeVoltageDetectStatus(base);
+
+ /* Check input parameters */
+ /* 1. Bandgap should not be disabled if any of regulator in normal drive strength or
+ if any of LVDs/HVDs are enabled or if VDD CORE glitch detect are enabled. */
+ if ((config->bandgapMode == kSPC_BandgapDisabled) &&
+ ((activeModeVDValue != 0UL)
+#if !(defined(FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) && FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT)
+ || (SPC_CheckActiveModeVddCoreGlitchDetectEnabled(base) == true)
+#endif /* FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT */
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+ || (config->DCDCOption.DCDCDriveStrength == kSPC_DCDC_NormalDriveStrength)
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+ || (config->SysLDOOption.SysLDODriveStrength == kSPC_SysLDO_NormalDriveStrength)
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+#if (defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS)
+ || (config->CoreLDOOption.CoreLDODriveStrength == kSPC_CoreLDO_NormalDriveStrength)
+#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
+ ))
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+ /* 2. Must disable system LDO high voltage detector before specifying SysLDO to overdrive voltage */
+ if (((activeModeVDValue & SPC_ACTIVE_CFG_SYS_HVDE_MASK) != 0UL) &&
+ (config->SysLDOOption.SysLDOVoltage == kSPC_SysLDO_OverDriveVoltage))
+ {
+ return kStatus_SPC_SYSLDOOverDriveVoltageFail;
+ }
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+ /* 3. To set System LDO's drive strength to low, all LVDs and HVDs must be disabled. */
+ if ((activeModeVDValue != 0UL) && (config->SysLDOOption.SysLDODriveStrength == kSPC_SysLDO_LowDriveStrength))
+ {
+ return kStatus_SPC_SYSLDOLowDriveStrengthIgnore;
+ }
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+#if (defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS)
+ /* 4. To set Core LDO's drive strength to low, all LVDs and HVDs must be disabled. */
+ if ((activeModeVDValue != 0UL) && (config->CoreLDOOption.CoreLDODriveStrength == kSPC_CoreLDO_LowDriveStrength))
+ {
+ return kStatus_SPC_CORELDOLowDriveStrengthIgnore;
+ }
+#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+ /* 5. Core LDO and DCDC should have same voltage level. */
+ if ((uint8_t)config->DCDCOption.DCDCVoltage != (uint8_t)config->CoreLDOOption.CoreLDOVoltage)
+ {
+ return kStatus_SPC_CORELDOVoltageWrong;
+ }
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+
+ if ((base->SC & SPC_SC_BUSY_MASK) != 0UL)
+ {
+ return kStatus_SPC_Busy;
+ }
+
+ base->ACTIVE_CFG =
+ ((base->ACTIVE_CFG) & ~(SPC_ACTIVE_CFG_BGMODE_MASK)) | SPC_ACTIVE_CFG_BGMODE(config->bandgapMode);
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT) && FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT)
+ SPC_EnableActiveModeCMPBandgapBuffer(base, config->lpBuff);
+#endif /* FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+ (void)SPC_SetActiveModeSystemLDORegulatorConfig(base, &config->SysLDOOption);
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+ (void)SPC_SetActiveModeDCDCRegulatorConfig(base, &config->DCDCOption);
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+
+ (void)SPC_SetActiveModeCoreLDORegulatorConfig(base, &config->CoreLDOOption);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configs regulators in Low Power mode.
+ *
+ * This function provides the method to config all on-chip regulators in Low Power mode.
+ *
+ * param base SPC peripheral base address.
+ * param config Pointer to spc_lowpower_mode_regulators_config_t structure.
+ * retval #kStatus_Success Config regulators in Low power mode successful.
+ * retval #kStatus_SPC_BandgapModeWrong The bandgap should not be disabled based on input settings.
+ * retval #kStatus_SPC_CORELDOLowDriveStrengthIgnore Set driver strength to low will be ignored.
+ * retval #kStatus_SPC_SYSLDOLowDriveStrengthIgnore Set driver strength to low will be ignored.
+ * retval #kStatus_SPC_CORELDOVoltageWrong Core LDO and System LDO do not have same voltage level.
+ */
+status_t SPC_SetLowPowerModeRegulatorsConfig(SPC_Type *base, const spc_lowpower_mode_regulators_config_t *config)
+{
+ assert(config != NULL);
+ uint32_t lpModeVDValue = SPC_GetLowPowerModeVoltageDetectStatus(base);
+
+ /* Check input parameters */
+ /* 1. Bandgap should not be disabled if any of regulator in normal drive strength or
+ if any of LVDs/HVDs are enabled or if VDD CORE glitch detect are enabled. */
+ if ((config->bandgapMode == kSPC_BandgapDisabled) &&
+ ((lpModeVDValue != 0UL)
+#if !(defined(FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) && FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT)
+ || (SPC_CheckLowPowerModeVddCoreGlitchDetectEnabled(base) == true)
+#endif /* FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT */
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+ || (config->DCDCOption.DCDCDriveStrength == kSPC_DCDC_NormalDriveStrength)
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+ || (config->SysLDOOption.SysLDODriveStrength == kSPC_SysLDO_NormalDriveStrength)
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+#if (defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS)
+ || (config->CoreLDOOption.CoreLDODriveStrength == kSPC_CoreLDO_NormalDriveStrength)
+#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
+ ))
+ {
+ return kStatus_SPC_BandgapModeWrong;
+ }
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+ /* 2. To set System LDO's drive strength to low, all LVDs and HVDs must be disabled. */
+ if ((lpModeVDValue != 0UL) && (config->SysLDOOption.SysLDODriveStrength == kSPC_SysLDO_LowDriveStrength))
+ {
+ return kStatus_SPC_SYSLDOLowDriveStrengthIgnore;
+ }
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+#if (defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS)
+ /* 3. To set Core LDO's drive strength to low, all LVDs and HVDs must be disabled. */
+ if ((lpModeVDValue != 0UL) && (config->CoreLDOOption.CoreLDODriveStrength == kSPC_CoreLDO_LowDriveStrength))
+ {
+ return kStatus_SPC_CORELDOLowDriveStrengthIgnore;
+ }
+#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+ /* 5. Core LDO and DCDC should have same voltage level. */
+ if ((uint8_t)config->DCDCOption.DCDCVoltage != (uint8_t)config->CoreLDOOption.CoreLDOVoltage)
+ {
+ return kStatus_SPC_CORELDOVoltageWrong;
+ }
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+ base->LP_CFG = ((base->LP_CFG) & ~(SPC_LP_CFG_BGMODE_MASK)) | SPC_LP_CFG_BGMODE(config->bandgapMode);
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT) && FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT)
+ SPC_EnableLowPowerModeCMPBandgapBuffer(base, config->lpBuff);
+#endif /* FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT */
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_COREVDD_IVS_EN_BIT) && FSL_FEATURE_MCX_SPC_HAS_COREVDD_IVS_EN_BIT)
+ SPC_EnableLowPowerModeCoreVDDInternalVoltageScaling(base, config->CoreIVS);
+#endif /* FSL_FEATURE_MCX_SPC_HAS_COREVDD_IVS_EN_BIT */
+ SPC_EnableLowPowerModeLowPowerIREF(base, config->lpIREF);
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+ (void)SPC_SetLowPowerModeSystemLDORegulatorConfig(base, &config->SysLDOOption);
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+ (void)SPC_SetLowPowerModeDCDCRegulatorConfig(base, &config->DCDCOption);
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+
+ (void)SPC_SetLowPowerModeCoreLDORegulatorConfig(base, &config->CoreLDOOption);
+
+ return kStatus_Success;
+}
diff --git a/hw/bsp/mcx/drivers/spc/fsl_spc.h b/hw/bsp/mcx/drivers/spc/fsl_spc.h
new file mode 100644
index 000000000..69a001098
--- /dev/null
+++ b/hw/bsp/mcx/drivers/spc/fsl_spc.h
@@ -0,0 +1,2433 @@
+/*
+ * Copyright 2022-2024 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FSL_SPC_H_
+#define FSL_SPC_H_
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup mcx_spc
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*! @{ */
+/*! @brief SPC driver version 2.4.2. */
+#define FSL_SPC_DRIVER_VERSION (MAKE_VERSION(2, 4, 2))
+/*! @} */
+
+#define SPC_EVD_CFG_REG_EVDISO_SHIFT 0UL
+#define SPC_EVD_CFG_REG_EVDLPISO_SHIFT 8UL
+#define SPC_EVD_CFG_REG_EVDSTAT_SHIFT 16UL
+
+#define SPC_EVD_CFG_REG_EVDISO(x) ((uint32_t)(x) << SPC_EVD_CFG_REG_EVDISO_SHIFT)
+#define SPC_EVD_CFG_REG_EVDLPISO(x) ((uint32_t)(x) << SPC_EVD_CFG_REG_EVDLPISO_SHIFT)
+#define SPC_EVD_CFG_REG_EVDSTAT(x) ((uint32_t)(x) << SPC_EVD_CFG_REG_EVDSTAT_SHIFT)
+
+#if (defined(SPC_GLITCH_DETECT_SC_CNT_SELECT_MASK))
+#define VDD_CORE_GLITCH_DETECT_SC GLITCH_DETECT_SC
+#define SPC_VDD_CORE_GLITCH_DETECT_SC_GLITCH_DETECT_FLAG_MASK SPC_GLITCH_DETECT_SC_GLITCH_DETECT_FLAG_MASK
+#define SPC_VDD_CORE_GLITCH_DETECT_SC_GLITCH_DETECT_FLAG SPC_GLITCH_DETECT_SC_GLITCH_DETECT_FLAG
+#define SPC_VDD_CORE_GLITCH_DETECT_SC_LOCK_MASK SPC_GLITCH_DETECT_SC_LOCK_MASK
+#define SPC_VDD_CORE_GLITCH_DETECT_SC_CNT_SELECT_MASK SPC_GLITCH_DETECT_SC_CNT_SELECT_MASK
+#define SPC_VDD_CORE_GLITCH_DETECT_SC_CNT_SELECT SPC_GLITCH_DETECT_SC_CNT_SELECT
+#define SPC_VDD_CORE_GLITCH_DETECT_SC_RE_MASK SPC_GLITCH_DETECT_SC_RE_MASK
+#define SPC_VDD_CORE_GLITCH_DETECT_SC_RE SPC_GLITCH_DETECT_SC_RE
+#define SPC_VDD_CORE_GLITCH_DETECT_SC_TIMEOUT_MASK SPC_GLITCH_DETECT_SC_TIMEOUT_MASK
+#define SPC_VDD_CORE_GLITCH_DETECT_SC_TIMEOUT SPC_GLITCH_DETECT_SC_TIMEOUT
+#define SPC_VDD_CORE_GLITCH_DETECT_SC_IE_MASK SPC_GLITCH_DETECT_SC_IE_MASK
+#define SPC_VDD_CORE_GLITCH_DETECT_SC_IE SPC_GLITCH_DETECT_SC_IE
+#endif
+
+/*!
+ * @brief SPC status enumeration.
+ *
+ * @note Some device(such as MCXA family) do not equip DCDC or System LDO, please refer to the reference manual
+ * to check.
+ */
+enum
+{
+ kStatus_SPC_Busy = MAKE_STATUS(kStatusGroup_SPC, 0U), /*!< The SPC instance is busy executing any
+ type of power mode transition. */
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+ kStatus_SPC_DCDCLowDriveStrengthIgnore = MAKE_STATUS(kStatusGroup_SPC, 1U), /*!< DCDC Low drive strength setting be
+ ignored for LVD/HVD enabled. */
+ kStatus_SPC_DCDCPulseRefreshModeIgnore = MAKE_STATUS(kStatusGroup_SPC, 2U), /*!< DCDC Pulse Refresh Mode drive
+ strength setting be ignored for LVD/HVD enabled. */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+ kStatus_SPC_SYSLDOOverDriveVoltageFail = MAKE_STATUS(kStatusGroup_SPC, 3U), /*!< SYS LDO regulate to Over drive
+ voltage failed for SYS LDO HVD must be disabled. */
+ kStatus_SPC_SYSLDOLowDriveStrengthIgnore = MAKE_STATUS(kStatusGroup_SPC, 4U), /*!< SYS LDO Low driver strength
+ setting be ignored for LDO LVD/HVD enabled. */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+ kStatus_SPC_CORELDOLowDriveStrengthIgnore = MAKE_STATUS(kStatusGroup_SPC, 5U), /*!< CORE LDO Low driver strength
+ setting be ignored for LDO LVD/HVD enabled. */
+ kStatus_SPC_CORELDOVoltageWrong = MAKE_STATUS(kStatusGroup_SPC, 7U), /*!< Core LDO voltage is wrong. */
+ kStatus_SPC_CORELDOVoltageSetFail = MAKE_STATUS(kStatusGroup_SPC, 8U), /*!< Core LDO voltage set fail. */
+ kStatus_SPC_BandgapModeWrong = MAKE_STATUS(kStatusGroup_SPC, 6U), /*!< Selected Bandgap Mode wrong. */
+};
+
+/*!
+ * @brief Voltage Detect Status Flags.
+ */
+enum _spc_voltage_detect_flags
+{
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD) && FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD)
+ kSPC_IOVDDHighVoltageDetectFlag = SPC_VD_STAT_IOVDD_HVDF_MASK, /*!< IO VDD High-Voltage detect flag. */
+ kSPC_IOVDDLowVoltageDetectFlag = SPC_VD_STAT_IOVDD_LVDF_MASK, /*!< IO VDD Low-Voltage detect flag. */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD */
+ kSPC_SystemVDDHighVoltageDetectFlag = SPC_VD_STAT_SYSVDD_HVDF_MASK, /*!< System VDD High-Voltage detect flag. */
+ kSPC_SystemVDDLowVoltageDetectFlag = SPC_VD_STAT_SYSVDD_LVDF_MASK, /*!< System VDD Low-Voltage detect flag. */
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD) && FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD)
+ kSPC_CoreVDDHighVoltageDetectFlag = SPC_VD_STAT_COREVDD_HVDF_MASK, /*!< Core VDD High-Voltage detect flag. */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD */
+ kSPC_CoreVDDLowVoltageDetectFlag = SPC_VD_STAT_COREVDD_LVDF_MASK, /*!< Core VDD Low-Voltage detect flag. */
+};
+
+/*!
+ * @brief SPC power domain isolation status.
+ * @note Some devices(such as MCXA family) do not contain WAKE Power Domain, please refer to the reference manual to
+ * check.
+ */
+enum _spc_power_domains
+{
+ kSPC_MAINPowerDomainRetain = 1UL << 16U, /*!< Peripherals and IO pads retain in MAIN Power Domain. */
+ kSPC_WAKEPowerDomainRetain = 1UL << 17U, /*!< Peripherals and IO pads retain in WAKE Power Domain. */
+};
+
+/*!
+ * @brief The enumeration of all analog module that can be controlled by SPC in active or low-power modes.
+ * @anchor spc_analog_module_control
+ */
+enum _spc_analog_module_control
+{
+ kSPC_controlVref = 1UL << 0UL, /*!< Enable/disable VREF in active or low-power modes. */
+ kSPC_controlUsb3vDet = 1UL << 1UL, /*!< Enable/disable USB3V_Det in active or low-power modes. */
+ kSPC_controlDac0 = 1UL << 4UL, /*!< Enable/disable DAC0 in active or low-power modes. */
+ kSPC_controlDac1 = 1UL << 5UL, /*!< Enable/disable DAC1 in active or low-power modes. */
+ kSPC_controlDac2 = 1UL << 6UL, /*!< Enable/disable DAC2 in active or low-power modes. */
+ kSPC_controlOpamp0 = 1UL << 8UL, /*!< Enable/disable OPAMP0 in active or low-power modes. */
+ kSPC_controlOpamp1 = 1UL << 9UL, /*!< Enable/disable OPAMP1 in active or low-power modes. */
+ kSPC_controlOpamp2 = 1UL << 10UL, /*!< Enable/disable OPAMP2 in active or low-power modes. */
+ kSPC_controlCmp0 = 1UL << 16UL, /*!< Enable/disable CMP0 in active or low-power modes. */
+ kSPC_controlCmp1 = 1UL << 17UL, /*!< Enable/disable CMP1 in active or low-power modes. */
+ kSPC_controlCmp2 = 1UL << 18UL, /*!< Enable/disable CMP2 in active or low-power modes. */
+ kSPC_controlCmp0Dac = 1UL << 20UL, /*!< Enable/disable CMP0_DAC in active or low-power modes. */
+ kSPC_controlCmp1Dac = 1UL << 21UL, /*!< Enable/disable CMP1_DAC in active or low-power modes. */
+ kSPC_controlCmp2Dac = 1UL << 22UL, /*!< Enable/disable CMP2_DAC in active or low-power modes. */
+ kSPC_controlAllModules = 0x770773UL, /*!< Enable/disable all modules in active or low-power modes. */
+};
+
+/*!
+ * @brief The enumeration of spc power domain, the connected power domain is chip specific, please refer to chip's RM
+ * for details.
+ */
+typedef enum _spc_power_domain_id
+{
+ kSPC_PowerDomain0 = 0U, /*!< Power domain0, the connected power domain is chip specific. */
+ kSPC_PowerDomain1 = 1U, /*!< Power domain1, the connected power domain is chip specific. */
+} spc_power_domain_id_t;
+
+/*!
+ * @brief The enumeration of Power domain's low power mode.
+ */
+typedef enum _spc_power_domain_low_power_mode
+{
+ kSPC_SleepWithSYSClockRunning = 0U, /*!< Power domain request SLEEP mode with SYS clock running. */
+ kSPC_DeepSleepWithSysClockOff = 1U, /*!< Power domain request deep sleep mode with system clock off. */
+ kSPC_PowerDownWithSysClockOff = 2U, /*!< Power domain request power down mode with system clock off. */
+ kSPC_DeepPowerDownWithSysClockOff = 4U, /*!< Power domain request deep power down mode with system clock off. */
+} spc_power_domain_low_power_mode_t;
+
+/*!
+ * @brief SPC low power request output pin polarity.
+ */
+typedef enum _spc_lowPower_request_pin_polarity
+{
+ kSPC_HighTruePolarity = 0x0U, /*!< Control the High Polarity of the Low Power Request Pin. */
+ kSPC_LowTruePolarity = 0x1U, /*!< Control the Low Polarity of the Low Power Request Pin. */
+} spc_lowpower_request_pin_polarity_t;
+
+/*!
+ * @brief SPC low power request output override.
+ */
+typedef enum _spc_lowPower_request_output_override
+{
+ kSPC_LowPowerRequestNotForced = 0x0U, /*!< Not Forced. */
+ kSPC_LowPowerRequestReserved = 0x1U, /*!< Reserved. */
+ kSPC_LowPowerRequestForcedLow = 0x2U, /*!< Forced Low (Ignore LowPower request output polarity setting.) */
+ kSPC_LowPowerRequestForcedHigh = 0x3U, /*!< Forced High (Ignore LowPower request output polarity setting.) */
+} spc_lowpower_request_output_override_t;
+
+/*!
+ * @brief SPC Bandgap mode enumeration in Active mode or Low Power mode.
+ */
+typedef enum _spc_bandgap_mode
+{
+ kSPC_BandgapDisabled = 0x0U, /*!< Bandgap disabled. */
+ kSPC_BandgapEnabledBufferDisabled = 0x1U, /*!< Bandgap enabled with Buffer disabled. */
+ kSPC_BandgapEnabledBufferEnabled = 0x2U, /*!< Bandgap enabled with Buffer enabled. */
+ kSPC_BandgapReserved = 0x3U, /*!< Reserved. */
+} spc_bandgap_mode_t;
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+/*!
+ * @brief DCDC regulator voltage level enumeration in Active mode or Low Power Mode.
+ *
+ * @note #kSPC_DCDC_RetentionVoltage not supported for all power modes.
+ */
+typedef enum _spc_dcdc_voltage_level
+{
+ kSPC_DCDC_RetentionVoltage = 0x0U, /*!< DCDC_CORE Regulator regulate to retention
+ Voltage(Only supportedin low power modes) */
+ kSPC_DCDC_MidVoltage = 0x1U, /*!< DCDC_CORE Regulator regulate to Mid Voltage(1.0V). */
+ kSPC_DCDC_NormalVoltage = 0x2U, /*!< DCDC_CORE Regulator regulate to Normal Voltage(1.1V). */
+ kSPC_DCDC_OverdriveVoltage = 0x3U, /*!< DCDC_CORE Regulator regulate to Safe-Mode Voltage(1.2V). */
+} spc_dcdc_voltage_level_t;
+
+/*!
+ * @brief DCDC regulator Drive Strength enumeration in Active mode or Low Power Mode.
+ *
+ * @note Different drive strength differ in these DCDC characteristics:
+ * Maximum load current
+ * Quiescent current
+ * Transient response.
+ */
+typedef enum _spc_dcdc_drive_strength
+{
+ kSPC_DCDC_PulseRefreshMode = 0x0U, /*!< DCDC_CORE Regulator Drive Strength set to Pulse Refresh Mode,
+ * This enum member is only useful for Low Power Mode config, please
+ * note that pulse refresh mode is invalid in SLEEP mode.
+ */
+ kSPC_DCDC_LowDriveStrength = 0x1U, /*!< DCDC_CORE regulator Drive Strength set to low. */
+ kSPC_DCDC_NormalDriveStrength = 0x2U, /*!< DCDC_CORE regulator Drive Strength set to Normal. */
+} spc_dcdc_drive_strength_t;
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+/*!
+ * @brief SYS LDO regulator voltage level enumeration in Active mode.
+ */
+typedef enum _spc_sys_ldo_voltage_level
+{
+ kSPC_SysLDO_NormalVoltage = 0x0U, /*!< SYS LDO VDD Regulator regulate to Normal Voltage(1.8V). */
+ kSPC_SysLDO_OverDriveVoltage = 0x1U, /*!< SYS LDO VDD Regulator regulate to Over Drive Voltage(2.5V). */
+} spc_sys_ldo_voltage_level_t;
+
+/*!
+ * @brief SYS LDO regulator Drive Strength enumeration in Active mode or Low Power mode.
+ */
+typedef enum _spc_sys_ldo_drive_strength
+{
+ kSPC_SysLDO_LowDriveStrength = 0x0U, /*!< SYS LDO VDD regulator Drive Strength set to low. */
+ kSPC_SysLDO_NormalDriveStrength = 0x1U, /*!< SYS LDO VDD regulator Drive Strength set to Normal. */
+} spc_sys_ldo_drive_strength_t;
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+/*!
+ * @brief Core LDO regulator voltage level enumeration in Active mode or Low Power mode.
+ */
+typedef enum _spc_core_ldo_voltage_level
+{
+ kSPC_CoreLDO_UnderDriveVoltage = 0x0U, /*!< @deprecated, to align with description of latest RM, please use
+ #kSPC_Core_LDO_RetentionVoltage as instead. */
+ kSPC_Core_LDO_RetentionVoltage = 0x0U, /*!< Core LDO VDD regulator regulate to retention voltage, please note that
+ only useful in low power modes and not all devices support this options
+ please refer to devices' RM for details. */
+ kSPC_CoreLDO_MidDriveVoltage = 0x1U, /*!< Core LDO VDD regulator regulate to Mid Drive Voltage. */
+ kSPC_CoreLDO_NormalVoltage = 0x2U, /*!< Core LDO VDD regulator regulate to Normal Voltage. */
+ kSPC_CoreLDO_OverDriveVoltage = 0x3U, /*!< Core LDO VDD regulator regulate to overdrive Voltage. */
+} spc_core_ldo_voltage_level_t;
+
+/*!
+ * @brief CORE LDO VDD regulator Drive Strength enumeration in Low Power mode.
+ */
+typedef enum _spc_core_ldo_drive_strength
+{
+ kSPC_CoreLDO_LowDriveStrength = 0x0U, /*!< Core LDO VDD regulator Drive Strength set to low. */
+ kSPC_CoreLDO_NormalDriveStrength = 0x1U, /*!< Core LDO VDD regulator Drive Strength set to Normal. */
+} spc_core_ldo_drive_strength_t;
+
+/*!
+ * @brief IO VDD Low-Voltage Level Select.
+ */
+typedef enum _spc_low_voltage_level_select
+{
+ kSPC_LowVoltageNormalLevel = 0x0U, /*!< @deprecated, please use kSPC_LowVoltageHighRange as instead. */
+ kSPC_LowVoltageSafeLevel = 0x1U, /*!< @deprecated, please use kSPC_LowVoltageLowRange as instead. */
+
+ kSPC_LowVoltageHighRange = 0x0U, /*!< High range LVD threshold. */
+ kSPC_LowVoltageLowRange = 0x1U, /*!< Low range LVD threshold. */
+} spc_low_voltage_level_select_t;
+
+#if !(defined(FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) && FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT)
+/*!
+ * @brief Used to select output of 4-bit ripple counter is used to monitor a glitch on VDD core.
+ */
+typedef enum _spc_vdd_core_glitch_ripple_counter_select
+{
+ kSPC_selectBit0Of4bitRippleCounter = 0x0U, /*!< Select bit-0 of 4-bit Ripple Counter
+ to detect glitch on VDD Core. */
+ kSPC_selectBit1Of4bitRippleCounter = 0x1U, /*!< Select bit-1 of 4-bit Ripple Counter
+ to detect glitch on VDD Core. */
+ kSPC_selectBit2Of4bitRippleCounter = 0x2U, /*!< Select bit-2 of 4-bit Ripple Counter
+ to detect glitch on VDD Core. */
+ kSPC_selectBit3Of4bitRippleCounter = 0x3U, /*!< Select bit-3 of 4-bit Ripple Counter
+ to detect glitch on VDD Core. */
+} spc_vdd_core_glitch_ripple_counter_select_t;
+#endif
+
+/*!
+ * @brief The list of the operating voltage for the SRAM's read/write timing margin.
+ */
+typedef enum _spc_sram_operate_voltage
+{
+ kSPC_sramOperateAt1P0V = 0x1U, /*!< SRAM configured for 1.0V operation. */
+ kSPC_sramOperateAt1P1V = 0x2U, /*!< SRAM configured for 1.1V operation. */
+ kSPC_sramOperateAt1P2V = 0x3U, /*!< SRAM configured for 1.2V operation. */
+} spc_sram_operate_voltage_t;
+
+#if !(defined(FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) && FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT)
+/*!
+ * @brief The configuration of VDD Core glitch detector.
+ */
+typedef struct _spc_vdd_core_glitch_detector_config
+{
+ spc_vdd_core_glitch_ripple_counter_select_t rippleCounterSelect; /*!< Used to set ripple counter. */
+ uint8_t resetTimeoutValue; /*!< The timeout value used to reset glitch detect/compare logic after an initial
+ glitch is detected. */
+ bool enableReset; /*!< Used to enable/disable POR/LVD reset that caused by CORE VDD glitch detect error. */
+ bool enableInterrupt; /*!< Used to enable/disable hardware interrupt if CORE VDD glitch detect error. */
+} spc_vdd_core_glitch_detector_config_t;
+#endif
+
+typedef struct _spc_sram_voltage_config
+{
+ spc_sram_operate_voltage_t operateVoltage; /*!< Specifies the operating voltage for the SRAM's
+ read/write timing margin. */
+ bool requestVoltageUpdate; /*!< Used to control whether request an SRAM trim value change. */
+} spc_sram_voltage_config_t;
+
+/*!
+ * @brief Low Power Request output pin configuration.
+ */
+typedef struct _spc_lowpower_request_config
+{
+ bool enable; /*!< Low Power Request Output enable. */
+ spc_lowpower_request_pin_polarity_t polarity; /*!< Low Power Request Output pin polarity select. */
+ spc_lowpower_request_output_override_t override; /*!< Low Power Request Output Override. */
+} spc_lowpower_request_config_t;
+
+/*!
+ * @brief Core LDO regulator options in Active mode.
+ */
+typedef struct _spc_active_mode_core_ldo_option
+{
+ spc_core_ldo_voltage_level_t CoreLDOVoltage; /*!< Core LDO Regulator Voltage Level selection in Active mode. */
+#if defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS
+ spc_core_ldo_drive_strength_t CoreLDODriveStrength; /*!< Core LDO Regulator Drive Strength
+ selection in Active mode */
+#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
+} spc_active_mode_core_ldo_option_t;
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+/*!
+ * @brief System LDO regulator options in Active mode.
+ */
+typedef struct _spc_active_mode_sys_ldo_option
+{
+ spc_sys_ldo_voltage_level_t SysLDOVoltage; /*!< System LDO Regulator Voltage Level selection in Active mode. */
+ spc_sys_ldo_drive_strength_t SysLDODriveStrength; /*!< System LDO Regulator Drive Strength
+ selection in Active mode. */
+} spc_active_mode_sys_ldo_option_t;
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+/*!
+ * @brief DCDC regulator options in Active mode.
+ */
+typedef struct _spc_active_mode_dcdc_option
+{
+ spc_dcdc_voltage_level_t DCDCVoltage; /*!< DCDC Regulator Voltage Level selection in Active mode. */
+ spc_dcdc_drive_strength_t DCDCDriveStrength; /*!< DCDC_CORE Regulator Drive Strength selection in Active mode. */
+} spc_active_mode_dcdc_option_t;
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+
+/*!
+ * @brief Core LDO regulator options in Low Power mode.
+ */
+typedef struct _spc_lowpower_mode_core_ldo_option
+{
+ spc_core_ldo_voltage_level_t CoreLDOVoltage; /*!< Core LDO Regulator Voltage Level selection in Low Power mode. */
+ spc_core_ldo_drive_strength_t CoreLDODriveStrength; /*!< Core LDO Regulator Drive Strength
+ selection in Low Power mode */
+} spc_lowpower_mode_core_ldo_option_t;
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+/*!
+ * @brief System LDO regulator options in Low Power mode.
+ */
+typedef struct _spc_lowpower_mode_sys_ldo_option
+{
+ spc_sys_ldo_drive_strength_t SysLDODriveStrength; /*!< System LDO Regulator Drive Strength
+ selection in Low Power mode. */
+} spc_lowpower_mode_sys_ldo_option_t;
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+/*!
+ * @brief DCDC regulator options in Low Power mode.
+ */
+typedef struct _spc_lowpower_mode_dcdc_option
+{
+ spc_dcdc_voltage_level_t DCDCVoltage; /*!< DCDC Regulator Voltage Level selection in Low Power mode. */
+ spc_dcdc_drive_strength_t DCDCDriveStrength; /*!< DCDC_CORE Regulator Drive Strength selection in Low Power mode. */
+} spc_lowpower_mode_dcdc_option_t;
+
+/*!
+ * @brief DCDC Burst configuration.
+ * @deprecated Do not recommend to use this structure.
+ */
+typedef struct _spc_dcdc_burst_config
+{
+ bool sofwareBurstRequest; /*!< Enable/Disable DCDC Software Burst Request. */
+ bool externalBurstRequest; /*!< Enable/Disable DCDC External Burst Request. */
+ bool stabilizeBurstFreq; /*!< Enable/Disable DCDC frequency stabilization. */
+ uint8_t freq; /*!< The frequency of the current burst. */
+} spc_dcdc_burst_config_t;
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+
+/*!
+ * @brief CORE/SYS/IO VDD Voltage Detect options.
+ */
+typedef struct _spc_voltage_detect_option
+{
+ bool HVDInterruptEnable; /*!< CORE/SYS/IO VDD High Voltage Detect interrupt enable. */
+ bool HVDResetEnable; /*!< CORE/SYS/IO VDD High Voltage Detect reset enable. */
+ bool LVDInterruptEnable; /*!< CORE/SYS/IO VDD Low Voltage Detect interrupt enable. */
+ bool LVDResetEnable; /*!< CORE/SYS/IO VDD Low Voltage Detect reset enable. */
+} spc_voltage_detect_option_t;
+
+/*!
+ * @brief Core Voltage Detect configuration.
+ */
+typedef struct _spc_core_voltage_detect_config
+{
+ spc_voltage_detect_option_t option; /*!< Core VDD Voltage Detect option. */
+} spc_core_voltage_detect_config_t;
+
+/*!
+ * @brief System Voltage Detect Configuration.
+ */
+typedef struct _spc_system_voltage_detect_config
+{
+ spc_voltage_detect_option_t option; /*!< System VDD Voltage Detect option. */
+ spc_low_voltage_level_select_t level; /*!< @deprecated, reserved for all devices, will removed in next release. */
+} spc_system_voltage_detect_config_t;
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD) && FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD)
+/*!
+ * @brief IO Voltage Detect Configuration.
+ */
+typedef struct _spc_io_voltage_detect_config
+{
+ spc_voltage_detect_option_t option; /*!< IO VDD Voltage Detect option. */
+ spc_low_voltage_level_select_t level; /*!< IO VDD Low-voltage level selection. */
+} spc_io_voltage_detect_config_t;
+#endif /* FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD */
+
+/*!
+ * @brief Active mode configuration.
+ */
+typedef struct _spc_active_mode_regulators_config
+{
+ spc_bandgap_mode_t bandgapMode; /*!< Specify bandgap mode in active mode. */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT) && FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT)
+ bool lpBuff; /*!< Enable/disable CMP bandgap buffer. */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+ spc_active_mode_dcdc_option_t DCDCOption; /*!< Specify DCDC configurations in active mode. */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+ spc_active_mode_sys_ldo_option_t SysLDOOption; /*!< Specify System LDO configurations in active mode. */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+ spc_active_mode_core_ldo_option_t CoreLDOOption; /*!< Specify Core LDO configurations in active mode. */
+} spc_active_mode_regulators_config_t;
+
+/*!
+ * @brief Low Power Mode configuration.
+ */
+typedef struct _spc_lowpower_mode_regulators_config
+{
+ bool lpIREF; /*!< Enable/disable low power IREF in low power modes. */
+ spc_bandgap_mode_t bandgapMode; /*!< Specify bandgap mode in low power modes. */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT) && FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT)
+ bool lpBuff; /*!< Enable/disable CMP bandgap buffer in low power modes. */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_COREVDD_IVS_EN_BIT) && FSL_FEATURE_MCX_SPC_HAS_COREVDD_IVS_EN_BIT)
+ bool CoreIVS; /*!< Enable/disable CORE VDD internal voltage scaling. */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_COREVDD_IVS_EN_BIT */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+ spc_lowpower_mode_dcdc_option_t DCDCOption; /*!< Specify DCDC configurations in low power modes. */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+ spc_lowpower_mode_sys_ldo_option_t SysLDOOption; /*!< Specify system LDO configurations in low power modes. */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+ spc_lowpower_mode_core_ldo_option_t CoreLDOOption; /*!< Specify core LDO configurations in low power modes. */
+} spc_lowpower_mode_regulators_config_t;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus */
+
+/*!
+ * @name SPC Status
+ * @{
+ */
+/*!
+ * @brief Gets Isolation status for each power domains.
+ *
+ * This function gets the status which indicates whether certain
+ * peripheral and the IO pads are in a latched state as a result
+ * of having been in POWERDOWN mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return Current isolation status for each power domains. See @ref _spc_power_domains for details.
+ */
+uint8_t SPC_GetPeriphIOIsolationStatus(SPC_Type *base);
+
+/*!
+ * @brief Clears peripherals and I/O pads isolation flags for each power domains.
+ *
+ * This function clears peripherals and I/O pads isolation flags for each power domains.
+ * After recovering from the POWERDOWN mode, user must invoke this function to release the
+ * I/O pads and certain peripherals to their normal run mode state. Before invoking this
+ * function, user must restore chip configuration in particular pin configuration for enabled
+ * WUU wakeup pins.
+ *
+ * @param base SPC peripheral base address.
+ */
+static inline void SPC_ClearPeriphIOIsolationFlag(SPC_Type *base)
+{
+ base->SC |= SPC_SC_ISO_CLR_MASK;
+}
+
+/*!
+ * @brief Gets SPC busy status flag.
+ *
+ * This function gets SPC busy status flag. When SPC executing any type of power mode
+ * transition in ACTIVE mode or any of the SOC low power mode, the SPC busy status flag is set
+ * and this function returns true. When changing CORE LDO voltage level and DCDC voltage level
+ * in ACTIVE mode, the SPC busy status flag is set and this function return true.
+ *
+ * @param base SPC peripheral base address.
+ * @return Ack busy flag.
+ * true - SPC is busy.
+ * false - SPC is not busy.
+ */
+static inline bool SPC_GetBusyStatusFlag(SPC_Type *base)
+{
+ return ((base->SC & SPC_SC_BUSY_MASK) != 0UL);
+}
+
+/*!
+ * @brief Checks system low power request.
+ *
+ * @note Only when all power domains request low power mode entry, the result of this function is true. That means when
+ * all power domains request low power mode entry, the SPC regulators will be controlled by LP_CFG register.
+ *
+ * @param base SPC peripheral base address.
+ * @return The system low power request check result.
+ * - \b true All power domains have requested low power mode and SPC has entered a low power state and power mode
+ * configuration are based on the LP_CFG configuration register.
+ * - \b false SPC in active mode and ACTIVE_CFG register control system power supply.
+ */
+static inline bool SPC_CheckLowPowerReqest(SPC_Type *base)
+{
+ return ((base->SC & SPC_SC_SPC_LP_REQ_MASK) == SPC_SC_SPC_LP_REQ_MASK);
+}
+
+/*!
+ * @brief Clears system low power request, set SPC in active mode.
+ *
+ * @param base SPC peripheral base address.
+ */
+static inline void SPC_ClearLowPowerRequest(SPC_Type *base)
+{
+ base->SC |= SPC_SC_SPC_LP_REQ_MASK;
+}
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SWITCH_STATE_BIT) && FSL_FEATURE_MCX_SPC_HAS_SWITCH_STATE_BIT)
+/*!
+ * @brief Checks whether the power switch is on.
+ *
+ * @param base SPC peripheral base address.
+ *
+ * @retval true The power switch is on.
+ * @retval false The power switch is off.
+ */
+static inline bool SPC_CheckSwitchState(SPC_Type *base)
+{
+ return ((base->SC & SPC_SC_SWITCH_STATE_MASK) != 0UL);
+}
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SWITCH_STATE_BIT */
+
+/*!
+ * @brief Gets selected power domain's requested low power mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param powerDomainId Power Domain Id, please refer to @ref spc_power_domain_id_t.
+ *
+ * @return The selected power domain's requested low power mode, please refer to @ref spc_power_domain_low_power_mode_t.
+ */
+spc_power_domain_low_power_mode_t SPC_GetPowerDomainLowPowerMode(SPC_Type *base, spc_power_domain_id_t powerDomainId);
+
+/*!
+ * @brief Checks power domain's low power request.
+ *
+ * @param base SPC peripheral base address.
+ * @param powerDomainId Power Domain Id, please refer to @ref spc_power_domain_id_t.
+ * @return The result of power domain's low power request.
+ * - \b true The selected power domain requests low power mode entry.
+ * - \b false The selected power domain does not request low power mode entry.
+ */
+static inline bool SPC_CheckPowerDomainLowPowerRequest(SPC_Type *base, spc_power_domain_id_t powerDomainId)
+{
+ assert((uint8_t)powerDomainId < SPC_PD_STATUS_COUNT);
+ return ((base->PD_STATUS[(uint8_t)powerDomainId] & SPC_PD_STATUS_PWR_REQ_STATUS_MASK) ==
+ SPC_PD_STATUS_PWR_REQ_STATUS_MASK);
+}
+
+/*!
+ * @brief Clears selected power domain's low power request flag.
+ *
+ * @param base SPC peripheral base address.
+ * @param powerDomainId Power Domain Id, please refer to @ref spc_power_domain_id_t.
+ */
+static inline void SPC_ClearPowerDomainLowPowerRequestFlag(SPC_Type *base, spc_power_domain_id_t powerDomainId)
+{
+ assert((uint8_t)powerDomainId < SPC_PD_STATUS_COUNT);
+ base->PD_STATUS[(uint8_t)powerDomainId] |= SPC_PD_STATUS_PD_LP_REQ_MASK;
+}
+
+/*! @} */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SRAMRETLDO_REG) && FSL_FEATURE_MCX_SPC_HAS_SRAMRETLDO_REG)
+/*!
+ * @name SRAM Retention LDO Control APIs
+ * @{
+ */
+
+/*!
+ * @brief Trims SRAM retention regulator reference voltage, trim step is 12 mV, range is around 0.48V to 0.85V.
+ *
+ * @param base SPC peripheral base address.
+ * @param trimValue Reference voltage trim value.
+ */
+static inline void SPC_TrimSRAMLdoRefVoltage(SPC_Type *base, uint8_t trimValue)
+{
+ base->SRAMRETLDO_REFTRIM =
+ ((base->SRAMRETLDO_REFTRIM & ~SPC_SRAMRETLDO_REFTRIM_REFTRIM_MASK) | SPC_SRAMRETLDO_REFTRIM_REFTRIM(trimValue));
+}
+
+/*!
+ * @brief Enables/disables SRAM retention LDO.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Used to enable/disable SRAM LDO :
+ * - \b true Enable SRAM LDO;
+ * - \b false Disable SRAM LDO.
+ */
+static inline void SPC_EnableSRAMLdo(SPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->SRAMRETLDO_CNTRL |= SPC_SRAMRETLDO_CNTRL_SRAMLDO_ON_MASK;
+ }
+ else
+ {
+ base->SRAMRETLDO_CNTRL &= ~SPC_SRAMRETLDO_CNTRL_SRAMLDO_ON_MASK;
+ }
+}
+
+/*!
+ * @brief
+ *
+ * @todo Need to check.
+ *
+ * @param base SPC peripheral base address.
+ * @param mask The OR'ed value of SRAM Array.
+ */
+static inline void SPC_RetainSRAMArray(SPC_Type *base, uint8_t mask)
+{
+ base->SRAMRETLDO_CNTRL |= SPC_SRAMRETLDO_CNTRL_SRAM_RET_EN(mask);
+}
+
+/*! @} */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SRAMRETLDO_REG */
+
+/*!
+ * @name Low Power Request configuration
+ * @{
+ */
+/*!
+ * @brief Configs Low power request output pin.
+ *
+ * This function config the low power request output pin
+ *
+ * @param base SPC peripheral base address.
+ * @param config Pointer the @ref spc_lowpower_request_config_t structure.
+ */
+void SPC_SetLowPowerRequestConfig(SPC_Type *base, const spc_lowpower_request_config_t *config);
+
+/*! @} */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_CFG_REG) && FSL_FEATURE_MCX_SPC_HAS_CFG_REG)
+/*!
+ * @name Integrated Power Switch Control APIs
+ * @{
+ */
+
+/*!
+ * @brief Enables/disables the integrated power switch manually.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Used to enable/disable the integrated power switch:
+ * - \b true Enable the integrated power switch;
+ * - \b false Disable the integrated power switch.
+ */
+static inline void SPC_EnableIntegratedPowerSwitchManually(SPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CFG |= (SPC_CFG_INTG_PWSWTCH_SLEEP_ACTIVE_EN_MASK | SPC_CFG_INTG_PWSWTCH_WKUP_ACTIVE_EN_MASK);
+ }
+ else
+ {
+ base->CFG &= ~(SPC_CFG_INTG_PWSWTCH_SLEEP_ACTIVE_EN_MASK | SPC_CFG_INTG_PWSWTCH_WKUP_ACTIVE_EN_MASK);
+ }
+}
+
+/*!
+ * @brief Enables/disables the integrated power switch automatically.
+ *
+ * To gate the integrated power switch when chip enter low power modes, and ungate the switch after wake-up from low
+ * power modes:
+ * @code
+ * SPC_EnableIntegratedPowerSwitchAutomatically(SPC, true, true);
+ * @endcode
+ *
+ * @param base SPC peripheral base address.
+ * @param sleepGate Enable the integrated power switch when chip enter low power modes:
+ * - \b true SPC asserts an output pin at low-power entry to power-gate the switch;
+ * - \b false SPC does not assert an output pin at low-power entry to power-gate the switch.
+ * @param wakeupUngate Enables the switch after wake-up from low power modes:
+ * - \b true SPC asserts an output pin at low-power exit to power-ungate the switch;
+ * - \b false SPC does not assert an output pin at low-power exit to power-ungate the switch.
+ */
+static inline void SPC_EnableIntegratedPowerSwitchAutomatically(SPC_Type *base, bool sleepGate, bool wakeupUngate)
+{
+ uint32_t tmp32 = ((base->CFG) & ~(SPC_CFG_INTG_PWSWTCH_SLEEP_EN_MASK | SPC_CFG_INTG_PWSWTCH_WKUP_EN_MASK));
+
+ tmp32 |= SPC_CFG_INTG_PWSWTCH_SLEEP_EN(sleepGate) | SPC_CFG_INTG_PWSWTCH_WKUP_EN(wakeupUngate);
+
+ base->CFG = tmp32;
+}
+
+/*! @} */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_CFG_REG */
+
+#if !(defined(FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) && FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT)
+/*!
+ * @name VDD Core Glitch Detector Control APIs
+ * @{
+ */
+
+/*!
+ * @brief Configures VDD Core Glitch detector, including ripple counter selection, timeout value and so on.
+ *
+ * @param base SPC peripheral base address.
+ * @param config Pointer to the structure in type of @ref spc_vdd_core_glitch_detector_config_t.
+ */
+void SPC_ConfigVddCoreGlitchDetector(SPC_Type *base, const spc_vdd_core_glitch_detector_config_t *config);
+
+/*!
+ * @brief Checks selected 4-bit glitch ripple counter's output.
+ *
+ * @param base SPC peripheral base address.
+ * @param rippleCounter The ripple counter to check, please refer to @ref spc_vdd_core_glitch_ripple_counter_select_t.
+ *
+ * @retval true The selected ripple counter output is 1, will generate interrupt or reset based on settings.
+ * @retval false The selected ripple counter output is 0.
+ */
+
+static inline bool SPC_CheckGlitchRippleCounterOutput(SPC_Type *base,
+ spc_vdd_core_glitch_ripple_counter_select_t rippleCounter)
+{
+ return ((base->VDD_CORE_GLITCH_DETECT_SC & SPC_VDD_CORE_GLITCH_DETECT_SC_GLITCH_DETECT_FLAG_MASK) ==
+ SPC_VDD_CORE_GLITCH_DETECT_SC_GLITCH_DETECT_FLAG(1UL << (uint32_t)(rippleCounter)));
+}
+
+/*!
+ * @brief Clears output of selected glitch ripple counter.
+ *
+ * @param base SPC peripheral base address.
+ * @param rippleCounter The ripple counter to check, please refer to @ref spc_vdd_core_glitch_ripple_counter_select_t.
+ */
+static inline void SPC_ClearGlitchRippleCounterOutput(SPC_Type *base,
+ spc_vdd_core_glitch_ripple_counter_select_t rippleCounter)
+{
+ base->VDD_CORE_GLITCH_DETECT_SC |=
+ SPC_VDD_CORE_GLITCH_DETECT_SC_GLITCH_DETECT_FLAG(1UL << (uint32_t)(rippleCounter));
+}
+
+/*!
+ * @brief After invoking this function, writes to SPC_VDD_CORE_GLITCH_DETECT_SC[RE] register are ignored.
+ *
+ * @param base SPC peripheral base address.
+ */
+static inline void SPC_LockVddCoreVoltageGlitchDetectResetControl(SPC_Type *base)
+{
+ base->VDD_CORE_GLITCH_DETECT_SC |= SPC_VDD_CORE_GLITCH_DETECT_SC_LOCK_MASK;
+}
+
+/*!
+ * @brief After invoking this function, writes to SPC_VDD_CORE_GLITCH_DETECT_SC[RE] register are allowed.
+ *
+ * @param base SPC peripheral base address.
+ */
+static inline void SPC_UnlockVddCoreVoltageGlitchDetectResetControl(SPC_Type *base)
+{
+ base->VDD_CORE_GLITCH_DETECT_SC &= ~SPC_VDD_CORE_GLITCH_DETECT_SC_LOCK_MASK;
+}
+
+/*!
+ * @brief Checks if SPC_VDD_CORE_GLITCH_DETECT_SC[RE] register is writable.
+ *
+ * @param base SPC peripheral base address.
+ *
+ * @retval true SPC_VDD_CORE_GLITCH_DETECT_SC[RE] register is writable.
+ * @retval false SPC_VDD_CORE_GLITCH_DETECT_SC[RE] register is not writable.
+ */
+static inline bool SPC_CheckVddCoreVoltageGlitchResetControlState(SPC_Type *base)
+{
+ return ((base->VDD_CORE_GLITCH_DETECT_SC & SPC_VDD_CORE_GLITCH_DETECT_SC_LOCK_MASK) != 0UL);
+}
+
+/*! @} */
+#endif
+
+/*!
+ * @name SRAM Control APIs
+ * @{
+ */
+
+/*!
+ * @brief Set SRAM operate voltage.
+ *
+ * @param base SPC peripheral base address.
+ * @param config The pointer to @ref spc_sram_voltage_config_t, specifies the configuration of sram voltage.
+ */
+void SPC_SetSRAMOperateVoltage(SPC_Type *base, const spc_sram_voltage_config_t *config);
+
+/*! @} */
+
+/*!
+ * @name Active Mode configuration
+ * @{
+ */
+
+/*!
+ * @brief Gets the Bandgap mode in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return Bandgap mode in the type of @ref spc_bandgap_mode_t enumeration.
+ */
+static inline spc_bandgap_mode_t SPC_GetActiveModeBandgapMode(SPC_Type *base)
+{
+ return (spc_bandgap_mode_t)(uint32_t)((base->ACTIVE_CFG & SPC_ACTIVE_CFG_BGMODE_MASK) >>
+ SPC_ACTIVE_CFG_BGMODE_SHIFT);
+}
+
+/*!
+ * @brief Gets all voltage detectors status in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return All voltage detectors status in Active mode.
+ */
+static inline uint32_t SPC_GetActiveModeVoltageDetectStatus(SPC_Type *base)
+{
+ uint32_t state;
+ state = base->ACTIVE_CFG &
+ (
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD) && FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD)
+ SPC_ACTIVE_CFG_IO_HVDE_MASK | SPC_ACTIVE_CFG_IO_LVDE_MASK |
+
+#endif /* FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD */
+ SPC_ACTIVE_CFG_SYS_HVDE_MASK | SPC_ACTIVE_CFG_SYS_LVDE_MASK | SPC_ACTIVE_CFG_CORE_LVDE_MASK
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD) && FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD)
+ | SPC_ACTIVE_CFG_CORE_HVDE_MASK
+
+#endif /* FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD */
+ );
+ return state;
+}
+
+/*!
+ * @brief Configs Bandgap mode in Active mode.
+ *
+ * @note To disable bandgap in Active mode:
+ * 1. Disable all LVD's and HVD's in active mode;
+ * 2. Disable Glitch detect;
+ * 3. Configure LDO's and DCDC to low drive strength in active mode;
+ * 4. Invoke this function to disable bandgap in active mode;
+ * otherwise the error status will be reported.
+ *
+ * @note Some other system resources(such as PLL, CMP) require bandgap to be enabled, to disable bandgap please
+ * take care of other system resources.
+ *
+ * @param base SPC peripheral base address.
+ * @param mode The Bandgap mode be selected.
+ *
+ * @retval #kStatus_SPC_BandgapModeWrong The Bandgap can not be disabled in active mode.
+ * @retval #kStatus_Success Config Bandgap mode in Active power mode successful.
+ */
+status_t SPC_SetActiveModeBandgapModeConfig(SPC_Type *base, spc_bandgap_mode_t mode);
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT) && FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT)
+/*!
+ * @brief Enables/Disable the CMP Bandgap Buffer in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable CMP Bandgap buffer.
+ * true - Enable Buffer Stored Reference voltage to CMP.
+ * false - Disable Buffer Stored Reference voltage to CMP.
+ */
+static inline void SPC_EnableActiveModeCMPBandgapBuffer(SPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->ACTIVE_CFG |= SPC_ACTIVE_CFG_LPBUFF_EN_MASK;
+ }
+ else
+ {
+ base->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_LPBUFF_EN_MASK;
+ }
+}
+#endif /* FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT */
+
+/*!
+ * @brief Sets the delay when the regulators change voltage level in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param delay The number of SPC timer clock cycles.
+ */
+static inline void SPC_SetActiveModeVoltageTrimDelay(SPC_Type *base, uint16_t delay)
+{
+ base->ACTIVE_VDELAY = SPC_ACTIVE_VDELAY_ACTIVE_VDELAY(delay);
+}
+
+/*!
+ * @brief Configs all settings of regulators in Active mode at a time.
+ *
+ * @note This function is used to overwrite all settings of regulators(including bandgap mode, regulators'
+ * drive strength and voltage level) in active mode at a time.
+ *
+ * @note Enable/disable LVDs/HVDs before invoking this function.
+ *
+ * @note This function will check input parameters based on hardware restrictions before setting registers, if input
+ * parameters do not satisfy hardware restrictions the specific error will be reported.
+ *
+ *
+ * @note Some hardware restrictions not covered, application should be aware of this and follow this hardware
+ * restrictions otherwise some unknown issue may occur:
+ * 1. If Core LDO's drive strength are set to same value in both Active mode and low power mode,
+ * the voltage level should also set to same value.
+ * 2. When switching Core LDO's drive strength from low to normal, ensure the LDO_CORE high voltage level is set
+ * to same level that was set prior to switching to the LDO_CORE drive strength. Otherwise, if the LVDs are
+ * enabled, an unexpected LVD can occur.
+ *
+ * @note If this function can not satisfy some tricky settings, please invoke other APIs in low-level function group.
+ *
+ * @param base SPC peripheral base address.
+ * @param config Pointer to spc_active_mode_regulators_config_t structure.
+ *
+ * @retval #kStatus_Success Config regulators in Active power mode successful.
+ * @retval #kStatus_SPC_BandgapModeWrong Based on input setting, bandgap can not be disabled.
+ * @retval #kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * @retval #kStatus_SPC_CORELDOLowDriveStrengthIgnore Any of LVDs/HVDs kept enabled before invoking this function.
+ * @retval #kStatus_SPC_SYSLDOOverDriveVoltageFail Fail to regulator to Over Drive Voltage due to
+ * System VDD HVD is not disabled.
+ * @retval #kStatus_SPC_SYSLDOLowDriveStrengthIgnore Any of LVDs/HVDs kept enabled before invoking this function.
+ * @retval #kStatus_SPC_CORELDOVoltageWrong Core LDO and System LDO do not have same voltage level.
+ */
+status_t SPC_SetActiveModeRegulatorsConfig(SPC_Type *base, const spc_active_mode_regulators_config_t *config);
+
+#if !(defined(FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) && FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT)
+/*!
+ * @brief Disables/Enables VDD Core Glitch Detect in Active mode.
+ *
+ * @note State of glitch detect disable feature will be ignored if bandgap is disabled and
+ * glitch detect hardware will be forced to OFF state.
+ *
+ * @param base SPC peripheral base address.
+ * @param disable Used to disable/enable VDD Core Glitch detect feature.
+ * - \b true Disable VDD Core Low Voltage detect;
+ * - \b false Enable VDD Core Low Voltage detect.
+ */
+static inline void SPC_DisableActiveModeVddCoreGlitchDetect(SPC_Type *base, bool disable)
+{
+ if (disable)
+ {
+ base->ACTIVE_CFG |= SPC_ACTIVE_CFG_GLITCH_DETECT_DISABLE_MASK;
+ }
+ else
+ {
+ base->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_GLITCH_DETECT_DISABLE_MASK;
+ }
+}
+
+/*!
+ * @brief Check if Glitch detect hardware is enabled in active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return Indicate if Glitch detector is enabled.
+ */
+static inline bool SPC_CheckActiveModeVddCoreGlitchDetectEnabled(SPC_Type *base)
+{
+ if ((base->ACTIVE_CFG & SPC_ACTIVE_CFG_GLITCH_DETECT_DISABLE_MASK) == 0UL)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+#endif /* FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT */
+
+/*!
+ * @brief Enables analog modules in active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param maskValue The mask of analog modules to enable in active mode, should be the OR'ed value
+ * of @ref spc_analog_module_control.
+ */
+static inline void SPC_EnableActiveModeAnalogModules(SPC_Type *base, uint32_t maskValue)
+{
+ base->ACTIVE_CFG1 |= SPC_ACTIVE_CFG1_SOC_CNTRL(maskValue);
+}
+
+/*!
+ * @brief Disables analog modules in active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param maskValue The mask of analog modules to disable in active mode, should be the OR'ed value
+ * of @ref spc_analog_module_control.
+ */
+static inline void SPC_DisableActiveModeAnalogModules(SPC_Type *base, uint32_t maskValue)
+{
+ base->ACTIVE_CFG1 &= ~SPC_ACTIVE_CFG1_SOC_CNTRL(maskValue);
+}
+
+/*!
+ * @brief Gets enabled analog modules that enabled in active mode.
+ *
+ * @param base SPC peripheral base address.
+ *
+ * @return The mask of enabled analog modules that enabled in active mode.
+ */
+static inline uint32_t SPC_GetActiveModeEnabledAnalogModules(SPC_Type *base)
+{
+ return base->ACTIVE_CFG1;
+}
+
+/*! @} */
+
+/*!
+ * @name Low Power mode configuration
+ * @{
+ */
+
+/*!
+ * @brief Gets the Bandgap mode in Low Power mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return Bandgap mode in the type of @ref spc_bandgap_mode_t enumeration.
+ */
+static inline spc_bandgap_mode_t SPC_GetLowPowerModeBandgapMode(SPC_Type *base)
+{
+ return (spc_bandgap_mode_t)(uint32_t)((base->LP_CFG & SPC_LP_CFG_BGMODE_MASK) >> SPC_LP_CFG_BGMODE_SHIFT);
+}
+
+/*!
+ * @brief Gets the status of all voltage detectors in Low Power mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return The status of all voltage detectors in low power mode.
+ */
+static inline uint32_t SPC_GetLowPowerModeVoltageDetectStatus(SPC_Type *base)
+{
+ uint32_t state;
+ state = base->LP_CFG & (
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD) && FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD)
+ SPC_LP_CFG_IO_HVDE_MASK | SPC_LP_CFG_IO_LVDE_MASK |
+
+#endif /* FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD */
+ SPC_LP_CFG_SYS_HVDE_MASK | SPC_LP_CFG_SYS_LVDE_MASK | SPC_LP_CFG_CORE_LVDE_MASK
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD) && FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD)
+ | SPC_LP_CFG_CORE_HVDE_MASK
+
+#endif /* FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD */
+ );
+ return state;
+}
+
+/*!
+ * @brief Enables/Disables Low Power IREF in low power modes.
+ *
+ * This function enables/disables Low Power IREF. Low Power IREF can only get
+ * disabled in Deep power down mode. In other low power modes, the Low Power IREF
+ * is always enabled.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable Low Power IREF.
+ * true - Enable Low Power IREF for Low Power modes.
+ * false - Disable Low Power IREF for Deep Power Down mode.
+ */
+static inline void SPC_EnableLowPowerModeLowPowerIREF(SPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->LP_CFG |= SPC_LP_CFG_LP_IREFEN_MASK;
+ }
+ else
+ {
+ base->LP_CFG &= ~SPC_LP_CFG_LP_IREFEN_MASK;
+ }
+}
+
+/*!
+ * @brief Configs Bandgap mode in Low Power mode.
+ *
+ * @note To disable Bandgap in Low-power mode:
+ * 1. Disable all LVD's ad HVD's in low power mode;
+ * 2. Disable Glitch detect in low power mode;
+ * 3. Configure LDO's and DCDC to low drive strength in low power mode;
+ * 4. Disable bandgap in low power mode;
+ * Otherwise, the error status will be reported.
+ *
+ * @note Some other system resources(such as PLL, CMP) require bandgap to be enabled, to disable bandgap please
+ * take care of other system resources.
+ *
+ * @param base SPC peripheral base address.
+ * @param mode The Bandgap mode be selected.
+ *
+ * @retval #kStatus_SPC_BandgapModeWrong The bandgap mode setting in Low Power mode is wrong.
+ * @retval #kStatus_Success Config Bandgap mode in Low Power power mode successful.
+ */
+status_t SPC_SetLowPowerModeBandgapmodeConfig(SPC_Type *base, spc_bandgap_mode_t mode);
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SRAMLDO_DPD_ON_BIT) && FSL_FEATURE_MCX_SPC_HAS_SRAMLDO_DPD_ON_BIT)
+/*!
+ * @brief Enables/disables SRAM_LDO deep power low power IREF.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Used to enable/disable low power IREF :
+ * - \b true: Low Power IREF is enabled ;
+ * - \b false: Low Power IREF is disabled for power saving.
+ */
+static inline void SPC_EnableSRAMLdOLowPowerModeIREF(SPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->LP_CFG |= SPC_LP_CFG_SRAMLDO_DPD_ON_MASK;
+ }
+ else
+ {
+ base->LP_CFG &= ~SPC_LP_CFG_SRAMLDO_DPD_ON_MASK;
+ }
+}
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SRAMLDO_DPD_ON_BIT */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT) && FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT)
+/*!
+ * @brief Enables/Disables CMP Bandgap Buffer.
+ *
+ * This function gates CMP bandgap buffer. CMP bandgap buffer is automatically disabled and turned off
+ * in Deep Power Down mode.
+ *
+ * @deprecated No longer used, please use SPC_EnableLowPowerModeCMPBandgapBuffer as instead.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable CMP Bandgap buffer.
+ * true - Enable Buffer Stored Reference Voltage to CMP.
+ * false - Disable Buffer Stored Reference Voltage to CMP.
+ */
+static inline void SPC_EnableLowPowerModeCMPBandgapBufferMode(SPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->LP_CFG |= SPC_LP_CFG_LPBUFF_EN_MASK;
+ }
+ else
+ {
+ base->LP_CFG &= ~SPC_LP_CFG_LPBUFF_EN_MASK;
+ }
+}
+
+/*!
+ * @brief Enables/Disables CMP Bandgap Buffer.
+ *
+ * This function gates CMP bandgap buffer. CMP bandgap buffer is automatically disabled and turned off
+ * in Deep Power Down mode.
+ *
+ * @deprecated No longer used.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable CMP Bandgap buffer.
+ * true - Enable Buffer Stored Reference Voltage to CMP.
+ * false - Disable Buffer Stored Reference Voltage to CMP.
+ */
+static inline void SPC_EnableLowPowerModeCMPBandgapBuffer(SPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->LP_CFG |= SPC_LP_CFG_LPBUFF_EN_MASK;
+ }
+ else
+ {
+ base->LP_CFG &= ~SPC_LP_CFG_LPBUFF_EN_MASK;
+ }
+}
+#endif /* FSL_FEATURE_MCX_SPC_HAS_LPBUFF_EN_BIT */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_COREVDD_IVS_EN_BIT) && FSL_FEATURE_MCX_SPC_HAS_COREVDD_IVS_EN_BIT)
+/*!
+ * @brief Enables/Disables CORE VDD IVS(Internal Voltage Scaling) in power down modes.
+ *
+ * This function gates CORE VDD IVS. When enabled, the IVS regulator will scale the
+ * external input CORE VDD to a lower voltage level to reduce internal leakage.
+ * IVS is invalid in Sleep or Deep power down mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable IVS.
+ * true - enable CORE VDD IVS in Power Down mode.
+ * false - disable CORE VDD IVS in Power Down mode.
+ */
+static inline void SPC_EnableLowPowerModeCoreVDDInternalVoltageScaling(SPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->LP_CFG |= SPC_LP_CFG_COREVDD_IVS_EN_MASK;
+ }
+ else
+ {
+ base->LP_CFG &= ~SPC_LP_CFG_COREVDD_IVS_EN_MASK;
+ }
+}
+#endif /* FSL_FEATURE_MCX_SPC_HAS_COREVDD_IVS_EN_BIT */
+
+/*!
+ * @brief Sets the delay when exit the low power modes.
+ *
+ * @param base SPC peripheral base address.
+ * @param delay The number of SPC timer clock cycles that the SPC waits on exit from low power modes.
+ */
+static inline void SPC_SetLowPowerWakeUpDelay(SPC_Type *base, uint16_t delay)
+{
+ base->LPWKUP_DELAY = SPC_LPWKUP_DELAY_LPWKUP_DELAY(delay);
+}
+
+/*!
+ * @brief Configs all settings of regulators in Low power mode at a time.
+ *
+ * @note This function is used to overwrite all settings of regulators(including bandgap mode, regulators'
+ * drive strength and voltage level) in low power mode at a time.
+ *
+ * @note Enable/disable LVDs/HVDs before invoking this function.
+ *
+ * @note This function will check input parameters based on hardware restrictions before setting registers, if input
+ * parameters do not satisfy hardware restrictions the specific error will be reported.
+ *
+ * @note Some hardware restrictions not covered, application should be aware of this and follow this hardware
+ * restrictions otherwise some unknown issue may occur:
+ * 1. If Core LDO's drive strength are set to same value in both Active mode and low power mode,
+ * the voltage level should also set to same value.
+ * 2. When switching Core LDO's drive strength from low to normal, ensure the LDO_CORE high voltage level is set
+ * to same level that was set prior to switching to the LDO_CORE drive strength. Otherwise, if the LVDs are
+ * enabled, an unexpected LVD can occur.
+ *
+ * @note If this function can not satisfy some tricky settings, please invoke other APIs in low-level function group.
+ *
+ * @param base SPC peripheral base address.
+ * @param config Pointer to spc_lowpower_mode_regulators_config_t structure.
+ * @retval #kStatus_Success Config regulators in Low power mode successful.
+ * @retval #kStatus_SPC_BandgapModeWrong The bandgap should not be disabled based on input settings.
+ * @retval #kStatus_SPC_CORELDOLowDriveStrengthIgnore Set driver strength to low will be ignored.
+ * @retval #kStatus_SPC_SYSLDOLowDriveStrengthIgnore Set driver strength to low will be ignored.
+ * @retval #kStatus_SPC_CORELDOVoltageWrong Core LDO and System LDO do not have same voltage level.
+ */
+status_t SPC_SetLowPowerModeRegulatorsConfig(SPC_Type *base, const spc_lowpower_mode_regulators_config_t *config);
+
+#if !(defined(FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT) && FSL_FEATURE_MCX_SPC_HAS_NO_GLITCH_DETECT)
+/*!
+ * @brief Disable/Enable VDD Core Glitch Detect in low power mode.
+ *
+ * @note State of glitch detect disable feature will be ignored if bandgap is disabled and
+ * glitch detect hardware will be forced to OFF state.
+ *
+ * @param base SPC peripheral base address.
+ * @param disable Used to disable/enable VDD Core Glitch detect feature.
+ * - \b true Disable VDD Core Low Voltage detect;
+ * - \b false Enable VDD Core Low Voltage detect.
+ */
+static inline void SPC_DisableLowPowerModeVddCoreGlitchDetect(SPC_Type *base, bool disable)
+{
+ if (disable)
+ {
+ base->LP_CFG |= SPC_LP_CFG_GLITCH_DETECT_DISABLE_MASK;
+ }
+ else
+ {
+ base->LP_CFG &= ~SPC_LP_CFG_GLITCH_DETECT_DISABLE_MASK;
+ }
+}
+
+/*!
+ * @brief Check if Glitch detect hardware is enabled in low power mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return Indicate if Glitch detector is enabled.
+ */
+static inline bool SPC_CheckLowPowerModeVddCoreGlitchDetectEnabled(SPC_Type *base)
+{
+ if ((base->LP_CFG & SPC_LP_CFG_GLITCH_DETECT_DISABLE_MASK) == 0UL)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+#endif
+
+/*!
+ * @brief Enables analog modules in low power modes.
+ *
+ * @param base SPC peripheral base address.
+ * @param maskValue The mask of analog modules to enable in low power modes, should be OR'ed value
+ of @ref spc_analog_module_control.
+ */
+static inline void SPC_EnableLowPowerModeAnalogModules(SPC_Type *base, uint32_t maskValue)
+{
+ base->LP_CFG1 |= SPC_LP_CFG1_SOC_CNTRL(maskValue);
+}
+
+/*!
+ * @brief Disables analog modules in low power modes.
+ *
+ * @param base SPC peripheral base address.
+ * @param maskValue The mask of analog modules to disable in low power modes, should be OR'ed value
+ of @ref spc_analog_module_control.
+ */
+static inline void SPC_DisableLowPowerModeAnalogModules(SPC_Type *base, uint32_t maskValue)
+{
+ base->LP_CFG1 &= ~SPC_LP_CFG1_SOC_CNTRL(maskValue);
+}
+
+/*!
+ * @brief Gets enabled analog modules that enabled in low power modes.
+ *
+ * @param base SPC peripheral base address.
+ *
+ * @return The mask of enabled analog modules that enabled in low power modes.
+ */
+static inline uint32_t SPC_GetLowPowerModeEnabledAnalogModules(SPC_Type *base)
+{
+ return base->LP_CFG1;
+}
+
+/*! @} */
+
+/*!
+ * @name Voltage Detect Status
+ * @{
+ */
+/*!
+ * @brief Get Voltage Detect Status Flags.
+ *
+ * @param base SPC peripheral base address.
+ * @return Voltage Detect Status Flags. See @ref _spc_voltage_detect_flags for details.
+ */
+static inline uint8_t SPC_GetVoltageDetectStatusFlag(SPC_Type *base)
+{
+ return (uint8_t)(base->VD_STAT);
+}
+
+/*!
+ * @brief Clear Voltage Detect Status Flags.
+ *
+ * @param base SPC peripheral base address.
+ * @param mask The mask of the voltage detect status flags. See @ref _spc_voltage_detect_flags for details.
+ */
+static inline void SPC_ClearVoltageDetectStatusFlag(SPC_Type *base, uint8_t mask)
+{
+ base->VD_STAT |= mask;
+}
+
+/*! @} */
+
+/*!
+ * @name Voltage Detect configuration for Core voltage domain.
+ * @{
+ */
+
+/*!
+ * @brief Configs CORE voltage detect options.
+ *
+ * @note: Setting both the voltage detect interrupt and reset
+ * enable will cause interrupt to be generated on exit from reset.
+ * If those conditioned is not desired, interrupt/reset so only one is enabled.
+ *
+ * @param base SPC peripheral base address.
+ * @param config Pointer to spc_core_voltage_detect_config_t structure.
+ */
+void SPC_SetCoreVoltageDetectConfig(SPC_Type *base, const spc_core_voltage_detect_config_t *config);
+
+/*!
+ * @brief Locks Core voltage detect reset setting.
+ *
+ * This function locks core voltage detect reset setting. After invoking this function
+ * any configuration of Core voltage detect reset will be ignored.
+ *
+ * @param base SPC peripheral base address.
+ */
+static inline void SPC_LockCoreVoltageDetectResetSetting(SPC_Type *base)
+{
+ base->VD_CORE_CFG |= SPC_VD_CORE_CFG_LOCK_MASK;
+}
+
+/*!
+ * @brief Unlocks Core voltage detect reset setting.
+ *
+ * This function unlocks core voltage detect reset setting. If locks the Core
+ * voltage detect reset setting, invoking this function to unlock.
+ *
+ * @param base SPC peripheral base address.
+ */
+static inline void SPC_UnlockCoreVoltageDetectResetSetting(SPC_Type *base)
+{
+ base->VD_CORE_CFG &= ~SPC_VD_CORE_CFG_LOCK_MASK;
+}
+
+/*!
+ * @brief Enables/Disables the Core Low Voltage Detector in Active mode.
+ *
+ * @note If the CORE_LDO low voltage detect is enabled in Active mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable Core LVD.
+ * true - Enable Core Low voltage detector in active mode.
+ * false - Disable Core Low voltage detector in active mode.
+ *
+ * @retval #kStatus_Success Enable/Disable Core Low Voltage Detect successfully.
+ */
+status_t SPC_EnableActiveModeCoreLowVoltageDetect(SPC_Type *base, bool enable);
+
+/*!
+ * @brief Enables/Disables the Core Low Voltage Detector in Low Power mode.
+ *
+ * This function enables/disables the Core Low Voltage Detector.
+ * If enabled the Core Low Voltage detector. The Bandgap mode in
+ * low power mode must be programmed so that Bandgap is enabled.
+ *
+ * @note If the CORE_LDO low voltage detect is enabled in Low Power mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low in Low Power mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable Core HVD.
+ * true - Enable Core Low voltage detector in low power mode.
+ * false - Disable Core Low voltage detector in low power mode.
+ *
+ * @retval #kStatus_Success Enable/Disable Core Low Voltage Detect in low power mode successfully.
+ */
+status_t SPC_EnableLowPowerModeCoreLowVoltageDetect(SPC_Type *base, bool enable);
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD) && FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD)
+/*!
+ * @brief Enables/Disables the Core High Voltage Detector in Active mode.
+ *
+ * @note If the CORE_LDO high voltage detect is enabled in Active mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable Core HVD.
+ * true - Enable Core High voltage detector in active mode.
+ * false - Disable Core High voltage detector in active mode.
+ *
+ * @retval #kStatus_Success Enable/Disable Core High Voltage Detect successfully.
+ */
+status_t SPC_EnableActiveModeCoreHighVoltageDetect(SPC_Type *base, bool enable);
+
+/*!
+ * @brief Enables/Disables the Core High Voltage Detector in Low Power mode.
+ *
+ * This function enables/disables the Core High Voltage Detector.
+ * If enabled the Core High Voltage detector. The Bandgap mode in
+ * low power mode must be programmed so that Bandgap is enabled.
+ *
+ * @note If the CORE_LDO high voltage detect is enabled in Low Power mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low in low power mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable Core HVD.
+ * true - Enable Core High voltage detector in low power mode.
+ * false - Disable Core High voltage detector in low power mode.
+ *
+ * @retval #kStatus_Success Enable/Disable Core High Voltage Detect in low power mode successfully.
+ */
+status_t SPC_EnableLowPowerModeCoreHighVoltageDetect(SPC_Type *base, bool enable);
+#endif /* FSL_FEATURE_MCX_SPC_HAS_COREVDD_HVD */
+
+/*! @} */
+
+/*!
+ * @name Voltage detect configuration for System Voltage domain
+ * @{
+ */
+/*!
+ * @brief Set system VDD Low-voltage level selection.
+ *
+ * This function selects the system VDD low-voltage level. Changing system VDD low-voltage level
+ * must be done after disabling the System VDD low voltage reset and interrupt.
+ *
+ * @deprecated In latest RM, reserved for all devices, will removed in next release.
+ *
+ * @param base SPC peripheral base address.
+ * @param level System VDD Low-Voltage level selection.
+ */
+void SPC_SetSystemVDDLowVoltageLevel(SPC_Type *base, spc_low_voltage_level_select_t level);
+
+/*!
+ * @brief Configs SYS voltage detect options.
+ *
+ * This function config SYS voltage detect options.
+ * @note: Setting both the voltage detect interrupt and reset
+ * enable will cause interrupt to be generated on exit from reset.
+ * If those conditioned is not desired, interrupt/reset so only one is enabled.
+ *
+ * @param base SPC peripheral base address.
+ * @param config Pointer to spc_system_voltage_detect_config_t structure.
+ */
+void SPC_SetSystemVoltageDetectConfig(SPC_Type *base, const spc_system_voltage_detect_config_t *config);
+
+/*!
+ * @brief Lock System voltage detect reset setting.
+ *
+ * This function locks system voltage detect reset setting. After invoking this function
+ * any configuration of System Voltage detect reset will be ignored.
+ *
+ * @param base SPC peripheral base address.
+ */
+static inline void SPC_LockSystemVoltageDetectResetSetting(SPC_Type *base)
+{
+ base->VD_SYS_CFG |= SPC_VD_SYS_CFG_LOCK_MASK;
+}
+
+/*!
+ * @brief Unlock System voltage detect reset setting.
+ *
+ * This function unlocks system voltage detect reset setting. If locks the System
+ * voltage detect reset setting, invoking this function to unlock.
+ *
+ * @param base SPC peripheral base address.
+ */
+static inline void SPC_UnlockSystemVoltageDetectResetSetting(SPC_Type *base)
+{
+ base->VD_SYS_CFG &= ~SPC_VD_SYS_CFG_LOCK_MASK;
+}
+
+/*!
+ * @brief Enables/Disables the System High Voltage Detector in Active mode.
+ *
+ * @note If the System_LDO high voltage detect is enabled in Active mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable System HVD.
+ * true - Enable System High voltage detector in active mode.
+ * false - Disable System High voltage detector in active mode.
+ *
+ * @retval #kStatus_Success Enable/Disable System High Voltage Detect successfully.
+ */
+status_t SPC_EnableActiveModeSystemHighVoltageDetect(SPC_Type *base, bool enable);
+
+/*!
+ * @brief Enables/Disable the System Low Voltage Detector in Active mode.
+ *
+ * @note If the System_LDO low voltage detect is enabled in Active mode,
+ * please note that the bandgap must be enabled and the drive strength of each
+ * regulator must not set to low in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable System LVD.
+ * true - Enable System Low voltage detector in active mode.
+ * false - Disable System Low voltage detector in active mode.
+ *
+ * @retval #kStatus_Success Enable/Disable the System Low Voltage Detect successfully.
+ */
+status_t SPC_EnableActiveModeSystemLowVoltageDetect(SPC_Type *base, bool enable);
+
+/*!
+ * @brief Enables/Disables the System High Voltage Detector in Low Power mode.
+ *
+ * @note If the System_LDO high voltage detect is enabled in Low Power mode, please note
+ * that the bandgap must be enabled and the drive strength of each regulator must
+ * not set to low in Low Power mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable System HVD.
+ * true - Enable System High voltage detector in low power mode.
+ * false - Disable System High voltage detector in low power mode.
+ *
+ * @retval #kStatus_Success Enable/Disable System High Voltage Detect in low power mode successfully.
+ */
+status_t SPC_EnableLowPowerModeSystemHighVoltageDetect(SPC_Type *base, bool enable);
+
+/*!
+ * @brief Enables/Disables the System Low Voltage Detector in Low Power mode.
+ *
+ * @note If the System_LDO low voltage detect is enabled in Low Power mode,
+ * please note that the bandgap must be enabled and the drive strength of each
+ * regulator must not set to low in Low Power mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable System HVD.
+ * true - Enable System Low voltage detector in low power mode.
+ * false - Disable System Low voltage detector in low power mode.
+ *
+ * @retval #kStatus_Success Enables System Low Voltage Detect in low power mode successfully.
+ */
+status_t SPC_EnableLowPowerModeSystemLowVoltageDetect(SPC_Type *base, bool enable);
+
+/*! @} */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD) && FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD)
+/*!
+ * @name Voltage detect configuration for IO voltage domain
+ * @{
+ */
+/*!
+ * @brief Set IO VDD Low-Voltage level selection.
+ *
+ * This function selects the IO VDD Low-voltage level. Changing IO VDD low-voltage level
+ * must be done after disabling the IO VDD low voltage reset and interrupt.
+ *
+ * @param base SPC peripheral base address.
+ * @param level IO VDD Low-voltage level selection.
+ */
+void SPC_SetIOVDDLowVoltageLevel(SPC_Type *base, spc_low_voltage_level_select_t level);
+
+/*!
+ * @brief Configs IO voltage detect options.
+ *
+ * This function config IO voltage detect options.
+ * @note: Setting both the voltage detect interrupt and reset
+ * enable will cause interrupt to be generated on exit from reset.
+ * If those conditioned is not desired, interrupt/reset so only one is enabled.
+ *
+ * @param base SPC peripheral base address.
+ * @param config Pointer to spc_voltage_detect_config_t structure.
+ */
+void SPC_SetIOVoltageDetectConfig(SPC_Type *base, const spc_io_voltage_detect_config_t *config);
+
+/*!
+ * @brief Lock IO Voltage detect reset setting.
+ *
+ * This function locks IO voltage detect reset setting. After invoking this function
+ * any configuration of system voltage detect reset will be ignored.
+ *
+ * @param base SPC peripheral base address.
+ */
+static inline void SPC_LockIOVoltageDetectResetSetting(SPC_Type *base)
+{
+ base->VD_IO_CFG |= SPC_VD_IO_CFG_LOCK_MASK;
+}
+
+/*!
+ * @brief Unlock IO voltage detect reset setting.
+ *
+ * This function unlocks IO voltage detect reset setting. If locks the IO
+ * voltage detect reset setting, invoking this function to unlock.
+ *
+ * @param base SPC peripheral base address.
+ */
+static inline void SPC_UnlockIOVoltageDetectResetSetting(SPC_Type *base)
+{
+ base->VD_IO_CFG &= ~SPC_VD_IO_CFG_LOCK_MASK;
+}
+
+/*!
+ * @brief Enables/Disables the IO High Voltage Detector in Active mode.
+ *
+ * @note If the IO high voltage detect is enabled in Active mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable IO HVD.
+ * true - Enable IO High voltage detector in active mode.
+ * false - Disable IO High voltage detector in active mode.
+ *
+ * @retval #kStatus_Success Enable/Disable IO High Voltage Detect successfully.
+ */
+status_t SPC_EnableActiveModeIOHighVoltageDetect(SPC_Type *base, bool enable);
+
+/*!
+ * @brief Enables/Disables the IO Low Voltage Detector in Active mode.
+ *
+ * @note If the IO low voltage detect is enabled in Active mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable IO LVD.
+ * true - Enable IO Low voltage detector in active mode.
+ * false - Disable IO Low voltage detector in active mode.
+ *
+ * @retval #kStatus_Success Enable IO Low Voltage Detect successfully.
+ */
+status_t SPC_EnableActiveModeIOLowVoltageDetect(SPC_Type *base, bool enable);
+
+/*!
+ * @brief Enables/Disables the IO High Voltage Detector in Low Power mode.
+ *
+ * @note If the IO high voltage detect is enabled in Low Power mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low in Low Power mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable IO HVD.
+ * true - Enable IO High voltage detector in low power mode.
+ * false - Disable IO High voltage detector in low power mode.
+ *
+ * @retval #kStatus_Success Enable IO High Voltage Detect in low power mode successfully.
+ */
+status_t SPC_EnableLowPowerModeIOHighVoltageDetect(SPC_Type *base, bool enable);
+
+/*!
+ * @brief Enables/Disables the IO Low Voltage Detector in Low Power mode.
+ *
+ * @note If the IO low voltage detect is enabled in Low Power mode, please note that the bandgap must be enabled
+ * and the drive strength of each regulator must not set to low in Low Power mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable IO LVD.
+ * true - Enable IO Low voltage detector in low power mode.
+ * false - Disable IO Low voltage detector in low power mode.
+ *
+ * @retval #kStatus_Success Enable/Disable IO Low Voltage Detect in low power mode successfully.
+ */
+status_t SPC_EnableLowPowerModeIOLowVoltageDetect(SPC_Type *base, bool enable);
+
+/*! @} */
+
+#endif /* FSL_FEATURE_MCX_SPC_HAS_IOVDD_VD */
+
+/*!
+ * @name External Voltage domains configuration
+ * @{
+ */
+/*!
+ * @brief Configs external voltage domains
+ *
+ * This function configs external voltage domains isolation.
+ *
+ * @param base SPC peripheral base address.
+ * @param lowPowerIsoMask The mask of external domains isolate enable during low power mode. Please read the Reference
+ * Manual for the Bitmap.
+ * @param IsoMask The mask of external domains isolate. Please read the Reference Manual for the Bitmap.
+ */
+void SPC_SetExternalVoltageDomainsConfig(SPC_Type *base, uint8_t lowPowerIsoMask, uint8_t IsoMask);
+
+/*!
+ * @brief Gets External Domains status.
+ *
+ * @param base SPC peripheral base address.
+ * @return The status of each external domain.
+ */
+static inline uint8_t SPC_GetExternalDomainsStatus(SPC_Type *base)
+{
+ return (uint8_t)(base->EVD_CFG >> SPC_EVD_CFG_REG_EVDSTAT_SHIFT);
+}
+
+/*! @} */
+
+/*!
+ * @name Low Level APIs To Set CORE LDO Regulator
+ * @{
+ */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_CNTRL_REG) && FSL_FEATURE_MCX_SPC_HAS_CNTRL_REG)
+/*!
+ * @brief Enable/Disable Core LDO regulator.
+ *
+ * @note The CORE LDO enable bit is write-once.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable CORE LDO Regulator.
+ * true - Enable CORE LDO Regulator.
+ * false - Disable CORE LDO Regulator.
+ */
+static inline void SPC_EnableCoreLDORegulator(SPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CNTRL |= SPC_CNTRL_CORELDO_EN_MASK;
+ }
+ else
+ {
+ /*
+ * $Branch Coverage Justification$
+ * If CORE_LDO is disabled, all RAMs data will powered off.
+ */
+ base->CNTRL &= ~SPC_CNTRL_CORELDO_EN_MASK;
+ }
+}
+#endif /* FSL_FEATURE_MCX_SPC_HAS_CNTRL_REG */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DPDOWN_PULLDOWN_DISABLE_BIT) && \
+ FSL_FEATURE_MCX_SPC_HAS_DPDOWN_PULLDOWN_DISABLE_BIT)
+/*!
+ * @brief Enable/Disable the CORE LDO Regulator pull down in Deep Power Down.
+ *
+ * @note This function only useful when enabled the CORE LDO Regulator.
+ *
+ * @param base SPC peripheral base address.
+ * @param pulldown Enable/Disable CORE LDO pulldown in Deep Power Down mode.
+ * true - CORE LDO Regulator will discharge in Deep Power Down mode.
+ * false - CORE LDO Regulator will not discharge in Deep Power Down mode.
+ */
+static inline void SPC_PullDownCoreLDORegulator(SPC_Type *base, bool pulldown)
+{
+ if (pulldown)
+ {
+ base->CORELDO_CFG &= ~SPC_CORELDO_CFG_DPDOWN_PULLDOWN_DISABLE_MASK;
+ }
+ else
+ {
+ base->CORELDO_CFG |= SPC_CORELDO_CFG_DPDOWN_PULLDOWN_DISABLE_MASK;
+ }
+}
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DPDOWN_PULLDOWN_DISABLE_BIT */
+
+/*!
+ * @brief Configs Core LDO Regulator in Active mode.
+ *
+ * @note The bandgap must be enabled before invoking this function.
+ * @note To set Core LDO as low drive strength, all HVDs/LVDs must be disabled previously.
+ *
+ * @param base SPC peripheral base address.
+ * @param option Pointer to the spc_active_mode_core_ldo_option_t structure.
+ *
+ * @retval kStatus_Success Config Core LDO regulator in Active power mode successful.
+ * @retval kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * @retval kStatus_SPC_BandgapModeWrong Bandgap should be enabled before invoking this function.
+ * @retval kStatus_SPC_CORELDOLowDriveStrengthIgnore To set Core LDO as low drive strength,
+ * all LVDs/HVDs must be disabled before invoking this function.
+ */
+status_t SPC_SetActiveModeCoreLDORegulatorConfig(SPC_Type *base, const spc_active_mode_core_ldo_option_t *option);
+
+/*!
+ * @brief Set Core LDO Regulator Voltage level in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param voltageLevel Specify the voltage level of CORE LDO Regulator in Active mode, please
+ refer to @ref spc_core_ldo_voltage_level_t.
+ *
+ * @note In active mode, the Core LDO voltage level should only be changed when the
+ * Core LDO is in normal drive strength.
+ *
+ * @note Update Core LDO voltage level will set Busy flag,
+ * this function return only when busy flag is cleared by hardware
+ *
+ * @retval kStatus_SPC_CORELDOVoltageSetFail The drive strength of Core LDO is not normal.
+ * @retval kStatus_Success Set Core LDO regulator voltage level in Active power mode successful.
+ */
+status_t SPC_SetActiveModeCoreLDORegulatorVoltageLevel(SPC_Type *base, spc_core_ldo_voltage_level_t voltageLevel);
+
+/*!
+ * @brief Gets CORE LDO Regulator Voltage level.
+ *
+ * This function returns the voltage level of CORE LDO Regulator in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return Voltage level of CORE LDO in type of @ref spc_core_ldo_voltage_level_t enumeration.
+ */
+static inline spc_core_ldo_voltage_level_t SPC_GetActiveModeCoreLDOVDDVoltageLevel(SPC_Type *base)
+{
+ return (spc_core_ldo_voltage_level_t)(uint32_t)((base->ACTIVE_CFG & SPC_ACTIVE_CFG_CORELDO_VDD_LVL_MASK) >>
+ SPC_ACTIVE_CFG_CORELDO_VDD_LVL_SHIFT);
+}
+
+#if (defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS)
+/*!
+ * @brief Set Core LDO VDD Regulator Drive Strength in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param driveStrength Specify the drive strength of CORE LDO Regulator in Active mode, please
+ refer to @ref spc_core_ldo_drive_strength_t.
+ *
+ * @retval #kStatus_Success Set Core LDO regulator drive strength in Active power mode successful.
+ * @retval #kStatus_SPC_CORELDOLowDriveStrengthIgnore If any voltage detect enabled,
+ core_ldo's drive strength can not set to low.
+ * @retval #kStatus_SPC_BandgapModeWrong The selected bandgap mode is not allowed.
+ */
+status_t SPC_SetActiveModeCoreLDORegulatorDriveStrength(SPC_Type *base, spc_core_ldo_drive_strength_t driveStrength);
+
+/*!
+ * @brief Gets CORE LDO VDD Regulator Drive Strength in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return Drive Strength of CORE LDO regulator in Active mode, please refer to @ref spc_core_ldo_drive_strength_t.
+ */
+static inline spc_core_ldo_drive_strength_t SPC_GetActiveModeCoreLDODriveStrength(SPC_Type *base)
+{
+ return (spc_core_ldo_drive_strength_t)(uint32_t)((base->ACTIVE_CFG & SPC_ACTIVE_CFG_CORELDO_VDD_DS_MASK) >>
+ SPC_ACTIVE_CFG_CORELDO_VDD_DS_SHIFT);
+}
+#endif /* defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
+
+/*!
+ * @brief Configs CORE LDO Regulator in low power mode
+ *
+ * This function configs CORE LDO Regulator in Low Power mode.
+ * If CORE LDO VDD Drive Strength is set to Normal, the CORE LDO VDD regulator voltage
+ * level in Active mode must be equal to the voltage level in Low power mode. And the Bandgap
+ * must be programmed to select bandgap enabled.
+ * Core VDD voltage levels for the Core LDO low power regulator can only be changed when the CORE
+ * LDO Drive Strength set as Normal.
+ *
+ * @param base SPC peripheral base address.
+ * @param option Pointer to the spc_lowpower_mode_core_ldo_option_t structure.
+ *
+ * @retval #kStatus_Success Config Core LDO regulator in power mode successfully.
+ * @retval #kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * @retval #kStatus_SPC_CORELDOLowDriveStrengthIgnore Set driver strength to low will be ignored.
+ * @retval #kStatus_SPC_CORELDOVoltageSetFail. Fail to change Core LDO voltage level.
+ */
+status_t SPC_SetLowPowerModeCoreLDORegulatorConfig(SPC_Type *base, const spc_lowpower_mode_core_ldo_option_t *option);
+
+/*!
+ * @brief Set Core LDO VDD Regulator Voltage level in Low power mode.
+ *
+ * @note If CORE LDO's drive strength is set to Normal, the CORE LDO VDD regulator voltage in active mode and low power
+ * mode must be same.
+ * @note Voltage level for the CORE LDO in low power mode can only be changed when the CORE LDO Drive Strength set as
+ * Normal.
+ *
+ * @param base SPC peripheral base address.
+ * @param voltageLevel Voltage level of CORE LDO Regulator in Low power mode, please
+ refer to @ref spc_core_ldo_voltage_level_t.
+ *
+ * @retval #kStatus_SPC_CORELDOVoltageWrong Voltage level in active mode and low power mode is not same.
+ * @retval #kStatus_Success Set Core LDO regulator voltage level in Low power mode successful.
+ * @retval #kStatus_SPC_CORELDOVoltageSetFail Fail to update voltage level because drive strength is incorrect.
+ */
+status_t SPC_SetLowPowerModeCoreLDORegulatorVoltageLevel(SPC_Type *base, spc_core_ldo_voltage_level_t voltageLevel);
+
+/*!
+ * @brief Gets the CORE LDO VDD Regulator Voltage Level for Low Power modes.
+ *
+ * @param base SPC peripheral base address.
+ * @return The CORE LDO VDD Regulator's voltage level.
+ */
+static inline spc_core_ldo_voltage_level_t SPC_GetLowPowerCoreLDOVDDVoltageLevel(SPC_Type *base)
+{
+ return ((spc_core_ldo_voltage_level_t)(uint32_t)((base->LP_CFG & SPC_LP_CFG_CORELDO_VDD_LVL_MASK) >>
+ SPC_LP_CFG_CORELDO_VDD_LVL_SHIFT));
+}
+
+/*!
+ * @brief Set Core LDO VDD Regulator Drive Strength in Low power mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param driveStrength Specify drive strength of CORE LDO in low power mode.
+ *
+ * @retval #kStatus_SPC_CORELDOLowDriveStrengthIgnore Some voltage detect enabled, CORE LDO's drive strength can not set
+ * as low.
+ * @retval #kStatus_Success Set Core LDO regulator drive strength in Low power mode successful.
+ * @retval #kStatus_SPC_BandgapModeWrong Bandgap is disabled when attempt to set CORE LDO work as normal drive strength.
+ */
+status_t SPC_SetLowPowerModeCoreLDORegulatorDriveStrength(SPC_Type *base, spc_core_ldo_drive_strength_t driveStrength);
+
+/*!
+ * @brief Gets CORE LDO VDD Drive Strength for Low Power modes.
+ *
+ * @param base SPC peripheral base address.
+ * @return The CORE LDO's VDD Drive Strength.
+ */
+static inline spc_core_ldo_drive_strength_t SPC_GetLowPowerCoreLDOVDDDriveStrength(SPC_Type *base)
+{
+ return (spc_core_ldo_drive_strength_t)(uint32_t)((base->LP_CFG & SPC_LP_CFG_CORELDO_VDD_DS_MASK) >>
+ SPC_LP_CFG_CORELDO_VDD_DS_SHIFT);
+}
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_SYS_LDO) && FSL_FEATURE_MCX_SPC_HAS_SYS_LDO)
+/*!
+ * @name Low Level APIs To Set System LDO Regulator
+ * @{
+ */
+
+/*!
+ * @brief Enable/Disable System LDO regulator.
+ *
+ * @note The SYSTEM LDO enable bit is write-once.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable System LDO Regulator.
+ * true - Enable System LDO Regulator.
+ * false - Disable System LDO Regulator.
+ */
+static inline void SPC_EnableSystemLDORegulator(SPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CNTRL |= SPC_CNTRL_SYSLDO_EN_MASK;
+ }
+ else
+ {
+ /*
+ * $Branch Coverage Justification$
+ * If SYSTEM_LDO is disabled, may cause some unexpected issues.
+ */
+ base->CNTRL &= ~SPC_CNTRL_SYSLDO_EN_MASK;
+ }
+}
+
+/*!
+ * @brief Enable/Disable current sink feature of System LDO Regulator.
+ *
+ * @param base SPC peripheral base address.
+ * @param sink Enable/Disable current sink feature.
+ * true - Enable current sink feature of System LDO Regulator.
+ * false - Disable current sink feature of System LDO Regulator.
+ */
+static inline void SPC_EnableSystemLDOSinkFeature(SPC_Type *base, bool sink)
+{
+ if (sink)
+ {
+ base->SYSLDO_CFG |= SPC_SYSLDO_CFG_ISINKEN_MASK;
+ }
+ else
+ {
+ base->SYSLDO_CFG &= ~SPC_SYSLDO_CFG_ISINKEN_MASK;
+ }
+}
+
+/*!
+ * @brief Configs System LDO VDD Regulator in Active mode.
+ *
+ * @note If System LDO VDD Drive Strength is set to Normal, the Bandgap mode in Active mode must be programmed
+ * to a value that enables the bandgap.
+ * @note If any voltage detects are kept enabled, configuration to set System LDO VDD drive strength to low will
+ * be ignored.
+ * @note If select System LDO VDD Regulator voltage level to Over Drive Voltage, the Drive Strength of System LDO VDD
+ * Regulator must be set to Normal otherwise the regulator Drive Strength will be forced to Normal.
+ * @note If select System LDO VDD Regulator voltage level to Over Drive Voltage, the High voltage detect must be
+ * disabled. Otherwise it will be fail to regulator to Over Drive Voltage.
+ *
+ * @param base SPC peripheral base address.
+ * @param option Pointer to the spc_active_mode_sys_ldo_option_t structure.
+ *
+ * @retval #kStatus_Success Config System LDO regulator in Active power mode successful.
+ * @retval #kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * @retval #kStatus_SPC_BandgapModeWrong The bandgap is not enabled before invoking this function.
+ * @retval #kStatus_SPC_SYSLDOOverDriveVoltageFail HVD of System VDD is not disable before setting to Over Drive
+ * voltage.
+ * @retval kStatus_SPC_SYSLDOLowDriveStrengthIgnore Set System LDO VDD regulator's driver strength to Low will be
+ * ignored.
+ */
+status_t SPC_SetActiveModeSystemLDORegulatorConfig(SPC_Type *base, const spc_active_mode_sys_ldo_option_t *option);
+
+/*!
+ * @brief Set System LDO Regulator voltage level in Active mode.
+ *
+ * @note The system LDO regulator can only operate at the overdrive voltage level for a limited amount of time for the
+ * life of chip.
+ *
+ * @param base SPC peripheral base address.
+ * @param voltageLevel Specify the voltage level of System LDO Regulator in Active mode.
+ *
+ * @retval #kStatus_Success Set System LDO Regulator voltage level in Active mode successfully.
+ * @retval #kStatus_SPC_SYSLDOOverDriveVoltageFail Must disable system LDO high voltage detector before specifying
+ * overdrive voltage.
+ */
+status_t SPC_SetActiveModeSystemLDORegulatorVoltageLevel(SPC_Type *base, spc_sys_ldo_voltage_level_t voltageLevel);
+
+/*!
+ * @brief Get System LDO Regulator voltage level in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return System LDO Regulator voltage level in Active mode, please refer to @ref spc_sys_ldo_voltage_level_t.
+ */
+static inline spc_sys_ldo_voltage_level_t SPC_GetActiveModeSystemLDORegulatorVoltageLevel(SPC_Type *base)
+{
+ return (spc_sys_ldo_voltage_level_t)(uint32_t)((base->ACTIVE_CFG & SPC_ACTIVE_CFG_SYSLDO_VDD_LVL_MASK) >>
+ SPC_ACTIVE_CFG_SYSLDO_VDD_LVL_SHIFT);
+}
+
+/*!
+ * @brief Set System LDO Regulator Drive Strength in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param driveStrength Specify the drive strength of System LDO Regulator in Active mode.
+ *
+ * @retval #kStatus_Success Set System LDO Regulator drive strength in Active mode successfully.
+ * @retval #kStatus_SPC_SYSLDOLowDriveStrengthIgnore Attempt to specify low drive strength is ignored due to any
+ voltage detect feature is enabled in active mode.
+ * @retval #kStatus_SPC_BandgapModeWrong Bandgap mode in Active mode must be programmed to a value that enables
+ the bandgap if attempt to specify normal drive strength.
+ */
+status_t SPC_SetActiveModeSystemLDORegulatorDriveStrength(SPC_Type *base, spc_sys_ldo_drive_strength_t driveStrength);
+
+/*!
+ * @brief Get System LDO Regulator Drive Strength in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return System LDO regulator drive strength in Active mode, please refer to @ref spc_sys_ldo_drive_strength_t.
+ */
+static inline spc_sys_ldo_drive_strength_t SPC_GetActiveModeSystemLDORegulatorDriveStrength(SPC_Type *base)
+{
+ return (spc_sys_ldo_drive_strength_t)(uint32_t)((base->ACTIVE_CFG & SPC_ACTIVE_CFG_SYSLDO_VDD_DS_MASK) >>
+ SPC_ACTIVE_CFG_SYSLDO_VDD_DS_SHIFT);
+}
+
+/*!
+ * @brief Configs System LDO regulator in low power modes.
+ *
+ * This function configs System LDO regulator in low power modes.
+ * If System LDO VDD Regulator Drive strength is set to normal, bandgap mode in low power
+ * mode must be programmed to a value that enables the Bandgap.
+ * If any High voltage detectors or Low Voltage detectors are kept enabled, configuration
+ * to set System LDO Regulator drive strength as Low will be ignored.
+ *
+ * @param base SPC peripheral base address.
+ * @param option Pointer to spc_lowpower_mode_sys_ldo_option_t structure.
+ *
+ * @retval #kStatus_Success Config System LDO regulator in Low Power Mode successfully.
+ * @retval #kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * @retval #kStatus_SPC_SYSLDOLowDriveStrengthIgnore Set driver strength to low will be ignored.
+ */
+status_t SPC_SetLowPowerModeSystemLDORegulatorConfig(SPC_Type *base, const spc_lowpower_mode_sys_ldo_option_t *option);
+
+/*!
+ * @brief Set System LDO Regulator drive strength in Low Power Mode.
+ *
+ * @param base SPC peripheral base address.
+ * @param driveStrength Specify the drive strength of System LDO Regulator in Low Power Mode.
+ *
+ * @retval #kStatus_Success Set System LDO Regulator drive strength in Low Power Mode successfully.
+ * @retval #kStatus_SPC_SYSLDOLowDriveStrengthIgnore Attempt to specify low drive strength is ignored due to any
+ voltage detect feature is enabled in low power mode.
+ * @retval #kStatus_SPC_BandgapModeWrong Bandgap mode in low power mode must be programmed to a value that enables
+ the bandgap if attempt to specify normal drive strength.
+ */
+status_t SPC_SetLowPowerModeSystemLDORegulatorDriveStrength(SPC_Type *base, spc_sys_ldo_drive_strength_t driveStrength);
+
+/*!
+ * @brief Get System LDO Regulator drive strength in Low Power Mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return System LDO regulator drive strength in Low Power Mode, please refer to @ref spc_sys_ldo_drive_strength_t.
+ */
+static inline spc_sys_ldo_drive_strength_t SPC_GetLowPowerModeSystemLDORegulatorDriveStrength(SPC_Type *base)
+{
+ return (spc_sys_ldo_drive_strength_t)(uint32_t)((base->LP_CFG & SPC_LP_CFG_SYSLDO_VDD_DS_MASK) >>
+ SPC_LP_CFG_SYSLDO_VDD_DS_SHIFT);
+}
+/*! @} */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_SYS_LDO */
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC) && FSL_FEATURE_MCX_SPC_HAS_DCDC)
+/*!
+ * @name Low Level APIs To Set DCDC Regulator
+ * @{
+ */
+
+/*!
+ * @brief Enable/Disable DCDC Regulator.
+ *
+ * @note The DCDC enable bit is write-once, settings only reset after a POR, LVD, or HVD event.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Enable/Disable DCDC Regulator.
+ * true - Enable DCDC Regulator.
+ * false - Disable DCDC Regulator.
+ */
+static inline void SPC_EnableDCDCRegulator(SPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CNTRL |= SPC_CNTRL_DCDC_EN_MASK;
+ }
+ else
+ {
+ /*
+ * $Branch Coverage Justification$
+ * If DCDC is disabled, all RAMs data will powered off.
+ */
+ base->CNTRL &= ~SPC_CNTRL_DCDC_EN_MASK;
+ }
+}
+
+/*!
+ * @brief Config DCDC Burst options
+ *
+ * @param base SPC peripheral base address.
+ * @param config Pointer to spc_dcdc_burst_config_t structure.
+ */
+void SPC_SetDCDCBurstConfig(SPC_Type *base, spc_dcdc_burst_config_t *config);
+
+/*!
+ * @brief Trigger a software burst request to DCDC.
+ *
+ * @param base SPC peripheral base address.
+ */
+static inline void SPC_TriggerDCDCBurstRequest(SPC_Type *base)
+{
+ /* Blocking until previous DCDC burst completed. */
+ while ((base->DCDC_BURST_CFG & SPC_DCDC_BURST_CFG_BURST_ACK_MASK) == 0UL)
+ {
+ }
+
+ base->DCDC_BURST_CFG |= SPC_DCDC_BURST_CFG_BURST_REQ_MASK;
+}
+
+/*!
+ * @brief Check if burst acknowledge flag is asserted.
+ *
+ * @param base SPC peripheral base address.
+ *
+ * @retval false DCDC burst not complete.
+ * @retval true DCDC burst complete.
+ */
+static inline bool SPC_CheckDCDCBurstAck(SPC_Type *base)
+{
+ return ((base->DCDC_BURST_CFG & SPC_DCDC_BURST_CFG_BURST_ACK_MASK) != 0UL);
+}
+
+/*!
+ * @brief Clear DCDC busrt acknowledge flag.
+ *
+ * @param base SPC periphral base address.
+ */
+static inline void SPC_ClearDCDCBurstAckFlag(SPC_Type *base)
+{
+ base->DCDC_BURST_CFG |= SPC_DCDC_BURST_CFG_BURST_ACK_MASK;
+}
+
+/*!
+ * @brief Set the count value of the reference clock to configure the period of DCDC not active.
+ *
+ * @note This function is only useful when DCDC's drive strength is set as pulse refresh.
+ * @note The pulse duration(time between on and off) is: reference clock period * (count + 2).
+ *
+ * @param base SPC peripheral base address.
+ * @param count The count value, 16 bit width.
+ */
+void SPC_SetDCDCRefreshCount(SPC_Type *base, uint16_t count);
+
+#if (defined(FSL_FEATURE_MCX_SPC_HAS_DCDC_CFG_BLEED_EN) && FSL_FEATURE_MCX_SPC_HAS_DCDC_CFG_BLEED_EN)
+/*!
+ * @brief Enable a bleed resistor to discharge DCDC output when DCDC is disabled.
+ *
+ * @param base SPC peripheral base address.
+ * @param enable Used to enable/disable bleed resistor.
+ */
+static inline void SPC_EnableDCDCBleedResistor(SPC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->DCDC_CFG |= SPC_DCDC_CFG_BLEED_EN_MASK;
+ }
+ else
+ {
+ base->DCDC_CFG &= ~SPC_DCDC_CFG_BLEED_EN_MASK;
+ }
+}
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC_CFG_BLEED_EN */
+
+/*!
+ * @brief Configs DCDC_CORE Regulator in Active mode.
+ *
+ * @note When changing the DCDC output voltage level, take care to change the CORE LDO voltage level.
+ *
+ * @param base SPC peripheral base address.
+ * @param option Pointer to the spc_active_mode_dcdc_option_t structure.
+ *
+ * @retval #kStatus_Success Config DCDC regulator in Active power mode successful.
+ * @retval #kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * @retval #kStatus_SPC_BandgapModeWrong Set DCDC_CORE Regulator drive strength to Normal, the Bandgap must be enabled.
+ */
+status_t SPC_SetActiveModeDCDCRegulatorConfig(SPC_Type *base, const spc_active_mode_dcdc_option_t *option);
+
+/*!
+ * @brief Set DCDC_CORE Regulator voltage level in Active mode.
+ *
+ * @note When changing the DCDC output voltage level, take care to change the CORE LDO voltage level.
+ *
+ * @param base SPC peripheral base address.
+ * @param voltageLevel Specify the DCDC_CORE Regulator voltage level, please refer to @ref spc_dcdc_voltage_level_t.
+ */
+static inline void SPC_SetActiveModeDCDCRegulatorVoltageLevel(SPC_Type *base, spc_dcdc_voltage_level_t voltageLevel)
+{
+ base->ACTIVE_CFG =
+ (base->ACTIVE_CFG & (~SPC_ACTIVE_CFG_DCDC_VDD_LVL_MASK)) | SPC_ACTIVE_CFG_DCDC_VDD_LVL(voltageLevel);
+}
+
+/*!
+ * @brief Get DCDC_CORE Regulator voltage level in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return DCDC_CORE Regulator voltage level, please refer to @ref spc_dcdc_voltage_level_t.
+ */
+static inline spc_dcdc_voltage_level_t SPC_GetActiveModeDCDCRegulatorVoltageLevel(SPC_Type *base)
+{
+ return (spc_dcdc_voltage_level_t)((uint32_t)((base->ACTIVE_CFG & SPC_ACTIVE_CFG_DCDC_VDD_LVL_MASK) >>
+ SPC_ACTIVE_CFG_DCDC_VDD_LVL_SHIFT));
+}
+
+/*!
+ * @brief Set DCDC_CORE Regulator drive strength in Active mode.
+ *
+ * @note To set DCDC drive strength as Normal, the bandgap must be enabled.
+ *
+ * @param base SPC peripheral base address.
+ * @param driveStrength Specify the DCDC_CORE regulator drive strength, please refer to @ref spc_dcdc_drive_strength_t.
+ *
+ * @retval #kStatus_Success Set DCDC_CORE Regulator drive strength in Active mode successfully.
+ * @retval #kStatus_SPC_BandgapModeWrong Set DCDC_CORE Regulator drive strength to Normal, the Bandgap must be enabled.
+ */
+status_t SPC_SetActiveModeDCDCRegulatorDriveStrength(SPC_Type *base, spc_dcdc_drive_strength_t driveStrength);
+
+/*!
+ * @brief Get DCDC_CORE Regulator drive strength in Active mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return DCDC_CORE Regulator drive strength, please refer to @ref spc_dcdc_drive_strength_t.
+ */
+static inline spc_dcdc_drive_strength_t SPC_GetActiveModeDCDCRegulatorDriveStrength(SPC_Type *base)
+{
+ return (spc_dcdc_drive_strength_t)((uint32_t)((base->ACTIVE_CFG & SPC_ACTIVE_CFG_DCDC_VDD_DS_MASK) >>
+ SPC_ACTIVE_CFG_DCDC_VDD_DS_SHIFT));
+}
+
+/*!
+ * @brief Configs DCDC_CORE Regulator in Low power modes.
+ *
+ * @note If DCDC_CORE Drive Strength is set to Normal, the Bandgap mode in Low Power mode must be programmed
+ * to a value that enables the Bandgap.
+ * @note In Deep Power Down mode, DCDC regulator is always turned off.
+ *
+ * @param base SPC peripheral base address.
+ * @param option Pointer to the spc_lowpower_mode_dcdc_option_t structure.
+ *
+ * @retval #kStatus_Success Config DCDC regulator in low power mode successfully.
+ * @retval #kStatus_SPC_Busy The SPC instance is busy to execute any type of power mode transition.
+ * @retval #kStatus_SPC_BandgapModeWrong The bandgap mode setting in Low Power mode is wrong.
+ */
+status_t SPC_SetLowPowerModeDCDCRegulatorConfig(SPC_Type *base, const spc_lowpower_mode_dcdc_option_t *option);
+
+/*!
+ * @brief Set DCDC_CORE Regulator drive strength in Low power mode.
+ *
+ * @note To set drive strength as normal, the bandgap must be enabled.
+ *
+ * @param base SPC peripheral base address.
+ * @param driveStrength Specify the DCDC_CORE Regulator drive strength, please refer to @ref spc_dcdc_drive_strength_t.
+ *
+ * @retval #kStatus_Success Set DCDC_CORE Regulator drive strength in Low power mode successfully.
+ * @retval #kStatus_SPC_BandgapModeWrong Set DCDC_CORE Regulator drive strength to Normal, the Bandgap must be enabled.
+ */
+status_t SPC_SetLowPowerModeDCDCRegulatorDriveStrength(SPC_Type *base, spc_dcdc_drive_strength_t driveStrength);
+
+/*!
+ * @brief Get DCDC_CORE Regulator drive strength in Low power mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return DCDC_CORE Regulator drive strength, please refer to @ref spc_dcdc_drive_strength_t.
+ */
+static inline spc_dcdc_drive_strength_t SPC_GetLowPowerModeDCDCRegulatorDriveStrength(SPC_Type *base)
+{
+ return (spc_dcdc_drive_strength_t)((uint32_t)((base->LP_CFG & SPC_LP_CFG_DCDC_VDD_DS_MASK) >>
+ SPC_LP_CFG_DCDC_VDD_DS_SHIFT));
+}
+
+/*!
+ * @brief Set DCDC_CORE Regulator voltage level in Low power mode.
+ *
+ * @note To change DCDC level in Low-Power mode:
+ * 1. Configure LP_CFG[DCDC_VDD_LVL] to desired level;
+ * 2. Configure LP_CFG[DCDC_VDD_DS] to low driver strength;
+ * 3. Configure ACTIVE_CFG[DCDC_VDD_LVL] to same level programmed in #1.
+ *
+ * @note After invoking this function, the voltage level in active mode(wakeup from low power modes) also changed,
+ * if it is necessary, please invoke SPC_SetActiveModeDCDCRegulatorVoltageLevel() to change to desried voltage level.
+ *
+ * @param base SPC peripheral base address.
+ * @param voltageLevel Specify the DCDC_CORE Regulator voltage level, please refer to @ref spc_dcdc_voltage_level_t.
+ */
+static inline void SPC_SetLowPowerModeDCDCRegulatorVoltageLevel(SPC_Type *base, spc_dcdc_voltage_level_t voltageLevel)
+{
+ base->LP_CFG = (base->LP_CFG & (~SPC_LP_CFG_DCDC_VDD_LVL_MASK)) | SPC_LP_CFG_DCDC_VDD_LVL(voltageLevel);
+ (void)SPC_SetLowPowerModeDCDCRegulatorDriveStrength(base, kSPC_DCDC_LowDriveStrength);
+ SPC_SetActiveModeDCDCRegulatorVoltageLevel(base, voltageLevel);
+}
+
+/*!
+ * @brief Get DCDC_CORE Regulator voltage level in Low power mode.
+ *
+ * @param base SPC peripheral base address.
+ * @return DCDC_CORE Regulator voltage level, please refer to @ref spc_dcdc_voltage_level_t.
+ */
+static inline spc_dcdc_voltage_level_t SPC_GetLowPowerModeDCDCRegulatorVoltageLevel(SPC_Type *base)
+{
+ return (spc_dcdc_voltage_level_t)((uint32_t)((base->LP_CFG & SPC_LP_CFG_DCDC_VDD_LVL_MASK) >>
+ SPC_LP_CFG_DCDC_VDD_LVL_SHIFT));
+}
+
+/*! @} */
+#endif /* FSL_FEATURE_MCX_SPC_HAS_DCDC */
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus */
+
+/*! @} */
+
+#endif /* FSL_SPC_H_ */
diff --git a/hw/bsp/mcx/family.c b/hw/bsp/mcx/family.c
index 2b9c60beb..2dfefeb92 100644
--- a/hw/bsp/mcx/family.c
+++ b/hw/bsp/mcx/family.c
@@ -60,9 +60,14 @@ void USB0_IRQHandler(void) {
void board_init(void) {
+
BOARD_InitPins();
+
BOARD_InitBootClocks();
+
+ #ifdef XTAL0_CLK_HZ
CLOCK_SetupExtClocking(XTAL0_CLK_HZ);
+ #endif
#if CFG_TUSB_OS == OPT_OS_NONE
// 1ms tick timer
@@ -84,15 +89,7 @@ void board_init(void) {
board_led_write(0);
#ifdef NEOPIXEL_PIN
- // Neopixel
- static uint32_t pixelData[NEOPIXEL_NUMBER];
- IOCON_PinMuxSet(IOCON, NEOPIXEL_PORT, NEOPIXEL_PIN, IOCON_PIO_DIG_FUNC4_EN);
-
- sctpix_init(NEOPIXEL_TYPE);
- sctpix_addCh(NEOPIXEL_CH, pixelData, NEOPIXEL_NUMBER);
- sctpix_setPixel(NEOPIXEL_CH, 0, 0x100010);
- sctpix_setPixel(NEOPIXEL_CH, 1, 0x100010);
- sctpix_show();
+ // No neo pixel support yet
#endif
// Button
@@ -103,9 +100,6 @@ void board_init(void) {
#endif
#ifdef UART_DEV
- // UART
-// IOCON_PinMuxSet(IOCON, UART_RX_PINMUX);
-// IOCON_PinMuxSet(IOCON, UART_TX_PINMUX);
// Enable UART when debug log is on
board_uart_init_clock();
@@ -115,6 +109,7 @@ void board_init(void) {
uart_config.baudRate_Bps = CFG_BOARD_UART_BAUDRATE;
uart_config.enableTx = true;
uart_config.enableRx = true;
+
LPUART_Init(UART_DEV, &uart_config, 12000000u);
#endif
@@ -196,17 +191,6 @@ void board_init(void) {
void board_led_write(bool state) {
GPIO_PinWrite(LED_GPIO, LED_PIN, state ? LED_STATE_ON : (1 - LED_STATE_ON));
-
-#ifdef NEOPIXEL_PIN
- if (state) {
- sctpix_setPixel(NEOPIXEL_CH, 0, 0x100000);
- sctpix_setPixel(NEOPIXEL_CH, 1, 0x101010);
- } else {
- sctpix_setPixel(NEOPIXEL_CH, 0, 0x001000);
- sctpix_setPixel(NEOPIXEL_CH, 1, 0x000010);
- }
- sctpix_show();
-#endif
}
uint32_t board_button_read(void) {
diff --git a/hw/bsp/mcx/family.cmake b/hw/bsp/mcx/family.cmake
index 413c1b372..f857ed31a 100644
--- a/hw/bsp/mcx/family.cmake
+++ b/hw/bsp/mcx/family.cmake
@@ -10,6 +10,9 @@ include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
if (MCU_VARIANT STREQUAL "MCXA153")
set(CMAKE_SYSTEM_CPU cortex-m33-nodsp-nofp CACHE INTERNAL "System Processor")
set(FAMILY_MCUS MCXA15 CACHE INTERNAL "")
+elseif (MCU_VARIANT STREQUAL "MCXA156")
+ set(CMAKE_SYSTEM_CPU cortex-m33 CACHE INTERNAL "System Processor")
+ set(FAMILY_MCUS MCXA15 CACHE INTERNAL "")
elseif (MCU_VARIANT STREQUAL "MCXN947")
set(CMAKE_SYSTEM_CPU cortex-m33 CACHE INTERNAL "System Processor")
set(FAMILY_MCUS MCXN9 CACHE INTERNAL "")
@@ -38,12 +41,14 @@ function(add_board_target BOARD_TARGET)
endif()
set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
+
add_library(${BOARD_TARGET} STATIC
${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
# driver
- ${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_gpio.c
- ${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_common_arm.c
- ${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_lpuart.c
+ ${SDK_DIR}/drivers/gpio/fsl_gpio.c
+ ${SDK_DIR}/drivers/common/fsl_common_arm.c
+ ${SDK_DIR}/drivers/lpuart/fsl_lpuart.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/drivers/spc/fsl_spc.c
# mcu
${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_clock.c
${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_reset.c
@@ -51,18 +56,27 @@ function(add_board_target BOARD_TARGET)
)
target_include_directories(${BOARD_TARGET} PUBLIC
${CMSIS_DIR}/CMSIS/Core/Include
+ ${SDK_DIR}/drivers/gpio/
+ ${SDK_DIR}/drivers/lpuart
+ ${SDK_DIR}/drivers/common
+ ${SDK_DIR}/drivers/port
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/drivers/spc
${SDK_DIR}/devices/${MCU_VARIANT}
${SDK_DIR}/devices/${MCU_VARIANT}/drivers
)
if (${FAMILY_MCUS} STREQUAL "MCXN9")
+
target_sources(${BOARD_TARGET} PRIVATE
- ${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_lpflexcomm.c
+ ${SDK_DIR}/drivers/lpflexcomm/fsl_lpflexcomm.c
+ )
+
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${SDK_DIR}/drivers/lpflexcomm
)
elseif(${FAMILY_MCUS} STREQUAL "MCXA15")
- target_sources(${BOARD_TARGET} PRIVATE
- ${SDK_DIR}/devices/${MCU_VARIANT}/drivers/fsl_spc.c
- )
+
+
endif()
update_board(${BOARD_TARGET})
diff --git a/hw/bsp/mcx/family.mk b/hw/bsp/mcx/family.mk
index 58149fb8d..a16f4b6c0 100644
--- a/hw/bsp/mcx/family.mk
+++ b/hw/bsp/mcx/family.mk
@@ -1,8 +1,6 @@
UF2_FAMILY_ID = 0x2abc77ec
SDK_DIR = hw/mcu/nxp/mcux-sdk
-DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5
-
include $(TOP)/$(BOARD_PATH)/board.mk
# Default to Highspeed PORT1
@@ -35,18 +33,19 @@ SRC_C += \
$(SDK_DIR)/devices/$(MCU_VARIANT)/system_$(MCU_CORE).c \
$(SDK_DIR)/devices/$(MCU_VARIANT)/drivers/fsl_clock.c \
$(SDK_DIR)/devices/$(MCU_VARIANT)/drivers/fsl_reset.c \
- $(SDK_DIR)/devices/$(MCU_VARIANT)/drivers/fsl_gpio.c \
- $(SDK_DIR)/devices/$(MCU_VARIANT)/drivers/fsl_lpuart.c \
- $(SDK_DIR)/devices/$(MCU_VARIANT)/drivers/fsl_common_arm.c \
+ ${SDK_DIR}/drivers/gpio/fsl_gpio.c \
+ ${SDK_DIR}/drivers/lpuart/fsl_lpuart.c \
+ ${SDK_DIR}/drivers/common/fsl_common_arm.c\
+ hw/bsp/mcx/drivers/spc/fsl_spc.c
# fsl_lpflexcomm for MCXN9
ifeq ($(MCU_VARIANT), MCXN947)
- SRC_C += $(SDK_DIR)/devices/$(MCU_VARIANT)/drivers/fsl_lpflexcomm.c
+ SRC_C += ${SDK_DIR}/drivers/lpflexcomm/fsl_lpflexcomm.c
endif
# fsl_spc for MCXNA15
ifeq ($(MCU_VARIANT), MCXA153)
- SRC_C += $(SDK_DIR)/devices/$(MCU_VARIANT)/drivers/fsl_spc.c
+
endif
INC += \
@@ -54,5 +53,15 @@ INC += \
$(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
$(TOP)/$(SDK_DIR)/devices/$(MCU_VARIANT) \
$(TOP)/$(SDK_DIR)/devices/$(MCU_VARIANT)/drivers \
+ $(TOP)/$(SDK_DIR)/drivers/ \
+ $(TOP)/$(SDK_DIR)/drivers/lpuart \
+ $(TOP)/$(SDK_DIR)/drivers/lpflexcomm \
+ $(TOP)/$(SDK_DIR)/drivers/common\
+ $(TOP)/$(SDK_DIR)/drivers/gpio\
+ $(TOP)/$(SDK_DIR)/drivers/port\
+ $(TOP)/hw/bsp/mcx/drivers/spc
+
+
+
SRC_S += $(SDK_DIR)/devices/$(MCU_VARIANT)/gcc/startup_$(MCU_CORE).S
diff --git a/hw/bsp/msp430/family.cmake b/hw/bsp/msp430/family.cmake
index ddd54b675..d9b4bf770 100644
--- a/hw/bsp/msp430/family.cmake
+++ b/hw/bsp/msp430/family.cmake
@@ -11,36 +11,37 @@ set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/msp430_${T
set(FAMILY_MCUS MSP430x5xx CACHE INTERNAL "")
-
#------------------------------------
# BOARD_TARGET
#------------------------------------
# only need to be built ONCE for all examples
function(add_board_target BOARD_TARGET)
- if (NOT TARGET ${BOARD_TARGET})
- add_library(${BOARD_TARGET} INTERFACE)
- target_compile_definitions(${BOARD_TARGET} INTERFACE
- CFG_TUD_ENDPOINT0_SIZE=8
- CFG_EXAMPLE_VIDEO_READONLY
- CFG_EXAMPLE_MSC_READONLY
- )
- target_include_directories(${BOARD_TARGET} INTERFACE
- ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
- ${SDK_DIR}
- )
+ if (TARGET ${BOARD_TARGET})
+ return()
+ endif ()
- update_board(${BOARD_TARGET})
+ add_library(${BOARD_TARGET} INTERFACE)
+ target_compile_definitions(${BOARD_TARGET} INTERFACE
+ CFG_TUD_ENDPOINT0_SIZE=8
+ CFG_EXAMPLE_VIDEO_READONLY
+ CFG_EXAMPLE_MSC_READONLY
+ )
+ target_include_directories(${BOARD_TARGET} INTERFACE
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${SDK_DIR}
+ )
- if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
- target_link_options(${BOARD_TARGET} INTERFACE
- "LINKER:--script=${LD_FILE_GNU}"
- -L${SDK_DIR}
- )
- elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
- target_link_options(${BOARD_TARGET} INTERFACE
- "LINKER:--config=${LD_FILE_IAR}"
- )
- endif ()
+ update_board(${BOARD_TARGET})
+
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_link_options(${BOARD_TARGET} INTERFACE
+ "LINKER:--script=${LD_FILE_GNU}"
+ -L${SDK_DIR}
+ )
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
+ target_link_options(${BOARD_TARGET} INTERFACE
+ "LINKER:--config=${LD_FILE_IAR}"
+ )
endif ()
endfunction()
@@ -75,7 +76,6 @@ function(family_configure_example TARGET RTOS)
)
target_link_libraries(${TARGET} PUBLIC board_${BOARD})
-
# Flashing
family_add_bin_hex(${TARGET})
family_flash_msp430flasher(${TARGET})
diff --git a/hw/bsp/msp430/family.mk b/hw/bsp/msp430/family.mk
index 06508ab2c..c973d9dcd 100644
--- a/hw/bsp/msp430/family.mk
+++ b/hw/bsp/msp430/family.mk
@@ -1,5 +1,4 @@
CROSS_COMPILE = msp430-elf-
-DEPS_SUBMODULES += hw/mcu/ti
SKIP_NANOLIB = 1
SDK_DIR = hw/mcu/ti/msp430/msp430-gcc-support-files/include
diff --git a/hw/bsp/nutiny_nuc121s/board.mk b/hw/bsp/nutiny_nuc121s/board.mk
index 161ff9041..06c47d544 100644
--- a/hw/bsp/nutiny_nuc121s/board.mk
+++ b/hw/bsp/nutiny_nuc121s/board.mk
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/nuvoton
-
CFLAGS += \
-flto \
-mthumb \
diff --git a/hw/bsp/nutiny_nuc125s/board.mk b/hw/bsp/nutiny_nuc125s/board.mk
index 081764fd3..50b9d866a 100644
--- a/hw/bsp/nutiny_nuc125s/board.mk
+++ b/hw/bsp/nutiny_nuc125s/board.mk
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/nuvoton
-
CFLAGS += \
-flto \
-mthumb \
diff --git a/hw/bsp/nutiny_nuc126v/board.mk b/hw/bsp/nutiny_nuc126v/board.mk
index 2466b3a31..e87d1aad0 100644
--- a/hw/bsp/nutiny_nuc126v/board.mk
+++ b/hw/bsp/nutiny_nuc126v/board.mk
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/nuvoton
-
CFLAGS += \
-flto \
-mthumb \
diff --git a/hw/bsp/nutiny_sdk_nuc120/board.mk b/hw/bsp/nutiny_sdk_nuc120/board.mk
index b54895b58..d982bdc06 100644
--- a/hw/bsp/nutiny_sdk_nuc120/board.mk
+++ b/hw/bsp/nutiny_sdk_nuc120/board.mk
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/nuvoton
-
CFLAGS += \
-flto \
-mthumb \
diff --git a/hw/bsp/nutiny_sdk_nuc505/board.mk b/hw/bsp/nutiny_sdk_nuc505/board.mk
index f3b389354..1dc8b244e 100644
--- a/hw/bsp/nutiny_sdk_nuc505/board.mk
+++ b/hw/bsp/nutiny_sdk_nuc505/board.mk
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/nuvoton
-
CFLAGS += \
-flto \
-mthumb \
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/family.c b/hw/bsp/rp2040/family.c
index 8c85c5cc8..a22924131 100644
--- a/hw/bsp/rp2040/family.c
+++ b/hw/bsp/rp2040/family.c
@@ -254,7 +254,7 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) {
int board_uart_read(uint8_t *buf, int len) {
#ifdef UART_DEV
int count = 0;
- while ( (count < len) && uart_is_readable(uart_inst) ) {
+ while ((count < len) && uart_is_readable(uart_inst)) {
buf[count] = uart_getc(uart_inst);
count++;
}
@@ -282,6 +282,10 @@ int board_getchar(void) {
return getchar_timeout_us(0);
}
+void board_putchar(int c) {
+ stdio_putchar(c);
+}
+
//--------------------------------------------------------------------+
// USB Interrupt Handler
// rp2040 implementation will install appropriate handler when initializing
diff --git a/hw/bsp/rp2040/family.mk b/hw/bsp/rp2040/family.mk
deleted file mode 100644
index 25d1ad9c5..000000000
--- a/hw/bsp/rp2040/family.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-JLINK_DEVICE = rp2040_m0_0
-PYOCD_TARGET = rp2040
-
-DEPS_SUBMODULES += hw/mcu/raspberry_pi/Pico-PIO-USB
-
-ifeq ($(DEBUG), 1)
-CMAKE_DEFSYM += -DCMAKE_BUILD_TYPE=Debug
-endif
-
-$(BUILD):
- cmake -S . -B $(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) -DPICO_BUILD_DOCS=0 $(CMAKE_DEFSYM)
-
-all: $(BUILD)
- $(MAKE) -C $(BUILD)
-
-flash: flash-pyocd
-flash-uf2:
- @$(CP) $(BUILD)/$(PROJECT).uf2 /media/$(USER)/RPI-RP2
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/rx/family.mk b/hw/bsp/rx/family.mk
index 02ea0dfa4..4ecf80409 100644
--- a/hw/bsp/rx/family.mk
+++ b/hw/bsp/rx/family.mk
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/renesas/rx
-
# Cross Compiler for RX
CROSS_COMPILE = rx-elf-
diff --git a/hw/bsp/same70_qmtech/board.mk b/hw/bsp/same70_qmtech/board.mk
index 281a947f3..7e949e135 100644
--- a/hw/bsp/same70_qmtech/board.mk
+++ b/hw/bsp/same70_qmtech/board.mk
@@ -1,4 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/microchip
ASF_DIR = hw/mcu/microchip/same70
CFLAGS += \
diff --git a/hw/bsp/same70_xplained/board.mk b/hw/bsp/same70_xplained/board.mk
index 60702f14a..2d97ecdc1 100644
--- a/hw/bsp/same70_xplained/board.mk
+++ b/hw/bsp/same70_xplained/board.mk
@@ -1,4 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/microchip
ASF_DIR = hw/mcu/microchip/same70
CFLAGS += \
diff --git a/hw/bsp/sltb009a/board.mk b/hw/bsp/sltb009a/board.mk
index 687761364..5dd7a158f 100644
--- a/hw/bsp/sltb009a/board.mk
+++ b/hw/bsp/sltb009a/board.mk
@@ -16,9 +16,6 @@ CFLAGS += \
SILABS_FAMILY = efm32gg12b
SILABS_CMSIS = hw/mcu/silabs/cmsis-dfp-$(SILABS_FAMILY)/Device/SiliconLabs/$(shell echo $(SILABS_FAMILY) | tr a-z A-Z)
-DEPS_SUBMODULES += hw/mcu/silabs/cmsis-dfp-$(SILABS_FAMILY)
-DEPS_SUBMODULES += lib/CMSIS_5
-
LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs
# All source paths should be relative to the top level.
diff --git a/hw/bsp/spresense/board.mk b/hw/bsp/spresense/board.mk
index 15fa0ff20..24f39d2b6 100644
--- a/hw/bsp/spresense/board.mk
+++ b/hw/bsp/spresense/board.mk
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += hw/mcu/sony/cxd56/spresense-exported-sdk
-
# Platforms are: Linux, Darwin, MSYS, CYGWIN
PLATFORM := $(firstword $(subst _, ,$(shell uname -s 2>/dev/null)))
diff --git a/hw/bsp/stm32c0/boards/stm32c071nucleo/board.h b/hw/bsp/stm32c0/boards/stm32c071nucleo/board.h
index c7d809717..751df2251 100644
--- a/hw/bsp/stm32c0/boards/stm32c071nucleo/board.h
+++ b/hw/bsp/stm32c0/boards/stm32c071nucleo/board.h
@@ -55,9 +55,45 @@
// Enable UART serial communication with the ST-Link
#define UART_DEV USART2
+#define UART_CLK_EN __HAL_RCC_USART2_CLK_ENABLE
#define UART_GPIO_PORT GPIOA
#define UART_GPIO_AF GPIO_AF1_USART2
#define UART_TX_PIN GPIO_PIN_2
#define UART_RX_PIN GPIO_PIN_3
+static inline void board_clock_init(void) {
+ RCC_OscInitTypeDef RCC_OscInitStruct = {0};
+ RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
+ RCC_CRSInitTypeDef RCC_CRSInitStruct = {0};
+
+ /* -1- Enable HSIUSB48 Oscillator */
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48;
+ RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
+
+ HAL_RCC_OscConfig(&RCC_OscInitStruct);
+
+ /* -2- Initializes the CPU, AHB and APB buses clocks */
+ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
+ |RCC_CLOCKTYPE_PCLK1;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSIUSB48;
+ RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
+
+ HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
+
+
+ __HAL_RCC_CRS_CLK_ENABLE();
+
+ // Configures CRS
+ RCC_CRSInitStruct.Prescaler = RCC_CRS_SYNC_DIV1;
+ RCC_CRSInitStruct.Source = RCC_CRS_SYNC_SOURCE_USB;
+ RCC_CRSInitStruct.Polarity = RCC_CRS_SYNC_POLARITY_RISING;
+ RCC_CRSInitStruct.ReloadValue = __HAL_RCC_CRS_RELOADVALUE_CALCULATE(48000000,1000);
+ RCC_CRSInitStruct.ErrorLimitValue = 34;
+ RCC_CRSInitStruct.HSI48CalibrationValue = 32;
+
+ HAL_RCCEx_CRSConfig(&RCC_CRSInitStruct);
+}
+
#endif /* BOARD_H_ */
diff --git a/hw/bsp/stm32c0/family.c b/hw/bsp/stm32c0/family.c
index ace3f2a71..09704b527 100644
--- a/hw/bsp/stm32c0/family.c
+++ b/hw/bsp/stm32c0/family.c
@@ -53,31 +53,16 @@ UART_HandleTypeDef UartHandle;
void board_init(void) {
HAL_Init();
-
- // Enable the HSIUSB48 48 MHz oscillator.
- RCC->CR |= RCC_CR_HSIUSB48ON;
-
- // Wait for HSIUSB48 to be ready.
- while (!(RCC->CR & RCC_CR_HSIUSB48RDY)) { }
-
- // Change the SYSCLK source to HSIUSB48.
- RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_SYSCLKSOURCE_HSIUSB48;
-
- // Wait for the SYSCLK source to change.
- while ((RCC->CFGR & RCC_CFGR_SWS) >> RCC_CFGR_SWS_Pos != RCC_SYSCLKSOURCE_HSIUSB48) { }
-
- // Disable HSI48 to save power.
- RCC->CR &= ~RCC_CR_HSION;
+ board_clock_init();
// Enable peripheral clocks.
- RCC->APBENR1 = RCC_APBENR1_USBEN | RCC_APBENR1_CRSEN | RCC_APBENR1_USART2EN;
- RCC->APBENR2 = RCC_APBENR2_USART1EN;
-
- // Enable all GPIO clocks.
- RCC->IOPENR = 0x2F;
-
- // Turn on CRS to make the HSIUSB48 clock more precise when USB is connected.
- CRS->CR |= CRS_CR_AUTOTRIMEN | CRS_CR_CEN;
+ __HAL_RCC_USB_CLK_ENABLE();
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+ __HAL_RCC_GPIOC_CLK_ENABLE();
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+ __HAL_RCC_SYSCFG_CLK_ENABLE();
+ __HAL_RCC_PWR_CLK_ENABLE();
#if CFG_TUSB_OS == OPT_OS_NONE
// 1ms tick timer
@@ -109,6 +94,7 @@ void board_init(void) {
}
#ifdef UART_DEV
+ UART_CLK_EN();
// UART
{
GPIO_InitTypeDef gpio_init = { 0 };
diff --git a/hw/bsp/stm32c0/family.mk b/hw/bsp/stm32c0/family.mk
index 9ff3a2fdf..bdb34454e 100644
--- a/hw/bsp/stm32c0/family.mk
+++ b/hw/bsp/stm32c0/family.mk
@@ -1,6 +1,4 @@
ST_FAMILY = c0
-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/stm32f0/family.mk b/hw/bsp/stm32f0/family.mk
index 431709de0..9b8305874 100644
--- a/hw/bsp/stm32f0/family.mk
+++ b/hw/bsp/stm32f0/family.mk
@@ -1,7 +1,5 @@
UF2_FAMILY_ID = 0x647824b6
ST_FAMILY = f0
-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/stm32f1/family.mk b/hw/bsp/stm32f1/family.mk
index 364616304..ca95f2315 100644
--- a/hw/bsp/stm32f1/family.mk
+++ b/hw/bsp/stm32f1/family.mk
@@ -1,6 +1,4 @@
ST_FAMILY = f1
-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/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..ef14a9d67 100644
--- a/hw/bsp/stm32f2/family.mk
+++ b/hw/bsp/stm32f2/family.mk
@@ -1,24 +1,17 @@
ST_FAMILY = f2
-
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-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 +33,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/stm32f7/family.mk b/hw/bsp/stm32f7/family.mk
index abeea784c..d3422e03c 100644
--- a/hw/bsp/stm32f7/family.mk
+++ b/hw/bsp/stm32f7/family.mk
@@ -1,6 +1,5 @@
UF2_FAMILY_ID = 0x53b80f00
ST_FAMILY = f7
-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/stm32g0/family.mk b/hw/bsp/stm32g0/family.mk
index 95b8e537d..d735ca92d 100644
--- a/hw/bsp/stm32g0/family.mk
+++ b/hw/bsp/stm32g0/family.mk
@@ -1,5 +1,4 @@
ST_FAMILY = g0
-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/max32666/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/stm32h7rs/FreeRTOSConfig/FreeRTOSConfig.h
similarity index 98%
rename from hw/bsp/max32666/FreeRTOSConfig/FreeRTOSConfig.h
rename to hw/bsp/stm32h7rs/FreeRTOSConfig/FreeRTOSConfig.h
index e5a76af85..9fd3f6c50 100644
--- a/hw/bsp/max32666/FreeRTOSConfig/FreeRTOSConfig.h
+++ b/hw/bsp/stm32h7rs/FreeRTOSConfig/FreeRTOSConfig.h
@@ -44,7 +44,7 @@
// skip if included from IAR assembler
#ifndef __IASMARM__
- #include "mxc_device.h"
+ #include "stm32h7rsxx.h"
#endif
/* Cortex M23/M33 port configuration. */
@@ -59,7 +59,7 @@
#define configTICK_RATE_HZ ( 1000 )
#define configMAX_PRIORITIES ( 5 )
#define configMINIMAL_STACK_SIZE ( 128 )
-#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 )
+#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*8*1024 )
#define configMAX_TASK_NAME_LEN 16
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
@@ -127,7 +127,7 @@
//--------------------------------------------------------------------+
// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header
-#define configPRIO_BITS __NVIC_PRIO_BITS
+#define configPRIO_BITS 4
/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<port, pindef->pin_init.Pin, GPIO_PIN_SET);
+
+ __HAL_RCC_I2C3_CLK_ENABLE();
+ __HAL_RCC_I2C3_FORCE_RESET();
+ __HAL_RCC_I2C3_RELEASE_RESET();
+ if (HAL_I2C_Init(&i2c_handle) != HAL_OK) {
+ return HAL_ERROR;
+ }
+
+ NVIC_SetPriority(EXTI8_IRQn, 12);
+ NVIC_EnableIRQ(EXTI8_IRQn);
+
+ return 0;
+}
+
+int32_t board_tcpp0203_deinit(void) {
+ return 0;
+}
+
+int32_t i2c_readreg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
+ TU_ASSERT (HAL_OK == HAL_I2C_Mem_Read(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000));
+ return 0;
+}
+
+int32_t i2c_writereg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
+ TU_ASSERT(HAL_OK == HAL_I2C_Mem_Write(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000));
+ return 0;
+}
+
+static inline void board_init2(void) {
+ TCPP0203_IO_t io_ctx;
+
+ io_ctx.Address = TCPP0203_I2C_ADDRESS_X68;
+ io_ctx.Init = board_tcpp0203_init;
+ io_ctx.DeInit = board_tcpp0203_deinit;
+ io_ctx.ReadReg = i2c_readreg;
+ io_ctx.WriteReg = i2c_writereg;
+
+ TU_ASSERT(TCPP0203_RegisterBusIO(&tcpp0203_obj, &io_ctx) == TCPP0203_OK, );
+
+ TU_ASSERT(TCPP0203_Init(&tcpp0203_obj) == TCPP0203_OK, );
+
+ TU_ASSERT(TCPP0203_SetPowerMode(&tcpp0203_obj, TCPP0203_POWER_MODE_NORMAL) == TCPP0203_OK, );
+}
+
+void board_vbus_set(uint8_t rhport, bool state) {
+ (void) state;
+ if (rhport == 1) {
+ TU_ASSERT(TCPP0203_SetGateDriverProvider(&tcpp0203_obj, TCPP0203_GD_PROVIDER_SWITCH_CLOSED) == TCPP0203_OK, );
+ }
+}
+
+void EXTI8_IRQHandler(void) {
+ __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_8);
+ if (tcpp0203_obj.IsInitialized) {
+ TU_ASSERT(TCPP0203_SetPowerMode(&tcpp0203_obj, TCPP0203_POWER_MODE_NORMAL) == TCPP0203_OK, );
+ TU_ASSERT(TCPP0203_SetGateDriverProvider(&tcpp0203_obj, TCPP0203_GD_PROVIDER_SWITCH_CLOSED) == TCPP0203_OK, );
+ }
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.mk b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.mk
new file mode 100644
index 000000000..cf0c2ff54
--- /dev/null
+++ b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.mk
@@ -0,0 +1,19 @@
+MCU_VARIANT = stm32h7s3xx
+CFLAGS += -DSTM32H7S3xx
+
+# For flash-jlink target
+JLINK_DEVICE = stm32h7s3xx
+
+# flash target using on-board stlink
+flash: flash-stlink
+
+# Linker
+LD_FILE_GCC = $(BOARD_PATH)/stm32h7s3xx_flash.ld
+LD_FILE_IAR = $(BOARD_PATH)/stm32h7s3xx_flash.icf
+
+SRC_C += \
+ $(ST_TCPP0203)/tcpp0203.c \
+ $(ST_TCPP0203)/tcpp0203_reg.c \
+
+INC += \
+ $(TOP)/$(ST_TCPP0203) \
diff --git a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/stm32h7s3xx_flash.icf b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/stm32h7s3xx_flash.icf
new file mode 100644
index 000000000..8ffaa74a7
--- /dev/null
+++ b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/stm32h7s3xx_flash.icf
@@ -0,0 +1,55 @@
+/*###ICF### Section handled by ICF editor, don't touch! ****/
+/*-Editor annotation file-*/
+/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
+/*-Specials-*/
+define symbol __ICFEDIT_intvec_start__ = 0x08000000;
+/*-Memory Regions-*/
+define symbol NONCACHEABLEBUFFER_size = 0x4000;
+define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
+define symbol __ICFEDIT_region_ROM_end__ = 0x0800FFFF;
+define symbol __ICFEDIT_region_RAM_start__ = 0x24000000;
+define symbol __ICFEDIT_region_RAM_end__ = 0x2404FFFF - NONCACHEABLEBUFFER_size;
+define symbol NONCACHEABLEBUFFER_start = __ICFEDIT_region_RAM_end__ + 1;
+define symbol NONCACHEABLEBUFFER_end = __ICFEDIT_region_RAM_end__ + NONCACHEABLEBUFFER_size;
+
+
+/*-Sizes-*/
+define symbol __ICFEDIT_size_cstack__ = 0x800;
+define symbol __ICFEDIT_size_heap__ = 0x200;
+/**** End of ICF editor section. ###ICF###*/
+
+define symbol __region_ITCM_start__ = 0x00000000;
+define symbol __region_ITCM_end__ = 0x0000FFFF;
+define symbol __region_DTCM_start__ = 0x20000000;
+define symbol __region_DTCM_end__ = 0x2000FFFF;
+define symbol __region_SRAMAHB_start__ = 0x30000000;
+define symbol __region_SRAMAHB_end__ = 0x30007FFF;
+define symbol __region_BKPSRAM_start__ = 0x38800000;
+define symbol __region_BKPSRAM_end__ = 0x38800FFF;
+
+export symbol NONCACHEABLEBUFFER_start;
+export symbol NONCACHEABLEBUFFER_size;
+
+export symbol __ICFEDIT_region_ROM_start__;
+export symbol __ICFEDIT_region_ROM_end__;
+define memory mem with size = 4G;
+define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
+define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
+define region NONCACHEABLE_region = mem:[from NONCACHEABLEBUFFER_start to NONCACHEABLEBUFFER_end];
+define region ITCM_region = mem:[from __region_ITCM_start__ to __region_ITCM_end__];
+define region DTCM_region = mem:[from __region_DTCM_start__ to __region_DTCM_end__];
+define region SRAMAHB_region = mem:[from __region_SRAMAHB_start__ to __region_SRAMAHB_end__];
+define region BKPSRAM_region = mem:[from __region_BKPSRAM_start__ to __region_BKPSRAM_end__];
+
+define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
+define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
+
+initialize by copy { readwrite };
+do not initialize { section .noinit };
+
+place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
+
+place in ROM_region { readonly };
+place in RAM_region { readwrite };
+place in NONCACHEABLE_region { section noncacheable_buffer };
+place in DTCM_region { block CSTACK, block HEAP };
diff --git a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/stm32h7s3xx_flash.ld b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/stm32h7s3xx_flash.ld
new file mode 100644
index 000000000..3bd7f0b89
--- /dev/null
+++ b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/stm32h7s3xx_flash.ld
@@ -0,0 +1,208 @@
+/*
+******************************************************************************
+**
+** @file : LinkerScript.ld
+**
+** @author : Auto-generated by STM32CubeIDE
+**
+** @brief : Linker script for STM32H7S3xx Device from STM32H7RS series
+** 64Kbytes FLASH
+** 456Kbytes RAM
+**
+** Set heap size, stack size and stack location according
+** to application requirements.
+**
+** Set memory bank area and size if external memory is used
+**
+** Target : STMicroelectronics STM32
+**
+** Distribution: The file is distributed as is, without any warranty
+** of any kind.
+**
+******************************************************************************
+** @attention
+**
+** Copyright (c) 2023 STMicroelectronics.
+** All rights reserved.
+**
+** This software is licensed under terms that can be found in the LICENSE file
+** in the root directory of this software component.
+** If no LICENSE file comes with this software, it is provided AS-IS.
+**
+******************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+_Min_Heap_Size = 0x200; /* required amount of heap */
+_Min_Stack_Size = 0x400; /* required amount of stack */
+
+__FLASH_BEGIN = 0x08000000;
+__FLASH_SIZE = 0x00010000;
+
+__RAM_BEGIN = 0x24000000;
+__RAM_SIZE = 0x4FC00;
+__RAM_NONCACHEABLEBUFFER_SIZE = 0x4000;
+
+/* Memories definition */
+MEMORY
+{
+ RAM (xrw) : ORIGIN = __RAM_BEGIN, LENGTH = __RAM_SIZE
+ RAM_NONCACHEABLEBUFFER (xrw) : ORIGIN = __RAM_BEGIN + __RAM_SIZE, LENGTH = __RAM_NONCACHEABLEBUFFER_SIZE
+
+ ITCM (xrw) : ORIGIN = 0x00000000, LENGTH = 0x00010000
+ DTCM (rw) : ORIGIN = 0x20000000, LENGTH = 0x00010000
+ SRAMAHB (rw) : ORIGIN = 0x30000000, LENGTH = 0x00008000
+ BKPSRAM (rw) : ORIGIN = 0x38800000, LENGTH = 0x00001000
+
+ FLASH (xrw) : ORIGIN = __FLASH_BEGIN, LENGTH = __FLASH_SIZE
+}
+
+/* Highest address of the user mode stack */
+_estack = ORIGIN(DTCM) + LENGTH(DTCM); /* end of "DTCM" Ram type memory */
+
+/* Sections */
+SECTIONS
+{
+ /* The startup code into "FLASH" Rom type memory */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data into "FLASH" Rom type memory */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ } >FLASH
+
+ /* Constant data into "FLASH" Rom type memory */
+ .rodata :
+ {
+ . = ALIGN(4);
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM.extab :
+ {
+ . = ALIGN(4);
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM :
+ {
+ . = ALIGN(4);
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ . = ALIGN(4);
+ } >FLASH
+
+ .preinit_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ .init_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ .fini_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT(.fini_array.*)))
+ KEEP (*(.fini_array*))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ /* Used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* Initialized data sections into "RAM" Ram type memory */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+ *(.RamFunc) /* .RamFunc sections */
+ *(.RamFunc*) /* .RamFunc* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+
+ } >RAM AT> FLASH
+
+ /* Uninitialized data section into "RAM" Ram type memory */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss section */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >RAM
+
+ RW_NONCACHEABLE :
+ {
+ __NONCACHEABLEBUFFER_BEGIN = .;/* create symbol for start of section */
+ KEEP(*(noncacheable_buffer))
+ __NONCACHEABLEBUFFER_END = .; /* create symbol for start of section */
+ } > RAM_NONCACHEABLEBUFFER
+
+ /* User_heap_stack section, used to check that there is enough "DTCM" Ram type memory left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >DTCM
+
+ /* Remove information from the compiler libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
diff --git a/hw/bsp/stm32h7rs/family.c b/hw/bsp/stm32h7rs/family.c
new file mode 100644
index 000000000..4b81deea0
--- /dev/null
+++ b/hw/bsp/stm32h7rs/family.c
@@ -0,0 +1,340 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019
+ * William D. Jones (thor0505@comcast.net),
+ * Ha Thach (tinyusb.org)
+ * Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ manufacturer: STMicroelectronics
+*/
+
+#include "stm32h7rsxx_hal.h"
+#include "bsp/board_api.h"
+
+TU_ATTR_UNUSED static void Error_Handler(void) { }
+
+typedef struct {
+ GPIO_TypeDef* port;
+ GPIO_InitTypeDef pin_init;
+ uint8_t active_state;
+} board_pindef_t;
+
+#include "board.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
+
+#ifdef UART_DEV
+UART_HandleTypeDef UartHandle = {
+ .Instance = UART_DEV,
+ .Init = {
+ .BaudRate = CFG_BOARD_UART_BAUDRATE,
+ .WordLength = UART_WORDLENGTH_8B,
+ .StopBits = UART_STOPBITS_1,
+ .Parity = UART_PARITY_NONE,
+ .HwFlowCtl = UART_HWCONTROL_NONE,
+ .Mode = UART_MODE_TX_RX,
+ .OverSampling = UART_OVERSAMPLING_16,
+ }
+};
+#endif
+
+#ifndef SWO_FREQ
+#define SWO_FREQ 4000000
+#endif
+
+//--------------------------------------------------------------------+
+// Forward USB interrupt events to TinyUSB IRQ Handler
+//--------------------------------------------------------------------+
+
+// Despite being call USB2_OTG_FS on some MCUs
+// OTG_FS is marked as RHPort0 by TinyUSB to be consistent across stm32 port
+void OTG_FS_IRQHandler(void) {
+ tusb_int_handler(0, true);
+}
+
+// Despite being call USB1_OTG_HS on some MCUs
+// OTG_HS is marked as RHPort1 by TinyUSB to be consistent across stm32 port
+void OTG_HS_IRQHandler(void) {
+ tusb_int_handler(1, true);
+}
+
+#ifdef TRACE_ETM
+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;
+ gpio_init.Mode = GPIO_MODE_AF_PP;
+ gpio_init.Pull = GPIO_PULLUP;
+ gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ gpio_init.Alternate = GPIO_AF0_TRACE;
+ HAL_GPIO_Init(GPIOE, &gpio_init);
+
+ // Enable trace clk, also in D1 and D3 domain
+ DBGMCU->CR |= DBGMCU_CR_DBG_TRACECKEN | DBGMCU_CR_DBG_CKD1EN | DBGMCU_CR_DBG_CKD3EN;
+}
+#else
+ #define trace_etm_init()
+#endif
+
+#ifdef LOGGER_SWO
+void log_swo_init(void)
+{
+ //UNLOCK FUNNEL
+ *(volatile uint32_t*)(0x5C004FB0) = 0xC5ACCE55; // SWTF_LAR
+ *(volatile uint32_t*)(0x5C003FB0) = 0xC5ACCE55; // SWO_LAR
+
+ //SWO current output divisor register
+ //To change it, you can use the following rule
+ // value = (CPU_Freq / 3 / SWO_Freq) - 1
+ *(volatile uint32_t*)(0x5C003010) = ((SystemCoreClock / 3 / SWO_FREQ) - 1); // SWO_CODR
+
+ //SWO selected pin protocol register
+ *(volatile uint32_t*)(0x5C0030F0) = 0x00000002; // SWO_SPPR
+
+ //Enable ITM input of SWO trace funnel
+ *(volatile uint32_t*)(0x5C004000) |= 0x00000001; // SWFT_CTRL
+}
+#else
+ #define log_swo_init()
+#endif
+
+void board_init(void) {
+ HAL_Init();
+
+ HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
+ // Implemented in board.h
+ SystemClock_Config();
+
+ // Enable All GPIOs clocks
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+ __HAL_RCC_GPIOC_CLK_ENABLE();
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+ __HAL_RCC_GPIOE_CLK_ENABLE();
+ __HAL_RCC_GPIOF_CLK_ENABLE();
+ __HAL_RCC_GPIOG_CLK_ENABLE();
+ __HAL_RCC_GPIOM_CLK_ENABLE();
+ __HAL_RCC_GPION_CLK_ENABLE();
+ __HAL_RCC_GPIOO_CLK_ENABLE();
+ __HAL_RCC_GPIOP_CLK_ENABLE();
+
+ log_swo_init();
+ trace_etm_init();
+
+ for (uint8_t i = 0; i < TU_ARRAY_SIZE(board_pindef); i++) {
+ HAL_GPIO_Init(board_pindef[i].port, &board_pindef[i].pin_init);
+ }
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+ // 1ms tick timer
+ SysTick_Config(SystemCoreClock / 1000);
+
+#elif CFG_TUSB_OS == OPT_OS_FREERTOS
+ // Explicitly disable systick to prevent its ISR runs before scheduler start
+ SysTick->CTRL &= ~1U;
+
+ // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
+ #ifdef USB_OTG_FS_PERIPH_BASE
+ NVIC_SetPriority(OTG_FS_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
+ #endif
+
+ NVIC_SetPriority(OTG_HS_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
+#endif
+
+
+
+#ifdef UART_DEV
+ UART_CLK_EN();
+ HAL_UART_Init(&UartHandle);
+#endif
+
+ //------------- USB FS -------------//
+#if (CFG_TUD_ENABLED && BOARD_TUD_RHPORT == 0) || (CFG_TUH_ENABLED && BOARD_TUH_RHPORT == 0)
+ // OTG_FS is marked as RHPort0 by TinyUSB to be consistent across stm32 port
+
+ HAL_PWREx_EnableUSBVoltageDetector();
+ HAL_PWREx_EnableUSBReg();
+
+ __HAL_RCC_USB2_OTG_FS_CLK_ENABLE();
+
+ // PM14 VUSB, PM10 ID, PM11 DM, PM12 DP
+ // Configure DM DP Pins
+ GPIO_InitTypeDef GPIO_InitStruct;
+ GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
+ HAL_GPIO_Init(GPIOM, &GPIO_InitStruct);
+
+ // This for ID line debug
+ GPIO_InitStruct.Pin = GPIO_PIN_10;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
+ HAL_GPIO_Init(GPIOM, &GPIO_InitStruct);
+
+#if OTG_FS_VBUS_SENSE
+ // Configure VBUS Pin
+ GPIO_InitStruct.Pin = GPIO_PIN_14;
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
+ HAL_GPIO_Init(GPIOM, &GPIO_InitStruct);
+
+ // Enable VBUS sense (B device) via pin PM14
+ USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBDEN;
+#else
+ // Disable VBUS sense (B device)
+ USB_OTG_FS->GCCFG &= ~USB_OTG_GCCFG_VBDEN;
+
+ // B-peripheral session valid override enable
+ USB_OTG_FS->GOTGCTL |= USB_OTG_GOTGCTL_BVALOEN;
+ USB_OTG_FS->GOTGCTL |= USB_OTG_GOTGCTL_BVALOVAL;
+#endif // vbus sense
+#endif
+
+ //------------- USB HS -------------//
+#if (CFG_TUD_ENABLED && BOARD_TUD_RHPORT == 1) || (CFG_TUH_ENABLED && BOARD_TUH_RHPORT == 1)
+
+ // Enable USB HS & ULPI Clocks
+ __HAL_RCC_USB_OTG_HS_CLK_ENABLE();
+ __HAL_RCC_USBPHYC_CLK_ENABLE();
+
+ // Enable USB power
+ HAL_PWREx_EnableUSBVoltageDetector();
+ HAL_PWREx_EnableUSBHSregulator();
+
+#if OTG_HS_VBUS_SENSE
+ // Configure VBUS Pin
+ GPIO_InitStruct.Pin = GPIO_PIN_9;
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
+ HAL_GPIO_Init(GPIOM, &GPIO_InitStruct);
+
+ // Enable VBUS sense (B device) via pin PM9
+ USB_OTG_HS->GCCFG |= USB_OTG_GCCFG_VBDEN;
+#else
+ // Disable VBUS sense (B device)
+ USB_OTG_HS->GCCFG &= ~USB_OTG_GCCFG_VBDEN;
+
+#if CFG_TUD_ENABLED && BOARD_TUD_RHPORT == 1
+ // B-peripheral session valid override enable
+ USB_OTG_HS->GCCFG |= USB_OTG_GCCFG_VBVALEXTOEN;
+ USB_OTG_HS->GCCFG |= USB_OTG_GCCFG_VBVALOVAL;
+#else
+ USB_OTG_HS->GCCFG |= USB_OTG_GCCFG_PULLDOWNEN;
+#endif
+
+#endif
+#endif
+
+ board_init2();
+
+#if CFG_TUH_ENABLED
+ board_vbus_set(BOARD_TUH_RHPORT, 1);
+#endif
+}
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+
+void board_led_write(bool state) {
+#ifdef PINID_LED
+ board_pindef_t* pindef = &board_pindef[PINID_LED];
+ GPIO_PinState pin_state = state == pindef->active_state ? GPIO_PIN_SET : GPIO_PIN_RESET;
+ HAL_GPIO_WritePin(pindef->port, pindef->pin_init.Pin, pin_state);
+#else
+ (void) state;
+#endif
+}
+
+uint32_t board_button_read(void) {
+#ifdef PINID_BUTTON
+ board_pindef_t* pindef = &board_pindef[PINID_BUTTON];
+ return pindef->active_state == HAL_GPIO_ReadPin(pindef->port, pindef->pin_init.Pin);
+#else
+ return 0;
+#endif
+}
+
+size_t board_get_unique_id(uint8_t id[], size_t max_len) {
+ (void) max_len;
+ volatile uint32_t * stm32_uuid = (volatile uint32_t *) UID_BASE;
+ uint32_t* id32 = (uint32_t*) (uintptr_t) id;
+ uint8_t const len = 12;
+
+ id32[0] = stm32_uuid[0];
+ id32[1] = stm32_uuid[1];
+ id32[2] = stm32_uuid[2];
+
+ return len;
+}
+
+int board_uart_read(uint8_t *buf, int len) {
+ (void) buf;
+ (void) len;
+ return 0;
+}
+
+int board_uart_write(void const *buf, int len) {
+#ifdef UART_DEV
+ HAL_UART_Transmit(&UartHandle, (uint8_t * )(uintptr_t)
+ buf, len, 0xffff);
+ return len;
+#else
+ (void) buf; (void) len;
+ return -1;
+#endif
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+
+void SysTick_Handler(void) {
+ HAL_IncTick();
+ system_ticks++;
+}
+
+uint32_t board_millis(void) {
+ return system_ticks;
+}
+
+#endif
+
+void HardFault_Handler(void) {
+ __asm("BKPT #0\n");
+}
+
+// Required by __libc_init_array in startup code if we are compiling using
+// -nostdlib/-nostartfiles.
+void _init(void) {
+}
diff --git a/hw/bsp/stm32h7rs/family.cmake b/hw/bsp/stm32h7rs/family.cmake
new file mode 100644
index 000000000..e5e98f914
--- /dev/null
+++ b/hw/bsp/stm32h7rs/family.cmake
@@ -0,0 +1,150 @@
+include_guard()
+
+set(ST_FAMILY h7rs)
+set(ST_PREFIX stm32${ST_FAMILY}xx)
+
+set(ST_HAL_DRIVER ${TOP}/hw/mcu/st/stm32${ST_FAMILY}xx_hal_driver)
+set(ST_CMSIS ${TOP}/hw/mcu/st/cmsis_device_${ST_FAMILY})
+set(ST_TCPP0203 ${TOP}/hw/mcu/st/stm32-tcpp0203)
+set(CMSIS_5 ${TOP}/lib/CMSIS_5)
+
+# include board specific
+include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
+
+# toolchain set up
+set(CMAKE_SYSTEM_CPU cortex-m7 CACHE INTERNAL "System Processor")
+set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
+
+set(FAMILY_MCUS STM32H7RS CACHE INTERNAL "")
+
+# ----------------------
+# Port & Speed Selection
+# ----------------------
+if (NOT DEFINED RHPORT_DEVICE)
+ set(RHPORT_DEVICE 1)
+endif ()
+if (NOT DEFINED RHPORT_HOST)
+ set(RHPORT_HOST 1)
+endif ()
+
+if (NOT DEFINED RHPORT_SPEED)
+ set(RHPORT_SPEED OPT_MODE_FULL_SPEED OPT_MODE_HIGH_SPEED)
+endif ()
+if (NOT DEFINED RHPORT_DEVICE_SPEED)
+ list(GET RHPORT_SPEED ${RHPORT_DEVICE} RHPORT_DEVICE_SPEED)
+endif ()
+if (NOT DEFINED RHPORT_HOST_SPEED)
+ list(GET RHPORT_SPEED ${RHPORT_HOST} RHPORT_HOST_SPEED)
+endif ()
+
+cmake_print_variables(RHPORT_DEVICE RHPORT_DEVICE_SPEED RHPORT_HOST RHPORT_HOST_SPEED)
+
+#------------------------------------
+# BOARD_TARGET
+#------------------------------------
+# only need to be built ONCE for all examples
+function(add_board_target BOARD_TARGET)
+ if (TARGET ${BOARD_TARGET})
+ return()
+ endif()
+
+ # Startup & Linker script
+ set(STARTUP_FILE_GNU ${ST_CMSIS}/Source/Templates/gcc/startup_${MCU_VARIANT}.s)
+ set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
+ set(STARTUP_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/startup_${MCU_VARIANT}.s)
+
+ if(NOT DEFINED LD_FILE_GNU)
+ set(LD_FILE_GNU ${ST_CMSIS}/Source/Templates/gcc/linker/${MCU_VARIANT}_flash.ld)
+ endif()
+ set(LD_FILE_Clang ${LD_FILE_GNU})
+ if(NOT DEFINED LD_FILE_IAR)
+ set(LD_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf)
+ endif()
+
+ add_library(${BOARD_TARGET} STATIC
+ ${ST_CMSIS}/Source/Templates/system_${ST_PREFIX}.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_cortex.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_dma.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_gpio.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_pwr.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_i2c.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_pwr_ex.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_rcc.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_rcc_ex.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_uart.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_uart_ex.c
+ ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
+ )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMSIS_5}/CMSIS/Core/Include
+ ${ST_CMSIS}/Include
+ ${ST_HAL_DRIVER}/Inc
+ )
+ target_compile_definitions(${BOARD_TARGET} PUBLIC
+ BOARD_TUD_RHPORT=${RHPORT_DEVICE}
+ BOARD_TUD_MAX_SPEED=${RHPORT_DEVICE_SPEED}
+ BOARD_TUH_RHPORT=${RHPORT_HOST}
+ BOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED}
+ SEGGER_RTT_SECTION="noncacheable_buffer"
+ BUFFER_SIZE_UP=0x3000
+ )
+
+ update_board(${BOARD_TARGET})
+
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--script=${LD_FILE_GNU}"
+ -nostartfiles
+ --specs=nosys.specs --specs=nano.specs
+ )
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--script=${LD_FILE_Clang}"
+ )
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--config=${LD_FILE_IAR}"
+ )
+ endif ()
+endfunction()
+
+
+#------------------------------------
+# Functions
+#------------------------------------
+function(family_configure_example TARGET RTOS)
+ family_configure_common(${TARGET} ${RTOS})
+
+ # Board target
+ add_board_target(board_${BOARD})
+
+ #---------- Port Specific ----------
+ # These files are built for each example since it depends on example's tusb_config.h
+ target_sources(${TARGET} PUBLIC
+ # BSP
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
+ )
+ target_include_directories(${TARGET} PUBLIC
+ # family, hw, board
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
+ )
+
+ # Add TinyUSB target and port source
+ family_add_tinyusb(${TARGET} OPT_MCU_STM32H7RS ${RTOS})
+ target_sources(${TARGET} PUBLIC
+ ${TOP}/src/portable/synopsys/dwc2/dcd_dwc2.c
+ ${TOP}/src/portable/synopsys/dwc2/hcd_dwc2.c
+ ${TOP}/src/portable/synopsys/dwc2/dwc2_common.c
+ )
+ target_link_libraries(${TARGET} PUBLIC board_${BOARD})
+
+ # Flashing
+ family_add_bin_hex(${TARGET})
+ family_flash_stlink(${TARGET})
+ family_flash_jlink(${TARGET})
+endfunction()
diff --git a/hw/bsp/stm32h7rs/family.mk b/hw/bsp/stm32h7rs/family.mk
new file mode 100644
index 000000000..9970059f8
--- /dev/null
+++ b/hw/bsp/stm32h7rs/family.mk
@@ -0,0 +1,95 @@
+ST_FAMILY = h7rs
+ST_PREFIX = stm32${ST_FAMILY}xx
+ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
+ST_HAL_DRIVER = hw/mcu/st/${ST_PREFIX}_hal_driver
+ST_TCPP0203 = hw/mcu/st/stm32-tcpp0203
+
+UF2_FAMILY_ID = 0x6db66083
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+CPU_CORE ?= cortex-m7
+
+# ----------------------
+# Port & Speed Selection
+# ----------------------
+RHPORT_SPEED ?= OPT_MODE_FULL_SPEED OPT_MODE_HIGH_SPEED
+RHPORT_DEVICE ?= 1
+RHPORT_HOST ?= 1
+
+# Determine RHPORT_DEVICE_SPEED if not defined
+ifndef RHPORT_DEVICE_SPEED
+ifeq ($(RHPORT_DEVICE), 0)
+ RHPORT_DEVICE_SPEED = $(firstword $(RHPORT_SPEED))
+else
+ RHPORT_DEVICE_SPEED = $(lastword $(RHPORT_SPEED))
+endif
+endif
+
+# Determine RHPORT_HOST_SPEED if not defined
+ifndef RHPORT_HOST_SPEED
+ifeq ($(RHPORT_HOST), 0)
+ RHPORT_HOST_SPEED = $(firstword $(RHPORT_SPEED))
+else
+ RHPORT_HOST_SPEED = $(lastword $(RHPORT_SPEED))
+endif
+endif
+
+# --------------
+# Compiler Flags
+# --------------
+CFLAGS += \
+ -DCFG_TUSB_MCU=OPT_MCU_STM32H7RS \
+ -DBOARD_TUD_RHPORT=${RHPORT_DEVICE} \
+ -DBOARD_TUD_MAX_SPEED=${RHPORT_DEVICE_SPEED} \
+ -DBOARD_TUH_RHPORT=${RHPORT_HOST} \
+ -DBOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED} \
+ -DSEGGER_RTT_SECTION=\"noncacheable_buffer\" \
+ -DBUFFER_SIZE_UP=0x3000 \
+
+# GCC Flags
+CFLAGS_GCC += \
+ -flto \
+
+# suppress warning caused by vendor mcu driver
+CFLAGS_GCC += \
+ -Wno-error=cast-align \
+ -Wno-error=unused-parameter \
+
+LDFLAGS_GCC += \
+ -nostdlib -nostartfiles \
+ --specs=nosys.specs --specs=nano.specs
+
+# -----------------
+# Sources & Include
+# -----------------
+
+SRC_C += \
+ src/portable/synopsys/dwc2/dcd_dwc2.c \
+ src/portable/synopsys/dwc2/hcd_dwc2.c \
+ src/portable/synopsys/dwc2/dwc2_common.c \
+ $(ST_CMSIS)/Source/Templates/system_${ST_PREFIX}.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_cortex.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_dma.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_gpio.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_i2c.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_uart_ex.c \
+
+INC += \
+ $(TOP)/$(BOARD_PATH) \
+ $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
+ $(TOP)/$(ST_CMSIS)/Include \
+ $(TOP)/$(ST_HAL_DRIVER)/Inc
+
+# Startup
+SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_$(MCU_VARIANT).s
+SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT).s
+
+# Linker
+LD_FILE_GCC ?= $(ST_CMSIS)/Source/Templates/gcc/linker/$(MCU_VARIANT)_flash.ld
+LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash.icf
diff --git a/hw/bsp/stm32h7rs/stm32h7rsxx_hal_conf.h b/hw/bsp/stm32h7rs/stm32h7rsxx_hal_conf.h
new file mode 100644
index 000000000..6fd90abde
--- /dev/null
+++ b/hw/bsp/stm32h7rs/stm32h7rsxx_hal_conf.h
@@ -0,0 +1,500 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * @file stm32h7rsxx_hal_conf.h
+ * @author MCD Application Team
+ * @brief HAL configuration template file.
+ * This file should be copied to the application folder and renamed
+ * to stm32h7rsxx_hal_conf.h.
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2022 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+/* USER CODE END Header */
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef STM32H7RSxx_HAL_CONF_H
+#define STM32H7RSxx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* ########################## Module Selection ############################## */
+/**
+ * @brief This is the list of modules to be used in the HAL driver
+ */
+#define HAL_MODULE_ENABLED
+/* #define HAL_ADC_MODULE_ENABLED */
+/* #define HAL_CEC_MODULE_ENABLED */
+/* #define HAL_CORDIC_MODULE_ENABLED */
+/* #define HAL_CRC_MODULE_ENABLED */
+/* #define HAL_CRYP_MODULE_ENABLED */
+/* #define HAL_DCMIPP_MODULE_ENABLED */
+/* #define HAL_DMA2D_MODULE_ENABLED */
+/* #define HAL_DTS_MODULE_ENABLED */
+/* #define HAL_ETH_MODULE_ENABLED */
+/* #define HAL_FDCAN_MODULE_ENABLED */
+/* #define HAL_GFXMMU_MODULE_ENABLED */
+/* #define HAL_GFXTIM_MODULE_ENABLED */
+/* #define HAL_GPU2D_MODULE_ENABLED */
+/* #define HAL_HASH_MODULE_ENABLED */
+/* #define HAL_HCD_MODULE_ENABLED */
+#define HAL_I2C_MODULE_ENABLED
+/* #define HAL_I2S_MODULE_ENABLED */
+/* #define HAL_I3C_MODULE_ENABLED */
+/* #define HAL_ICACHE_MODULE_ENABLED */
+/* #define HAL_IRDA_MODULE_ENABLED */
+/* #define HAL_IWDG_MODULE_ENABLED */
+/* #define HAL_JPEG_MODULE_ENABLED */
+/* #define HAL_LPTIM_MODULE_ENABLED */
+/* #define HAL_LTDC_MODULE_ENABLED */
+/* #define HAL_MCE_MODULE_ENABLED */
+/* #define HAL_MDF_MODULE_ENABLED */
+/* #define HAL_MMC_MODULE_ENABLED */
+/* #define HAL_NAND_MODULE_ENABLED */
+/* #define HAL_NOR_MODULE_ENABLED */
+/* #define HAL_PCD_MODULE_ENABLED */
+/* #define HAL_PKA_MODULE_ENABLED */
+/* #define HAL_PSSI_MODULE_ENABLED */
+/* #define HAL_RAMECC_MODULE_ENABLED */
+/* #define HAL_RCC_MODULE_ENABLED */
+/* #define HAL_RNG_MODULE_ENABLED */
+/* #define HAL_RTC_MODULE_ENABLED */
+/* #define HAL_SAI_MODULE_ENABLED */
+/* #define HAL_SD_MODULE_ENABLED */
+/* #define HAL_SDRAM_MODULE_ENABLED */
+/* #define HAL_SMARTCARD_MODULE_ENABLED */
+/* #define HAL_SMBUS_MODULE_ENABLED */
+/* #define HAL_SPDIFRX_MODULE_ENABLED */
+/* #define HAL_SPI_MODULE_ENABLED */
+/* #define HAL_SRAM_MODULE_ENABLED */
+/* #define HAL_TIM_MODULE_ENABLED */
+#define HAL_UART_MODULE_ENABLED
+/* #define HAL_USART_MODULE_ENABLED */
+/* #define HAL_WWDG_MODULE_ENABLED */
+#define HAL_XSPI_MODULE_ENABLED
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_PWR_MODULE_ENABLED
+#define HAL_DMA_MODULE_ENABLED
+#define HAL_RCC_MODULE_ENABLED
+#define HAL_FLASH_MODULE_ENABLED
+#define HAL_EXTI_MODULE_ENABLED
+#define HAL_CORTEX_MODULE_ENABLED
+
+/* ########################## Oscillator Values adaptation ####################*/
+/**
+ * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSE is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSE_VALUE)
+#define HSE_VALUE 24000000UL /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSE_STARTUP_TIMEOUT)
+#define HSE_STARTUP_TIMEOUT 100UL /*!< Time out for HSE start up (in ms) */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief Internal High Speed oscillator (HSI) value.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSI is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSI_VALUE)
+#define HSI_VALUE 64000000UL /*!< Value of the Internal oscillator in Hz */
+#endif /* HSI_VALUE */
+
+/**
+ * @brief Internal Low-power oscillator (CSI) default value.
+ * This value is the default CSI range value after Reset.
+ */
+#if !defined (CSI_VALUE)
+#define CSI_VALUE 4000000UL /*!< Value of the Internal oscillator in Hz */
+#endif /* CSI_VALUE */
+
+/**
+ * @brief Internal High Speed oscillator (HSI48) value for USB OTG FS and RNG.
+ * This internal oscillator is mainly dedicated to provide a high precision clock to
+ * the USB peripheral by means of a special Clock Recovery System (CRS) circuitry.
+ * When the CRS is not used, the HSI48 RC oscillator runs on it default frequency
+ * which is subject to manufacturing process variations.
+ */
+ #if !defined (HSI48_VALUE)
+ #define HSI48_VALUE 48000000UL /*!< Value of the Internal High Speed oscillator for USB OTG FS/RNG in Hz.
+ The real value my vary depending on manufacturing process variations. */
+ #endif /* HSI48_VALUE */
+
+/**
+* @brief Internal Low Speed oscillator (LSI) value.
+ */
+#if !defined (LSI_VALUE)
+#define LSI_VALUE 32000UL /*!< LSI Typical Value in Hz.
+ Value of the Internal Low Speed oscillator in Hz.
+ The real value may vary depending on the variations
+ in voltage and temperature.*/
+#endif /* LSI_VALUE */
+
+/**
+* @brief External Low Speed oscillator (LSE) value.
+*/
+#if !defined (LSE_VALUE)
+#define LSE_VALUE 32768UL /*!< Value of the External oscillator in Hz*/
+#endif /* LSE_VALUE */
+
+#if !defined (LSE_STARTUP_TIMEOUT)
+#define LSE_STARTUP_TIMEOUT 5000UL /*!< Time out for LSE start up (in ms) */
+#endif /* LSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief External clock source for digital audio interfaces: SPI/I2S, SAI and ADF
+ * This value is used by the RCC HAL module to provide the digital audio interfaces
+ * frequency. This clock source is inserted directly through I2S_CKIN pad.
+ */
+#if !defined (EXTERNAL_CLOCK_VALUE)
+#define EXTERNAL_CLOCK_VALUE 48000UL /*!< Value of the external clock source in Hz */
+#endif /* EXTERNAL_CLOCK_VALUE */
+
+/* Tip: To avoid modifying this file each time you need to use different HSE,
+ === you can define the HSE value in your toolchain compiler preprocessor. */
+
+/* ########################### System Configuration ######################### */
+/**
+ * @brief This is the HAL system configuration section
+ */
+#define VDD_VALUE 3300UL /*!< Value of VDD in mv */
+#define TICK_INT_PRIORITY (15UL)/*!< tick interrupt priority (lowest by default) */
+#define USE_RTOS 0U
+
+/* ########################## Assert Selection ############################## */
+/**
+* @brief Uncomment the line below to expanse the "assert_param" macro in the
+* HAL drivers code
+*/
+/* #define USE_FULL_ASSERT 1U */
+
+/* ################## Register callback feature configuration ############### */
+/**
+* @brief Set below the peripheral configuration to "1U" to add the support
+* of HAL callback registration/unregistration feature for the HAL
+* driver(s). This allows user application to provide specific callback
+* functions thanks to HAL_PPP_RegisterCallback() rather than overwriting
+* the default weak callback functions (see each stm32h7rsxx_hal_ppp.h file
+* for possible callback identifiers defined in HAL_PPP_CallbackIDTypeDef
+* for each PPP peripheral).
+*/
+#define USE_HAL_ADC_REGISTER_CALLBACKS 0U
+#define USE_HAL_CEC_REGISTER_CALLBACKS 0U
+#define USE_HAL_CORDIC_REGISTER_CALLBACKS 0U
+#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U
+#define USE_HAL_DCMIPP_REGISTER_CALLBACKS 0U
+#define USE_HAL_FDCAN_REGISTER_CALLBACKS 0U
+#define USE_HAL_GFXMMU_REGISTER_CALLBACKS 0U
+#define USE_HAL_HASH_REGISTER_CALLBACKS 0U
+#define USE_HAL_I2C_REGISTER_CALLBACKS 0U
+#define USE_HAL_I2S_REGISTER_CALLBACKS 0U
+#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U
+#define USE_HAL_JPEG_REGISTER_CALLBACKS 0U
+#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U
+#define USE_HAL_MDF_REGISTER_CALLBACKS 0U
+#define USE_HAL_MMC_REGISTER_CALLBACKS 0U
+#define USE_HAL_NAND_REGISTER_CALLBACKS 0U
+#define USE_HAL_NOR_REGISTER_CALLBACKS 0U
+#define USE_HAL_PCD_REGISTER_CALLBACKS 0U
+#define USE_HAL_PKA_REGISTER_CALLBACKS 0U
+#define USE_HAL_PSSI_REGISTER_CALLBACKS 0U
+#define USE_HAL_RNG_REGISTER_CALLBACKS 0U
+#define USE_HAL_RTC_REGISTER_CALLBACKS 0U
+#define USE_HAL_SAI_REGISTER_CALLBACKS 0U
+#define USE_HAL_SD_REGISTER_CALLBACKS 0U
+#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U
+#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U
+#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U
+#define USE_HAL_SPDIFRX_REGISTER_CALLBACKS 0U
+#define USE_HAL_SPI_REGISTER_CALLBACKS 0U
+#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U
+#define USE_HAL_TIM_REGISTER_CALLBACKS 0U
+#define USE_HAL_UART_REGISTER_CALLBACKS 0U
+#define USE_HAL_USART_REGISTER_CALLBACKS 0U
+#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U
+#define USE_HAL_XSPI_REGISTER_CALLBACKS 0U
+
+/* ################## SPI peripheral configuration ########################## */
+
+/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
+* Activated: CRC code is present inside driver
+* Deactivated: CRC code cleaned from driver
+*/
+
+#define USE_SPI_CRC 1U
+
+/* ################## CRYP peripheral configuration ########################## */
+
+#define USE_HAL_CRYP_SUSPEND_RESUME 0U
+
+/* ################## HASH peripheral configuration ########################## */
+
+#define USE_HAL_HASH_SUSPEND_RESUME 0U
+
+/* ################## SDMMC peripheral configuration ######################### */
+
+#define USE_SD_TRANSCEIVER 0U
+
+/* Includes ------------------------------------------------------------------*/
+/**
+ * @brief Include module's header file
+ */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_CEC_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_cec.h"
+#endif /* HAL_CEC_MODULE_ENABLED */
+
+#ifdef HAL_CORDIC_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_cordic.h"
+#endif /* HAL_CORDIC_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DCMIPP_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_dcmipp.h"
+#endif /* HAL_DCMIPP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DTS_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_dts.h"
+#endif /* HAL_DTS_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_EXTI_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_exti.h"
+#endif /* HAL_EXTI_MODULE_ENABLED */
+
+#ifdef HAL_FDCAN_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_fdcan.h"
+#endif /* HAL_FDCAN_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_GFXMMU_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_gfxmmu.h"
+#endif /* HAL_GFXMMU_MODULE_ENABLED */
+
+#ifdef HAL_GFXTIM_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_gfxtim.h"
+#endif /* HAL_GFXTIM_MODULE_ENABLED */
+
+#ifdef HAL_GPU2D_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_gpu2d.h"
+#endif /* HAL_GPU2D_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_hcd.h"
+#endif /* HAL_HCD_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_I3C_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_i3c.h"
+#endif /* HAL_I3C_MODULE_ENABLED */
+
+#ifdef HAL_ICACHE_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_icache.h"
+#endif /* HAL_ICACHE_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_JPEG_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_jpeg.h"
+#endif /* HAL_JPEG_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_LPTIM_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_lptim.h"
+#endif /* HAL_LPTIM_MODULE_ENABLED */
+
+#ifdef HAL_MCE_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_mce.h"
+#endif /* HAL_MCE_MODULE_ENABLED */
+
+#ifdef HAL_MDF_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_mdf.h"
+#endif /* HAL_MDF_MODULE_ENABLED */
+
+#ifdef HAL_MMC_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_mmc.h"
+#endif /* HAL_MMC_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_PKA_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_pka.h"
+#endif /* HAL_PKA_MODULE_ENABLED */
+
+#ifdef HAL_PSSI_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_pssi.h"
+#endif /* HAL_PSSI_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RAMECC_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_ramecc.h"
+#endif /* HAL_RAMECC_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_SMBUS_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_smbus.h"
+#endif /* HAL_SMBUS_MODULE_ENABLED */
+
+#ifdef HAL_SPDIFRX_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_spdifrx.h"
+#endif /* HAL_SPDIFRX_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_XSPI_MODULE_ENABLED
+ #include "stm32h7rsxx_hal_xspi.h"
+#endif /* HAL_XSPI_MODULE_ENABLED */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+ #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(uint8_t *file, uint32_t line);
+#else
+ #define assert_param(expr) ((void)0U)
+#endif /* USE_FULL_ASSERT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STM32H7RSxx_HAL_CONF_H */
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/stm32l4/family.mk b/hw/bsp/stm32l4/family.mk
index 950b6f9cb..01d059236 100644
--- a/hw/bsp/stm32l4/family.mk
+++ b/hw/bsp/stm32l4/family.mk
@@ -1,5 +1,4 @@
ST_FAMILY = l4
-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/max78002/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/stm32n6/FreeRTOSConfig/FreeRTOSConfig.h
similarity index 97%
rename from hw/bsp/max78002/FreeRTOSConfig/FreeRTOSConfig.h
rename to hw/bsp/stm32n6/FreeRTOSConfig/FreeRTOSConfig.h
index e5a76af85..a1b83c802 100644
--- a/hw/bsp/max78002/FreeRTOSConfig/FreeRTOSConfig.h
+++ b/hw/bsp/stm32n6/FreeRTOSConfig/FreeRTOSConfig.h
@@ -44,10 +44,11 @@
// skip if included from IAR assembler
#ifndef __IASMARM__
- #include "mxc_device.h"
+ #include "stm32n6xx.h"
#endif
-/* Cortex M23/M33 port configuration. */
+/* Cortex M55 port configuration. */
+#define configENABLE_MVE 0
#define configENABLE_MPU 0
#define configENABLE_FPU 1
#define configENABLE_TRUSTZONE 0
@@ -59,7 +60,7 @@
#define configTICK_RATE_HZ ( 1000 )
#define configMAX_PRIORITIES ( 5 )
#define configMINIMAL_STACK_SIZE ( 128 )
-#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 )
+#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*8*1024 )
#define configMAX_TASK_NAME_LEN 16
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
@@ -127,7 +128,7 @@
//--------------------------------------------------------------------+
// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header
-#define configPRIO_BITS __NVIC_PRIO_BITS
+#define configPRIO_BITS 4
/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<ROM
+
+ /* The program code and other data into "RAM" Ram type memory */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+ *(.RamFunc) /* .RamFunc sections */
+ *(.RamFunc*) /* .RamFunc* sections */
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ } >ROM
+
+ /* Constant data into "RAM" Ram type memory */
+ .rodata :
+ {
+ . = ALIGN(4);
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ . = ALIGN(4);
+ } >ROM
+
+ .ARM.extab (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ . = ALIGN(4);
+ } >ROM
+
+ .ARM (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ . = ALIGN(4);
+ } >ROM
+
+ .preinit_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ . = ALIGN(4);
+ } >ROM
+
+ .init_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ . = ALIGN(4);
+ } >ROM
+
+ .fini_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT(.fini_array.*)))
+ KEEP (*(.fini_array*))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ . = ALIGN(4);
+ } >ROM
+
+ /* Used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* Initialized data sections into "RAM" Ram type memory */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+
+ } >RAM AT> ROM
+
+ .noncacheable :
+ {
+ . = ALIGN(8);
+ __snoncacheable = .;/* create symbol for start of section */
+ KEEP(*(.noncacheable))
+ . = ALIGN(8);
+ __enoncacheable = .; /* create symbol for end of section */
+ } > RAM
+
+
+ .gnu.sgstubs :
+ {
+ . = ALIGN(4);
+ *(.gnu.sgstubs*) /* Secure Gateway stubs */
+ . = ALIGN(4);
+ } >ROM
+ /* Uninitialized data section into "RAM" Ram type memory */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss section */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >RAM
+
+ /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >RAM
+
+ /* Remove information from the compiler libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
diff --git a/hw/bsp/stm32n6/boards/stm32n657nucleo/board.cmake b/hw/bsp/stm32n6/boards/stm32n657nucleo/board.cmake
new file mode 100644
index 000000000..e88efefb9
--- /dev/null
+++ b/hw/bsp/stm32n6/boards/stm32n657nucleo/board.cmake
@@ -0,0 +1,17 @@
+set(MCU_VARIANT stm32n657xx)
+set(JLINK_DEVICE stm32n6xx)
+
+set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/STM32N657XX_AXISRAM2_fsbl.ld)
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC
+ STM32N657xx
+ )
+ target_sources(${TARGET} PUBLIC
+ ${ST_TCPP0203}/tcpp0203.c
+ ${ST_TCPP0203}/tcpp0203_reg.c
+ )
+ target_include_directories(${TARGET} PUBLIC
+ ${ST_TCPP0203}
+ )
+endfunction()
diff --git a/hw/bsp/stm32n6/boards/stm32n657nucleo/board.h b/hw/bsp/stm32n6/boards/stm32n657nucleo/board.h
new file mode 100644
index 000000000..963ecad61
--- /dev/null
+++ b/hw/bsp/stm32n6/boards/stm32n657nucleo/board.h
@@ -0,0 +1,283 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ name: STM32 N657X0-Q Nucleo
+ url: https://www.st.com/en/evaluation-tools/nucleo-n657x0-q.html
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stm32n657xx.h"
+#include "stm32n6xx_ll_exti.h"
+#include "stm32n6xx_ll_system.h"
+#include "tcpp0203.h"
+
+#define UART_DEV USART1
+#define UART_CLK_EN __HAL_RCC_USART1_CLK_ENABLE
+
+#define BOARD_TUD_RHPORT 1
+
+// VBUS Sense detection
+#define OTG_FS_VBUS_SENSE 1
+#define OTG_HS_VBUS_SENSE 1
+
+#define PINID_LED 0
+#define PINID_BUTTON 1
+#define PINID_UART_TX 2
+#define PINID_UART_RX 3
+#define PINID_TCPP0203_EN 4
+
+static board_pindef_t board_pindef[] = {
+ {// LED
+ .port = GPIOG,
+ .pin_init = {.Pin = GPIO_PIN_10, .Mode = GPIO_MODE_OUTPUT_PP, .Pull = GPIO_PULLDOWN, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0},
+ .active_state = 1},
+ {// Button
+ .port = GPIOC,
+ .pin_init = {.Pin = GPIO_PIN_13, .Mode = GPIO_MODE_INPUT, .Pull = GPIO_PULLDOWN, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0},
+ .active_state = 1},
+ {// UART TX
+ .port = GPIOE,
+ .pin_init = {.Pin = GPIO_PIN_5, .Mode = GPIO_MODE_AF_PP, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_LOW, .Alternate = GPIO_AF7_USART1},
+ .active_state = 0},
+ {// UART RX
+ .port = GPIOE,
+ .pin_init = {.Pin = GPIO_PIN_6, .Mode = GPIO_MODE_AF_PP, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_LOW, .Alternate = GPIO_AF7_USART1},
+ .active_state = 0},
+ {// VBUS input pin used for TCPP0203 EN
+ .port = GPIOA,
+ .pin_init = {.Pin = GPIO_PIN_7, .Mode = GPIO_MODE_OUTPUT_PP, .Pull = GPIO_PULLDOWN, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0},
+ .active_state = 0},
+ {
+ // I2C SCL for TCPP0203
+ .port = GPIOB,
+ .pin_init = {.Pin = GPIO_PIN_10, .Mode = GPIO_MODE_AF_OD, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_LOW, .Alternate = GPIO_AF4_I2C2},
+ },
+ {
+ // I2C SDA for TCPP0203
+ .port = GPIOB,
+ .pin_init = {.Pin = GPIO_PIN_11, .Mode = GPIO_MODE_AF_OD, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_LOW, .Alternate = GPIO_AF4_I2C2},
+ },
+ {
+ // INT for TCPP0203
+ .port = GPIOD,
+ .pin_init = {.Pin = GPIO_PIN_2, .Mode = GPIO_MODE_IT_FALLING, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0},
+ },
+};
+
+//--------------------------------------------------------------------+
+// RCC Clock
+//--------------------------------------------------------------------+
+void SystemClock_Config(void) {
+ RCC_OscInitTypeDef RCC_OscInitStruct = {0};
+ RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
+ /* Configure the power domain */
+ if (HAL_PWREx_ConfigSupply(PWR_EXTERNAL_SOURCE_SUPPLY) != HAL_OK) {
+ Error_Handler();
+ }
+
+ /* Get current CPU/System buses clocks configuration */
+ /* and if necessary switch to intermediate HSI clock */
+ /* to ensure target clock can be set */
+ HAL_RCC_GetClockConfig(&RCC_ClkInitStruct);
+ if ((RCC_ClkInitStruct.CPUCLKSource == RCC_CPUCLKSOURCE_IC1) ||
+ (RCC_ClkInitStruct.SYSCLKSource == RCC_SYSCLKSOURCE_IC2_IC6_IC11)) {
+ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_CPUCLK | RCC_CLOCKTYPE_SYSCLK);
+ RCC_ClkInitStruct.CPUCLKSource = RCC_CPUCLKSOURCE_HSI;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct) != HAL_OK) {
+ Error_Handler();
+ }
+ }
+
+ /* HSE selected as source (stable clock on Level 0 samples */
+ /* PLL1 output = ((HSE/PLLM)*PLLN)/PLLP1/PLLP2 */
+ /* = ((48000000/3)*75)/1/1 */
+ /* = (16000000*75)/1/1 */
+ /* = 1200000000 (1200 MHz) */
+ /* PLL2 off */
+ /* PLL3 off */
+ /* PLL4 off */
+
+ /* Enable HSE && HSI */
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
+ RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
+ RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
+ RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
+ RCC_OscInitStruct.HSEState = RCC_HSE_ON; /* 48 MHz */
+
+ RCC_OscInitStruct.PLL1.PLLState = RCC_PLL_ON;
+ RCC_OscInitStruct.PLL1.PLLSource = RCC_PLLSOURCE_HSE;
+ RCC_OscInitStruct.PLL1.PLLM = 3;
+ RCC_OscInitStruct.PLL1.PLLN = 75; /* PLL1 VCO = 48/3 * 75 = 1200MHz */
+ RCC_OscInitStruct.PLL1.PLLP1 = 1; /* PLL output = PLL VCO frequency / (PLLP1 * PLLP2) */
+ RCC_OscInitStruct.PLL1.PLLP2 = 1; /* PLL output = 1200 MHz */
+ RCC_OscInitStruct.PLL1.PLLFractional = 0;
+
+ if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
+ /* Initialization error */
+ Error_Handler();
+ }
+
+ /* Select PLL1 outputs as CPU and System bus clock source */
+ /* CPUCLK = ic1_ck = PLL1 output/ic1_divider = 600 MHz */
+ /* SYSCLK = ic2_ck = PLL1 output/ic2_divider = 400 MHz */
+ /* Configure the HCLK clock divider */
+ /* HCLK = PLL1 SYSCLK/HCLK divider = 200 MHz */
+ /* PCLKx = HCLK / PCLKx divider = 200 MHz */
+ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_CPUCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK |
+ RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_PCLK4 | RCC_CLOCKTYPE_PCLK5);
+ RCC_ClkInitStruct.CPUCLKSource = RCC_CPUCLKSOURCE_IC1;
+ RCC_ClkInitStruct.IC1Selection.ClockSelection = RCC_ICCLKSOURCE_PLL1;
+ RCC_ClkInitStruct.IC1Selection.ClockDivider = 2;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_IC2_IC6_IC11;
+ RCC_ClkInitStruct.IC2Selection.ClockSelection = RCC_ICCLKSOURCE_PLL1;
+ RCC_ClkInitStruct.IC2Selection.ClockDivider = 3;
+ RCC_ClkInitStruct.IC6Selection.ClockSelection = RCC_ICCLKSOURCE_PLL1;
+ RCC_ClkInitStruct.IC6Selection.ClockDivider = 3;
+ RCC_ClkInitStruct.IC11Selection.ClockSelection = RCC_ICCLKSOURCE_PLL1;
+ RCC_ClkInitStruct.IC11Selection.ClockDivider = 3;
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV1;
+ RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV1;
+ RCC_ClkInitStruct.APB5CLKDivider = RCC_APB5_DIV1;
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct) != HAL_OK) {
+ /* Initialization Error */
+ Error_Handler();
+ }
+
+ /** Initializes the peripherals clock
+ */
+ RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
+ PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USBOTGHS1;
+ PeriphClkInitStruct.UsbOtgHs1ClockSelection = RCC_USBPHY1REFCLKSOURCE_HSE_DIRECT;
+
+ if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
+ /* Initialization Error */
+ Error_Handler();
+ }
+
+ /** Set USB OTG HS PHY1 Reference Clock Source */
+ PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USBPHY1;
+ PeriphClkInitStruct.UsbPhy1ClockSelection = RCC_USBPHY1REFCLKSOURCE_HSE_DIRECT;
+
+ if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
+ /* Initialization Error */
+ Error_Handler();
+ }
+}
+
+//--------------------------------------------------------------------+
+// USB PD
+//--------------------------------------------------------------------+
+static I2C_HandleTypeDef i2c_handle = {
+ .Instance = I2C2,
+ .Init = {
+ .Timing = 0x20C0EDFF,
+ .OwnAddress1 = 0,
+ .AddressingMode = I2C_ADDRESSINGMODE_7BIT,
+ .DualAddressMode = I2C_DUALADDRESS_DISABLE,
+ .OwnAddress2 = 0,
+ .OwnAddress2Masks = I2C_OA2_NOMASK,
+ .GeneralCallMode = I2C_GENERALCALL_DISABLE,
+ .NoStretchMode = I2C_NOSTRETCH_DISABLE,
+ }};
+static TCPP0203_Object_t tcpp0203_obj = {0};
+
+int32_t board_tcpp0203_init(void) {
+ board_pindef_t *pindef = &board_pindef[PINID_TCPP0203_EN];
+ HAL_GPIO_WritePin(pindef->port, pindef->pin_init.Pin, GPIO_PIN_SET);
+
+ __HAL_RCC_I2C2_CLK_ENABLE();
+ __HAL_RCC_I2C2_FORCE_RESET();
+ __HAL_RCC_I2C2_RELEASE_RESET();
+ if (HAL_I2C_Init(&i2c_handle) != HAL_OK) {
+ return HAL_ERROR;
+ }
+
+ NVIC_SetPriority(EXTI8_IRQn, 12);
+ NVIC_EnableIRQ(EXTI8_IRQn);
+
+ return 0;
+}
+
+int32_t board_tcpp0203_deinit(void) {
+ return 0;
+}
+
+int32_t i2c_readreg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
+ TU_ASSERT(HAL_OK == HAL_I2C_Mem_Read(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000));
+ return 0;
+}
+
+int32_t i2c_writereg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) {
+ TU_ASSERT(HAL_OK == HAL_I2C_Mem_Write(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000));
+ return 0;
+}
+
+static inline void board_init2(void) {
+ TCPP0203_IO_t io_ctx;
+
+ io_ctx.Address = TCPP0203_I2C_ADDRESS_X68;
+ io_ctx.Init = board_tcpp0203_init;
+ io_ctx.DeInit = board_tcpp0203_deinit;
+ io_ctx.ReadReg = i2c_readreg;
+ io_ctx.WriteReg = i2c_writereg;
+
+ TU_ASSERT(TCPP0203_RegisterBusIO(&tcpp0203_obj, &io_ctx) == TCPP0203_OK, );
+
+ TU_ASSERT(TCPP0203_Init(&tcpp0203_obj) == TCPP0203_OK, );
+
+ TU_ASSERT(TCPP0203_SetPowerMode(&tcpp0203_obj, TCPP0203_POWER_MODE_NORMAL) == TCPP0203_OK, );
+}
+
+void board_vbus_set(uint8_t rhport, bool state) {
+ (void) state;
+ if (rhport == 1) {
+ TU_ASSERT(TCPP0203_SetGateDriverProvider(&tcpp0203_obj, TCPP0203_GD_PROVIDER_SWITCH_CLOSED) == TCPP0203_OK, );
+ }
+}
+
+void EXTI8_IRQHandler(void) {
+ __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_8);
+ if (tcpp0203_obj.IsInitialized) {
+ TU_ASSERT(TCPP0203_SetPowerMode(&tcpp0203_obj, TCPP0203_POWER_MODE_NORMAL) == TCPP0203_OK, );
+ TU_ASSERT(TCPP0203_SetGateDriverProvider(&tcpp0203_obj, TCPP0203_GD_PROVIDER_SWITCH_CLOSED) == TCPP0203_OK, );
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/bsp/stm32n6/boards/stm32n657nucleo/board.mk b/hw/bsp/stm32n6/boards/stm32n657nucleo/board.mk
new file mode 100644
index 000000000..05717699c
--- /dev/null
+++ b/hw/bsp/stm32n6/boards/stm32n657nucleo/board.mk
@@ -0,0 +1,17 @@
+MCU_VARIANT = stm32n657xx
+CFLAGS += -DSTM32N657xx
+JLINK_DEVICE = stm32n6xx
+
+LD_FILE_GCC = $(BOARD_PATH)/STM32N657XX_AXISRAM2_fsbl.ld
+
+# flash target using on-board stlink
+flash: flash-stlink
+
+PORT = 1
+
+SRC_C += \
+ $(ST_TCPP0203)/tcpp0203.c \
+ $(ST_TCPP0203)/tcpp0203_reg.c \
+
+INC += \
+ $(TOP)/$(ST_TCPP0203) \
diff --git a/hw/bsp/stm32n6/family.c b/hw/bsp/stm32n6/family.c
new file mode 100644
index 000000000..1d0616d8e
--- /dev/null
+++ b/hw/bsp/stm32n6/family.c
@@ -0,0 +1,280 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019
+ * William D. Jones (thor0505@comcast.net),
+ * Ha Thach (tinyusb.org)
+ * Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ manufacturer: STMicroelectronics
+*/
+
+// Suppress warning caused by mcu driver
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+#endif
+
+#include "stm32n6xx_hal.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+#include "bsp/board_api.h"
+
+TU_ATTR_UNUSED static void Error_Handler(void) { }
+
+void HardFault_Handler(void);
+
+typedef struct {
+ GPIO_TypeDef* port;
+ GPIO_InitTypeDef pin_init;
+ uint8_t active_state;
+} board_pindef_t;
+
+#include "board.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
+
+#ifdef UART_DEV
+UART_HandleTypeDef UartHandle = {
+ .Instance = UART_DEV,
+ .Init = {
+ .BaudRate = CFG_BOARD_UART_BAUDRATE,
+ .WordLength = UART_WORDLENGTH_8B,
+ .StopBits = UART_STOPBITS_1,
+ .Parity = UART_PARITY_NONE,
+ .HwFlowCtl = UART_HWCONTROL_NONE,
+ .Mode = UART_MODE_TX_RX,
+ .OverSampling = UART_OVERSAMPLING_16,
+ }
+};
+#endif
+
+#ifndef SWO_FREQ
+#define SWO_FREQ 4000000
+#endif
+
+//--------------------------------------------------------------------+
+// Forward USB interrupt events to TinyUSB IRQ Handler
+//--------------------------------------------------------------------+
+
+// Despite being call USB2_OTG_FS on some MCUs
+// OTG_FS is marked as RHPort0 by TinyUSB to be consistent across stm32 port
+void USB2_OTG_HS_IRQHandler(void) {
+ tusb_int_handler(0, true);
+}
+
+// Despite being call USB1_OTG_HS on some MCUs
+// OTG_HS is marked as RHPort1 by TinyUSB to be consistent across stm32 port
+void USB1_OTG_HS_IRQHandler(void) {
+ tusb_int_handler(1, true);
+}
+
+void board_init(void) {
+
+ /* Enable BusFault and SecureFault handlers (HardFault is default) */
+ SCB->SHCSR |= (SCB_SHCSR_BUSFAULTENA_Msk | SCB_SHCSR_SECUREFAULTENA_Msk);
+
+ HAL_PWREx_EnableVddA();
+ HAL_PWREx_EnableVddIO2();
+ HAL_PWREx_EnableVddIO3();
+ HAL_PWREx_EnableVddIO4();
+ HAL_PWREx_EnableVddIO5();
+
+ HAL_Init();
+
+ // Implemented in board.h
+ SystemClock_Config();
+
+ // Enable All GPIOs clocks
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+ __HAL_RCC_GPIOC_CLK_ENABLE();
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+ __HAL_RCC_GPIOE_CLK_ENABLE();
+ __HAL_RCC_GPIOF_CLK_ENABLE();
+ __HAL_RCC_GPIOG_CLK_ENABLE();
+ __HAL_RCC_GPIOH_CLK_ENABLE();
+ __HAL_RCC_GPION_CLK_ENABLE();
+ __HAL_RCC_GPIOO_CLK_ENABLE();
+ __HAL_RCC_GPIOP_CLK_ENABLE();
+ __HAL_RCC_GPIOQ_CLK_ENABLE();
+
+ // HAL_ICACHE_Enable();
+
+ for (uint8_t i = 0; i < TU_ARRAY_SIZE(board_pindef); i++) {
+ HAL_GPIO_Init(board_pindef[i].port, &board_pindef[i].pin_init);
+ }
+
+ NVIC_SetPriority(UCPD1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
+ NVIC_EnableIRQ(UCPD1_IRQn);
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+ // 1ms tick timer
+ SysTick_Config(SystemCoreClock / 1000);
+
+#elif CFG_TUSB_OS == OPT_OS_FREERTOS
+ // Explicitly disable systick to prevent its ISR runs before scheduler start
+ SysTick->CTRL &= ~1U;
+
+ // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
+
+ NVIC_SetPriority(USB1_OTG_HS_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
+#endif
+
+
+
+#ifdef UART_DEV
+ UART_CLK_EN();
+ HAL_UART_Init(&UartHandle);
+#endif
+
+
+ __HAL_RCC_USB1_OTG_HS_CLK_ENABLE();
+ __HAL_RCC_PWR_CLK_ENABLE();
+ HAL_PWREx_EnableVddUSBVMEN();
+ while(__HAL_PWR_GET_FLAG(PWR_FLAG_USB33RDY));
+ HAL_PWREx_EnableVddUSB();
+
+ LL_AHB5_GRP1_ForceReset(0x00800000);
+ __HAL_RCC_USB1_OTG_HS_FORCE_RESET();
+ __HAL_RCC_USB1_OTG_HS_PHY_FORCE_RESET();
+
+ LL_RCC_HSE_SelectHSEDiv2AsDiv2Clock();
+ LL_AHB5_GRP1_ReleaseReset(0x00800000);
+
+ /* Peripheral clock enable */
+ __HAL_RCC_USB1_OTG_HS_CLK_ENABLE();
+
+ /* Required few clock cycles before accessing USB PHY Controller Registers */
+ for (volatile uint32_t i = 0; i < 10; i++) {
+ __NOP(); // No Operation instruction to create a delay
+ }
+
+ USB1_HS_PHYC->USBPHYC_CR &= ~(0x7 << 0x4);
+
+ USB1_HS_PHYC->USBPHYC_CR |= (0x1 << 16) |
+ (0x2 << 4) |
+ (0x1 << 2) |
+ 0x1U;
+
+ __HAL_RCC_USB1_OTG_HS_PHY_RELEASE_RESET();
+
+ /* Required few clock cycles before Releasing Reset */
+ for (volatile uint32_t i = 0; i < 10; i++) {
+ __NOP(); // No Operation instruction to create a delay
+ }
+
+ __HAL_RCC_USB1_OTG_HS_RELEASE_RESET();
+
+ /* Peripheral PHY clock enable */
+ __HAL_RCC_USB1_OTG_HS_PHY_CLK_ENABLE();
+
+ board_init2();
+
+#if CFG_TUH_ENABLED
+ board_vbus_set(BOARD_TUH_RHPORT, 1);
+#endif
+}
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+
+void board_led_write(bool state) {
+#ifdef PINID_LED
+ board_pindef_t* pindef = &board_pindef[PINID_LED];
+ GPIO_PinState pin_state = state == pindef->active_state ? GPIO_PIN_SET : GPIO_PIN_RESET;
+ HAL_GPIO_WritePin(pindef->port, pindef->pin_init.Pin, pin_state);
+#else
+ (void) state;
+#endif
+}
+
+uint32_t board_button_read(void) {
+#ifdef PINID_BUTTON
+ board_pindef_t* pindef = &board_pindef[PINID_BUTTON];
+ return pindef->active_state == HAL_GPIO_ReadPin(pindef->port, pindef->pin_init.Pin);
+#else
+ return 0;
+#endif
+}
+
+size_t board_get_unique_id(uint8_t id[], size_t max_len) {
+ (void) max_len;
+ volatile uint32_t * stm32_uuid = (volatile uint32_t *) UID_BASE;
+ uint32_t* id32 = (uint32_t*) (uintptr_t) id;
+ uint8_t const len = 12;
+
+ id32[0] = stm32_uuid[0];
+ id32[1] = stm32_uuid[1];
+ id32[2] = stm32_uuid[2];
+
+ return len;
+}
+
+int board_uart_read(uint8_t *buf, int len) {
+ (void) buf;
+ (void) len;
+ return 0;
+}
+
+int board_uart_write(void const *buf, int len) {
+#ifdef UART_DEV
+ HAL_UART_Transmit(&UartHandle, (uint8_t * )(uintptr_t)
+ buf, len, 0xffff);
+ return len;
+#else
+ (void) buf; (void) len;
+ return -1;
+#endif
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+
+void SysTick_Handler(void) {
+ HAL_IncTick();
+ system_ticks++;
+}
+
+uint32_t board_millis(void) {
+ return system_ticks;
+}
+
+#endif
+
+void HardFault_Handler(void) {
+ __asm("BKPT #0\n");
+}
+
+// Required by __libc_init_array in startup code if we are compiling using
+// -nostdlib/-nostartfiles.
+void _init(void) {
+}
diff --git a/hw/bsp/stm32n6/family.cmake b/hw/bsp/stm32n6/family.cmake
new file mode 100644
index 000000000..76763937e
--- /dev/null
+++ b/hw/bsp/stm32n6/family.cmake
@@ -0,0 +1,148 @@
+include_guard()
+
+set(ST_FAMILY n6)
+set(ST_PREFIX stm32${ST_FAMILY}xx)
+
+set(ST_HAL_DRIVER ${TOP}/hw/mcu/st/stm32${ST_FAMILY}xx_hal_driver)
+set(ST_CMSIS ${TOP}/hw/mcu/st/cmsis_device_${ST_FAMILY})
+set(CMSIS_5 ${TOP}/lib/CMSIS_5)
+set(ST_TCPP0203 ${TOP}/hw/mcu/st/stm32-tcpp0203)
+
+# include board specific
+include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
+
+# toolchain set up
+set(CMAKE_SYSTEM_CPU cortex-m55 CACHE INTERNAL "System Processor")
+set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
+
+set(FAMILY_MCUS STM32N6 CACHE INTERNAL "")
+
+# ----------------------
+# Port & Speed Selection
+# ----------------------
+if (NOT DEFINED RHPORT_DEVICE)
+ set(RHPORT_DEVICE 1)
+endif ()
+if (NOT DEFINED RHPORT_HOST)
+ set(RHPORT_HOST 1)
+endif ()
+
+# N6 are all high speed
+if (NOT DEFINED RHPORT_DEVICE_SPEED)
+ set(RHPORT_DEVICE_SPEED OPT_MODE_HIGH_SPEED)
+endif ()
+if (NOT DEFINED RHPORT_HOST_SPEED)
+ set(RHPORT_HOST_SPEED OPT_MODE_HIGH_SPEED)
+endif ()
+
+cmake_print_variables(RHPORT_DEVICE RHPORT_DEVICE_SPEED RHPORT_HOST RHPORT_HOST_SPEED)
+
+#------------------------------------
+# BOARD_TARGET
+#------------------------------------
+# only need to be built ONCE for all examples
+function(add_board_target BOARD_TARGET)
+ if (TARGET ${BOARD_TARGET})
+ return()
+ endif()
+
+ # Startup & Linker script
+ set(STARTUP_FILE_GNU ${ST_CMSIS}/Source/Templates/gcc/startup_${MCU_VARIANT}.s)
+ set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
+ set(STARTUP_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/startup_${MCU_VARIANT}.s)
+
+ if(NOT DEFINED LD_FILE_GNU)
+ set(LD_FILE_GNU ${ST_CMSIS}/Source/Templates/gcc/linker/${MCU_VARIANT}_flash.ld)
+ endif()
+ set(LD_FILE_Clang ${LD_FILE_GNU})
+ if(NOT DEFINED LD_FILE_IAR)
+ set(LD_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf)
+ endif()
+
+ add_library(${BOARD_TARGET} STATIC
+ ${ST_CMSIS}/Source/Templates/system_${ST_PREFIX}_fsbl.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_dma.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_gpio.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_pwr.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_i2c.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_pwr_ex.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_rcc.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_rcc_ex.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_uart.c
+ ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_uart_ex.c
+ ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
+ )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMSIS_5}/CMSIS/Core/Include
+ ${ST_CMSIS}/Include
+ ${ST_HAL_DRIVER}/Inc
+ )
+ target_compile_definitions(${BOARD_TARGET} PUBLIC
+ BOARD_TUD_RHPORT=${RHPORT_DEVICE}
+ BOARD_TUD_MAX_SPEED=${RHPORT_DEVICE_SPEED}
+ BOARD_TUH_RHPORT=${RHPORT_HOST}
+ BOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED}
+ SEGGER_RTT_SECTION="noncacheable_buffer"
+ BUFFER_SIZE_UP=0x3000
+ )
+
+ update_board(${BOARD_TARGET})
+
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--script=${LD_FILE_GNU}"
+ -nostartfiles
+ --specs=nosys.specs --specs=nano.specs
+ )
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--script=${LD_FILE_Clang}"
+ )
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
+ target_link_options(${BOARD_TARGET} PUBLIC
+ "LINKER:--config=${LD_FILE_IAR}"
+ )
+ endif ()
+endfunction()
+
+
+#------------------------------------
+# Functions
+#------------------------------------
+function(family_configure_example TARGET RTOS)
+ family_configure_common(${TARGET} ${RTOS})
+
+ # Board target
+ add_board_target(board_${BOARD})
+
+ #---------- Port Specific ----------
+ # These files are built for each example since it depends on example's tusb_config.h
+ target_sources(${TARGET} PUBLIC
+ # BSP
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
+ )
+ target_include_directories(${TARGET} PUBLIC
+ # family, hw, board
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
+ )
+
+ # Add TinyUSB target and port source
+ family_add_tinyusb(${TARGET} OPT_MCU_STM32N6 ${RTOS})
+ target_sources(${TARGET} PUBLIC
+ ${TOP}/src/portable/synopsys/dwc2/dcd_dwc2.c
+ ${TOP}/src/portable/synopsys/dwc2/hcd_dwc2.c
+ ${TOP}/src/portable/synopsys/dwc2/dwc2_common.c
+ )
+ target_link_libraries(${TARGET} PUBLIC board_${BOARD})
+
+ # Flashing
+ family_add_bin_hex(${TARGET})
+ family_flash_stlink(${TARGET})
+ family_flash_jlink(${TARGET})
+endfunction()
diff --git a/hw/bsp/stm32n6/family.mk b/hw/bsp/stm32n6/family.mk
new file mode 100644
index 000000000..37087ed42
--- /dev/null
+++ b/hw/bsp/stm32n6/family.mk
@@ -0,0 +1,89 @@
+ST_FAMILY = n6
+ST_PREFIX = stm32${ST_FAMILY}xx
+ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
+ST_HAL_DRIVER = hw/mcu/st/${ST_PREFIX}_hal_driver
+ST_TCPP0203 = hw/mcu/st/stm32-tcpp0203
+
+UF2_FAMILY_ID = 0x6db66083
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+CPU_CORE ?= cortex-m55
+
+# ----------------------
+# Port & Speed Selection
+# ----------------------
+RHPORT_DEVICE ?= 1
+RHPORT_HOST ?= 1
+
+ifndef RHPORT_DEVICE_SPEED
+ RHPORT_DEVICE_SPEED = OPT_MODE_HIGH_SPEED
+endif
+
+ifndef RHPORT_HOST_SPEED
+ RHPORT_HOST_SPEED = OPT_MODE_HIGH_SPEED
+endif
+
+# --------------
+# Compiler Flags
+# --------------
+CFLAGS += \
+ -DCFG_TUSB_MCU=OPT_MCU_STM32N6 \
+ -DBOARD_TUD_RHPORT=${RHPORT_DEVICE} \
+ -DBOARD_TUD_MAX_SPEED=${RHPORT_DEVICE_SPEED} \
+ -DBOARD_TUH_RHPORT=${RHPORT_HOST} \
+ -DBOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED} \
+ -DSEGGER_RTT_SECTION=\"noncacheable_buffer\" \
+ -DBUFFER_SIZE_UP=0x3000 \
+
+# GCC Flags
+CFLAGS_GCC += \
+ -flto \
+
+# suppress warning caused by vendor mcu driver
+CFLAGS_GCC += \
+ -Wno-error=cast-align \
+ -Wno-error=unused-parameter \
+
+LDFLAGS_GCC += \
+ -nostdlib -nostartfiles \
+ --specs=nosys.specs --specs=nano.specs
+
+# -----------------
+# Sources & Include
+# -----------------
+
+SRC_C += \
+ src/portable/synopsys/dwc2/dcd_dwc2.c \
+ src/portable/synopsys/dwc2/hcd_dwc2.c \
+ src/portable/synopsys/dwc2/dwc2_common.c \
+ $(ST_CMSIS)/Source/Templates/system_${ST_PREFIX}_fsbl.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_dma.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_gpio.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_hcd.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_i2c.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pcd.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_pcd_ex.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_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_rif.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_uart.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_uart_ex.c \
+ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_ll_usb.c \
+
+INC += \
+ $(TOP)/$(BOARD_PATH) \
+ $(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
+ $(TOP)/$(ST_CMSIS)/Include \
+ $(TOP)/$(ST_HAL_DRIVER)/Inc
+
+# Startup
+SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_$(MCU_VARIANT)_fsbl.s
+SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT).s
+
+# Linker
+LD_FILE_GCC ?= $(ST_CMSIS)/Source/Templates/gcc/linker/$(MCU_VARIANT)_flash.ld
+LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash.icf
diff --git a/hw/bsp/stm32n6/partition_stm32n657xx.h b/hw/bsp/stm32n6/partition_stm32n657xx.h
new file mode 100644
index 000000000..4efdc5668
--- /dev/null
+++ b/hw/bsp/stm32n6/partition_stm32n657xx.h
@@ -0,0 +1,792 @@
+/**
+ ******************************************************************************
+ * @file partition_stm32n657xx.h
+ * @author MCD Application Team
+ * @brief CMSIS STM32N657xx Device Initial Setup for Secure / Non-Secure Zones
+ * for ARMCM55 based on CMSIS CORE V5.3.1 partition_ARMCM33.h Template.
+ *
+ * This file contains:
+ * - Initialize Security Attribution Unit (SAU) CTRL register
+ * - Setup behavior of Sleep and Exception Handling
+ * - Setup behavior of Floating Point Unit
+ * - Setup Interrupt Target
+ *
+ ******************************************************************************/
+/*
+ * Copyright (c) 2009-2016 ARM Limited. All rights reserved.
+ * Portions Copyright (c) 2023 STMicroelectronics, all rights reserved
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PARTITION_STM32N657XX_H
+#define PARTITION_STM32N657XX_H
+
+/*
+//-------- <<< Use Configuration Wizard in Context Menu >>> -----------------
+*/
+
+/*
+// Initialize Security Attribution Unit (SAU) CTRL register
+*/
+#define SAU_INIT_CTRL 0
+
+/*
+// Enable SAU
+// Value for SAU->CTRL register bit ENABLE
+*/
+#define SAU_INIT_CTRL_ENABLE 0
+
+/*
+// When SAU is disabled
+// <0=> All Memory is Secure
+// <1=> All Memory is Non-Secure
+// Value for SAU->CTRL register bit ALLNS
+// When all Memory is Non-Secure (ALLNS is 1), IDAU can override memory map configuration.
+*/
+#define SAU_INIT_CTRL_ALLNS 0
+
+/*
+//
+*/
+
+/*
+// Initialize Security Attribution Unit (SAU) Address Regions
+// SAU configuration specifies regions to be one of:
+// - Secure and Non-Secure Callable
+// - Non-Secure
+// Note: All memory regions not configured by SAU are Secure
+*/
+#define SAU_REGIONS_MAX 8 /* Max. number of SAU regions */
+
+/*
+// Initialize SAU Region 0
+// Setup SAU Region 0 memory attributes
+*/
+#define SAU_INIT_REGION0 0
+
+/*
+// Start Address <0-0xFFFFFFE0>
+*/
+#define SAU_INIT_START0 0x00000000 /* start address of SAU region 0 */
+
+/*
+// End Address <0x1F-0xFFFFFFFF>
+*/
+#define SAU_INIT_END0 0x00000000 /* end address of SAU region 0 */
+
+/*
+// Region is
+// <0=>Non-Secure
+// <1=>Secure, Non-Secure Callable
+*/
+#define SAU_INIT_NSC0 0
+/*
+//
+*/
+
+/*
+// Initialize SAU Region 1
+// Setup SAU Region 1 memory attributes
+*/
+#define SAU_INIT_REGION1 0
+
+/*
+// Start Address <0-0xFFFFFFE0>
+*/
+#define SAU_INIT_START1 0x00000000 /* start address of SAU region 1 */
+
+/*
+// End Address <0x1F-0xFFFFFFFF>
+*/
+#define SAU_INIT_END1 0x00000000 /* end address of SAU region 1 */
+
+/*
+// Region is
+// <0=>Non-Secure
+// <1=>Secure, Non-Secure Callable
+*/
+#define SAU_INIT_NSC1 0
+/*
+//
+*/
+
+/*
+// Initialize SAU Region 2
+// Setup SAU Region 2 memory attributes
+*/
+#define SAU_INIT_REGION2 0
+
+/*
+// Start Address <0-0xFFFFFFE0>
+*/
+#define SAU_INIT_START2 0x00000000 /* start address of SAU region 2 */
+
+/*
+// End Address <0x1F-0xFFFFFFFF>
+*/
+#define SAU_INIT_END2 0x00000000 /* end address of SAU region 2 */
+
+/*
+// Region is
+// <0=>Non-Secure
+// <1=>Secure, Non-Secure Callable
+*/
+#define SAU_INIT_NSC2 0
+/*
+//
+*/
+
+/*
+// Initialize SAU Region 3
+// Setup SAU Region 3 memory attributes
+*/
+#define SAU_INIT_REGION3 0
+
+/*
+// Start Address <0-0xFFFFFFE0>
+*/
+#define SAU_INIT_START3 0x00000000 /* start address of SAU region 3 */
+
+/*
+// End Address <0x1F-0xFFFFFFFF>
+*/
+#define SAU_INIT_END3 0x00000000 /* end address of SAU region 3 */
+
+/*
+// Region is
+// <0=>Non-Secure
+// <1=>Secure, Non-Secure Callable
+*/
+#define SAU_INIT_NSC3 0
+/*
+//
+*/
+
+/*
+// Initialize SAU Region 4
+// Setup SAU Region 4 memory attributes
+*/
+#define SAU_INIT_REGION4 0
+
+/*
+// Start Address <0-0xFFFFFFE0>
+*/
+#define SAU_INIT_START4 0x00000000 /* start address of SAU region 4 */
+
+/*
+// End Address <0x1F-0xFFFFFFFF>
+*/
+#define SAU_INIT_END4 0x00000000 /* end address of SAU region 4 */
+
+/*
+// Region is
+// <0=>Non-Secure
+// <1=>Secure, Non-Secure Callable
+*/
+#define SAU_INIT_NSC4 0
+/*
+//
+*/
+
+/*
+// Initialize SAU Region 5
+// Setup SAU Region 5 memory attributes
+*/
+#define SAU_INIT_REGION5 0
+
+/*
+// Start Address <0-0xFFFFFFE0>
+*/
+#define SAU_INIT_START5 0x00000000 /* start address of SAU region 5 */
+
+/*
+// End Address <0x1F-0xFFFFFFFF>
+*/
+#define SAU_INIT_END5 0x00000000 /* end address of SAU region 5 */
+
+/*
+// Region is
+// <0=>Non-Secure
+// <1=>Secure, Non-Secure Callable
+*/
+#define SAU_INIT_NSC5 0
+/*
+//
+*/
+
+/*
+// Initialize SAU Region 6
+// Setup SAU Region 6 memory attributes
+*/
+#define SAU_INIT_REGION6 0
+
+/*
+// Start Address <0-0xFFFFFFE0>
+*/
+#define SAU_INIT_START6 0x00000000 /* start address of SAU region 6 */
+
+/*
+// End Address <0x1F-0xFFFFFFFF>
+*/
+#define SAU_INIT_END6 0x00000000 /* end address of SAU region 6 */
+
+/*
+// Region is
+// <0=>Non-Secure
+// <1=>Secure, Non-Secure Callable
+*/
+#define SAU_INIT_NSC6 0
+/*
+//
+*/
+
+/*
+// Initialize SAU Region 7
+// Setup SAU Region 7 memory attributes
+*/
+#define SAU_INIT_REGION7 0
+
+/*
+// Start Address <0-0xFFFFFFE0>
+*/
+#define SAU_INIT_START7 0x00000000 /* start address of SAU region 7 */
+
+/*
+// End Address <0x1F-0xFFFFFFFF>
+*/
+#define SAU_INIT_END7 0x00000000 /* end address of SAU region 7 */
+
+/*
+// Region is
+// <0=>Non-Secure
+// <1=>Secure, Non-Secure Callable
+*/
+#define SAU_INIT_NSC7 0
+/*
+//
+*/
+
+/*
+//
+*/
+
+/*
+// Setup behaviour of Sleep and Exception Handling
+*/
+#define SCB_CSR_AIRCR_INIT 0
+
+/*
+// Deep Sleep can be enabled by
+// <0=>Secure and Non-Secure state
+// <1=>Secure state only
+// Value for SCB->CSR register bit DEEPSLEEPS
+*/
+#define SCB_CSR_DEEPSLEEPS_VAL 0
+
+/*
+// System reset request accessible from
+// <0=> Secure and Non-Secure state
+// <1=> Secure state only
+// Value for SCB->AIRCR register bit SYSRESETREQS
+*/
+#define SCB_AIRCR_SYSRESETREQS_VAL 0
+
+/*
+// Priority of Non-Secure exceptions is
+// <0=> Not altered
+// <1=> Lowered to 0x04-0x07
+// Value for SCB->AIRCR register bit PRIS
+*/
+#define SCB_AIRCR_PRIS_VAL 0
+
+/*
+// BusFault, HardFault, and NMI target
+// <0=> Secure state
+// <1=> Non-Secure state
+// Value for SCB->AIRCR register bit BFHFNMINS
+*/
+#define SCB_AIRCR_BFHFNMINS_VAL 0
+
+/*
+//
+*/
+
+/*
+// Setup behaviour of Floating Point Unit
+*/
+#define TZ_FPU_NS_USAGE 1
+
+/*
+// Floating Point Unit usage
+// <0=> Secure state only
+// <3=> Secure and Non-Secure state
+// Value for SCB->NSACR register bits CP10, CP11
+*/
+#define SCB_NSACR_CP10_11_VAL 3
+
+/*
+// Treat floating-point registers as Secure
+// <0=> Disabled
+// <1=> Enabled
+// Value for FPU->FPCCR register bit TS
+*/
+#define FPU_FPCCR_TS_VAL 0
+
+/*
+// Clear on return (CLRONRET) accessibility
+// <0=> Secure and Non-Secure state
+// <1=> Secure state only
+// Value for FPU->FPCCR register bit CLRONRETS
+*/
+#define FPU_FPCCR_CLRONRETS_VAL 0
+
+/*
+// Clear floating-point caller saved registers on exception return
+// <0=> Disabled
+// <1=> Enabled
+// Value for FPU->FPCCR register bit CLRONRET
+*/
+#define FPU_FPCCR_CLRONRET_VAL 1
+
+/*
+//
+*/
+
+/*
+// Setup Interrupt Target
+*/
+
+/*
+// Initialize ITNS 0 (Interrupts 0..31)
+*/
+#define NVIC_INIT_ITNS0 1
+
+/*
+// Interrupts 0..31
+// PVD_IRQn <0=> Secure state <1=> Non-Secure state
+// Reserved <0=> Secure state <1=> Non-Secure state
+// DTS_IRQn <0=> Secure state <1=> Non-Secure state
+// RCC_IRQn <0=> Secure state <1=> Non-Secure state
+// LOCKUP_IRQn <0=> Secure state <1=> Non-Secure state
+// CACHE_ECC_IRQn <0=> Secure state <1=> Non-Secure state
+// TCM_ECC_IRQn <0=> Secure state <1=> Non-Secure state
+// BKP_ECC_IRQn <0=> Secure state <1=> Non-Secure state
+// FPU_IRQn <0=> Secure state <1=> Non-Secure state
+// Reserved <0=> Secure state <1=> Non-Secure state
+// RTC_S_IRQn <0=> Secure state <1=> Non-Secure state
+// TAMP_IRQn <0=> Secure state <1=> Non-Secure state
+// RIFSC_TAMPER_IRQn <0=> Secure state <1=> Non-Secure state
+// IAC_IRQn <0=> Secure state <1=> Non-Secure state
+// RCC_S_IRQn <0=> Secure state <1=> Non-Secure state
+// Reserved <0=> Secure state <1=> Non-Secure state
+// RTC_IRQn <0=> Secure state <1=> Non-Secure state
+// Reserved <0=> Secure state <1=> Non-Secure state
+// IWDG_IRQn <0=> Secure state <1=> Non-Secure state
+// WWDG_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI0_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI1_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI2_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI3_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI4_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI5_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI6_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI7_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI8_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI9_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI10_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI11_IRQn <0=> Secure state <1=> Non-Secure state
+*/
+#define NVIC_INIT_ITNS0_VAL 0x00000000
+
+/*
+//
+*/
+
+/*
+// Initialize ITNS 1 (Interrupts 32..63)
+*/
+#define NVIC_INIT_ITNS1 1
+
+/*
+// Interrupts 32..63
+// EXTI12_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI13_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI14_IRQn <0=> Secure state <1=> Non-Secure state
+// EXTI15_IRQn <0=> Secure state <1=> Non-Secure state
+// SAES_IRQn <0=> Secure state <1=> Non-Secure state
+// CRYP_IRQn <0=> Secure state <1=> Non-Secure state
+// PKA_IRQn <0=> Secure state <1=> Non-Secure state
+// HASH_IRQn <0=> Secure state <1=> Non-Secure state
+// RNG_IRQn <0=> Secure state <1=> Non-Secure state
+// Reserved <0=> Secure state <1=> Non-Secure state
+// MCE1_IRQn <0=> Secure state <1=> Non-Secure state
+// MCE2_IRQn <0=> Secure state <1=> Non-Secure state
+// MCE3_IRQn <0=> Secure state <1=> Non-Secure state
+// MCE4_IRQn <0=> Secure state <1=> Non-Secure state
+// ADC1_2_IRQn <0=> Secure state <1=> Non-Secure state
+// CSI_IRQn <0=> Secure state <1=> Non-Secure state
+// DCMIPP_IRQn <0=> Secure state <1=> Non-Secure state
+// Reserved <0=> Secure state <1=> Non-Secure state
+// Reserved <0=> Secure state <1=> Non-Secure state
+// Reserved <0=> Secure state <1=> Non-Secure state
+// PAHB_ERR_IRQn <0=> Secure state <1=> Non-Secure state
+// NPU0_IRQn <0=> Secure state <1=> Non-Secure state
+// NPU1_IRQn <0=> Secure state <1=> Non-Secure state
+// NPU2_IRQn <0=> Secure state <1=> Non-Secure state
+// NPU3_IRQn <0=> Secure state <1=> Non-Secure state
+// CACHEAXI_IRQn <0=> Secure state <1=> Non-Secure state
+// LTDC_LO_IRQn <0=> Secure state <1=> Non-Secure state
+// LTDC_LO_ERR_IRQn <0=> Secure state <1=> Non-Secure state
+// DMA2D_IRQn <0=> Secure state <1=> Non-Secure state
+// JPEG_IRQn <0=> Secure state <1=> Non-Secure state
+// VENC_IRQn <0=> Secure state <1=> Non-Secure state
+// GFXMMU_IRQn <0=> Secure state <1=> Non-Secure state
+*/
+#define NVIC_INIT_ITNS1_VAL 0x00000000
+
+/*
+//
+*/
+
+/*
+// Initialize ITNS 2 (Interrupts 64..95)
+*/
+#define NVIC_INIT_ITNS2 1
+
+/*
+// Interrupts 64..95
+// GFXTIM_IRQn <0=> Secure state <1=> Non-Secure state
+// GPU2D_IRQn <0=> Secure state <1=> Non-Secure state
+// GPU2D_ER_IRQn <0=> Secure state <1=> Non-Secure state
+// ICACHE_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel0_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel1_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel2_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel3_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel4_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel5_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel6_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel7_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel8_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel9_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel10_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel11_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel12_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel13_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel14_IRQn <0=> Secure state <1=> Non-Secure state
+// HPDMA1_Channel15_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel0_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel1_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel2_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel3_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel4_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel5_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel6_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel7_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel8_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel9_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel10_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel11_IRQn <0=> Secure state <1=> Non-Secure state
+*/
+#define NVIC_INIT_ITNS2_VAL 0x00000000
+
+/*
+//
+*/
+
+/*
+// Initialize ITNS 3 (Interrupts 96..127)
+*/
+#define NVIC_INIT_ITNS3 1
+
+/*
+// Interrupts 96..127
+// GPDMA1_Channel12_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel13_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel14_IRQn <0=> Secure state <1=> Non-Secure state
+// GPDMA1_Channel15_IRQn <0=> Secure state <1=> Non-Secure state
+// I2C1_EV_IRQn <0=> Secure state <1=> Non-Secure state
+// I2C1_ER_IRQn <0=> Secure state <1=> Non-Secure state
+// I2C2_EV_IRQn <0=> Secure state <1=> Non-Secure state
+// I2C2_ER_IRQn <0=> Secure state <1=> Non-Secure state
+// I2C3_EV_IRQn <0=> Secure state <1=> Non-Secure state
+// I2C3_ER_IRQn <0=> Secure state <1=> Non-Secure state
+// I2C4_EV_IRQn <0=> Secure state <1=> Non-Secure state
+// I2C4_ER_IRQn <0=> Secure state <1=> Non-Secure state
+// I3C1_EV_IRQn <0=> Secure state <1=> Non-Secure state
+// I3C1_ER_IRQn <0=> Secure state <1=> Non-Secure state
+// I3C2_EV_IRQn <0=> Secure state <1=> Non-Secure state
+// I3C2_ER_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM1_BRK_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM1_UP_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM1_TRG_COM_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM1_CC_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM2_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM3_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM4_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM5_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM6_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM7_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM8_BRK_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM8_UP_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM8_TRG_COM_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM8_CC_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM9_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM10_IRQn <0=> Secure state <1=> Non-Secure state
+
+*/
+#define NVIC_INIT_ITNS3_VAL 0x00000000
+
+/*
+//
+*/
+
+/*
+// Initialize ITNS 4 (Interrupts 128..159)
+*/
+#define NVIC_INIT_ITNS4 1
+
+/*
+// Interrupts 128..159
+// TIM11_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM12_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM13_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM14_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM15_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM16_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM17_IRQn <0=> Secure state <1=> Non-Secure state
+// TIM18_IRQn <0=> Secure state <1=> Non-Secure state
+// LPTIM1_IRQn <0=> Secure state <1=> Non-Secure state
+// LPTIM2_IRQn <0=> Secure state <1=> Non-Secure state
+// LPTIM3_IRQn <0=> Secure state <1=> Non-Secure state
+// LPTIM4_IRQn <0=> Secure state <1=> Non-Secure state
+// LPTIM5_IRQn <0=> Secure state <1=> Non-Secure state
+// ADF1_FLT0_IRQn <0=> Secure state <1=> Non-Secure state
+// MDF1_FLT0_IRQn <0=> Secure state <1=> Non-Secure state
+// MDF1_FLT1_IRQn <0=> Secure state <1=> Non-Secure state
+// MDF1_FLT2_IRQn <0=> Secure state <1=> Non-Secure state
+// MDF1_FLT3_IRQn <0=> Secure state <1=> Non-Secure state
+// MDF1_FLT4_IRQn <0=> Secure state <1=> Non-Secure state
+// MDF1_FLT5_IRQn <0=> Secure state <1=> Non-Secure state
+// SAI1_A_IRQn <0=> Secure state <1=> Non-Secure state
+// SAI1_B_IRQn <0=> Secure state <1=> Non-Secure state
+// SAI2_A_IRQn <0=> Secure state <1=> Non-Secure state
+// SAI2_B_IRQn <0=> Secure state <1=> Non-Secure state
+// SPDIFRX1_IRQn <0=> Secure state <1=> Non-Secure state
+// SPI1_IRQn <0=> Secure state <1=> Non-Secure state
+// SPI2_IRQn <0=> Secure state <1=> Non-Secure state
+// SPI3_IRQn <0=> Secure state <1=> Non-Secure state
+// SPI4_IRQn <0=> Secure state <1=> Non-Secure state
+// SPI5_IRQn <0=> Secure state <1=> Non-Secure state
+// SPI6_IRQn <0=> Secure state <1=> Non-Secure state
+// USART1_IRQn <0=> Secure state <1=> Non-Secure state
+
+*/
+#define NVIC_INIT_ITNS4_VAL 0x00000000
+
+/*
+//
+*/
+
+/*
+// Initialize ITNS 5 (Interrupts 160..191)
+*/
+#define NVIC_INIT_ITNS5 1
+
+/*
+// Interrupts 160..191
+// USART2_IRQn <0=> Secure state <1=> Non-Secure state
+// USART3_IRQn <0=> Secure state <1=> Non-Secure state
+// UART4_IRQn <0=> Secure state <1=> Non-Secure state
+// UART5_IRQn <0=> Secure state <1=> Non-Secure state
+// USART6_IRQn <0=> Secure state <1=> Non-Secure state
+// UART7_IRQn <0=> Secure state <1=> Non-Secure state
+// UART8_IRQn <0=> Secure state <1=> Non-Secure state
+// UART9_IRQn <0=> Secure state <1=> Non-Secure state
+// USART10_IRQn <0=> Secure state <1=> Non-Secure state
+// LPUART1_IRQn <0=> Secure state <1=> Non-Secure state
+// XSPI1_IRQn <0=> Secure state <1=> Non-Secure state
+// XSPI2_IRQn <0=> Secure state <1=> Non-Secure state
+// XSPI3_IRQn <0=> Secure state <1=> Non-Secure state
+// FMC_IRQn <0=> Secure state <1=> Non-Secure state
+// SDMMC1_IRQn <0=> Secure state <1=> Non-Secure state
+// SDMMC2_IRQn <0=> Secure state <1=> Non-Secure state
+// UCPD1_IRQn <0=> Secure state <1=> Non-Secure state
+// USB1_OTG_HS_IRQn <0=> Secure state <1=> Non-Secure state
+// USB2_OTG_HS_IRQn <0=> Secure state <1=> Non-Secure state
+// ETH1_IRQn <0=> Secure state <1=> Non-Secure state
+// FDCAN1_IT0_IRQn <0=> Secure state <1=> Non-Secure state
+// FDCAN1_IT1_IRQn <0=> Secure state <1=> Non-Secure state
+// FDCAN2_IT0_IRQn <0=> Secure state <1=> Non-Secure state
+// FDCAN2_IT1_IRQn <0=> Secure state <1=> Non-Secure state
+// FDCAN3_IT0_IRQn <0=> Secure state <1=> Non-Secure state
+// FDCAN3_IT1_IRQn <0=> Secure state <1=> Non-Secure state
+// FDCAN_CU_IRQn <0=> Secure state <1=> Non-Secure state
+// MDIOS_IRQn <0=> Secure state <1=> Non-Secure state
+// DCMI_PSSI_IRQn <0=> Secure state <1=> Non-Secure state
+// WAKEUP_PIN_IRQn <0=> Secure state <1=> Non-Secure state
+// CTI_INT0_IRQn <0=> Secure state <1=> Non-Secure state
+// CTI_INT1_IRQn <0=> Secure state <1=> Non-Secure state
+
+*/
+#define NVIC_INIT_ITNS5_VAL 0x00000000
+
+/*
+//
+*/
+
+/*
+// Initialize ITNS 6 (Interrupts 192..223)
+*/
+#define NVIC_INIT_ITNS6 1
+
+/*
+// Interrupts 192..223
+// Reserved <0=> Secure state <1=> Non-Secure state
+// LTDC_UP_IRQn <0=> Secure state <1=> Non-Secure state
+// LTDC_UP_ERR_IRQn <0=> Secure state <1=> Non-Secure state
+
+*/
+#define NVIC_INIT_ITNS6_VAL 0x00000000
+
+/*
+//
+*/
+
+/*
+//
+*/
+
+
+
+/*
+ max 8 SAU regions.
+ SAU regions are defined in partition.h
+ */
+
+#define SAU_INIT_REGION(n) \
+ SAU->RNR = (n & SAU_RNR_REGION_Msk); \
+ SAU->RBAR = (SAU_INIT_START##n & SAU_RBAR_BADDR_Msk); \
+ SAU->RLAR = (SAU_INIT_END##n & SAU_RLAR_LADDR_Msk) | \
+ ((SAU_INIT_NSC##n << SAU_RLAR_NSC_Pos) & SAU_RLAR_NSC_Msk) | 1U
+
+/**
+ \brief Setup a SAU Region
+ \details Writes the region information contained in SAU_Region to the
+ registers SAU_RNR, SAU_RBAR, and SAU_RLAR
+ */
+__STATIC_INLINE void TZ_SAU_Setup (void)
+{
+
+#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U)
+
+ #if defined (SAU_INIT_REGION0) && (SAU_INIT_REGION0 == 1U)
+ SAU_INIT_REGION(0);
+ #endif
+
+ #if defined (SAU_INIT_REGION1) && (SAU_INIT_REGION1 == 1U)
+ SAU_INIT_REGION(1);
+ #endif
+
+ #if defined (SAU_INIT_REGION2) && (SAU_INIT_REGION2 == 1U)
+ SAU_INIT_REGION(2);
+ #endif
+
+ #if defined (SAU_INIT_REGION3) && (SAU_INIT_REGION3 == 1U)
+ SAU_INIT_REGION(3);
+ #endif
+
+ #if defined (SAU_INIT_REGION4) && (SAU_INIT_REGION4 == 1U)
+ SAU_INIT_REGION(4);
+ #endif
+
+ #if defined (SAU_INIT_REGION5) && (SAU_INIT_REGION5 == 1U)
+ SAU_INIT_REGION(5);
+ #endif
+
+ #if defined (SAU_INIT_REGION6) && (SAU_INIT_REGION6 == 1U)
+ SAU_INIT_REGION(6);
+ #endif
+
+ #if defined (SAU_INIT_REGION7) && (SAU_INIT_REGION7 == 1U)
+ SAU_INIT_REGION(7);
+ #endif
+
+ /* repeat this for all possible SAU regions */
+
+#endif /* defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) */
+
+
+ #if defined (SAU_INIT_CTRL) && (SAU_INIT_CTRL == 1U)
+ SAU->CTRL = ((SAU_INIT_CTRL_ENABLE << SAU_CTRL_ENABLE_Pos) & SAU_CTRL_ENABLE_Msk) |
+ ((SAU_INIT_CTRL_ALLNS << SAU_CTRL_ALLNS_Pos) & SAU_CTRL_ALLNS_Msk) ;
+ #endif
+
+ #if defined (SCB_CSR_AIRCR_INIT) && (SCB_CSR_AIRCR_INIT == 1U)
+ SCB->SCR = (SCB->SCR & ~(SCB_SCR_SLEEPDEEPS_Msk )) |
+ ((SCB_CSR_DEEPSLEEPS_VAL << SCB_SCR_SLEEPDEEPS_Pos) & SCB_SCR_SLEEPDEEPS_Msk);
+
+ SCB->AIRCR = (SCB->AIRCR & ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_SYSRESETREQS_Msk |
+ SCB_AIRCR_BFHFNMINS_Msk | SCB_AIRCR_PRIS_Msk) ) |
+ ((0x05FAU << SCB_AIRCR_VECTKEY_Pos) & SCB_AIRCR_VECTKEY_Msk) |
+ ((SCB_AIRCR_SYSRESETREQS_VAL << SCB_AIRCR_SYSRESETREQS_Pos) & SCB_AIRCR_SYSRESETREQS_Msk) |
+ ((SCB_AIRCR_PRIS_VAL << SCB_AIRCR_PRIS_Pos) & SCB_AIRCR_PRIS_Msk) |
+ ((SCB_AIRCR_BFHFNMINS_VAL << SCB_AIRCR_BFHFNMINS_Pos) & SCB_AIRCR_BFHFNMINS_Msk);
+ #endif /* defined (SCB_CSR_AIRCR_INIT) && (SCB_CSR_AIRCR_INIT == 1U) */
+
+ #if defined (__FPU_USED) && (__FPU_USED == 1U) && \
+ defined (TZ_FPU_NS_USAGE) && (TZ_FPU_NS_USAGE == 1U)
+
+ SCB->NSACR = (SCB->NSACR & ~(SCB_NSACR_CP10_Msk | SCB_NSACR_CP11_Msk)) |
+ ((SCB_NSACR_CP10_11_VAL << SCB_NSACR_CP10_Pos) & (SCB_NSACR_CP10_Msk | SCB_NSACR_CP11_Msk));
+
+ FPU->FPCCR = (FPU->FPCCR & ~(FPU_FPCCR_TS_Msk | FPU_FPCCR_CLRONRETS_Msk | FPU_FPCCR_CLRONRET_Msk)) |
+ ((FPU_FPCCR_TS_VAL << FPU_FPCCR_TS_Pos ) & FPU_FPCCR_TS_Msk ) |
+ ((FPU_FPCCR_CLRONRETS_VAL << FPU_FPCCR_CLRONRETS_Pos) & FPU_FPCCR_CLRONRETS_Msk) |
+ ((FPU_FPCCR_CLRONRET_VAL << FPU_FPCCR_CLRONRET_Pos ) & FPU_FPCCR_CLRONRET_Msk );
+ #endif
+
+ #if defined (NVIC_INIT_ITNS0) && (NVIC_INIT_ITNS0 == 1U)
+ NVIC->ITNS[0] = NVIC_INIT_ITNS0_VAL;
+ #endif
+
+ #if defined (NVIC_INIT_ITNS1) && (NVIC_INIT_ITNS1 == 1U)
+ NVIC->ITNS[1] = NVIC_INIT_ITNS1_VAL;
+ #endif
+
+ #if defined (NVIC_INIT_ITNS2) && (NVIC_INIT_ITNS2 == 1U)
+ NVIC->ITNS[2] = NVIC_INIT_ITNS2_VAL;
+ #endif
+
+ #if defined (NVIC_INIT_ITNS3) && (NVIC_INIT_ITNS3 == 1U)
+ NVIC->ITNS[3] = NVIC_INIT_ITNS3_VAL;
+ #endif
+
+ #if defined (NVIC_INIT_ITNS4) && (NVIC_INIT_ITNS4 == 1U)
+ NVIC->ITNS[4] = NVIC_INIT_ITNS4_VAL;
+ #endif
+
+ #if defined (NVIC_INIT_ITNS5) && (NVIC_INIT_ITNS5 == 1U)
+ NVIC->ITNS[5] = NVIC_INIT_ITNS5_VAL;
+ #endif
+
+ #if defined (NVIC_INIT_ITNS6) && (NVIC_INIT_ITNS6 == 1U)
+ NVIC->ITNS[6] = NVIC_INIT_ITNS6_VAL;
+ #endif
+
+}
+
+#endif /* PARTITION_STM32N657XX_H */
diff --git a/hw/bsp/stm32n6/stm32n6xx_hal_conf.h b/hw/bsp/stm32n6/stm32n6xx_hal_conf.h
new file mode 100644
index 000000000..00cb31159
--- /dev/null
+++ b/hw/bsp/stm32n6/stm32n6xx_hal_conf.h
@@ -0,0 +1,504 @@
+/**
+ ******************************************************************************
+ * @file stm32n6xx_hal_conf_template.h
+ * @author MCD Application Team
+ * @brief HAL configuration template file.
+ * This file should be copied to the application folder and renamed
+ * to stm32n6xx_hal_conf.h.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2023 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef STM32N6xx_HAL_CONF_H
+#define STM32N6xx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* ########################## Module Selection ############################## */
+/**
+ * @brief This is the list of modules to be used in the HAL driver
+ */
+#define HAL_MODULE_ENABLED
+/*#define HAL_ADC_MODULE_ENABLED */
+/*#define HAL_BSEC_MODULE_ENABLED */
+/*#define HAL_CRC_MODULE_ENABLED */
+/*#define HAL_CRYP_MODULE_ENABLED */
+/*#define HAL_DCMI_MODULE_ENABLED */
+/*#define HAL_DCMIPP_MODULE_ENABLED */
+/*#define HAL_DMA2D_MODULE_ENABLED */
+/*#define HAL_DTS_MODULE_ENABLED */
+/*#define HAL_ETH_MODULE_ENABLED */
+/*#define HAL_EXTI_MODULE_ENABLED */
+/*#define HAL_FDCAN_MODULE_ENABLED */
+/*#define HAL_GFXMMU_MODULE_ENABLED */
+/*#define HAL_GFXTIM_MODULE_ENABLED */
+/*#define HAL_HASH_MODULE_ENABLED */
+/*#define HAL_HCD_MODULE_ENABLED */
+#define HAL_I2C_MODULE_ENABLED
+/*#define HAL_I2S_MODULE_ENABLED */
+/*#define HAL_I3C_MODULE_ENABLED */
+/*#define HAL_ICACHE_MODULE_ENABLED */
+/*#define HAL_IRDA_MODULE_ENABLED */
+/*#define HAL_IWDG_MODULE_ENABLED */
+/*#define HAL_JPEG_MODULE_ENABLED */
+/*#define HAL_LPTIM_MODULE_ENABLED */
+/*#define HAL_LTDC_MODULE_ENABLED */
+/*#define HAL_MCE_MODULE_ENABLED */
+/*#define HAL_MDF_MODULE_ENABLED */
+/*#define HAL_MMC_MODULE_ENABLED */
+/*#define HAL_NAND_MODULE_ENABLED */
+/*#define HAL_NOR_MODULE_ENABLED */
+/*#define HAL_PCD_MODULE_ENABLED */
+/*#define HAL_PKA_MODULE_ENABLED */
+/*#define HAL_PSSI_MODULE_ENABLED */
+/*#define HAL_RAMCFG_MODULE_ENABLED */
+/*#define HAL_RIF_MODULE_ENABLED */
+/*#define HAL_RNG_MODULE_ENABLED */
+/*#define HAL_RTC_MODULE_ENABLED */
+/*#define HAL_SAI_MODULE_ENABLED */
+/*#define HAL_SD_MODULE_ENABLED */
+/*#define HAL_SDIO_MODULE_ENABLED */
+/*#define HAL_SDRAM_MODULE_ENABLED */
+/*#define HAL_SMARTCARD_MODULE_ENABLED*/
+/*#define HAL_SMBUS_MODULE_ENABLED */
+/*#define HAL_SPDIFRX_MODULE_ENABLED */
+/*#define HAL_SPI_MODULE_ENABLED */
+/*#define HAL_SRAM_MODULE_ENABLED */
+/*#define HAL_TIM_MODULE_ENABLED */
+#define HAL_UART_MODULE_ENABLED
+/*#define HAL_USART_MODULE_ENABLED */
+/*#define HAL_WWDG_MODULE_ENABLED */
+/*#define HAL_XSPI_MODULE_ENABLED */
+/*#define HAL_CACHEAXI_MODULE_ENABLED */
+/*#define HAL_MDIOS_MODULE_ENABLED */
+/*#define HAL_GPU2D_MODULE_ENABLED */
+/*#define HAL_CACHEAXI_MODULE_ENABLED */
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_EXTI_MODULE_ENABLED
+#define HAL_DMA_MODULE_ENABLED
+#define HAL_RCC_MODULE_ENABLED
+#define HAL_PWR_MODULE_ENABLED
+#define HAL_CORTEX_MODULE_ENABLED
+
+/* ########################## Oscillator Values adaptation ####################*/
+/**
+ * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSE is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSE_VALUE)
+#define HSE_VALUE 48000000UL /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSE_STARTUP_TIMEOUT)
+#define HSE_STARTUP_TIMEOUT 100UL /*!< Time out for HSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief External Low Speed oscillator (LSE) value.
+ * This value is used by the UART, RTC HAL module to compute the system frequency
+ */
+#if !defined (LSE_VALUE)
+#define LSE_VALUE 32768UL /*!< Value of the External oscillator in Hz */
+#endif /* LSE_VALUE */
+
+#if !defined (LSE_STARTUP_TIMEOUT)
+#define LSE_STARTUP_TIMEOUT 5000UL /*!< Time out for LSE start up, in ms */
+#endif /* LSE_STARTUP_TIMEOUT */
+
+/**
+ * @brief Internal Multiple Speed oscillator (MSI) default value.
+ * This value is the default MSI range value after Reset.
+ */
+#if !defined (MSI_VALUE)
+#define MSI_VALUE 4000000UL /*!< Value of the Internal oscillator in Hz */
+#endif /* MSI_VALUE */
+
+/**
+ * @brief Internal High Speed oscillator (HSI) value.
+ * This value is used by the RCC HAL module to compute the system frequency
+ * (when HSI is used as system clock source, directly or through the PLL).
+ */
+#if !defined (HSI_VALUE)
+#define HSI_VALUE 64000000UL /*!< Value of the Internal oscillator in Hz */
+#endif /* HSI_VALUE */
+
+/**
+ * @brief Internal Low Speed oscillator (LSI) value.
+ */
+#if !defined (LSI_VALUE)
+#define LSI_VALUE 32000UL /*!< LSI Typical Value in Hz */
+#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz */
+/* The real value may vary depending on the variations in voltage and temperature.*/
+
+/* Tip: To avoid modifying this file each time you need to use different HSE,
+ === you can define the HSE value in your toolchain compiler preprocessor. */
+
+/* ########################### System Configuration ######################### */
+/**
+ * @brief This is the HAL system configuration section
+ */
+#define VDD_VALUE 3300UL /*!< Value of VDD in mv */
+#define TICK_INT_PRIORITY 15U /*!< tick interrupt priority (lowest by default) */
+#define USE_RTOS 0U
+
+/* ########################## Assert Selection ############################## */
+/**
+ * @brief Uncomment the line below to expanse the "assert_param" macro in the
+ * HAL drivers code
+ */
+/* #define USE_FULL_ASSERT 1U */
+
+/* ################## Register callback feature configuration ############### */
+/**
+ * @brief Set below the peripheral configuration to "1U" to add the support
+ * of HAL callback registration/unregistration feature for the HAL
+ * driver(s). This allows user application to provide specific callback
+ * functions thanks to HAL_PPP_RegisterCallback() rather than overwriting
+ * the default weak callback functions (see each stm32n6xx_hal_ppp.h file
+ * for possible callback identifiers defined in HAL_PPP_CallbackIDTypeDef
+ * for each PPP peripheral).
+ */
+#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
+#define USE_HAL_CACHEAXI_REGISTER_CALLBACKS 0U /* CACHEAXI register callback disabled */
+#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */
+#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U /* DCMI register callback disabled */
+#define USE_HAL_DCMIPP_REGISTER_CALLBACKS 0U /* DCMIPP register callback disabled */
+#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U /* DMA2D register callback disabled */
+#define USE_HAL_DTS_REGISTER_CALLBACKS 0U /* DTS register callback disabled */
+#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */
+#define USE_HAL_FDCAN_REGISTER_CALLBACKS 0U /* FDCAN register callback disabled */
+#define USE_HAL_GFXMMU_REGISTER_CALLBACKS 0U /* GFXMMU register callback disabled */
+#define USE_HAL_GFXTIM_REGISTER_CALLBACKS 0U /* GFXTIM register callback disabled */
+#define USE_HAL_HASH_REGISTER_CALLBACKS 0U /* HASH register callback disabled */
+#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */
+#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */
+#define USE_HAL_I2S_REGISTER_CALLBACKS 0U /* I2S register callback disabled */
+#define USE_HAL_I3C_REGISTER_CALLBACKS 0U /* I3C register callback disabled */
+#define USE_HAL_IWDG_REGISTER_CALLBACKS 0U /* IWDG register callback disabled */
+#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */
+#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */
+#define USE_HAL_LTDC_REGISTER_CALLBACKS 0U /* LTDC register callback disabled */
+#define USE_HAL_MCE_REGISTER_CALLBACKS 0U /* MCE register callback disabled */
+#define USE_HAL_MDF_REGISTER_CALLBACKS 0U /* MDF register callback disabled */
+#define USE_HAL_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */
+#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */
+#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */
+#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */
+#define USE_HAL_PKA_REGISTER_CALLBACKS 0U /* PKA register callback disabled */
+#define USE_HAL_PSSI_REGISTER_CALLBACKS 0U /* PSSI register callback disabled */
+#define USE_HAL_RAMCFG_REGISTER_CALLBACKS 0U /* RAMCFG register callback disabled */
+#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */
+#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */
+#define USE_HAL_SAI_REGISTER_CALLBACKS 0U /* SAI register callback disabled */
+#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */
+#define USE_HAL_SDIO_REGISTER_CALLBACKS 0U /* SDIO register callback disabled */
+#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U /* SDRAM register callback disabled */
+#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */
+#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U /* SMBUS register callback disabled */
+#define USE_HAL_SPDIFRX_REGISTER_CALLBACKS 0U /* SPDIFRX register callback disabled */
+#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */
+#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */
+#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */
+#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */
+#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */
+#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */
+#define USE_HAL_XSPI_REGISTER_CALLBACKS 0U /* XSPI register callback disabled */
+
+/* ################## SPI peripheral configuration ########################## */
+
+/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
+ * Activated: CRC code is present inside driver
+ * Deactivated: CRC code cleaned from driver
+ */
+#define USE_SPI_CRC 0U
+
+/* ################## SDMMC peripheral configuration ######################### */
+
+#define USE_SD_TRANSCEIVER 0U
+
+/* ################## SDIO peripheral configuration ########################## */
+#define USE_SDIO_TRANSCEIVER 1U
+#define SDIO_MAX_IO_NUMBER 7U /*!< SDIO device support maximum IO number */
+
+/* Includes ------------------------------------------------------------------*/
+/**
+ * @brief Include module's header file
+ */
+#ifdef HAL_RCC_MODULE_ENABLED
+#include "stm32n6xx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+#include "stm32n6xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_RIF_MODULE_ENABLED
+#include "stm32n6xx_hal_rif.h"
+#endif /* HAL_RIF_MODULE_ENABLED */
+
+#ifdef HAL_DMA_MODULE_ENABLED
+#include "stm32n6xx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_CACHEAXI_MODULE_ENABLED
+#include "stm32n6xx_hal_cacheaxi.h"
+#endif /* HAL_CACHEAXI_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+#include "stm32n6xx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+#include "stm32n6xx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_BSEC_MODULE_ENABLED
+#include "stm32n6xx_hal_bsec.h"
+#endif /* HAL_BSEC_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+#include "stm32n6xx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+#include "stm32n6xx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_DCMI_MODULE_ENABLED
+#include "stm32n6xx_hal_dcmi.h"
+#endif /* HAL_DCMI_MODULE_ENABLED */
+
+#ifdef HAL_DCMIPP_MODULE_ENABLED
+#include "stm32n6xx_hal_dcmipp.h"
+#endif /* HAL_DCMIPP_MODULE_ENABLED */
+
+#ifdef HAL_DMA2D_MODULE_ENABLED
+#include "stm32n6xx_hal_dma2d.h"
+#endif /* HAL_DMA2D_MODULE_ENABLED */
+
+#ifdef HAL_DTS_MODULE_ENABLED
+#include "stm32n6xx_hal_dts.h"
+#endif /* HAL_DTS_MODULE_ENABLED */
+
+#ifdef HAL_ETH_MODULE_ENABLED
+#include "stm32n6xx_hal_eth.h"
+#endif /* HAL_ETH_MODULE_ENABLED */
+
+#ifdef HAL_EXTI_MODULE_ENABLED
+#include "stm32n6xx_hal_exti.h"
+#endif /* HAL_EXTI_MODULE_ENABLED */
+
+#ifdef HAL_FDCAN_MODULE_ENABLED
+#include "stm32n6xx_hal_fdcan.h"
+#endif /* HAL_FDCAN_MODULE_ENABLED */
+
+#ifdef HAL_GFXMMU_MODULE_ENABLED
+#include "stm32n6xx_hal_gfxmmu.h"
+#endif /* HAL_GFXMMU_MODULE_ENABLED */
+
+#ifdef HAL_GFXTIM_MODULE_ENABLED
+#include "stm32n6xx_hal_gfxtim.h"
+#endif /* HAL_GFXTIM_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+#include "stm32n6xx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_GPU2D_MODULE_ENABLED
+#include "stm32n6xx_hal_gpu2d.h"
+#endif /* HAL_GPU2D_MODULE_ENABLED */
+
+#ifdef HAL_HASH_MODULE_ENABLED
+#include "stm32n6xx_hal_hash.h"
+#endif /* HAL_HASH_MODULE_ENABLED */
+
+#ifdef HAL_HCD_MODULE_ENABLED
+#include "stm32n6xx_hal_hcd.h"
+#endif /* HAL_HCD_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+#include "stm32n6xx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_I2S_MODULE_ENABLED
+ #include "stm32n6xx_hal_i2s.h"
+#endif /* HAL_I2S_MODULE_ENABLED */
+
+#ifdef HAL_I3C_MODULE_ENABLED
+#include "stm32n6xx_hal_i3c.h"
+#endif /* HAL_I3C_MODULE_ENABLED */
+
+#ifdef HAL_ICACHE_MODULE_ENABLED
+#include "stm32n6xx_hal_icache.h"
+#endif /* HAL_ICACHE_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+#include "stm32n6xx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+#include "stm32n6xx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_JPEG_MODULE_ENABLED
+#include "stm32n6xx_hal_jpeg.h"
+#endif /* HAL_JPEG_MODULE_ENABLED */
+
+#ifdef HAL_LPTIM_MODULE_ENABLED
+#include "stm32n6xx_hal_lptim.h"
+#endif /* HAL_LPTIM_MODULE_ENABLED */
+
+#ifdef HAL_LTDC_MODULE_ENABLED
+#include "stm32n6xx_hal_ltdc.h"
+#endif /* HAL_LTDC_MODULE_ENABLED */
+
+#ifdef HAL_MCE_MODULE_ENABLED
+#include "stm32n6xx_hal_mce.h"
+#endif /* HAL_MCE_MODULE_ENABLED */
+
+#ifdef HAL_MDF_MODULE_ENABLED
+#include "stm32n6xx_hal_mdf.h"
+#endif /* HAL_MDF_MODULE_ENABLED */
+
+#ifdef HAL_MDIOS_MODULE_ENABLED
+#include "stm32n6xx_hal_mdios.h"
+#endif /* HAL_MDIOS_MODULE_ENABLED */
+
+#ifdef HAL_MMC_MODULE_ENABLED
+#include "stm32n6xx_hal_mmc.h"
+#endif /* HAL_MMC_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+#include "stm32n6xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_NOR_MODULE_ENABLED
+#include "stm32n6xx_hal_nor.h"
+#endif /* HAL_NOR_MODULE_ENABLED */
+
+#ifdef HAL_NAND_MODULE_ENABLED
+#include "stm32n6xx_hal_nand.h"
+#endif /* HAL_NAND_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+#include "stm32n6xx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_PKA_MODULE_ENABLED
+#include "stm32n6xx_hal_pka.h"
+#endif /* HAL_PKA_MODULE_ENABLED */
+
+#ifdef HAL_PSSI_MODULE_ENABLED
+#include "stm32n6xx_hal_pssi.h"
+#endif /* HAL_PSSI_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+#include "stm32n6xx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_RAMCFG_MODULE_ENABLED
+#include "stm32n6xx_hal_ramcfg.h"
+#endif /* HAL_RAMCFG_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+#include "stm32n6xx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+#include "stm32n6xx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+#include "stm32n6xx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SD_MODULE_ENABLED
+#include "stm32n6xx_hal_sd.h"
+#endif /* HAL_SD_MODULE_ENABLED */
+
+#ifdef HAL_SDIO_MODULE_ENABLED
+#include "stm32n6xx_hal_sdio.h"
+#endif /* HAL_SDIO_MODULE_ENABLED */
+
+#ifdef HAL_SDRAM_MODULE_ENABLED
+#include "stm32n6xx_hal_sdram.h"
+#endif /* HAL_SDRAM_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+#include "stm32n6xx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_SMBUS_MODULE_ENABLED
+#include "stm32n6xx_hal_smbus.h"
+#endif /* HAL_SMBUS_MODULE_ENABLED */
+
+#ifdef HAL_SPDIFRX_MODULE_ENABLED
+#include "stm32n6xx_hal_spdifrx.h"
+#endif /* HAL_SPDIFRX_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+#include "stm32n6xx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_SRAM_MODULE_ENABLED
+#include "stm32n6xx_hal_sram.h"
+#endif /* HAL_SRAM_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+#include "stm32n6xx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+#include "stm32n6xx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+#include "stm32n6xx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+#include "stm32n6xx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+#ifdef HAL_XSPI_MODULE_ENABLED
+#include "stm32n6xx_hal_xspi.h"
+#endif /* HAL_XSPI_MODULE_ENABLED */
+
+/* Exported macros -----------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+void assert_failed(uint8_t *file, uint32_t line);
+#else
+#define assert_param(expr) ((void)0U)
+#endif /* USE_FULL_ASSERT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STM32N6xx_HAL_CONF_H */
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..3694b1ca0 100644
--- a/hw/bsp/stm32u5/family.mk
+++ b/hw/bsp/stm32u5/family.mk
@@ -1,5 +1,4 @@
ST_FAMILY = u5
-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
@@ -57,5 +56,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/hw/bsp/xmc4000/family.mk b/hw/bsp/xmc4000/family.mk
index a1679a2f0..4eed7360a 100644
--- a/hw/bsp/xmc4000/family.mk
+++ b/hw/bsp/xmc4000/family.mk
@@ -1,8 +1,6 @@
UF2_FAMILY_ID = 0x00
SDK_DIR = hw/mcu/infineon/mtb-xmclib-cat3
-DEPS_SUBMODULES += ${SDK_DIR}
-
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= cortex-m4
diff --git a/hw/bsp/zephyr_board_aliases.cmake b/hw/bsp/zephyr_board_aliases.cmake
index 91ffc3a39..b60e97ef4 100644
--- a/hw/bsp/zephyr_board_aliases.cmake
+++ b/hw/bsp/zephyr_board_aliases.cmake
@@ -1 +1,2 @@
set(pca10056_BOARD_ALIAS nrf52840dk/nrf52840)
+set(stm32n657nucleo_BOARD_ALIAS nucleo_n657x0_q)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 55c52033c..99d3059fc 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,9 +1,6 @@
-# TODO more docs and example on how to use this file
-# TINYUSB_TARGET_PREFIX and TINYUSB_TARGET_SUFFIX can be used to change the name of the target
-
cmake_minimum_required(VERSION 3.20)
-# Add tinyusb to a existing target
+# Add tinyusb to a existing target, DCD and HCD drivers are not included
function(tinyusb_target_add TARGET)
target_sources(${TARGET} PRIVATE
# common
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index 388168424..a877dc900 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -108,19 +108,19 @@
#endif
// Put swap buffer in USB section only if necessary
-#if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING
+#if USE_LINEAR_BUFFER
#define IN_SW_BUF_MEM_ATTR TU_ATTR_ALIGNED(4)
#else
#define IN_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN
#endif
-#if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING
+#if USE_LINEAR_BUFFER
#define OUT_SW_BUF_MEM_ATTR TU_ATTR_ALIGNED(4)
#else
#define OUT_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN
#endif
// EP IN software buffers and mutexes
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
tu_static IN_SW_BUF_MEM_ATTR struct {
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ);
@@ -144,12 +144,11 @@ tu_static IN_SW_BUF_MEM_ATTR struct {
tu_static osal_mutex_def_t ep_in_ff_mutex_wr_3;
#endif
#endif
-#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+#endif// CFG_TUD_AUDIO_ENABLE_EP_IN
// Linear buffer TX in case:
// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR
-// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && USE_LINEAR_BUFFER
tu_static CFG_TUD_MEM_SECTION struct {
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0
TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX);
@@ -161,10 +160,10 @@ tu_static CFG_TUD_MEM_SECTION struct {
TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX);
#endif
} lin_buf_in;
-#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
+#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && USE_LINEAR_BUFFER
// EP OUT software buffers and mutexes
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
tu_static OUT_SW_BUF_MEM_ATTR struct {
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ);
@@ -188,12 +187,11 @@ tu_static OUT_SW_BUF_MEM_ATTR struct {
tu_static osal_mutex_def_t ep_out_ff_mutex_rd_3;
#endif
#endif
-#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT
// Linear buffer RX in case:
// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR
-// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && USE_LINEAR_BUFFER
tu_static CFG_TUD_MEM_SECTION struct {
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0
TUD_EPBUF_DEF(buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX);
@@ -205,18 +203,18 @@ tu_static CFG_TUD_MEM_SECTION struct {
TUD_EPBUF_DEF(buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX);
#endif
} lin_buf_out;
-#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
+#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && USE_LINEAR_BUFFER
// Control buffers
-tu_static uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
-
-#if CFG_TUD_AUDIO > 1
-tu_static uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
-#endif
-
-#if CFG_TUD_AUDIO > 2
-tu_static uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
-#endif
+tu_static CFG_TUD_MEM_SECTION struct {
+ TUD_EPBUF_DEF(buf1, CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ);
+ #if CFG_TUD_AUDIO > 1
+ TUD_EPBUF_DEF(buf2, CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ);
+ #endif
+ #if CFG_TUD_AUDIO > 2
+ TUD_EPBUF_DEF(buf3, CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ);
+ #endif
+} ctrl_buf;
// Active alternate setting of interfaces
tu_static uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
@@ -229,59 +227,6 @@ tu_static uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
#endif
-// Software encoding/decoding support FIFOs
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
- #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
- tu_static TU_ATTR_ALIGNED(4) uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ];
- tu_static tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
- #if CFG_FIFO_MUTEX
- tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];// No need for read mutex as only USB driver reads from FIFO
- #endif
- #endif
-
- #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
- tu_static TU_ATTR_ALIGNED(4) uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ];
- tu_static tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];
- #if CFG_FIFO_MUTEX
- tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];// No need for read mutex as only USB driver reads from FIFO
- #endif
- #endif
-
- #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
- tu_static TU_ATTR_ALIGNED(4) uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ];
- tu_static tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
- #if CFG_FIFO_MUTEX
- tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];// No need for read mutex as only USB driver reads from FIFO
- #endif
- #endif
-#endif
-
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
- #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
- tu_static TU_ATTR_ALIGNED(4) uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ];
- tu_static tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];
- #if CFG_FIFO_MUTEX
- tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];// No need for write mutex as only USB driver writes into FIFO
- #endif
- #endif
-
- #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
- tu_static TU_ATTR_ALIGNED(4) uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ];
- tu_static tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];
- #if CFG_FIFO_MUTEX
- tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];// No need for write mutex as only USB driver writes into FIFO
- #endif
- #endif
-
- #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
- tu_static TU_ATTR_ALIGNED(4) uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ];
- tu_static tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO];
- #if CFG_FIFO_MUTEX
- tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO];// No need for write mutex as only USB driver writes into FIFO
- #endif
- #endif
-#endif
-
// Aligned buffer for feedback EP
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
tu_static CFG_TUD_MEM_SECTION struct {
@@ -363,19 +308,6 @@ typedef struct
} feedback;
#endif// CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-// Decoding parameters - parameters are set when alternate AS interface is set by host
-// Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently.
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
- audio_format_type_t format_type_rx;
- uint8_t n_channels_rx;
-
- #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
- audio_data_format_type_I_t format_type_I_rx;
- uint8_t n_bytes_per_sample_rx;
- uint8_t n_ff_used_rx;
- #endif
-#endif
-
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
uint32_t sample_rate_tx;
uint16_t packet_sz_tx[3];
@@ -384,15 +316,10 @@ typedef struct
#endif
// Encoding parameters - parameters are set when alternate AS interface is set by host
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL)
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
audio_format_type_t format_type_tx;
uint8_t n_channels_tx;
uint8_t n_bytes_per_sample_tx;
-
- #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
- audio_data_format_type_I_t format_type_I_tx;
- uint8_t n_ff_used_tx;
- #endif
#endif
/*------------- From this point, data is not cleared by bus reset -------------*/
@@ -405,40 +332,21 @@ typedef struct
uint8_t *alt_setting;// We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP!
// EP Transfer buffers and FIFOs
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
tu_fifo_t ep_out_ff;
#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
tu_fifo_t ep_in_ff;
#endif
-// Support FIFOs for software encoding and decoding
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
- tu_fifo_t *rx_supp_ff;
- uint8_t n_rx_supp_ff;
- uint16_t rx_supp_ff_sz_max;
- #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
- uint8_t n_channels_per_ff_rx;
- #endif
-#endif
-
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
- tu_fifo_t *tx_supp_ff;
- uint8_t n_tx_supp_ff;
- uint16_t tx_supp_ff_sz_max;
- #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
- uint8_t n_channels_per_ff_tx;
- #endif
-#endif
-
-// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
+// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && USE_LINEAR_BUFFER
uint8_t *lin_buf_out;
#define USE_LINEAR_BUFFER_RX 1
#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && USE_LINEAR_BUFFER
uint8_t *lin_buf_in;
#define USE_LINEAR_BUFFER_TX 1
#endif
@@ -604,18 +512,10 @@ tu_static CFG_TUD_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO];
static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received);
#endif
-#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
-static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received);
-#endif
-
#if CFG_TUD_AUDIO_ENABLE_EP_IN
static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t *audio);
#endif
-#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
-static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t *audio);
-#endif
-
static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const *p_request);
static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p_request);
@@ -626,11 +526,8 @@ static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id);
static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id);
static uint8_t audiod_get_audio_fct_idx(audiod_function_t *audio);
-#if (CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_ENCODING)) || (CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING)
-static void audiod_parse_for_AS_params(audiod_function_t *audio, uint8_t const *p_desc, uint8_t const *p_desc_end, uint8_t const as_itf);
-#endif
-
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+static void audiod_parse_flow_control_params(audiod_function_t *audio, uint8_t const *p_desc);
static bool audiod_calc_tx_packet_sz(audiod_function_t *audio);
static uint16_t audiod_tx_packet_size(const uint16_t *norminal_size, uint16_t data_count, uint16_t fifo_depth, uint16_t max_size);
#endif
@@ -651,7 +548,7 @@ bool tud_audio_n_mounted(uint8_t func_id) {
// READ API
//--------------------------------------------------------------------+
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
uint16_t tud_audio_n_available(uint8_t func_id) {
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
@@ -673,36 +570,7 @@ tu_fifo_t *tud_audio_n_get_ep_out_ff(uint8_t func_id) {
return NULL;
}
-#endif
-
-#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
-// Delete all content in the support RX FIFOs
-bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx) {
- TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
- return tu_fifo_clear(&_audiod_fct[func_id].rx_supp_ff[ff_idx]);
-}
-
-uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx) {
- TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
- return tu_fifo_count(&_audiod_fct[func_id].rx_supp_ff[ff_idx]);
-}
-
-uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void *buffer, uint16_t bufsize) {
- TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
- return tu_fifo_read_n(&_audiod_fct[func_id].rx_supp_ff[ff_idx], buffer, bufsize);
-}
-
-tu_fifo_t *tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx) {
- if (func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff) return &_audiod_fct[func_id].rx_supp_ff[ff_idx];
- return NULL;
-}
-#endif
-
-// This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO (or support FIFOs + decoding of received stream into audio channels).
-// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_DECODING = 0.
-
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT
-
+// This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO.
static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received) {
uint8_t idxItf = 0;
uint8_t const *dummy2;
@@ -711,62 +579,24 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t *audio, uint16_t
idx_audio_fct = audiod_get_audio_fct_idx(audio);
TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2));
- // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO)
+ // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO
TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
- #if CFG_TUD_AUDIO_ENABLE_DECODING
-
- switch (audio->format_type_rx) {
- case AUDIO_FORMAT_TYPE_UNDEFINED:
- // INDIVIDUAL DECODING PROCEDURE REQUIRED HERE!
- TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n");
- TU_BREAKPOINT();
- break;
-
- case AUDIO_FORMAT_TYPE_I:
-
- switch (audio->format_type_I_rx) {
- case AUDIO_DATA_FORMAT_TYPE_I_PCM:
- TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received));
- break;
-
- default:
- // DESIRED CFG_TUD_AUDIO_FORMAT_TYPE_I_RX NOT IMPLEMENTED!
- TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_RX encoding not implemented!\r\n");
- TU_BREAKPOINT();
- break;
- }
- break;
-
- default:
- // Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!
- TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!\r\n");
- TU_BREAKPOINT();
- break;
- }
-
- // Prepare for next transmission
- TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
-
- #else
-
- #if USE_LINEAR_BUFFER_RX
+ #if USE_LINEAR_BUFFER_RX
// Data currently is in linear buffer, copy into EP OUT FIFO
TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received));
// Schedule for next receive
TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
- #else
+ #else
// Data is already placed in EP FIFO, schedule for next receive
TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false);
- #endif
+ #endif
- #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+ #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
if (audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT) {
audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->ep_out_ff));
}
- #endif
-
#endif
// Call a weak callback here - a possibility for user to get informed decoding was completed
@@ -777,103 +607,11 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t *audio, uint16_t
#endif//CFG_TUD_AUDIO_ENABLE_EP_OUT
-// The following functions are used in case CFG_TUD_AUDIO_ENABLE_DECODING != 0
-#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
-
-// Decoding according to 2.3.1.5 Audio Streams
-
-// Helper function
-static inline void *audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesPerSample, void *dst, const void *dst_end, void *src, uint8_t const n_ff_used) {
- // Due to one FIFO contains 2 channels, data always aligned to (nBytesPerSample * 2)
- uint16_t *dst16 = dst;
- uint16_t *src16 = src;
- const uint16_t *dst_end16 = dst_end;
- uint32_t *dst32 = dst;
- uint32_t *src32 = src;
- const uint32_t *dst_end32 = dst_end;
-
- if (nBytesPerSample == 1) {
- while (dst16 < dst_end16) {
- *dst16++ = *src16++;
- src16 += n_ff_used - 1;
- }
- return src16;
- } else if (nBytesPerSample == 2) {
- while (dst32 < dst_end32) {
- *dst32++ = *src32++;
- src32 += n_ff_used - 1;
- }
- return src32;
- } else if (nBytesPerSample == 3) {
- while (dst16 < dst_end16) {
- *dst16++ = *src16++;
- *dst16++ = *src16++;
- *dst16++ = *src16++;
- src16 += 3 * (n_ff_used - 1);
- }
- return src16;
- } else// nBytesPerSample == 4
- {
- while (dst32 < dst_end32) {
- *dst32++ = *src32++;
- *dst32++ = *src32++;
- src32 += 2 * (n_ff_used - 1);
- }
- return src32;
- }
-}
-
-static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received) {
- (void) rhport;
-
- // Determine amount of samples
- uint8_t const n_ff_used = audio->n_ff_used_rx;
- uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used;
- uint8_t cnt_ff;
-
- // Decode
- uint8_t *src;
- uint8_t *dst_end;
-
- tu_fifo_buffer_info_t info;
-
- for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) {
- tu_fifo_get_write_info(&audio->rx_supp_ff[cnt_ff], &info);
-
- if (info.len_lin != 0) {
- info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin);
- src = &audio->lin_buf_out[cnt_ff * audio->n_channels_per_ff_rx * audio->n_bytes_per_sample_rx];
- dst_end = info.ptr_lin + info.len_lin;
- src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_lin, dst_end, src, n_ff_used);
-
- // Handle wrapped part of FIFO
- info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap);
- if (info.len_wrap != 0) {
- dst_end = info.ptr_wrap + info.len_wrap;
- audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_wrap, dst_end, src, n_ff_used);
- }
- tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
- }
- }
-
- // Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it
- // TU_VERIFY(cnt != n_bytes);
-
- #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
- if (audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT) {
- audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->rx_supp_ff[0]));
- }
- #endif
-
- return true;
-}
-#endif//CFG_TUD_AUDIO_ENABLE_DECODING
-
//--------------------------------------------------------------------+
// WRITE API
//--------------------------------------------------------------------+
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
/**
* \brief Write data to EP in buffer
@@ -902,43 +640,47 @@ tu_fifo_t *tud_audio_n_get_ep_in_ff(uint8_t func_id) {
return NULL;
}
-#endif
+// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission.
+// n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame.
+static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t *audio) {
+ uint8_t idxItf;
+ uint8_t const *dummy2;
-#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
+ uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio);
+ TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio, &idxItf, &dummy2));
-uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id)// Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit
-{
- TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
- audiod_function_t *audio = &_audiod_fct[func_id];
+ // Only send something if current alternate interface is not 0 as in this case nothing is to be sent due to UAC2 specifications
+ if (audio->alt_setting[idxItf] == 0) return false;
- uint16_t n_bytes_copied = tu_fifo_count(&audio->tx_supp_ff[0]);
+ // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or
+ // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer().
+ TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
- TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio));
+ // Send everything in ISO EP FIFO
+ uint16_t n_bytes_tx;
- n_bytes_copied -= tu_fifo_count(&audio->tx_supp_ff[0]);
- n_bytes_copied = n_bytes_copied * audio->tx_supp_ff[0].item_size;
+ #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+ // packet_sz_tx is based on total packet size
+ n_bytes_tx = audiod_tx_packet_size(audio->packet_sz_tx, tu_fifo_count(&audio->ep_in_ff), audio->ep_in_ff.depth, audio->ep_in_sz);
+ #else
+ n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz);// Limit up to max packet size, more can not be done for ISO
+ #endif
+ #if USE_LINEAR_BUFFER_TX
+ tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx);
+ TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
+ #else
+ // Send everything in ISO EP FIFO
+ TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx));
+ #endif
- return n_bytes_copied;
-}
+ // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame
+ TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
-bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx) {
- TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
- return tu_fifo_clear(&_audiod_fct[func_id].tx_supp_ff[ff_idx]);
-}
-
-uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void *data, uint16_t len) {
- TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
- return tu_fifo_write_n(&_audiod_fct[func_id].tx_supp_ff[ff_idx], data, len);
-}
-
-tu_fifo_t *tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) {
- if (func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff) return &_audiod_fct[func_id].tx_supp_ff[ff_idx];
- return NULL;
+ return true;
}
#endif
-
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_done_cb() is called in inform user
bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t *data) {
@@ -962,223 +704,8 @@ bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t *data)
}
#endif
-// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission.
-// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_ENCODING = 0 and use tud_audio_n_write.
-
-// n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame.
-#if CFG_TUD_AUDIO_ENABLE_EP_IN
-static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t *audio) {
- uint8_t idxItf;
- uint8_t const *dummy2;
-
- uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio);
- TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio, &idxItf, &dummy2));
-
- // Only send something if current alternate interface is not 0 as in this case nothing is to be sent due to UAC2 specifications
- if (audio->alt_setting[idxItf] == 0) return false;
-
- // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or
- // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer().
- TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
-
- // Send everything in ISO EP FIFO
- uint16_t n_bytes_tx;
-
- // If support FIFOs are used, encode and schedule transmit
- #if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
- switch (audio->format_type_tx) {
- case AUDIO_FORMAT_TYPE_UNDEFINED:
- // INDIVIDUAL ENCODING PROCEDURE REQUIRED HERE!
- TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n");
- TU_BREAKPOINT();
- n_bytes_tx = 0;
- break;
-
- case AUDIO_FORMAT_TYPE_I:
-
- switch (audio->format_type_I_tx) {
- case AUDIO_DATA_FORMAT_TYPE_I_PCM:
-
- n_bytes_tx = audiod_encode_type_I_pcm(rhport, audio);
- break;
-
- default:
- // YOUR ENCODING IS REQUIRED HERE!
- TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_TX encoding not implemented!\r\n");
- TU_BREAKPOINT();
- n_bytes_tx = 0;
- break;
- }
- break;
-
- default:
- // Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!
- TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n");
- TU_BREAKPOINT();
- n_bytes_tx = 0;
- break;
- }
-
- TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
-
- #else
- // No support FIFOs, if no linear buffer required schedule transmit, else put data into linear buffer and schedule
- #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
- // packet_sz_tx is based on total packet size, here we want size for each support buffer.
- n_bytes_tx = audiod_tx_packet_size(audio->packet_sz_tx, tu_fifo_count(&audio->ep_in_ff), audio->ep_in_ff.depth, audio->ep_in_sz);
- #else
- n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz);// Limit up to max packet size, more can not be done for ISO
- #endif
- #if USE_LINEAR_BUFFER_TX
- tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx);
- TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
- #else
- // Send everything in ISO EP FIFO
- TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx));
- #endif
-
- #endif
-
- // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame
- TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
-
- return true;
-}
-
-#endif//CFG_TUD_AUDIO_ENABLE_EP_IN
-
-#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
-// Take samples from the support buffer and encode them into the IN EP software FIFO
-// Returns number of bytes written into linear buffer
-
-/* 2.3.1.7.1 PCM Format
-The PCM (Pulse Coded Modulation) format is the most commonly used audio format to represent audio
-data streams. The audio data is not compressed and uses a signed two’s-complement fixed point format. It
-is left-justified (the sign bit is the Msb) and data is padded with trailing zeros to fill the remaining unused
-bits of the subslot. The binary point is located to the right of the sign bit so that all values lie within the
-range [-1, +1)
- */
-
-/*
- * This function encodes channels saved within the support FIFOs into one stream by interleaving the PCM samples
- * in the support FIFOs according to 2.3.1.5 Audio Streams. It does not control justification (left or right) and
- * does not change the number of bytes per sample.
- * */
-
-// Helper function
-static inline void *audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesPerSample, void *src, const void *src_end, void *dst, uint8_t const n_ff_used) {
- // Due to one FIFO contains 2 channels, data always aligned to (nBytesPerSample * 2)
- uint16_t *dst16 = dst;
- uint16_t *src16 = src;
- const uint16_t *src_end16 = src_end;
- uint32_t *dst32 = dst;
- uint32_t *src32 = src;
- const uint32_t *src_end32 = src_end;
-
- if (nBytesPerSample == 1) {
- while (src16 < src_end16) {
- *dst16++ = *src16++;
- dst16 += n_ff_used - 1;
- }
- return dst16;
- } else if (nBytesPerSample == 2) {
- while (src32 < src_end32) {
- *dst32++ = *src32++;
- dst32 += n_ff_used - 1;
- }
- return dst32;
- } else if (nBytesPerSample == 3) {
- while (src16 < src_end16) {
- *dst16++ = *src16++;
- *dst16++ = *src16++;
- *dst16++ = *src16++;
- dst16 += 3 * (n_ff_used - 1);
- }
- return dst16;
- } else// nBytesPerSample == 4
- {
- while (src32 < src_end32) {
- *dst32++ = *src32++;
- *dst32++ = *src32++;
- dst32 += 2 * (n_ff_used - 1);
- }
- return dst32;
- }
-}
-
-static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t *audio) {
- // This function relies on the fact that the length of the support FIFOs was configured to be a multiple of the active sample size in bytes s.t. no sample is split within a wrap
- // This is ensured within set_interface, where the FIFOs are reconfigured according to this size
-
- // We encode directly into IN EP's linear buffer - abort if previous transfer not complete
- TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in));
-
- // Determine amount of samples
- uint8_t const n_ff_used = audio->n_ff_used_tx;
- uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]);
- uint8_t cnt_ff;
-
- for (cnt_ff = 1; cnt_ff < n_ff_used; cnt_ff++) {
- uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]);
- if (count < nBytesPerFFToSend) {
- nBytesPerFFToSend = count;
- }
- }
-
- #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
- const uint16_t norm_packet_sz_tx[3] = {audio->packet_sz_tx[0] / n_ff_used,
- audio->packet_sz_tx[1] / n_ff_used,
- audio->packet_sz_tx[2] / n_ff_used};
- // packet_sz_tx is based on total packet size, here we want size for each support buffer.
- nBytesPerFFToSend = audiod_tx_packet_size(norm_packet_sz_tx, nBytesPerFFToSend, audio->tx_supp_ff[0].depth, audio->ep_in_sz / n_ff_used);
- // Check if there is enough data
- if (nBytesPerFFToSend == 0) return 0;
- #else
- // Check if there is enough data
- if (nBytesPerFFToSend == 0) return 0;
- // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT!
- nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, audio->ep_in_sz / n_ff_used);
- // Round to full number of samples (flooring)
- uint16_t const nSlotSize = audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx;
- nBytesPerFFToSend = (nBytesPerFFToSend / nSlotSize) * nSlotSize;
- #endif
-
- // Encode
- uint8_t *dst;
- uint8_t *src_end;
-
- tu_fifo_buffer_info_t info;
-
- for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) {
- dst = &audio->lin_buf_in[cnt_ff * audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx];
-
- tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info);
-
- if (info.len_lin != 0) {
- info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin);// Limit up to desired length
- src_end = (uint8_t *) info.ptr_lin + info.len_lin;
- dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_lin, src_end, dst, n_ff_used);
-
- // Limit up to desired length
- info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap);
-
- // Handle wrapped part of FIFO
- if (info.len_wrap != 0) {
- src_end = (uint8_t *) info.ptr_wrap + info.len_wrap;
- audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_wrap, src_end, dst, n_ff_used);
- }
-
- tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
- }
- }
-
- return nBytesPerFFToSend * n_ff_used;
-}
-#endif//CFG_TUD_AUDIO_ENABLE_ENCODING
-
-// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent
-
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent
static inline bool audiod_fb_send(audiod_function_t *audio) {
bool apply_correction = (TUSB_SPEED_FULL == tud_speed_get()) && audio->feedback.format_correction;
// Format the feedback value
@@ -1223,18 +750,18 @@ void audiod_init(void) {
// Initialize control buffers
switch (i) {
case 0:
- audio->ctrl_buf = ctrl_buf_1;
+ audio->ctrl_buf = ctrl_buf.buf1;
audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ;
break;
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ > 0
case 1:
- audio->ctrl_buf = ctrl_buf_2;
+ audio->ctrl_buf = ctrl_buf.buf2;
audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ;
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ > 0
case 2:
- audio->ctrl_buf = ctrl_buf_3;
+ audio->ctrl_buf = ctrl_buf.buf3;
audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ;
break;
#endif
@@ -1260,7 +787,7 @@ void audiod_init(void) {
}
// Initialize IN EP FIFO if required
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
switch (i) {
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
@@ -1288,7 +815,7 @@ void audiod_init(void) {
break;
#endif
}
-#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+#endif// CFG_TUD_AUDIO_ENABLE_EP_IN
// Initialize linear buffers
#if USE_LINEAR_BUFFER_TX
@@ -1312,7 +839,7 @@ void audiod_init(void) {
#endif// USE_LINEAR_BUFFER_TX
// Initialize OUT EP FIFO if required
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
switch (i) {
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
@@ -1340,7 +867,7 @@ void audiod_init(void) {
break;
#endif
}
-#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT
// Initialize linear buffers
#if USE_LINEAR_BUFFER_RX
@@ -1382,150 +909,6 @@ void audiod_init(void) {
#endif
}
#endif// CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-
- // Initialize TX support FIFOs if required
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
-
- switch (i) {
- #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
- case 0:
- audio->tx_supp_ff = tx_supp_ff_1;
- audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO;
- audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ;
- for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++) {
- tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true);
- #if CFG_FIFO_MUTEX
- tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_1[cnt]), NULL);
- #endif
- }
-
- break;
- #endif// CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
-
- #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
- case 1:
- audio->tx_supp_ff = tx_supp_ff_2;
- audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO;
- audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ;
- for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++) {
- tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true);
- #if CFG_FIFO_MUTEX
- tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_2[cnt]), NULL);
- #endif
- }
-
- break;
- #endif// CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
-
- #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
- case 2:
- audio->tx_supp_ff = tx_supp_ff_3;
- audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO;
- audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ;
- for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++) {
- tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true);
- #if CFG_FIFO_MUTEX
- tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_3[cnt]), NULL);
- #endif
- }
-
- break;
- #endif// CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
- }
-#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
-
- // Set encoding parameters for Type_I formats
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
- switch (i) {
- #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
- case 0:
- audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX;
- break;
- #endif
- #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
- case 1:
- audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX;
- break;
- #endif
- #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
- case 2:
- audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX;
- break;
- #endif
- }
-#endif// CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
-
- // Initialize RX support FIFOs if required
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
-
- switch (i) {
- #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
- case 0:
- audio->rx_supp_ff = rx_supp_ff_1;
- audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO;
- audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ;
- for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++) {
- tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true);
- #if CFG_FIFO_MUTEX
- tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_1[cnt]), NULL);
- #endif
- }
-
- break;
- #endif// CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
-
- #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
- case 1:
- audio->rx_supp_ff = rx_supp_ff_2;
- audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO;
- audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ;
- for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++) {
- tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true);
- #if CFG_FIFO_MUTEX
- tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_2[cnt]), NULL);
- #endif
- }
-
- break;
- #endif// CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
-
- #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
- case 2:
- audio->rx_supp_ff = rx_supp_ff_3;
- audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO;
- audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ;
- for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++) {
- tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true);
- #if CFG_FIFO_MUTEX
- tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_3[cnt]), NULL);
- #endif
- }
-
- break;
- #endif// CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
- }
-#endif// CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
-
- // Set encoding parameters for Type_I formats
-#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
- switch (i) {
- #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
- case 0:
- audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX;
- break;
- #endif
- #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
- case 1:
- audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX;
- break;
- #endif
- #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
- case 2:
- audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX;
- break;
- #endif
- }
-#endif// CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
}
}
@@ -1540,25 +923,13 @@ void audiod_reset(uint8_t rhport) {
audiod_function_t *audio = &_audiod_fct[i];
tu_memclr(audio, ITF_MEM_RESET_SIZE);
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
tu_fifo_clear(&audio->ep_in_ff);
#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
tu_fifo_clear(&audio->ep_out_ff);
#endif
-
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
- for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) {
- tu_fifo_clear(&audio->tx_supp_ff[cnt]);
- }
-#endif
-
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
- for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) {
- tu_fifo_clear(&audio->rx_supp_ff[cnt]);
- }
-#endif
}
}
@@ -1632,20 +1003,22 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint
ep_fb = desc_ep->bEndpointAddress;
}
#endif
- // Data EP
- if (desc_ep->bmAttributes.usage == 0) {
- if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
#if CFG_TUD_AUDIO_ENABLE_EP_IN
- ep_in = desc_ep->bEndpointAddress;
- ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size);
- #endif
- } else {
- #if CFG_TUD_AUDIO_ENABLE_EP_OUT
- ep_out = desc_ep->bEndpointAddress;
- ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size);
- #endif
- }
+ // Data or data with implicit feedback IN EP
+ if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN
+ && (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) {
+ ep_in = desc_ep->bEndpointAddress;
+ ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size);
}
+ #endif
+ #if CFG_TUD_AUDIO_ENABLE_EP_OUT
+ // Data OUT EP
+ if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT
+ && desc_ep->bmAttributes.usage == 0) {
+ ep_out = desc_ep->bEndpointAddress;
+ ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size);
+ }
+ #endif
}
}
@@ -1681,10 +1054,10 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint
if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) {
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
- if (desc_ep->bmAttributes.usage == 0) {
- if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
- _audiod_fct[i].interval_tx = desc_ep->bInterval;
- }
+ // For data or data with implicit feedback IN EP
+ if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN
+ && (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) {
+ _audiod_fct[i].interval_tx = desc_ep->bInterval;
}
}
} else if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL) {
@@ -1783,13 +1156,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
#endif
// Clear FIFOs, since data is no longer valid
- #if !CFG_TUD_AUDIO_ENABLE_ENCODING
tu_fifo_clear(&audio->ep_in_ff);
- #else
- for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) {
- tu_fifo_clear(&audio->tx_supp_ff[cnt]);
- }
- #endif
// Invoke callback - can be used to stop data sampling
TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
@@ -1812,13 +1179,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
#endif
// Clear FIFOs, since data is no longer valid
- #if !CFG_TUD_AUDIO_ENABLE_DECODING
tu_fifo_clear(&audio->ep_out_ff);
- #else
- for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) {
- tu_fifo_clear(&audio->rx_supp_ff[cnt]);
- }
- #endif
// Invoke callback - can be used to stop data sampling
TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
@@ -1848,7 +1209,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
while (p_desc_end - p_desc > 0) {
// Find correct interface
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *) p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const *) p_desc)->bAlternateSetting == alt) {
-#if (CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_ENCODING)) || (CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING)
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
uint8_t const *p_desc_parse_for_params = p_desc;
#endif
// From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary
@@ -1868,28 +1229,18 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
usbd_edpt_clear_stall(rhport, ep_addr);
#if CFG_TUD_AUDIO_ENABLE_EP_IN
- if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00)// Check if usage is data EP
+ // For data or data with implicit feedback IN EP
+ if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2))
{
// Save address
audio->ep_in = ep_addr;
audio->ep_in_as_intf_num = itf;
audio->ep_in_sz = tu_edpt_packet_size(desc_ep);
- // If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters
- #if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
- audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf);
-
- // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap
- #if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
- const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx)) * (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx));
- for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) {
- tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
- }
- audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx;
- TU_ASSERT(audio->n_ff_used_tx <= audio->n_tx_supp_ff);
- #endif
+ // If flow control is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters
+ #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+ audiod_parse_flow_control_params(audio, p_desc_parse_for_params);
#endif
-
// Schedule first transmit if alternate interface is not zero i.e. streaming is disabled - in case no sample data is available a ZLP is loaded
// It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there
TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id]));
@@ -1897,7 +1248,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
#endif// CFG_TUD_AUDIO_ENABLE_EP_IN
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
-
if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT)// Checking usage not necessary
{
// Save address
@@ -1905,20 +1255,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
audio->ep_out_as_intf_num = itf;
audio->ep_out_sz = tu_edpt_packet_size(desc_ep);
- #if CFG_TUD_AUDIO_ENABLE_DECODING
- audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf);
-
- // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap
- #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
- const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sample_rx) * audio->n_bytes_per_sample_rx;
- for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) {
- tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
- }
- audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx;
- TU_ASSERT(audio->n_ff_used_rx <= audio->n_rx_supp_ff);
- #endif
- #endif
-
// Prepare for incoming data
#if USE_LINEAR_BUFFER_RX
TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
@@ -1971,12 +1307,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
case AUDIO_FEEDBACK_METHOD_FIFO_COUNT: {
// Initialize the threshold level to half filled
- uint16_t fifo_lvl_thr;
- #if CFG_TUD_AUDIO_ENABLE_DECODING
- fifo_lvl_thr = tu_fifo_depth(&audio->rx_supp_ff[0]) / 2;
- #else
- fifo_lvl_thr = tu_fifo_depth(&audio->ep_out_ff) / 2;
- #endif
+ uint16_t fifo_lvl_thr = tu_fifo_depth(&audio->ep_out_ff) / 2;
audio->feedback.compute.fifo_count.fifo_lvl_thr = fifo_lvl_thr;
audio->feedback.compute.fifo_count.fifo_lvl_avg = ((uint32_t) fifo_lvl_thr) << 16;
// Avoid 64bit division
@@ -2555,86 +1886,22 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) {
return false;
}
-#if (CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_ENCODING)) || (CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING)
-// p_desc points to the AS interface of alternate setting zero
-// itf is the interface number of the corresponding interface - we check if the interface belongs to EP in or EP out to see if it is a TX or RX parameter
-// Currently, only AS interfaces with an EP (in or out) are supposed to be parsed for!
-static void audiod_parse_for_AS_params(audiod_function_t *audio, uint8_t const *p_desc, uint8_t const *p_desc_end, uint8_t const as_itf) {
- #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) return;// Abort, this interface has no EP, this driver does not support this currently
- #endif
- #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (as_itf != audio->ep_in_as_intf_num) return;
- #endif
- #if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (as_itf != audio->ep_out_as_intf_num) return;
- #endif
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
+static void audiod_parse_flow_control_params(audiod_function_t *audio, uint8_t const *p_desc) {
p_desc = tu_desc_next(p_desc);// Exclude standard AS interface descriptor of current alternate interface descriptor
- // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
- while (p_desc_end - p_desc > 0) {
- // Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished
- if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break;
-
- // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels
- if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) {
- #if CFG_TUD_AUDIO_ENABLE_EP_IN
- if (as_itf == audio->ep_in_as_intf_num) {
- audio->n_channels_tx = ((audio_desc_cs_as_interface_t const *) p_desc)->bNrChannels;
- audio->format_type_tx = (audio_format_type_t) (((audio_desc_cs_as_interface_t const *) p_desc)->bFormatType);
-
- #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
- audio->format_type_I_tx = (audio_data_format_type_I_t) (((audio_desc_cs_as_interface_t const *) p_desc)->bmFormats);
- #endif
- }
- #endif
-
- #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
- if (as_itf == audio->ep_out_as_intf_num) {
- audio->n_channels_rx = ((audio_desc_cs_as_interface_t const *) p_desc)->bNrChannels;
- audio->format_type_rx = ((audio_desc_cs_as_interface_t const *) p_desc)->bFormatType;
- #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
- audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const *) p_desc)->bmFormats;
- #endif
- }
- #endif
- }
+ // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels
+ if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) {
+ audio->n_channels_tx = ((audio_desc_cs_as_interface_t const *) p_desc)->bNrChannels;
+ audio->format_type_tx = (audio_format_type_t) (((audio_desc_cs_as_interface_t const *) p_desc)->bFormatType);
// Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats)
- #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
- if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const *) p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I) {
- #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break;// Abort loop, this interface has no EP, this driver does not support this currently
- #endif
- #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (as_itf != audio->ep_in_as_intf_num) break;
- #endif
- #if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (as_itf != audio->ep_out_as_intf_num) break;
- #endif
-
- #if CFG_TUD_AUDIO_ENABLE_EP_IN
- if (as_itf == audio->ep_in_as_intf_num) {
- audio->n_bytes_per_sample_tx = ((audio_desc_type_I_format_t const *) p_desc)->bSubslotSize;
- }
- #endif
-
- #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
- if (as_itf == audio->ep_out_as_intf_num) {
- audio->n_bytes_per_sample_rx = ((audio_desc_type_I_format_t const *) p_desc)->bSubslotSize;
- }
- #endif
- }
- #endif
-
- // Other format types are not supported yet
-
p_desc = tu_desc_next(p_desc);
+ if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const *) p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I) {
+ audio->n_bytes_per_sample_tx = ((audio_desc_type_I_format_t const *) p_desc)->bSubslotSize;
+ }
}
}
-#endif
-
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
static bool audiod_calc_tx_packet_sz(audiod_function_t *audio) {
TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I);
diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h
index 0a7bff212..603535b2a 100644
--- a/src/class/audio/audio_device.h
+++ b/src/class/audio/audio_device.h
@@ -206,153 +206,6 @@
// Audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74)
#define CFG_TUD_AUDIO_INTERRUPT_EP_SZ 6
-// Use software encoding/decoding
-
-// The software coding feature of the driver is not mandatory. It is useful if, for instance, you have two I2S streams which need to be interleaved
-// into a single PCM stream as SAMPLE_1 | SAMPLE_2 | SAMPLE_3 | SAMPLE_4.
-//
-// Currently, only PCM type I encoding/decoding is supported!
-//
-// If the coding feature is to be used, support FIFOs need to be configured. Their sizes and numbers are defined below.
-
-// Encoding/decoding is done in software and thus time consuming. If you can encode/decode your stream more efficiently do not use the
-// support FIFOs but write/read directly into/from the EP_X_SW_BUFFER_FIFOs using
-// - tud_audio_n_write() or
-// - tud_audio_n_read().
-// To write/read to/from the support FIFOs use
-// - tud_audio_n_write_support_ff() or
-// - tud_audio_n_read_support_ff().
-//
-// The encoding/decoding format type done is defined below.
-//
-// The encoding/decoding starts when the private callback functions
-// - audio_tx_done_cb()
-// - audio_rx_done_cb()
-// are invoked. If support FIFOs are used, the corresponding encoding/decoding functions are called from there.
-// Once encoding/decoding is done the result is put directly into the EP_X_SW_BUFFER_FIFOs. You can use the public callback functions
-// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb()
-// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb()
-// if you want to get informed what happened.
-//
-// If you don't use the support FIFOs you may use the public callback functions
-// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb()
-// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb()
-// to write/read from/into the EP_X_SW_BUFFER_FIFOs at the right time.
-//
-// If you need a different encoding which is not support so far implement it in the
-// - audio_tx_done_cb()
-// - audio_rx_done_cb()
-// functions.
-
-// Enable encoding/decodings - for these to work, support FIFOs need to be setup in appropriate numbers and size
-// The actual coding parameters of active AS alternate interface is parsed from the descriptors
-
-// The item size of the FIFO is always fixed to one i.e. bytes! Furthermore, the actively used FIFO depth is reconfigured such that the depth is a multiple
-// of the current sample size in order to avoid samples to get split up in case of a wrap in the FIFO ring buffer (depth = (max_depth / sample_sz) * sample_sz)!
-// This is important to remind in case you use DMAs! If the sample sizes changes, the DMA MUST BE RECONFIGURED just like the FIFOs for a different depth!!!
-
-// For PCM encoding/decoding
-
-#ifndef CFG_TUD_AUDIO_ENABLE_ENCODING
-#define CFG_TUD_AUDIO_ENABLE_ENCODING 0
-#endif
-
-#ifndef CFG_TUD_AUDIO_ENABLE_DECODING
-#define CFG_TUD_AUDIO_ENABLE_DECODING 0
-#endif
-
-// This enabling allows to save the current coding parameters e.g. # of bytes per sample etc. - TYPE_I includes common PCM encoding
-#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
-#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING 0
-#endif
-
-#ifndef CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
-#define CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING 0
-#endif
-
-// Type I Coding parameters not given within UAC2 descriptors
-// It would be possible to allow for a more flexible setting and not fix this parameter as done below. However, this is most often not needed and kept for later if really necessary. The more flexible setting could be implemented within set_interface(), however, how the values are saved per alternate setting is to be determined!
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
-#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX
-#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO
-#endif
-#if CFG_TUD_AUDIO > 1
-#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX
-#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO
-#endif
-#endif
-#if CFG_TUD_AUDIO > 2
-#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX
-#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO
-#endif
-#endif
-#endif
-
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
-#ifndef CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX
-#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO
-#endif
-#if CFG_TUD_AUDIO > 1
-#ifndef CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX
-#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO
-#endif
-#endif
-#if CFG_TUD_AUDIO > 2
-#ifndef CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX
-#error You must tell the driver the number of channels per FIFO for the interleaved encoding! E.g. for an I2S interface having two channels, CHANNEL_PER_FIFO = 2 as the I2S stream having two channels is usually saved within one FIFO
-#endif
-#endif
-#endif
-
-// Remaining types not support so far
-
-// Number of support FIFOs to set up - multiple channels can be handled by one FIFO - very common is two channels per FIFO stemming from one I2S interface
-#ifndef CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO
-#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO 0
-#endif
-#ifndef CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO
-#define CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO 0
-#endif
-#ifndef CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO
-#define CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO 0
-#endif
-
-#ifndef CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO
-#define CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO 0
-#endif
-#ifndef CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO
-#define CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO 0
-#endif
-#ifndef CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO
-#define CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO 0
-#endif
-
-// Size of support FIFOs IN BYTES - if size > 0 there are as many FIFOs set up as CFG_TUD_AUDIO_FUNC_X_N_TX_SUPP_SW_FIFO and CFG_TUD_AUDIO_FUNC_X_N_RX_SUPP_SW_FIFO
-#ifndef CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ
-#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of TX channels) / (# of TX support FIFOs) * max(# of bytes per sample)
-#endif
-#ifndef CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ
-#define CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ 0
-#endif
-#ifndef CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ
-#define CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ 0
-#endif
-
-#ifndef CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ
-#define CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ 0 // FIFO size - minimum size: ceil(f_s/1000) * max(# of RX channels) / (# of RX support FIFOs) * max(# of bytes per sample)
-#endif
-#ifndef CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ
-#define CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ 0
-#endif
-#ifndef CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ
-#define CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ 0
-#endif
-
-//static_assert(sizeof(tud_audio_desc_lengths) != CFG_TUD_AUDIO, "Supply audio function descriptor pack length!");
-
-// Supported types of this driver:
-// AUDIO_DATA_FORMAT_TYPE_I_PCM - Required definitions: CFG_TUD_AUDIO_N_CHANNELS and CFG_TUD_AUDIO_BYTES_PER_CHANNEL
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -368,38 +221,23 @@ extern "C" {
//--------------------------------------------------------------------+
bool tud_audio_n_mounted (uint8_t func_id);
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
uint16_t tud_audio_n_available (uint8_t func_id);
uint16_t tud_audio_n_read (uint8_t func_id, void* buffer, uint16_t bufsize);
bool tud_audio_n_clear_ep_out_ff (uint8_t func_id); // Delete all content in the EP OUT FIFO
tu_fifo_t* tud_audio_n_get_ep_out_ff (uint8_t func_id);
#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
-bool tud_audio_n_clear_rx_support_ff (uint8_t func_id, uint8_t ff_idx); // Delete all content in the support RX FIFOs
-uint16_t tud_audio_n_available_support_ff (uint8_t func_id, uint8_t ff_idx);
-uint16_t tud_audio_n_read_support_ff (uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize);
-tu_fifo_t* tud_audio_n_get_rx_support_ff (uint8_t func_id, uint8_t ff_idx);
-#endif
-
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
uint16_t tud_audio_n_write (uint8_t func_id, const void * data, uint16_t len);
bool tud_audio_n_clear_ep_in_ff (uint8_t func_id); // Delete all content in the EP IN FIFO
tu_fifo_t* tud_audio_n_get_ep_in_ff (uint8_t func_id);
#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
-uint16_t tud_audio_n_flush_tx_support_ff (uint8_t func_id); // Force all content in the support TX FIFOs to be written into EP SW FIFO
-bool tud_audio_n_clear_tx_support_ff (uint8_t func_id, uint8_t ff_idx);
-uint16_t tud_audio_n_write_support_ff (uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len);
-tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_idx);
-#endif
-
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
bool tud_audio_int_n_write (uint8_t func_id, const audio_interrupt_data_t * data);
#endif
-
//--------------------------------------------------------------------+
// Application API (Interface0)
//--------------------------------------------------------------------+
@@ -408,35 +246,21 @@ static inline bool tud_audio_mounted (void);
// RX API
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
static inline uint16_t tud_audio_available (void);
static inline bool tud_audio_clear_ep_out_ff (void); // Delete all content in the EP OUT FIFO
static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize);
static inline tu_fifo_t* tud_audio_get_ep_out_ff (void);
#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
-static inline bool tud_audio_clear_rx_support_ff (uint8_t ff_idx);
-static inline uint16_t tud_audio_available_support_ff (uint8_t ff_idx);
-static inline uint16_t tud_audio_read_support_ff (uint8_t ff_idx, void* buffer, uint16_t bufsize);
-static inline tu_fifo_t* tud_audio_get_rx_support_ff (uint8_t ff_idx);
-#endif
-
// TX API
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
static inline uint16_t tud_audio_write (const void * data, uint16_t len);
static inline bool tud_audio_clear_ep_in_ff (void);
static inline tu_fifo_t* tud_audio_get_ep_in_ff (void);
#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
-static inline uint16_t tud_audio_flush_tx_support_ff (void);
-static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t ff_idx);
-static inline uint16_t tud_audio_write_support_ff (uint8_t ff_idx, const void * data, uint16_t len);
-static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx);
-#endif
-
// INT CTR API
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
@@ -593,7 +417,7 @@ static inline bool tud_audio_mounted(void)
// RX API
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT
static inline uint16_t tud_audio_available(void)
{
@@ -617,33 +441,9 @@ static inline tu_fifo_t* tud_audio_get_ep_out_ff(void)
#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
-
-static inline bool tud_audio_clear_rx_support_ff(uint8_t ff_idx)
-{
- return tud_audio_n_clear_rx_support_ff(0, ff_idx);
-}
-
-static inline uint16_t tud_audio_available_support_ff(uint8_t ff_idx)
-{
- return tud_audio_n_available_support_ff(0, ff_idx);
-}
-
-static inline uint16_t tud_audio_read_support_ff(uint8_t ff_idx, void* buffer, uint16_t bufsize)
-{
- return tud_audio_n_read_support_ff(0, ff_idx, buffer, bufsize);
-}
-
-static inline tu_fifo_t* tud_audio_get_rx_support_ff(uint8_t ff_idx)
-{
- return tud_audio_n_get_rx_support_ff(0, ff_idx);
-}
-
-#endif
-
// TX API
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
+#if CFG_TUD_AUDIO_ENABLE_EP_IN
static inline uint16_t tud_audio_write(const void * data, uint16_t len)
{
@@ -662,30 +462,6 @@ static inline tu_fifo_t* tud_audio_get_ep_in_ff(void)
#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
-
-static inline uint16_t tud_audio_flush_tx_support_ff(void)
-{
- return tud_audio_n_flush_tx_support_ff(0);
-}
-
-static inline uint16_t tud_audio_clear_tx_support_ff(uint8_t ff_idx)
-{
- return tud_audio_n_clear_tx_support_ff(0, ff_idx);
-}
-
-static inline uint16_t tud_audio_write_support_ff(uint8_t ff_idx, const void * data, uint16_t len)
-{
- return tud_audio_n_write_support_ff(0, ff_idx, data, len);
-}
-
-static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx)
-{
- return tud_audio_n_get_tx_support_ff(0, ff_idx);
-}
-
-#endif
-
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
static inline bool tud_audio_int_write(const audio_interrupt_data_t * data)
{
diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h
index 5cbd658fe..10ba16a7c 100644
--- a/src/class/cdc/cdc.h
+++ b/src/class/cdc/cdc.h
@@ -192,6 +192,11 @@ typedef enum {
CDC_LINE_CODING_STOP_BITS_2 = 2, // 2 bits
} cdc_line_coding_stopbits_t;
+#define CDC_LINE_CODING_STOP_BITS_TEXT(STOP_BITS) ( \
+ STOP_BITS == CDC_LINE_CODING_STOP_BITS_1 ? "1" : \
+ STOP_BITS == CDC_LINE_CODING_STOP_BITS_1_5 ? "1.5" : \
+ STOP_BITS == CDC_LINE_CODING_STOP_BITS_2 ? "2" : "?" )
+
// TODO Backward compatible for typos. Maybe removed in the future release
#define CDC_LINE_CONDING_STOP_BITS_1 CDC_LINE_CODING_STOP_BITS_1
#define CDC_LINE_CONDING_STOP_BITS_1_5 CDC_LINE_CODING_STOP_BITS_1_5
@@ -205,22 +210,31 @@ typedef enum {
CDC_LINE_CODING_PARITY_SPACE = 4,
} cdc_line_coding_parity_t;
+#define CDC_LINE_CODING_PARITY_CHAR(PARITY) ( \
+ PARITY == CDC_LINE_CODING_PARITY_NONE ? 'N' : \
+ PARITY == CDC_LINE_CODING_PARITY_ODD ? 'O' : \
+ PARITY == CDC_LINE_CODING_PARITY_EVEN ? 'E' : \
+ PARITY == CDC_LINE_CODING_PARITY_MARK ? 'M' : \
+ PARITY == CDC_LINE_CODING_PARITY_SPACE ? 'S' : '?' )
+
//--------------------------------------------------------------------+
// Management Element Notification (Notification Endpoint)
//--------------------------------------------------------------------+
+#define CDC_REQ_TYPE_NOTIF 0xA1 ///< Direction IN; Type Class; Recipient Interface
+
/// 6.3 Notification Codes
typedef enum {
- CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status.
- CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request.
+ CDC_NOTIF_NETWORK_CONNECTION = 0x00, // notify the host about network connection status.
+ CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, // notify the host that a response is available.
CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08,
CDC_NOTIF_RING_DETECT = 0x09,
CDC_NOTIF_SERIAL_STATE = 0x20,
CDC_NOTIF_CALL_STATE_CHANGE = 0x28,
CDC_NOTIF_LINE_STATE_CHANGE = 0x29,
- CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred
+ CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, // notify the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred
CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40,
-}cdc_notification_request_t;
+} cdc_notify_request_t;
//--------------------------------------------------------------------+
// Class Specific Functional Descriptor (Communication Interface)
@@ -231,8 +245,7 @@ TU_ATTR_PACKED_BEGIN
TU_ATTR_BIT_FIELD_ORDER_BEGIN
/// Header Functional Descriptor (Communication Interface)
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific
uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUNC_DESC_
@@ -240,8 +253,7 @@ typedef struct TU_ATTR_PACKED
}cdc_desc_func_header_t;
/// Union Functional Descriptor (Communication Interface)
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific
uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
@@ -259,14 +271,13 @@ typedef struct TU_ATTR_PACKED
}
/// Country Selection Functional Descriptor (Communication Interface)
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific
uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
uint8_t iCountryCodeRelDate ; ///< Index of a string giving the release date for the implemented ISO 3166 Country Codes.
uint16_t wCountryCode ; ///< Country code in the format as defined in [ISO3166], release date as specified inoffset 3 for the first supported country.
-}cdc_desc_func_country_selection_t;
+} cdc_desc_func_country_selection_t;
#define cdc_desc_func_country_selection_n_t(no_country) \
struct TU_ATTR_PACKED { \
@@ -283,8 +294,7 @@ typedef struct TU_ATTR_PACKED
/// \brief Call Management Functional Descriptor
/// \details This functional descriptor describes the processing of calls for the Communications Class interface.
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific
uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
@@ -298,8 +308,7 @@ typedef struct TU_ATTR_PACKED
uint8_t bDataInterface;
}cdc_desc_func_call_management_t;
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t support_comm_request : 1; ///< Device supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature.
uint8_t support_line_request : 1; ///< Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State.
uint8_t support_send_break : 1; ///< Device supports the request Send_Break
@@ -311,8 +320,7 @@ TU_VERIFY_STATIC(sizeof(cdc_acm_capability_t) == 1, "mostly problem with compile
/// Abstract Control Management Functional Descriptor
/// This functional descriptor describes the commands supported by by the Communications Class interface with SubClass code of \ref CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific
uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
@@ -321,8 +329,7 @@ typedef struct TU_ATTR_PACKED
/// \brief Direct Line Management Functional Descriptor
/// \details This functional descriptor describes the commands supported by the Communications Class interface with SubClass code of \ref CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific
uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
@@ -384,16 +391,14 @@ typedef struct TU_ATTR_PACKED
}cdc_desc_func_telephone_call_state_reporting_capabilities_t;
// TODO remove
-static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc) {
return p_desc[2];
}
//--------------------------------------------------------------------+
// Requests
//--------------------------------------------------------------------+
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint32_t bit_rate;
uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits
uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space
@@ -402,15 +407,58 @@ typedef struct TU_ATTR_PACKED
TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct");
-typedef struct TU_ATTR_PACKED
-{
- uint16_t dtr : 1;
- uint16_t rts : 1;
- uint16_t : 6;
- uint16_t : 8;
+typedef union TU_ATTR_PACKED {
+ struct TU_ATTR_PACKED {
+ uint8_t dtr : 1;
+ uint8_t rts : 1;
+ uint8_t : 6;
+ };
+ uint8_t value;
} cdc_line_control_state_t;
-TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct");
+TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 1, "size is not correct");
+
+//--------------------------------------------------------------------+
+// Notifications
+//--------------------------------------------------------------------+
+// PSTN 1.2 section 6.5.4 table 31
+typedef union TU_ATTR_PACKED {
+ struct TU_ATTR_PACKED {
+ uint16_t bRxCarrier : 1; // DCD
+ uint16_t bTxCarrier : 1; // DSR
+ uint16_t bBreak : 1; // Break Detected
+ uint16_t bRingSignal : 1;
+ uint16_t bFraming : 1;
+ uint16_t bParity : 1;
+ uint16_t bOverRun : 1;
+ uint16_t : 9;
+ };
+ struct TU_ATTR_PACKED {
+ uint16_t dcd : 1;
+ uint16_t dsr : 1;
+ uint16_t brk : 1;
+ uint16_t :13;
+ };
+ uint16_t value;
+} cdc_notify_uart_state_t;
+
+TU_VERIFY_STATIC(sizeof(cdc_notify_uart_state_t) == 2, "size is not correct");
+
+// CDC 1.2 section 6.3.3 table 21
+typedef struct TU_ATTR_PACKED {
+ uint32_t upstream_bitrate;
+ uint32_t downstream_bitrate;
+} cdc_notify_conn_speed_change_t;
+
+typedef struct TU_ATTR_PACKED {
+ tusb_control_request_t request;
+ union {
+ cdc_notify_uart_state_t serial_state;
+ cdc_notify_conn_speed_change_t conn_speed_change;
+ };
+} cdc_notify_msg_t;
+
+TU_VERIFY_STATIC(sizeof(cdc_notify_msg_t) == 16, "size is not correct");
TU_ATTR_PACKED_END // End of all packed definitions
TU_ATTR_BIT_FIELD_ORDER_END
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c
index efb672201..4e4e01eaf 100644
--- a/src/class/cdc/cdc_device.c
+++ b/src/class/cdc/cdc_device.c
@@ -46,13 +46,13 @@
#define BULK_PACKET_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
typedef struct {
+ uint8_t rhport;
uint8_t itf_num;
- uint8_t ep_notif;
uint8_t ep_in;
uint8_t ep_out;
- // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
- uint8_t line_state;
+ uint8_t ep_notify;
+ uint8_t line_state; // Bit 0: DTR, Bit 1: RTS
/*------------- From this point, data is not cleared by bus reset -------------*/
char wanted_char;
@@ -74,6 +74,10 @@ typedef struct {
typedef struct {
TUD_EPBUF_DEF(epout, CFG_TUD_CDC_EP_BUFSIZE);
TUD_EPBUF_DEF(epin, CFG_TUD_CDC_EP_BUFSIZE);
+
+ #if CFG_TUD_CDC_NOTIFY
+ TUD_EPBUF_TYPE_DEF(cdc_notify_msg_t, epnotify);
+ #endif
} cdcd_epbuf_t;
//--------------------------------------------------------------------+
@@ -82,7 +86,7 @@ typedef struct {
static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
CFG_TUD_MEM_SECTION static cdcd_epbuf_t _cdcd_epbuf[CFG_TUD_CDC];
-static tud_cdc_configure_fifo_t _cdcd_fifo_cfg;
+static tud_cdc_configure_t _cdcd_cfg = TUD_CDC_CONFIGURE_DEFAULT();
static bool _prep_out_transaction(uint8_t itf) {
const uint8_t rhport = 0;
@@ -101,7 +105,7 @@ static bool _prep_out_transaction(uint8_t itf) {
TU_VERIFY(available >= CFG_TUD_CDC_EP_BUFSIZE);
// claim endpoint
- TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_out));
+ TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_out));
// fifo can be changed before endpoint is claimed
available = tu_fifo_remaining(&p_cdc->rx_ff);
@@ -110,7 +114,7 @@ static bool _prep_out_transaction(uint8_t itf) {
return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_epbuf->epout, CFG_TUD_CDC_EP_BUFSIZE);
} else {
// Release endpoint since we don't make any transfer
- usbd_edpt_release(rhport, p_cdc->ep_out);
+ usbd_edpt_release(p_cdc->rhport, p_cdc->ep_out);
return false;
}
}
@@ -118,10 +122,9 @@ static bool _prep_out_transaction(uint8_t itf) {
//--------------------------------------------------------------------+
// APPLICATION API
//--------------------------------------------------------------------+
-
-bool tud_cdc_configure_fifo(const tud_cdc_configure_fifo_t* cfg) {
- TU_VERIFY(cfg);
- _cdcd_fifo_cfg = (*cfg);
+bool tud_cdc_configure(const tud_cdc_configure_t* driver_cfg) {
+ TU_VERIFY(driver_cfg);
+ _cdcd_cfg = *driver_cfg;
return true;
}
@@ -142,6 +145,42 @@ void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding) {
(*coding) = _cdcd_itf[itf].line_coding;
}
+#if CFG_TUD_CDC_NOTIFY
+bool tud_cdc_n_notify_uart_state (uint8_t itf, const cdc_notify_uart_state_t *state) {
+ cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
+ cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf];
+ TU_VERIFY(tud_ready() && p_cdc->ep_notify != 0);
+ TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notify));
+
+ cdc_notify_msg_t* notify_msg = &p_epbuf->epnotify;
+ notify_msg->request.bmRequestType = CDC_REQ_TYPE_NOTIF;
+ notify_msg->request.bRequest = CDC_NOTIF_SERIAL_STATE;
+ notify_msg->request.wValue = 0;
+ notify_msg->request.wIndex = p_cdc->itf_num;
+ notify_msg->request.wLength = sizeof(cdc_notify_uart_state_t);
+ notify_msg->serial_state = *state;
+
+ return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_notify, (uint8_t *)notify_msg, 8 + sizeof(cdc_notify_uart_state_t));
+}
+
+bool tud_cdc_n_notify_conn_speed_change(uint8_t itf, const cdc_notify_conn_speed_change_t* conn_speed_change) {
+ cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
+ cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf];
+ TU_VERIFY(tud_ready() && p_cdc->ep_notify != 0);
+ TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notify));
+
+ cdc_notify_msg_t* notify_msg = &p_epbuf->epnotify;
+ notify_msg->request.bmRequestType = CDC_REQ_TYPE_NOTIF;
+ notify_msg->request.bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE;
+ notify_msg->request.wValue = 0;
+ notify_msg->request.wIndex = p_cdc->itf_num;
+ notify_msg->request.wLength = sizeof(cdc_notify_conn_speed_change_t);
+ notify_msg->conn_speed_change = *conn_speed_change;
+
+ return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_notify, (uint8_t *)notify_msg, 8 + sizeof(cdc_notify_conn_speed_change_t));
+}
+#endif
+
void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted) {
_cdcd_itf[itf].wanted_char = wanted;
}
@@ -175,7 +214,7 @@ void tud_cdc_n_read_flush(uint8_t itf) {
//--------------------------------------------------------------------+
uint32_t tud_cdc_n_write(uint8_t itf, const void* buffer, uint32_t bufsize) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
- uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX));
+ uint16_t wr_count = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX));
// flush if queue more than packet size
if (tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE
@@ -186,36 +225,31 @@ uint32_t tud_cdc_n_write(uint8_t itf, const void* buffer, uint32_t bufsize) {
tud_cdc_n_write_flush(itf);
}
- return ret;
+ return wr_count;
}
uint32_t tud_cdc_n_write_flush(uint8_t itf) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf];
-
- // Skip if usb is not ready yet
- TU_VERIFY(tud_ready(), 0);
+ TU_VERIFY(tud_ready(), 0); // Skip if usb is not ready yet
// No data to send
if (!tu_fifo_count(&p_cdc->tx_ff)) {
return 0;
}
- const uint8_t rhport = 0;
-
- // Claim the endpoint
- TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_in), 0);
+ TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_in), 0); // Claim the endpoint
// Pull data from FIFO
const uint16_t count = tu_fifo_read_n(&p_cdc->tx_ff, p_epbuf->epin, CFG_TUD_CDC_EP_BUFSIZE);
if (count) {
- TU_ASSERT(usbd_edpt_xfer(rhport, p_cdc->ep_in, p_epbuf->epin, count), 0);
+ TU_ASSERT(usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_in, p_epbuf->epin, count), 0);
return count;
} else {
// Release endpoint since we don't make any transfer
// Note: data is dropped if terminal is not connected
- usbd_edpt_release(rhport, p_cdc->ep_in);
+ usbd_edpt_release(p_cdc->rhport, p_cdc->ep_in);
return 0;
}
}
@@ -233,8 +267,6 @@ bool tud_cdc_n_write_clear(uint8_t itf) {
//--------------------------------------------------------------------+
void cdcd_init(void) {
tu_memclr(_cdcd_itf, sizeof(_cdcd_itf));
- tu_memclr(&_cdcd_fifo_cfg, sizeof(_cdcd_fifo_cfg));
-
for (uint8_t i = 0; i < CFG_TUD_CDC; i++) {
cdcd_interface_t* p_cdc = &_cdcd_itf[i];
@@ -249,10 +281,10 @@ void cdcd_init(void) {
// Config RX fifo
tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, TU_ARRAY_SIZE(p_cdc->rx_ff_buf), 1, false);
- // Config TX fifo as overwritable at initialization and will be changed to non-overwritable
- // if terminal supports DTR bit. Without DTR we do not know if data is actually polled by terminal.
- // In this way, the most current data is prioritized.
- tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true);
+ // TX fifo can be configured to change to overwritable if not connected (DTR bit not set). Without DTR we do not
+ // know if data is actually polled by terminal. This way the most current data is prioritized.
+ // Default: is overwritable
+ tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, _cdcd_cfg.tx_overwritabe_if_not_connected);
#if OSAL_MUTEX_REQUIRED
osal_mutex_t mutex_rd = osal_mutex_create(&p_cdc->rx_ff_mutex);
@@ -294,13 +326,13 @@ void cdcd_reset(uint8_t rhport) {
cdcd_interface_t* p_cdc = &_cdcd_itf[i];
tu_memclr(p_cdc, ITF_MEM_RESET_SIZE);
- if (!_cdcd_fifo_cfg.rx_persistent) {
+ if (!_cdcd_cfg.rx_persistent) {
tu_fifo_clear(&p_cdc->rx_ff);
}
- if (!_cdcd_fifo_cfg.tx_persistent) {
+ if (!_cdcd_cfg.tx_persistent) {
tu_fifo_clear(&p_cdc->tx_ff);
}
- tu_fifo_set_overwritable(&p_cdc->tx_ff, true);
+ tu_fifo_set_overwritable(&p_cdc->tx_ff, _cdcd_cfg.tx_overwritabe_if_not_connected);
}
}
@@ -321,6 +353,7 @@ uint16_t cdcd_open(uint8_t rhport, const tusb_desc_interface_t* itf_desc, uint16
TU_ASSERT(cdc_id < CFG_TUD_CDC, 0);
//------------- Control Interface -------------//
+ p_cdc->rhport = rhport;
p_cdc->itf_num = itf_desc->bInterfaceNumber;
uint16_t drv_len = sizeof(tusb_desc_interface_t);
@@ -335,9 +368,8 @@ uint16_t cdcd_open(uint8_t rhport, const tusb_desc_interface_t* itf_desc, uint16
if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) {
// notification endpoint
const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc;
-
TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
- p_cdc->ep_notif = desc_ep->bEndpointAddress;
+ p_cdc->ep_notify = desc_ep->bEndpointAddress;
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
@@ -414,8 +446,12 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ
p_cdc->line_state = (uint8_t) request->wValue;
- // Disable fifo overwriting if DTR bit is set
- tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr);
+ // If enabled: fifo overwriting is disabled if DTR bit is set and vice versa
+ if (_cdcd_cfg.tx_overwritabe_if_not_connected) {
+ tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr);
+ } else {
+ tu_fifo_set_overwritable(&p_cdc->tx_ff, false);
+ }
TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts);
@@ -453,7 +489,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
// Identify which interface to use
for (itf = 0; itf < CFG_TUD_CDC; itf++) {
p_cdc = &_cdcd_itf[itf];
- if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in)) {
+ if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in) || (ep_addr == p_cdc->ep_notify)) {
break;
}
}
@@ -496,13 +532,18 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
// xferred_bytes is multiple of EP Packet size and not zero
if (!tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE - 1)))) {
if (usbd_edpt_claim(rhport, p_cdc->ep_in)) {
- usbd_edpt_xfer(rhport, p_cdc->ep_in, NULL, 0);
+ TU_ASSERT(usbd_edpt_xfer(rhport, p_cdc->ep_in, NULL, 0));
}
}
}
}
- // nothing to do with notif endpoint for now
+ // Sent notification to host
+ if (ep_addr == p_cdc->ep_notify) {
+ if (tud_cdc_notify_complete_cb) {
+ tud_cdc_notify_complete_cb(itf);
+ }
+ }
return true;
}
diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h
index 2d5ba2575..a34e07e1d 100644
--- a/src/class/cdc/cdc_device.h
+++ b/src/class/cdc/cdc_device.h
@@ -32,6 +32,10 @@
//--------------------------------------------------------------------+
// Class Driver Configuration
//--------------------------------------------------------------------+
+#ifndef CFG_TUD_CDC_NOTIFY
+ #define CFG_TUD_CDC_NOTIFY 0
+#endif
+
#if !defined(CFG_TUD_CDC_EP_BUFSIZE) && defined(CFG_TUD_CDC_EPSIZE)
#warning CFG_TUD_CDC_EPSIZE is renamed to CFG_TUD_CDC_EP_BUFSIZE, please update to use the new name
#define CFG_TUD_CDC_EP_BUFSIZE CFG_TUD_CDC_EPSIZE
@@ -48,14 +52,24 @@
//--------------------------------------------------------------------+
// Driver Configuration
//--------------------------------------------------------------------+
-
typedef struct TU_ATTR_PACKED {
- uint8_t rx_persistent : 1; // keep rx fifo on bus reset or disconnect
- uint8_t tx_persistent : 1; // keep tx fifo on bus reset or disconnect
-} tud_cdc_configure_fifo_t;
+ uint8_t rx_persistent : 1; // keep rx fifo data even with bus reset or disconnect
+ uint8_t tx_persistent : 1; // keep tx fifo data even with reset or disconnect
+ uint8_t tx_overwritabe_if_not_connected : 1; // if not connected, tx fifo can be overwritten
+} tud_cdc_configure_t;
-// Configure CDC FIFOs behavior
-bool tud_cdc_configure_fifo(tud_cdc_configure_fifo_t const* cfg);
+#define TUD_CDC_CONFIGURE_DEFAULT() { \
+ .rx_persistent = 0, \
+ .tx_persistent = 0, \
+ .tx_overwritabe_if_not_connected = 1, \
+}
+
+// Configure CDC driver behavior
+bool tud_cdc_configure(const tud_cdc_configure_t* driver_cfg);
+
+// Backward compatible
+#define tud_cdc_configure_fifo_t tud_cdc_configure_t
+#define tud_cdc_configure_fifo tud_cdc_configure
//--------------------------------------------------------------------+
// Application API (Multiple Ports) i.e. CFG_TUD_CDC > 1
@@ -116,6 +130,23 @@ uint32_t tud_cdc_n_write_available(uint8_t itf);
// Clear the transmit FIFO
bool tud_cdc_n_write_clear(uint8_t itf);
+
+#if CFG_TUD_CDC_NOTIFY
+// Send UART status notification: DCD, DSR etc ..
+bool tud_cdc_n_notify_uart_state(uint8_t itf, const cdc_notify_uart_state_t *state);
+
+// Send connection speed change notification
+bool tud_cdc_n_notify_conn_speed_change(uint8_t itf, const cdc_notify_conn_speed_change_t* conn_speed_change);
+
+TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_notify_uart_state(const cdc_notify_uart_state_t* state) {
+ return tud_cdc_n_notify_uart_state(0, state);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_notify_conn_speed_change(const cdc_notify_conn_speed_change_t* conn_speed_change) {
+ return tud_cdc_n_notify_conn_speed_change(0, conn_speed_change);
+}
+#endif
+
//--------------------------------------------------------------------+
// Application API (Single Port)
//--------------------------------------------------------------------+
@@ -185,7 +216,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_write_clear(void) {
}
//--------------------------------------------------------------------+
-// Application Callback API (weak is optional)
+// Application Callback API
//--------------------------------------------------------------------+
// Invoked when received new data
@@ -197,6 +228,9 @@ TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
// Invoked when a TX is complete and therefore space becomes available in TX buffer
TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf);
+// Invoked when a notification is sent to host
+TU_ATTR_WEAK void tud_cdc_notify_complete_cb(uint8_t itf);
+
// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts);
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index 4058857c5..f4567fac4 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -24,7 +24,7 @@
* This file is part of the TinyUSB stack.
*
* Contribution
- * - Heiko Kuester: CH34x support
+ * - Heiko Kuester: add support of CH34x & PL2303, improve support of FTDI & CP210x
*/
#include "tusb_option.h"
@@ -35,13 +35,19 @@
#include "host/usbh_pvt.h"
#include "cdc_host.h"
+#include "serial/ftdi_sio.h"
+#include "serial/cp210x.h"
+#include "serial/ch34x.h"
+#include "serial/pl2303.h"
// Level where CFG_TUSB_DEBUG must be at least for this driver is logged
#ifndef CFG_TUH_CDC_LOG_LEVEL
- #define CFG_TUH_CDC_LOG_LEVEL CFG_TUH_LOG_LEVEL
+ #define CFG_TUH_CDC_LOG_LEVEL 2
#endif
-#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__)
+#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__)
+#define TU_LOG_CDC(_cdc, _format, ...) TU_LOG_DRV("[:%u:%u] CDCh %s " _format "\r\n", _cdc->daddr, _cdc->bInterfaceNumber, \
+ serial_drivers[_cdc->serial_drid].name, ##__VA_ARGS__)
//--------------------------------------------------------------------+
// Host CDC Interface
@@ -56,30 +62,40 @@ typedef struct {
uint8_t ep_notif;
uint8_t serial_drid; // Serial Driver ID
bool mounted; // Enumeration is complete
- cdc_acm_capability_t acm_capability;
- TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width
- uint8_t line_state; // DTR (bit0), RTS (bit1)
+ struct {
+ TU_ATTR_ALIGNED(4) cdc_line_coding_t coding; // Baudrate, stop bits, parity, data width
+ cdc_line_control_state_t control_state; // DTR, RTS
+ } line, requested_line;
- #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X
- cdc_line_coding_t requested_line_coding;
- // 1 byte padding
- #endif
+ tuh_xfer_cb_t user_complete_cb; // required since we handle request internally first
- tuh_xfer_cb_t user_control_cb;
+ union {
+ struct {
+ cdc_acm_capability_t capability;
+ } acm;
+
+ #if CFG_TUH_CDC_FTDI
+ ftdi_private_t ftdi;
+ #endif
+
+ #if CFG_TUH_CDC_PL2303
+ pl2303_private_t pl2303;
+ #endif
+ };
struct {
tu_edpt_stream_t tx;
tu_edpt_stream_t rx;
uint8_t tx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE];
- uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE];
+ uint8_t rx_ff_buf[CFG_TUH_CDC_RX_BUFSIZE];
} stream;
} cdch_interface_t;
typedef struct {
TUH_EPBUF_DEF(tx, CFG_TUH_CDC_TX_EPSIZE);
- TUH_EPBUF_DEF(rx, CFG_TUH_CDC_TX_EPSIZE);
+ TUH_EPBUF_DEF(rx, CFG_TUH_CDC_RX_EPSIZE);
} cdch_epbuf_t;
static cdch_interface_t cdch_data[CFG_TUH_CDC];
@@ -89,58 +105,70 @@ CFG_TUH_MEM_SECTION static cdch_epbuf_t cdch_epbuf[CFG_TUH_CDC];
// Serial Driver
//--------------------------------------------------------------------+
-//------------- ACM prototypes -------------//
-static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
-static void acm_process_config(tuh_xfer_t* xfer);
+// General driver
+static void cdch_process_set_config(tuh_xfer_t *xfer);
+static void cdch_process_line_state_on_enum(tuh_xfer_t *xfer); // invoked after set config is processed
+static void cdch_internal_control_complete(tuh_xfer_t *xfer);
+static void cdch_set_line_coding_stage1_baudrate_complete(tuh_xfer_t *xfer);
+static void cdch_set_line_coding_stage2_data_format_complete(tuh_xfer_t *xfer);
-static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+//------------- ACM prototypes -------------//
+static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer);
+static void acm_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer);
+
+static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
//------------- FTDI prototypes -------------//
#if CFG_TUH_CDC_FTDI
-#include "serial/ftdi_sio.h"
-
static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST};
+static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len);
+static bool ftdi_proccess_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer);
+static void ftdi_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t *xfer);
-static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len);
-static void ftdi_process_config(tuh_xfer_t* xfer);
-
-static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-static bool ftdi_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool ftdi_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool ftdi_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
#endif
//------------- CP210X prototypes -------------//
#if CFG_TUH_CDC_CP210X
-#include "serial/cp210x.h"
-
static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIST};
-static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
-static void cp210x_process_config(tuh_xfer_t* xfer);
+static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer);
+static void cp210x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer);
-static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool cp210x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
#endif
//------------- CH34x prototypes -------------//
#if CFG_TUH_CDC_CH34X
-#include "serial/ch34x.h"
-
static uint16_t const ch34x_vid_pid_list[][2] = {CFG_TUH_CDC_CH34X_VID_PID_LIST};
-static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len);
-static void ch34x_process_config(tuh_xfer_t* xfer);
+static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+static bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer);
+static void ch34x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer);
-static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
-static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+#endif
+
+//------------- PL2303 prototypes -------------//
+#if CFG_TUH_CDC_PL2303
+static uint16_t const pl2303_vid_pid_list[][2] = {CFG_TUH_CDC_PL2303_VID_PID_LIST};
+static const pl2303_type_data_t pl2303_type_data[PL2303_TYPE_COUNT] = {PL2303_TYPE_DATA};
+
+static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer);
+static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer);
+
+static bool pl2303_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+static bool pl2303_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
#endif
//------------- Common -------------//
@@ -159,31 +187,48 @@ enum {
SERIAL_DRIVER_CH34X,
#endif
+#if CFG_TUH_CDC_PL2303
+ SERIAL_DRIVER_PL2303,
+#endif
+
SERIAL_DRIVER_COUNT
};
+typedef bool (*serial_driver_func_t)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
typedef struct {
uint16_t const (*vid_pid_list)[2];
uint16_t const vid_pid_count;
- bool (*const open)(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len);
- void (*const process_set_config)(tuh_xfer_t* xfer);
- bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
- bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
- bool (*const set_data_format)(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
- bool (*const set_line_coding)(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+ bool (*const open)(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len);
+ bool (*const process_set_config)(cdch_interface_t * p_cdc, tuh_xfer_t * xfer);
+ void (*const request_complete)(cdch_interface_t * p_cdc, tuh_xfer_t * xfer); // internal request complete handler to update line state
+
+ serial_driver_func_t set_control_line_state, set_baudrate, set_data_format, set_line_coding;
+
+ #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL
+ const char * name;
+ #endif
} cdch_serial_driver_t;
+#if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL
+ #define DRIVER_NAME_DECLARE(_str) .name = _str
+#else
+ #define DRIVER_NAME_DECLARE(_str)
+#endif
+
// Note driver list must be in the same order as SERIAL_DRIVER enum
static const cdch_serial_driver_t serial_drivers[] = {
{
.vid_pid_list = NULL,
.vid_pid_count = 0,
.open = acm_open,
- .process_set_config = acm_process_config,
+ .process_set_config = acm_process_set_config,
+ .request_complete = acm_internal_control_complete,
.set_control_line_state = acm_set_control_line_state,
- .set_baudrate = acm_set_baudrate,
- .set_data_format = acm_set_data_format,
- .set_line_coding = acm_set_line_coding
+ .set_baudrate = acm_set_line_coding,
+ .set_data_format = acm_set_line_coding,
+ .set_line_coding = acm_set_line_coding,
+ DRIVER_NAME_DECLARE("ACM")
},
#if CFG_TUH_CDC_FTDI
@@ -191,11 +236,13 @@ static const cdch_serial_driver_t serial_drivers[] = {
.vid_pid_list = ftdi_vid_pid_list,
.vid_pid_count = TU_ARRAY_SIZE(ftdi_vid_pid_list),
.open = ftdi_open,
- .process_set_config = ftdi_process_config,
- .set_control_line_state = ftdi_sio_set_modem_ctrl,
- .set_baudrate = ftdi_sio_set_baudrate,
+ .process_set_config = ftdi_proccess_set_config,
+ .request_complete = ftdi_internal_control_complete,
+ .set_control_line_state = ftdi_set_modem_ctrl,
+ .set_baudrate = ftdi_set_baudrate,
.set_data_format = ftdi_set_data_format,
- .set_line_coding = ftdi_set_line_coding
+ .set_line_coding = NULL, // 2 stage set line coding
+ DRIVER_NAME_DECLARE("FTDI")
},
#endif
@@ -204,11 +251,13 @@ static const cdch_serial_driver_t serial_drivers[] = {
.vid_pid_list = cp210x_vid_pid_list,
.vid_pid_count = TU_ARRAY_SIZE(cp210x_vid_pid_list),
.open = cp210x_open,
- .process_set_config = cp210x_process_config,
+ .process_set_config = cp210x_process_set_config,
+ .request_complete = cp210x_internal_control_complete,
.set_control_line_state = cp210x_set_modem_ctrl,
.set_baudrate = cp210x_set_baudrate,
.set_data_format = cp210x_set_data_format,
- .set_line_coding = cp210x_set_line_coding
+ .set_line_coding = NULL, // 2 stage set line coding
+ DRIVER_NAME_DECLARE("CP210x")
},
#endif
@@ -217,13 +266,31 @@ static const cdch_serial_driver_t serial_drivers[] = {
.vid_pid_list = ch34x_vid_pid_list,
.vid_pid_count = TU_ARRAY_SIZE(ch34x_vid_pid_list),
.open = ch34x_open,
- .process_set_config = ch34x_process_config,
+ .process_set_config = ch34x_process_set_config,
+ .request_complete = ch34x_internal_control_complete,
+
.set_control_line_state = ch34x_set_modem_ctrl,
.set_baudrate = ch34x_set_baudrate,
.set_data_format = ch34x_set_data_format,
- .set_line_coding = ch34x_set_line_coding
+ .set_line_coding = NULL, // 2 stage set line coding
+ DRIVER_NAME_DECLARE("CH34x")
},
#endif
+
+ #if CFG_TUH_CDC_PL2303
+ {
+ .vid_pid_list = pl2303_vid_pid_list,
+ .vid_pid_count = TU_ARRAY_SIZE(pl2303_vid_pid_list),
+ .open = pl2303_open,
+ .process_set_config = pl2303_process_set_config,
+ .request_complete = pl2303_internal_control_complete,
+ .set_control_line_state = pl2303_set_modem_ctrl,
+ .set_baudrate = pl2303_set_line_coding,
+ .set_data_format = pl2303_set_line_coding,
+ .set_line_coding = pl2303_set_line_coding,
+ DRIVER_NAME_DECLARE("PL2303")
+ }
+ #endif
};
TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial driver count mismatch");
@@ -232,17 +299,20 @@ TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial d
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
-static inline cdch_interface_t* get_itf(uint8_t idx) {
+TU_ATTR_ALWAYS_INLINE static inline cdch_interface_t * get_itf(uint8_t idx) {
TU_ASSERT(idx < CFG_TUH_CDC, NULL);
- cdch_interface_t* p_cdc = &cdch_data[idx];
-
+ cdch_interface_t * p_cdc = &cdch_data[idx];
return (p_cdc->daddr != 0) ? p_cdc : NULL;
}
+TU_ATTR_ALWAYS_INLINE static inline uint8_t get_idx_by_ptr(cdch_interface_t* p_cdc) {
+ return (uint8_t) (p_cdc - cdch_data);
+}
+
static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) {
for(uint8_t i=0; idaddr == daddr) &&
+ cdch_interface_t * p_cdc = &cdch_data[i];
+ if ((p_cdc->daddr == daddr) &&
(ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) {
return i;
}
@@ -251,15 +321,67 @@ static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) {
return TUSB_INDEX_INVALID_8;
}
-static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const *itf_desc) {
+// determine the interface from the completed transfer
+static cdch_interface_t* get_itf_by_xfer(const tuh_xfer_t * xfer) {
+ TU_VERIFY(xfer->daddr != 0, NULL);
+ for(uint8_t i=0; idaddr == xfer->daddr) {
+ switch (p_cdc->serial_drid) {
+ #if CFG_TUH_CDC_CP210X
+ case SERIAL_DRIVER_CP210X:
+ #endif
+ case SERIAL_DRIVER_ACM: {
+ // Driver use wIndex for bInterfaceNumber
+ const uint8_t itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ if (p_cdc->bInterfaceNumber == itf_num) {
+ return p_cdc;
+ }
+ break;
+ }
+
+ #if CFG_TUH_CDC_FTDI
+ case SERIAL_DRIVER_FTDI: {
+ // FTDI uses wIndex for channel number, if channel is 0 then it is the default channel
+ const uint8_t channel = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ if (p_cdc->ftdi.channel == 0 || p_cdc->ftdi.channel == channel) {
+ return p_cdc;
+ }
+ break;
+ }
+ #endif
+
+ #if CFG_TUH_CDC_CH34X
+ case SERIAL_DRIVER_CH34X:
+ // ch34x has only one interface
+ return p_cdc;
+ #endif
+
+ #if CFG_TUH_CDC_PL2303
+ case SERIAL_DRIVER_PL2303:
+ // pl2303 has only one interface
+ return p_cdc;
+ #endif
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t const * itf_desc) {
for(uint8_t i=0; idaddr = daddr;
p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber;
p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass;
p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol;
- p_cdc->line_state = 0;
+ p_cdc->line.coding = (cdc_line_coding_t) { 0, 0, 0, 0 };
+ p_cdc->line.control_state.value = 0;
return p_cdc;
}
}
@@ -267,9 +389,7 @@ static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const
return NULL;
}
-static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t const *desc_ep);
-static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num);
-static void cdch_internal_control_complete(tuh_xfer_t* xfer);
+static bool open_ep_stream_pair(cdch_interface_t * p_cdc , tusb_desc_endpoint_t const *desc_ep);
//--------------------------------------------------------------------+
// APPLICATION API
@@ -277,21 +397,20 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer);
uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num) {
for (uint8_t i = 0; i < CFG_TUH_CDC; i++) {
- const cdch_interface_t* p_cdc = &cdch_data[i];
- if (p_cdc->daddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i;
+ const cdch_interface_t * p_cdc = &cdch_data[i];
+ if (p_cdc->daddr == daddr && p_cdc->bInterfaceNumber == itf_num) { return i; }
}
-
return TUSB_INDEX_INVALID_8;
}
-bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) {
- cdch_interface_t* p_cdc = get_itf(idx);
+bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t * info) {
+ cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc && info);
info->daddr = p_cdc->daddr;
- // re-construct descriptor
- tusb_desc_interface_t* desc = &info->desc;
+ // re-construct interface descriptor
+ tusb_desc_interface_t * desc = &info->desc;
desc->bLength = sizeof(tusb_desc_interface_t);
desc->bDescriptorType = TUSB_DESC_INTERFACE;
@@ -307,31 +426,22 @@ bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) {
}
bool tuh_cdc_mounted(uint8_t idx) {
- cdch_interface_t* p_cdc = get_itf(idx);
+ cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
return p_cdc->mounted;
}
-bool tuh_cdc_get_dtr(uint8_t idx) {
- cdch_interface_t* p_cdc = get_itf(idx);
+bool tuh_cdc_get_control_line_state_local(uint8_t idx, uint16_t* line_state) {
+ cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
-
- return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false;
+ *line_state = p_cdc->line.control_state.value;
+ return true;
}
-bool tuh_cdc_get_rts(uint8_t idx) {
- cdch_interface_t* p_cdc = get_itf(idx);
+bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t * line_coding) {
+ cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
-
- return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false;
-}
-
-bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) {
- cdch_interface_t* p_cdc = get_itf(idx);
- TU_VERIFY(p_cdc);
-
- *line_coding = p_cdc->line_coding;
-
+ *line_coding = p_cdc->line.coding;
return true;
}
@@ -339,31 +449,27 @@ bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding)
// Write
//--------------------------------------------------------------------+
-uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) {
- cdch_interface_t* p_cdc = get_itf(idx);
+uint32_t tuh_cdc_write(uint8_t idx, void const * buffer, uint32_t bufsize) {
+ cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
-
return tu_edpt_stream_write(p_cdc->daddr, &p_cdc->stream.tx, buffer, bufsize);
}
uint32_t tuh_cdc_write_flush(uint8_t idx) {
- cdch_interface_t* p_cdc = get_itf(idx);
+ cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
-
return tu_edpt_stream_write_xfer(p_cdc->daddr, &p_cdc->stream.tx);
}
bool tuh_cdc_write_clear(uint8_t idx) {
- cdch_interface_t* p_cdc = get_itf(idx);
+ cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
-
return tu_edpt_stream_clear(&p_cdc->stream.tx);
}
uint32_t tuh_cdc_write_available(uint8_t idx) {
- cdch_interface_t* p_cdc = get_itf(idx);
+ cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
-
return tu_edpt_stream_write_available(p_cdc->daddr, &p_cdc->stream.tx);
}
@@ -371,29 +477,26 @@ uint32_t tuh_cdc_write_available(uint8_t idx) {
// Read
//--------------------------------------------------------------------+
-uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) {
- cdch_interface_t* p_cdc = get_itf(idx);
+uint32_t tuh_cdc_read (uint8_t idx, void * buffer, uint32_t bufsize) {
+ cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
-
return tu_edpt_stream_read(p_cdc->daddr, &p_cdc->stream.rx, buffer, bufsize);
}
uint32_t tuh_cdc_read_available(uint8_t idx) {
- cdch_interface_t* p_cdc = get_itf(idx);
+ cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
-
return tu_edpt_stream_read_available(&p_cdc->stream.rx);
}
-bool tuh_cdc_peek(uint8_t idx, uint8_t* ch) {
- cdch_interface_t* p_cdc = get_itf(idx);
+bool tuh_cdc_peek(uint8_t idx, uint8_t * ch) {
+ cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
-
return tu_edpt_stream_peek(&p_cdc->stream.rx, ch);
}
bool tuh_cdc_read_clear (uint8_t idx) {
- cdch_interface_t* p_cdc = get_itf(idx);
+ cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
bool ret = tu_edpt_stream_clear(&p_cdc->stream.rx);
@@ -405,218 +508,115 @@ bool tuh_cdc_read_clear (uint8_t idx) {
// Control Endpoint API
//--------------------------------------------------------------------+
-static void process_internal_control_complete(tuh_xfer_t* xfer, uint8_t itf_num) {
- uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
- cdch_interface_t* p_cdc = get_itf(idx);
- TU_ASSERT(p_cdc, );
- uint16_t const value = tu_le16toh(xfer->setup->wValue);
-
- if (xfer->result == XFER_RESULT_SUCCESS) {
- switch (p_cdc->serial_drid) {
- case SERIAL_DRIVER_ACM:
- switch (xfer->setup->bRequest) {
- case CDC_REQUEST_SET_CONTROL_LINE_STATE:
- p_cdc->line_state = (uint8_t) value;
- break;
-
- case CDC_REQUEST_SET_LINE_CODING: {
- uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength));
- memcpy(&p_cdc->line_coding, xfer->buffer, len);
- break;
- }
-
- default: break;
- }
- break;
-
- #if CFG_TUH_CDC_FTDI
- case SERIAL_DRIVER_FTDI:
- switch (xfer->setup->bRequest) {
- case FTDI_SIO_MODEM_CTRL:
- p_cdc->line_state = (uint8_t) value;
- break;
-
- case FTDI_SIO_SET_BAUD_RATE:
- p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate;
- break;
-
- default: break;
- }
- break;
- #endif
-
- #if CFG_TUH_CDC_CP210X
- case SERIAL_DRIVER_CP210X:
- switch(xfer->setup->bRequest) {
- case CP210X_SET_MHS:
- p_cdc->line_state = (uint8_t) value;
- break;
-
- case CP210X_SET_BAUDRATE: {
- uint32_t baudrate;
- memcpy(&baudrate, xfer->buffer, sizeof(uint32_t));
- p_cdc->line_coding.bit_rate = tu_le32toh(baudrate);
- break;
- }
-
- default: break;
- }
- break;
- #endif
-
- #if CFG_TUH_CDC_CH34X
- case SERIAL_DRIVER_CH34X:
- switch (xfer->setup->bRequest) {
- case CH34X_REQ_WRITE_REG:
- // register write request
- switch (value) {
- case CH34X_REG16_DIVISOR_PRESCALER:
- // baudrate
- p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate;
- break;
-
- case CH32X_REG16_LCR2_LCR:
- // data format
- p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits;
- p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity;
- p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits;
- break;
-
- default: break;
- }
- break;
-
- case CH34X_REQ_MODEM_CTRL: {
- // set modem controls RTS/DTR request. Note: signals are inverted
- uint16_t const modem_signal = ~value;
- if (modem_signal & CH34X_BIT_RTS) {
- p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS;
- } else {
- p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_RTS;
- }
-
- if (modem_signal & CH34X_BIT_DTR) {
- p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR;
- } else {
- p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_DTR;
- }
- break;
- }
-
- default: break;
- }
- break;
- #endif
-
- default: break;
- }
- }
-
- xfer->complete_cb = p_cdc->user_control_cb;
- if (xfer->complete_cb) {
- xfer->complete_cb(xfer);
- }
-}
-
-// internal control complete to update state such as line state, encoding
-static void cdch_internal_control_complete(tuh_xfer_t* xfer) {
- uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
- process_internal_control_complete(xfer, itf_num);
-}
-
bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- cdch_interface_t* p_cdc = get_itf(idx);
+ cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
- cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid];
+ TU_LOG_CDC(p_cdc, "set control line state dtr = %u rts = %u", p_cdc->requested_line.control_state.dtr, p_cdc->requested_line.control_state.rts);
+ const cdch_serial_driver_t * driver = &serial_drivers[p_cdc->serial_drid];
- if (complete_cb) {
- return driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data);
- } else {
- // blocking
- xfer_result_t result = XFER_RESULT_INVALID;
- bool ret = driver->set_control_line_state(p_cdc, line_state, complete_cb, (uintptr_t) &result);
+ p_cdc->requested_line.control_state.value = (uint8_t) line_state;
+ p_cdc->user_complete_cb = complete_cb;
+ TU_VERIFY(driver->set_control_line_state(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data));
- if (user_data) {
- // user_data is not NULL, return result via user_data
- *((xfer_result_t*) user_data) = result;
- }
-
- TU_VERIFY(ret && result == XFER_RESULT_SUCCESS);
- p_cdc->line_state = (uint8_t) line_state;
- return true;
+ if (!complete_cb) {
+ // blocking, update line state if request was successful
+ p_cdc->line.control_state.value = (uint8_t) line_state;
}
+
+ return true;
}
bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- cdch_interface_t* p_cdc = get_itf(idx);
+ cdch_interface_t *p_cdc = get_itf(idx);
TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
- cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid];
+ TU_LOG_CDC(p_cdc, "set baudrate %lu", baudrate);
+ const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid];
- if (complete_cb) {
- return driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data);
- } else {
- // blocking
- xfer_result_t result = XFER_RESULT_INVALID;
- bool ret = driver->set_baudrate(p_cdc, baudrate, complete_cb, (uintptr_t) &result);
+ p_cdc->requested_line = p_cdc->line; // keep current line coding
+ p_cdc->requested_line.coding.bit_rate = baudrate;
+ p_cdc->user_complete_cb = complete_cb;
+ TU_VERIFY(driver->set_baudrate(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data));
- if (user_data) {
- // user_data is not NULL, return result via user_data
- *((xfer_result_t*) user_data) = result;
- }
-
- TU_VERIFY(ret && result == XFER_RESULT_SUCCESS);
- p_cdc->line_coding.bit_rate = baudrate;
- return true;
+ if (!complete_cb) {
+ p_cdc->line.coding.bit_rate = baudrate;
}
+
+ return true;
}
bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits,
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- cdch_interface_t* p_cdc = get_itf(idx);
+ cdch_interface_t *p_cdc = get_itf(idx);
TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
- cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid];
+ TU_LOG_CDC(p_cdc, "set data format %u%c%s",
+ data_bits, CDC_LINE_CODING_PARITY_CHAR(parity),
+ CDC_LINE_CODING_STOP_BITS_TEXT(stop_bits));
+ const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid];
- if (complete_cb) {
- return driver->set_data_format(p_cdc, stop_bits, parity, data_bits, complete_cb, user_data);
- } else {
+ p_cdc->requested_line = p_cdc->line; // keep current line coding
+ p_cdc->requested_line.coding.stop_bits = stop_bits;
+ p_cdc->requested_line.coding.parity = parity;
+ p_cdc->requested_line.coding.data_bits = data_bits;
+
+ p_cdc->user_complete_cb = complete_cb;
+ TU_VERIFY(driver->set_data_format(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data));
+
+ if (!complete_cb) {
// blocking
- xfer_result_t result = XFER_RESULT_INVALID;
- bool ret = driver->set_data_format(p_cdc, stop_bits, parity, data_bits, complete_cb, (uintptr_t) &result);
-
- if (user_data) {
- // user_data is not NULL, return result via user_data
- *((xfer_result_t*) user_data) = result;
- }
-
- TU_VERIFY(ret && result == XFER_RESULT_SUCCESS);
- p_cdc->line_coding.stop_bits = stop_bits;
- p_cdc->line_coding.parity = parity;
- p_cdc->line_coding.data_bits = data_bits;
- return true;
+ p_cdc->line.coding.stop_bits = stop_bits;
+ p_cdc->line.coding.parity = parity;
+ p_cdc->line.coding.data_bits = data_bits;
}
+
+ return true;
}
-bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- cdch_interface_t* p_cdc = get_itf(idx);
+bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ cdch_interface_t *p_cdc = get_itf(idx);
TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
- cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid];
+ TU_LOG_CDC(p_cdc, "set line coding %lu %u%c%s",
+ line_coding->bit_rate, line_coding->data_bits,
+ CDC_LINE_CODING_PARITY_CHAR(line_coding->parity),
+ CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits));
+ cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid];
+ p_cdc->requested_line.coding = *line_coding;
+ p_cdc->user_complete_cb = complete_cb;
- if ( complete_cb ) {
- return driver->set_line_coding(p_cdc, line_coding, complete_cb, user_data);
- } else {
- // blocking
- xfer_result_t result = XFER_RESULT_INVALID;
- bool ret = driver->set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result);
+ if (driver->set_line_coding) {
+ // driver support set_line_coding request
+ TU_VERIFY(driver->set_line_coding(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data));
- if (user_data) {
- // user_data is not NULL, return result via user_data
- *((xfer_result_t*) user_data) = result;
+ if (!complete_cb) {
+ p_cdc->line.coding = *line_coding;
}
+ } else {
+ // driver does not support set_line_coding and need 2 stage to set baudrate and data format separately
+ if (complete_cb) {
+ // non-blocking
+ TU_VERIFY(driver->set_baudrate(p_cdc, cdch_set_line_coding_stage1_baudrate_complete, user_data));
+ } else {
+ // blocking
+ xfer_result_t result = XFER_RESULT_INVALID;
- TU_VERIFY(ret && result == XFER_RESULT_SUCCESS);
- p_cdc->line_coding = *line_coding;
- return true;
+ TU_VERIFY(driver->set_baudrate(p_cdc, NULL, (uintptr_t) &result));
+ if (user_data) {
+ *((xfer_result_t *) user_data) = result;
+ }
+ TU_VERIFY(result == XFER_RESULT_SUCCESS);
+ p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; // update baudrate
+
+ result = XFER_RESULT_INVALID;
+ TU_VERIFY(driver->set_data_format(p_cdc, NULL, (uintptr_t) &result));
+ if (user_data) {
+ *((xfer_result_t *) user_data) = result;
+ }
+ TU_VERIFY(result == XFER_RESULT_SUCCESS);
+ p_cdc->line.coding = p_cdc->requested_line.coding; // update data format
+ }
}
+
+ return true;
}
//--------------------------------------------------------------------+
@@ -627,8 +627,8 @@ bool cdch_init(void) {
TU_LOG_DRV("sizeof(cdch_interface_t) = %u\r\n", sizeof(cdch_interface_t));
tu_memclr(cdch_data, sizeof(cdch_data));
for (size_t i = 0; i < CFG_TUH_CDC; i++) {
- cdch_interface_t* p_cdc = &cdch_data[i];
- cdch_epbuf_t* epbuf = &cdch_epbuf[i];
+ cdch_interface_t *p_cdc = &cdch_data[i];
+ cdch_epbuf_t *epbuf = &cdch_epbuf[i];
tu_edpt_stream_init(&p_cdc->stream.tx, true, true, false,
p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE,
epbuf->tx, CFG_TUH_CDC_TX_EPSIZE);
@@ -643,7 +643,7 @@ bool cdch_init(void) {
bool cdch_deinit(void) {
for (size_t i = 0; i < CFG_TUH_CDC; i++) {
- cdch_interface_t* p_cdc = &cdch_data[i];
+ cdch_interface_t *p_cdc = &cdch_data[i];
tu_edpt_stream_deinit(&p_cdc->stream.tx);
tu_edpt_stream_deinit(&p_cdc->stream.rx);
}
@@ -652,9 +652,9 @@ bool cdch_deinit(void) {
void cdch_close(uint8_t daddr) {
for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) {
- cdch_interface_t* p_cdc = &cdch_data[idx];
+ cdch_interface_t *p_cdc = &cdch_data[idx];
if (p_cdc->daddr == daddr) {
- TU_LOG_DRV(" CDCh close addr = %u index = %u\r\n", daddr, idx);
+ TU_LOG_CDC(p_cdc, "close");
// Invoke application callback
if (tuh_cdc_umount_cb) {
@@ -672,45 +672,50 @@ 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);
+ cdch_interface_t *p_cdc = get_itf(idx);
TU_ASSERT(p_cdc);
- if ( ep_addr == p_cdc->stream.tx.ep_addr ) {
+ if (ep_addr == p_cdc->stream.tx.ep_addr) {
// invoke tx complete callback to possibly refill tx fifo
if (tuh_cdc_tx_complete_cb) {
tuh_cdc_tx_complete_cb(idx);
}
- if ( 0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx) ) {
+ if (0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx)) {
// If there is no data left, a ZLP should be sent if:
// - xferred_bytes is multiple of EP Packet size and not zero
tu_edpt_stream_write_zlp_if_needed(daddr, &p_cdc->stream.tx, xferred_bytes);
}
- } else if ( ep_addr == p_cdc->stream.rx.ep_addr ) {
+ } else if (ep_addr == p_cdc->stream.rx.ep_addr) {
#if CFG_TUH_CDC_FTDI
- if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI && xferred_bytes > 2) {
+ if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) {
// FTDI reserve 2 bytes for status
// uint8_t status[2] = {p_cdc->stream.rx.ep_buf[0], p_cdc->stream.rx.ep_buf[1]};
- tu_edpt_stream_read_xfer_complete_with_buf(&p_cdc->stream.rx, p_cdc->stream.rx.ep_buf+2, xferred_bytes-2);
- }else
+ if (xferred_bytes > 2) {
+ tu_edpt_stream_read_xfer_complete_with_buf(&p_cdc->stream.rx, p_cdc->stream.rx.ep_buf + 2, xferred_bytes - 2);
+
+ if (tuh_cdc_rx_cb) {
+ tuh_cdc_rx_cb(idx); // invoke receive callback
+ }
+ }
+ } else
#endif
{
tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes);
- }
- // invoke receive callback
- if (tuh_cdc_rx_cb) {
- tuh_cdc_rx_cb(idx);
+ if (tuh_cdc_rx_cb) {
+ tuh_cdc_rx_cb(idx); // invoke receive callback
+ }
}
// prepare for next transfer if needed
tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx);
- }else if ( ep_addr == p_cdc->ep_notif ) {
+ } else if (ep_addr == p_cdc->ep_notif) {
// TODO handle notification endpoint
- }else {
+ } else {
TU_ASSERT(false);
}
@@ -721,7 +726,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t
// Enumeration
//--------------------------------------------------------------------+
-static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const* desc_ep) {
+static bool open_ep_stream_pair(cdch_interface_t *p_cdc, tusb_desc_endpoint_t const *desc_ep) {
for (size_t i = 0; i < 2; i++) {
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType &&
TUSB_XFER_BULK == desc_ep->bmAttributes.xfer);
@@ -733,7 +738,7 @@ static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t co
tu_edpt_stream_open(&p_cdc->stream.tx, desc_ep);
}
- desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(desc_ep);
+ desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep);
}
return true;
@@ -741,10 +746,9 @@ static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t co
bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
(void) rhport;
-
// For CDC: only support ACM subclass
// Note: Protocol 0xFF can be RNDIS device
- if (TUSB_CLASS_CDC == itf_desc->bInterfaceClass &&
+ if (TUSB_CLASS_CDC == itf_desc->bInterfaceClass &&
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) {
return acm_open(daddr, itf_desc, max_len);
} else if (SERIAL_DRIVER_COUNT > 1 &&
@@ -753,10 +757,12 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d
TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid));
for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) {
- cdch_serial_driver_t const* driver = &serial_drivers[dr];
+ const cdch_serial_driver_t *driver = &serial_drivers[dr];
for (size_t i = 0; i < driver->vid_pid_count; i++) {
if (driver->vid_pid_list[i][0] == vid && driver->vid_pid_list[i][1] == pid) {
- return driver->open(daddr, itf_desc, max_len);
+ const bool ret = driver->open(daddr, itf_desc, max_len);
+ TU_LOG_DRV("[:%u:%u] CDCh %s open %s\r\n", daddr, itf_desc->bInterfaceNumber, driver->name, ret ? "OK" : "FAILED");
+ return ret;
}
}
}
@@ -765,123 +771,170 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d
return false;
}
-static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) {
- TU_LOG_DRV("CDCh Set Configure complete\r\n");
- p_cdc->mounted = true;
- if (tuh_cdc_mount_cb) {
- tuh_cdc_mount_cb(idx);
- }
-
- // Prepare for incoming data
- tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx);
-
- // notify usbh that driver enumeration is complete
- usbh_driver_set_config_complete(p_cdc->daddr, itf_num);
-}
-
bool cdch_set_config(uint8_t daddr, uint8_t itf_num) {
tusb_control_request_t request;
request.wIndex = tu_htole16((uint16_t) itf_num);
-
- // fake transfer to kick-off process
- tuh_xfer_t xfer;
- xfer.daddr = daddr;
- xfer.result = XFER_RESULT_SUCCESS;
- xfer.setup = &request;
- xfer.user_data = 0; // initial state
-
uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num);
- cdch_interface_t * p_cdc = get_itf(idx);
+ cdch_interface_t *p_cdc = get_itf(idx);
TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
+ TU_LOG_CDC(p_cdc, "set config");
+
+ // fake transfer to kick-off process_set_config()
+ tuh_xfer_t xfer;
+ xfer.daddr = daddr;
+ xfer.result = XFER_RESULT_SUCCESS;
+ xfer.setup = &request;
+ xfer.user_data = 0; // initial state 0
+ cdch_process_set_config(&xfer);
- serial_drivers[p_cdc->serial_drid].process_set_config(&xfer);
return true;
}
+static void set_config_complete(cdch_interface_t *p_cdc, bool success) {
+ if (success) {
+ const uint8_t idx = get_idx_by_ptr(p_cdc);
+ p_cdc->mounted = true;
+ if (tuh_cdc_mount_cb) {
+ tuh_cdc_mount_cb(idx);
+ }
+ // Prepare for incoming data
+ tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx);
+ } else {
+ // clear the interface entry
+ p_cdc->daddr = 0;
+ p_cdc->bInterfaceNumber = 0;
+ }
+
+ // notify usbh that driver enumeration is complete
+ const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0;
+ usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset);
+}
+
+static void cdch_process_set_config(tuh_xfer_t *xfer) {
+ cdch_interface_t *p_cdc = get_itf_by_xfer(xfer);
+ TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,);
+ TU_LOG_DRV(" state = %u\r\n", xfer->user_data);
+ const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid];
+
+ if (!driver->process_set_config(p_cdc, xfer)) {
+ set_config_complete(p_cdc, false);
+ }
+}
+
+static bool set_line_state_on_enum(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
+ enum {
+ ENUM_SET_LINE_CODING = 0,
+ ENUM_SET_LINE_CONTROL,
+ ENUM_SET_LINE_COMPLETE,
+ };
+ const uint8_t idx = get_idx_by_ptr(p_cdc);
+ const uintptr_t state = xfer->user_data;
+
+ switch (state) {
+ case ENUM_SET_LINE_CODING: {
+ #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
+ // ch34x already set line coding in serial init
+ if (p_cdc->serial_drid != SERIAL_DRIVER_CH34X) {
+ const cdc_line_coding_t line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM;
+ TU_ASSERT(tuh_cdc_set_line_coding(idx, &line_coding,
+ cdch_process_line_state_on_enum, ENUM_SET_LINE_CONTROL));
+ break;
+ }
+ #endif
+ TU_ATTR_FALLTHROUGH;
+ }
+
+ case ENUM_SET_LINE_CONTROL:
+ #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
+ TU_ASSERT(tuh_cdc_set_control_line_state(idx, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM,
+ cdch_process_line_state_on_enum, ENUM_SET_LINE_COMPLETE));
+ break;
+ #else
+ TU_ATTR_FALLTHROUGH;
+ #endif
+
+ case ENUM_SET_LINE_COMPLETE:
+ set_config_complete(p_cdc, true);
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+static void cdch_process_line_state_on_enum(tuh_xfer_t *xfer) {
+ cdch_interface_t *p_cdc = get_itf_by_xfer(xfer);
+ TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,);
+ if (xfer->result != XFER_RESULT_SUCCESS || !set_line_state_on_enum(p_cdc, xfer)) {
+ set_config_complete(p_cdc, false);
+ }
+}
+
+
+static void cdch_internal_control_complete(tuh_xfer_t *xfer) {
+ cdch_interface_t *p_cdc = get_itf_by_xfer(xfer);
+ TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,);
+ TU_LOG_DRV(" request result = %u\r\n", xfer->result);
+ const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid];
+ driver->request_complete(p_cdc, xfer);
+
+ // Invoke application callback
+ xfer->complete_cb = p_cdc->user_complete_cb;
+ if (xfer->complete_cb) {
+ xfer->complete_cb(xfer);
+ }
+}
+
+static void cdch_set_line_coding_stage1_baudrate_complete(tuh_xfer_t *xfer) {
+ cdch_interface_t *p_cdc = get_itf_by_xfer(xfer);
+ TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,);
+ TU_LOG_DRV(" stage1 set baudrate result = %u\r\n", xfer->result);
+ const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid];
+
+ if (xfer->result == XFER_RESULT_SUCCESS) {
+ p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; // update baudrate
+ TU_ASSERT(driver->set_data_format(p_cdc, cdch_set_line_coding_stage2_data_format_complete, xfer->user_data),);
+ } else {
+ xfer->complete_cb = p_cdc->user_complete_cb;
+ if (xfer->complete_cb) {
+ xfer->complete_cb(xfer);
+ }
+ }
+}
+
+static void cdch_set_line_coding_stage2_data_format_complete(tuh_xfer_t *xfer) {
+ cdch_interface_t *p_cdc = get_itf_by_xfer(xfer);
+ TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,);
+ TU_LOG_DRV(" stage2 set data format result = %u\r\n", xfer->result);
+
+ if (xfer->result == XFER_RESULT_SUCCESS) {
+ p_cdc->line.coding = p_cdc->requested_line.coding; // update data format
+ }
+
+ xfer->complete_cb = p_cdc->user_complete_cb;
+ if (xfer->complete_cb) {
+ xfer->complete_cb(xfer);
+ }
+}
+
//--------------------------------------------------------------------+
// ACM
//--------------------------------------------------------------------+
-enum {
- CONFIG_ACM_SET_CONTROL_LINE_STATE = 0,
- CONFIG_ACM_SET_LINE_CODING,
- CONFIG_ACM_COMPLETE,
-};
+// internal control complete to update state such as line state, encoding
+static void acm_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
+ TU_VERIFY (xfer->result == XFER_RESULT_SUCCESS,);
+ const tusb_control_request_t * setup = xfer->setup;
-static bool acm_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) {
- uint8_t const* p_desc_end = ((uint8_t const*) itf_desc) + max_len;
+ switch (setup->bRequest) {
+ case CDC_REQUEST_SET_CONTROL_LINE_STATE:
+ p_cdc->line.control_state = p_cdc->requested_line.control_state;
+ break;
- cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc);
- TU_VERIFY(p_cdc);
- p_cdc->serial_drid = SERIAL_DRIVER_ACM;
-
- //------------- Control Interface -------------//
- uint8_t const* p_desc = tu_desc_next(itf_desc);
-
- // Communication Functional Descriptors
- while ((p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc))) {
- if (CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc)) {
- // save ACM bmCapabilities
- p_cdc->acm_capability = ((cdc_desc_func_acm_t const*) p_desc)->bmCapabilities;
- }
-
- p_desc = tu_desc_next(p_desc);
- }
-
- // Open notification endpoint of control interface if any
- if (itf_desc->bNumEndpoints == 1) {
- TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc));
- tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc;
-
- TU_ASSERT(tuh_edpt_open(daddr, desc_ep));
- p_cdc->ep_notif = desc_ep->bEndpointAddress;
-
- p_desc = tu_desc_next(p_desc);
- }
-
- //------------- Data Interface (if any) -------------//
- if ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
- (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const*) p_desc)->bInterfaceClass)) {
- // next to endpoint descriptor
- p_desc = tu_desc_next(p_desc);
-
- // data endpoints expected to be in pairs
- TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const*) p_desc));
- }
-
- return true;
-}
-
-static void acm_process_config(tuh_xfer_t* xfer) {
- uintptr_t const state = xfer->user_data;
- uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
- uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
- cdch_interface_t* p_cdc = get_itf(idx);
- TU_ASSERT(p_cdc,);
-
- switch (state) {
- case CONFIG_ACM_SET_CONTROL_LINE_STATE:
- #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
- if (p_cdc->acm_capability.support_line_request) {
- TU_ASSERT(acm_set_control_line_state(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, acm_process_config, CONFIG_ACM_SET_LINE_CODING),);
- break;
- }
- #endif
- TU_ATTR_FALLTHROUGH;
-
- case CONFIG_ACM_SET_LINE_CODING:
- #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
- if (p_cdc->acm_capability.support_line_request) {
- cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
- TU_ASSERT(acm_set_line_coding(p_cdc, &line_coding, acm_process_config, CONFIG_ACM_COMPLETE),);
- break;
- }
- #endif
- TU_ATTR_FALLTHROUGH;
-
- case CONFIG_ACM_COMPLETE:
- // itf_num+1 to account for data interface as well
- set_config_complete(p_cdc, idx, itf_num + 1);
+ case CDC_REQUEST_SET_LINE_CODING:
+ p_cdc->line.coding = p_cdc->requested_line.coding;
break;
default:
@@ -889,135 +942,21 @@ static void acm_process_config(tuh_xfer_t* xfer) {
}
}
-static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- TU_VERIFY(p_cdc->acm_capability.support_line_request);
- TU_LOG_DRV("CDC ACM Set Control Line State\r\n");
+static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ TU_VERIFY(p_cdc->acm.capability.support_line_request);
- tusb_control_request_t const request = {
+ const tusb_control_request_t request = {
.bmRequestType_bit = {
.recipient = TUSB_REQ_RCPT_INTERFACE,
.type = TUSB_REQ_TYPE_CLASS,
.direction = TUSB_DIR_OUT
},
.bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
- .wValue = tu_htole16(line_state),
+ .wValue = tu_htole16((uint16_t) p_cdc->requested_line.control_state.value),
.wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber),
.wLength = 0
};
- p_cdc->user_control_cb = complete_cb;
-
- tuh_xfer_t xfer = {
- .daddr = p_cdc->daddr,
- .ep_addr = 0,
- .setup = &request,
- .buffer = NULL,
- .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call
- .user_data = user_data
- };
-
- TU_ASSERT(tuh_control_xfer(&xfer));
- return true;
-}
-
-static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- TU_LOG_DRV("CDC ACM Set Line Conding\r\n");
-
- tusb_control_request_t const request = {
- .bmRequestType_bit = {
- .recipient = TUSB_REQ_RCPT_INTERFACE,
- .type = TUSB_REQ_TYPE_CLASS,
- .direction = TUSB_DIR_OUT
- },
- .bRequest = CDC_REQUEST_SET_LINE_CODING,
- .wValue = 0,
- .wIndex = tu_htole16(p_cdc->bInterfaceNumber),
- .wLength = tu_htole16(sizeof(cdc_line_coding_t))
- };
-
- // use usbh enum buf to hold line coding since user line_coding variable does not live long enough
- uint8_t* enum_buf = usbh_get_enum_buf();
- memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t));
-
- p_cdc->user_control_cb = complete_cb;
- tuh_xfer_t xfer = {
- .daddr = p_cdc->daddr,
- .ep_addr = 0,
- .setup = &request,
- .buffer = enum_buf,
- .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call
- .user_data = user_data
- };
-
- TU_ASSERT(tuh_control_xfer(&xfer));
- return true;
-}
-
-static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits,
- tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- TU_LOG_DRV("CDC ACM Set Data Format\r\n");
-
- cdc_line_coding_t line_coding;
- line_coding.bit_rate = p_cdc->line_coding.bit_rate;
- line_coding.stop_bits = stop_bits;
- line_coding.parity = parity;
- line_coding.data_bits = data_bits;
-
- return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data);
-}
-
-static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- TU_VERIFY(p_cdc->acm_capability.support_line_request);
- cdc_line_coding_t line_coding = p_cdc->line_coding;
- line_coding.bit_rate = baudrate;
- return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data);
-}
-
-//--------------------------------------------------------------------+
-// FTDI
-//--------------------------------------------------------------------+
-#if CFG_TUH_CDC_FTDI
-
-enum {
- CONFIG_FTDI_RESET = 0,
- CONFIG_FTDI_MODEM_CTRL,
- CONFIG_FTDI_SET_BAUDRATE,
- CONFIG_FTDI_SET_DATA,
- CONFIG_FTDI_COMPLETE
-};
-
-static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) {
- // FTDI Interface includes 1 vendor interface + 2 bulk endpoints
- TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2);
- TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len);
-
- cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc);
- TU_VERIFY(p_cdc);
-
- TU_LOG_DRV("FTDI opened\r\n");
- p_cdc->serial_drid = SERIAL_DRIVER_FTDI;
-
- // endpoint pair
- tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
-
- // data endpoints expected to be in pairs
- return open_ep_stream_pair(p_cdc, desc_ep);
-}
-
-// set request without data
-static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- tusb_control_request_t const request = {
- .bmRequestType_bit = {
- .recipient = TUSB_REQ_RCPT_DEVICE,
- .type = TUSB_REQ_TYPE_VENDOR,
- .direction = TUSB_DIR_OUT
- },
- .bRequest = command,
- .wValue = tu_htole16(value),
- .wIndex = 0,
- .wLength = 0
- };
-
tuh_xfer_t xfer = {
.daddr = p_cdc->daddr,
.ep_addr = 0,
@@ -1030,125 +969,502 @@ static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint1
return tuh_control_xfer(&xfer);
}
-static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data);
+static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ TU_VERIFY(p_cdc->acm.capability.support_line_request);
+ TU_VERIFY((p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8) ||
+ p_cdc->requested_line.coding.data_bits == 16);
+
+ tusb_control_request_t const request = {
+ .bmRequestType_bit = {
+ .recipient = TUSB_REQ_RCPT_INTERFACE,
+ .type = TUSB_REQ_TYPE_CLASS,
+ .direction = TUSB_DIR_OUT
+ },
+ .bRequest = CDC_REQUEST_SET_LINE_CODING,
+ .wValue = 0,
+ .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber),
+ .wLength = tu_htole16((uint16_t) sizeof(cdc_line_coding_t))
+ };
+
+ // use usbh enum buf to hold line coding since user line_coding variable does not live long enough
+ uint8_t *enum_buf = usbh_get_enum_buf();
+ memcpy(enum_buf, &p_cdc->requested_line.coding, sizeof(cdc_line_coding_t));
+
+ tuh_xfer_t xfer = {
+ .daddr = p_cdc->daddr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = enum_buf,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
+
+ return tuh_control_xfer(&xfer);
}
-static bool ftdi_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits,
- tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- (void) p_cdc;
- (void) stop_bits;
- (void) parity;
- (void) data_bits;
- (void) complete_cb;
- (void) user_data;
- // TODO not implemented yet
- return false;
-}
+//------------- Enumeration -------------//
+enum {
+ CONFIG_ACM_COMPLETE = 0
+};
-static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- (void) p_cdc;
- (void) line_coding;
- (void) complete_cb;
- (void) user_data;
- // TODO not implemented yet
- return false;
-}
+static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
+ uint8_t const *p_desc_end = ((uint8_t const *) itf_desc) + max_len;
+
+ cdch_interface_t *p_cdc = make_new_itf(daddr, itf_desc);
+ TU_VERIFY(p_cdc);
+
+ p_cdc->serial_drid = SERIAL_DRIVER_ACM;
+
+ //------------- Control Interface -------------//
+ uint8_t const *p_desc = tu_desc_next(itf_desc);
+
+ // Communication Functional Descriptors
+ while ((p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc))) {
+ if (CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc)) {
+ // save ACM bmCapabilities
+ p_cdc->acm.capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities;
+ }
+
+ p_desc = tu_desc_next(p_desc);
+ }
+
+ // Open notification endpoint of control interface if any
+ if (itf_desc->bNumEndpoints == 1) {
+ TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc));
+ tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
+
+ TU_ASSERT(tuh_edpt_open(daddr, desc_ep));
+ p_cdc->ep_notif = desc_ep->bEndpointAddress;
+
+ p_desc = tu_desc_next(p_desc);
+ }
+
+ //------------- Data Interface (if any) -------------//
+ if ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
+ (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass)) {
+ // next to endpoint descriptor
+ p_desc = tu_desc_next(p_desc);
+
+ // data endpoints expected to be in pairs
+ TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const *) p_desc));
+ }
-static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- TU_LOG_DRV("CDC FTDI Set Control Line State\r\n");
- p_cdc->user_control_cb = complete_cb;
- TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state,
- complete_cb ? cdch_internal_control_complete : NULL, user_data));
return true;
}
-static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) {
- const uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
- uint32_t divisor;
+static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
+ TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS);
+ (void) p_cdc;
+ const uintptr_t state = xfer->user_data;
- /* divisor shifted 3 bits to the left */
- uint32_t divisor3 = base / (2 * baud);
- divisor = (divisor3 >> 3);
- divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14;
+ switch (state) {
+ case CONFIG_ACM_COMPLETE: {
+ xfer->user_data = 0; // kick-off set line state on enum
+ cdch_process_line_state_on_enum(xfer);
+ break;
+ }
- /* Deal with special cases for highest baud rates. */
- if (divisor == 1) { /* 1.0 */
- divisor = 0;
+ default:
+ return false; // invalid state
}
- else if (divisor == 0x4001) { /* 1.5 */
+
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// FTDI
+//--------------------------------------------------------------------+
+#if CFG_TUH_CDC_FTDI
+
+static bool ftdi_determine_type(cdch_interface_t *p_cdc);
+static uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc);
+
+//------------- Control Request -------------//
+
+// set request without data
+static bool ftdi_set_request(cdch_interface_t *p_cdc, uint8_t request, uint8_t requesttype,
+ uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ tusb_control_request_t const request_setup = {
+ .bmRequestType = requesttype,
+ .bRequest = request,
+ .wValue = tu_htole16(value),
+ .wIndex = tu_htole16(index),
+ .wLength = 0
+ };
+
+ tuh_xfer_t xfer = {
+ .daddr = p_cdc->daddr,
+ .ep_addr = 0,
+ .setup = &request_setup,
+ .buffer = NULL,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
+
+ return tuh_control_xfer(&xfer);
+}
+
+#ifdef CFG_TUH_CDC_FTDI_LATENCY
+static int8_t ftdi_write_latency_timer(cdch_interface_t * p_cdc, uint16_t latency,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ if (p_cdc->ftdi.chip_type == FTDI_SIO /* || p_cdc->ftdi.chip_type == FT232A */ )
+ return FTDI_NOT_POSSIBLE;
+ return ftdi_set_request(p_cdc, FTDI_SIO_SET_LATENCY_TIMER_REQUEST, FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
+ latency, p_cdc->ftdi.channel, complete_cb, user_data) ? FTDI_REQUESTED : FTDI_FAIL;
+}
+#endif
+
+static inline bool ftdi_sio_reset(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ return ftdi_set_request(p_cdc, FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, FTDI_SIO_RESET_SIO,
+ p_cdc->ftdi.channel, complete_cb, user_data);
+}
+
+
+//------------- Driver API -------------//
+
+// internal control complete to update state such as line state, line_coding
+static void ftdi_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t *xfer) {
+ TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,);
+ const tusb_control_request_t * setup = xfer->setup;
+ if (xfer->result == XFER_RESULT_SUCCESS) {
+ if (setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST &&
+ setup->bmRequestType == FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE ) {
+ p_cdc->line.control_state = p_cdc->requested_line.control_state;
+ }
+ if (setup->bRequest == FTDI_SIO_SET_DATA_REQUEST &&
+ setup->bmRequestType == FTDI_SIO_SET_DATA_REQUEST_TYPE ) {
+ p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits;
+ p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity;
+ p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits;
+ }
+ if (setup->bRequest == FTDI_SIO_SET_BAUDRATE_REQUEST &&
+ setup->bmRequestType == FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE ) {
+ p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate;
+ }
+ }
+}
+
+static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 7 && p_cdc->requested_line.coding.data_bits <= 8, 0);
+ uint16_t value = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3
+ (p_cdc->requested_line.coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding
+ (p_cdc->requested_line.coding.stop_bits & 0x3UL) << 11); // stop bits quantity is stored in bits 11-12, same coding
+ // not each FTDI supports 1.5 stop bits
+ return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE,
+ value, p_cdc->ftdi.channel, complete_cb, user_data);
+}
+
+static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ uint32_t index_value = ftdi_get_divisor(p_cdc);
+ TU_VERIFY(index_value);
+ uint16_t value = (uint16_t) index_value;
+ uint16_t index = (uint16_t) (index_value >> 16);
+ if (p_cdc->ftdi.channel) {
+ index = (uint16_t) ((index << 8) | p_cdc->ftdi.channel);
+ }
+
+ return ftdi_set_request(p_cdc, FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
+ value, index, complete_cb, user_data);
+}
+
+static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ uint16_t line_state = (uint16_t) ((p_cdc->requested_line.control_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) |
+ (p_cdc->requested_line.control_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW));
+ return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ line_state, p_cdc->ftdi.channel, complete_cb ? cdch_internal_control_complete : NULL, user_data);
+}
+
+//------------- Enumeration -------------//
+enum {
+ CONFIG_FTDI_DETERMINE_TYPE = 0,
+ CONFIG_FTDI_WRITE_LATENCY,
+ CONFIG_FTDI_SIO_RESET,
+ CONFIG_FTDI_FLOW_CONTROL,
+ CONFIG_FTDI_COMPLETE
+};
+
+static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) {
+ // FTDI Interface includes 1 vendor interface + 2 bulk endpoints
+ TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff &&
+ itf_desc->bNumEndpoints == 2);
+ TU_VERIFY(sizeof(tusb_desc_interface_t) + 2 * sizeof(tusb_desc_endpoint_t) <= max_len);
+
+ cdch_interface_t *p_cdc = make_new_itf(daddr, itf_desc);
+ TU_VERIFY(p_cdc);
+
+ p_cdc->serial_drid = SERIAL_DRIVER_FTDI;
+
+ // endpoint pair
+ tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
+
+ /*
+ * NOTE: Some customers have programmed FT232R/FT245R devices
+ * with an endpoint size of 0 - not good.
+ */
+ TU_ASSERT(desc_ep->wMaxPacketSize != 0);
+
+ // data endpoints expected to be in pairs
+ return open_ep_stream_pair(p_cdc, desc_ep);
+}
+
+static bool ftdi_proccess_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
+ TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS);
+ const uintptr_t state = xfer->user_data;
+ switch (state) {
+ // from here sequence overtaken from Linux Kernel function ftdi_port_probe()
+ case CONFIG_FTDI_DETERMINE_TYPE:
+ // determine type
+ if (p_cdc->bInterfaceNumber == 0) {
+ TU_ASSERT(ftdi_determine_type(p_cdc));
+ } else {
+ // other interfaces have same type as interface 0
+ uint8_t const idx_itf0 = tuh_cdc_itf_get_index(xfer->daddr, 0);
+ cdch_interface_t const *p_cdc_itf0 = get_itf(idx_itf0);
+ TU_ASSERT(p_cdc_itf0);
+ p_cdc->ftdi.chip_type = p_cdc_itf0->ftdi.chip_type;
+ }
+ TU_ATTR_FALLTHROUGH;
+
+ case CONFIG_FTDI_WRITE_LATENCY:
+ #ifdef CFG_TUH_CDC_FTDI_LATENCY
+ int8_t result = ftdi_write_latency_timer(p_cdc, CFG_TUH_CDC_FTDI_LATENCY, ftdi_process_config,
+ CONFIG_FTDI_SIO_RESET);
+ TU_ASSERT(result != FTDI_FAIL);
+ if (result == FTDI_REQUESTED) {
+ break;
+ }// else FTDI_NOT_POSSIBLE => continue directly with next state
+ #endif
+ TU_ATTR_FALLTHROUGH;
+
+ // from here sequence overtaken from Linux Kernel function ftdi_open()
+ case CONFIG_FTDI_SIO_RESET:
+ TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, CONFIG_FTDI_FLOW_CONTROL));
+ break;
+
+ case CONFIG_FTDI_FLOW_CONTROL:
+ // disable flow control
+ TU_ASSERT(ftdi_set_request(p_cdc, FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, FTDI_SIO_DISABLE_FLOW_CTRL,
+ p_cdc->ftdi.channel, cdch_process_set_config, CONFIG_FTDI_COMPLETE));
+ break;
+
+ case CONFIG_FTDI_COMPLETE: {
+ xfer->user_data = 0; // kick-off set line state on enum
+ cdch_process_line_state_on_enum(xfer);
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+//------------- Helper -------------//
+
+static bool ftdi_determine_type(cdch_interface_t *p_cdc) {
+ tusb_desc_device_t desc_dev;
+ TU_VERIFY(tuh_descriptor_get_device_local(p_cdc->daddr, &desc_dev));
+ uint16_t const version = desc_dev.bcdDevice;
+ uint8_t const itf_num = p_cdc->bInterfaceNumber;
+
+ p_cdc->ftdi.chip_type = FTDI_UNKNOWN;
+
+ /* Assume Hi-Speed type */
+ p_cdc->ftdi.channel = CHANNEL_A + itf_num;
+
+ switch (version) {
+ case 0x200:
+ // FT232A not supported to keep it simple (no extra _read_latency_timer()) not testable
+ // p_cdc->ftdi.chip_type = FT232A;
+ // p_cdc->ftdi.baud_base = 48000000 / 2;
+ // p_cdc->ftdi.channel = 0;
+ // /*
+ // * FT232B devices have a bug where bcdDevice gets set to 0x200
+ // * when iSerialNumber is 0. Assume it is an FT232B in case the
+ // * latency timer is readable.
+ // */
+ // if (desc->iSerialNumber == 0 &&
+ // _read_latency_timer(port) >= 0) {
+ // p_cdc->ftdi.chip_type = FTDI_FT232B;
+ // }
+ break;
+
+ case 0x400 : p_cdc->ftdi.chip_type = FTDI_FT232B; p_cdc->ftdi.channel = 0; break;
+ case 0x500 : p_cdc->ftdi.chip_type = FTDI_FT2232C; break;
+ case 0x600 : p_cdc->ftdi.chip_type = FTDI_FT232R; p_cdc->ftdi.channel = 0; break;
+ case 0x700 : p_cdc->ftdi.chip_type = FTDI_FT2232H; break;
+ case 0x800 : p_cdc->ftdi.chip_type = FTDI_FT4232H; break;
+ case 0x900 : p_cdc->ftdi.chip_type = FTDI_FT232H; break;
+ case 0x1000: p_cdc->ftdi.chip_type = FTDI_FTX; break;
+ case 0x2800: p_cdc->ftdi.chip_type = FTDI_FT2233HP; break;
+ case 0x2900: p_cdc->ftdi.chip_type = FTDI_FT4233HP; break;
+ case 0x3000: p_cdc->ftdi.chip_type = FTDI_FT2232HP; break;
+ case 0x3100: p_cdc->ftdi.chip_type = FTDI_FT4232HP; break;
+ case 0x3200: p_cdc->ftdi.chip_type = FTDI_FT233HP; break;
+ case 0x3300: p_cdc->ftdi.chip_type = FTDI_FT232HP; break;
+ case 0x3600: p_cdc->ftdi.chip_type = FTDI_FT4232HA; break;
+
+ default:
+ if (version < 0x200) {
+ p_cdc->ftdi.chip_type = FTDI_SIO;
+ p_cdc->ftdi.channel = 0;
+ }
+ break;
+ }
+
+ #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL
+ const char * ftdi_chip_name[] = { FTDI_CHIP_NAMES };
+ TU_LOG_CDC(p_cdc, "%s detected (bcdDevice = 0x%04x)",
+ ftdi_chip_name[p_cdc->ftdi.chip_type], version);
+ #endif
+
+ return (p_cdc->ftdi.chip_type != FTDI_UNKNOWN);
+}
+
+// FT232A not supported
+//static uint32_t ftdi_232am_baud_base_to_divisor(uint32_t baud, uint32_t base)
+//{
+// uint32_t divisor;
+// /* divisor shifted 3 bits to the left */
+// uint32_t divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud);
+// if ((divisor3 & 0x7) == 7)
+// divisor3++; /* round x.7/8 up to x+1 */
+// divisor = divisor3 >> 3;
+// divisor3 &= 0x7;
+// if (divisor3 == 1)
+// divisor |= 0xc000; /* +0.125 */
+// else if (divisor3 >= 4)
+// divisor |= 0x4000; /* +0.5 */
+// else if (divisor3 != 0)
+// divisor |= 0x8000; /* +0.25 */
+// else if (divisor == 1)
+// divisor = 0; /* special case for maximum baud rate */
+// return divisor;
+//}
+
+// FT232A not supported
+//static inline uint32_t ftdi_232am_baud_to_divisor(uint32_t baud)
+//{
+// return ftdi_232am_baud_base_to_divisor(baud, (uint32_t) 48000000);
+//}
+
+static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) {
+ uint8_t divfrac[8] = {0, 3, 2, 4, 1, 5, 6, 7};
+ uint32_t divisor;
+ /* divisor shifted 3 bits to the left */
+ uint32_t divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud);
+ divisor = divisor3 >> 3;
+ divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14;
+ /* Deal with special cases for highest baud rates. */
+ if (divisor == 1) /* 1.0 */ {
+ divisor = 0;
+ } else if (divisor == 0x4001) /* 1.5 */ {
divisor = 1;
}
-
return divisor;
}
-static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) {
- return ftdi_232bm_baud_base_to_divisor(baud, 48000000u);
+static inline uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) {
+ return ftdi_232bm_baud_base_to_divisor(baud, 48000000);
}
-static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate);
- TU_LOG_DRV("CDC FTDI Set BaudRate = %" PRIu32 ", divisor = 0x%04x\r\n", baudrate, divisor);
+static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, uint32_t base) {
+ static const unsigned char divfrac[8] = {0, 3, 2, 4, 1, 5, 6, 7};
+ uint32_t divisor;
+ uint32_t divisor3;
- p_cdc->user_control_cb = complete_cb;
- p_cdc->requested_line_coding.bit_rate = baudrate;
- TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor,
- complete_cb ? cdch_internal_control_complete : NULL, user_data));
+ /* hi-speed baud rate is 10-bit sampling instead of 16-bit */
+ divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud);
- return true;
+ divisor = divisor3 >> 3;
+ divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14;
+ /* Deal with special cases for highest baud rates. */
+ if (divisor == 1) /* 1.0 */ {
+ divisor = 0;
+ } else if (divisor == 0x4001) /* 1.5 */ {
+ divisor = 1;
+ }
+ /*
+ * Set this bit to turn off a divide by 2.5 on baud rate generator
+ * This enables baud rates up to 12Mbaud but cannot reach below 1200
+ * baud with this bit set
+ */
+ divisor |= 0x00020000;
+ return divisor;
}
-static void ftdi_process_config(tuh_xfer_t* xfer) {
- uintptr_t const state = xfer->user_data;
- uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
- uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
- cdch_interface_t * p_cdc = get_itf(idx);
- TU_ASSERT(p_cdc, );
+static inline uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud) {
+ return ftdi_2232h_baud_base_to_divisor(baud, (uint32_t) 120000000);
+}
- switch(state) {
- // Note may need to read FTDI eeprom
- case CONFIG_FTDI_RESET:
- TU_ASSERT(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL),);
+static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) {
+ uint32_t baud = p_cdc->requested_line.coding.bit_rate;
+ uint32_t div_value = 0;
+ TU_VERIFY(baud);
+
+ switch (p_cdc->ftdi.chip_type) {
+ case FTDI_UNKNOWN:
+ return 0;
+ case FTDI_SIO:
+ switch (baud) {
+ case 300: div_value = ftdi_sio_b300; break;
+ case 600: div_value = ftdi_sio_b600; break;
+ case 1200: div_value = ftdi_sio_b1200; break;
+ case 2400: div_value = ftdi_sio_b2400; break;
+ case 4800: div_value = ftdi_sio_b4800; break;
+ case 9600: div_value = ftdi_sio_b9600; break;
+ case 19200: div_value = ftdi_sio_b19200; break;
+ case 38400: div_value = ftdi_sio_b38400; break;
+ case 57600: div_value = ftdi_sio_b57600; break;
+ case 115200: div_value = ftdi_sio_b115200; break;
+ default:
+ // Baudrate not supported
+ return 0;
+ break;
+ }
break;
-
- case CONFIG_FTDI_MODEM_CTRL:
- #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
- TU_ASSERT(ftdi_sio_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),);
+ // FT232A not supported
+ // case FT232A:
+ // if (baud <= 3000000) {
+ // div_value = ftdi_232am_baud_to_divisor(baud);
+ // } else {
+ // // Baud rate too high!
+ // baud = 9600;
+ // div_value = ftdi_232am_baud_to_divisor(9600);
+ // div_okay = false;
+ // }
+ // break;
+ case FTDI_FT232B:
+ case FTDI_FT2232C:
+ case FTDI_FT232R:
+ case FTDI_FTX:
+ TU_VERIFY(baud <= 3000000); // else Baud rate too high!
+ div_value = ftdi_232bm_baud_to_divisor(baud);
break;
- #else
- TU_ATTR_FALLTHROUGH;
- #endif
-
- case CONFIG_FTDI_SET_BAUDRATE: {
- #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
- cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
- TU_ASSERT(ftdi_sio_set_baudrate(p_cdc, line_coding.bit_rate, ftdi_process_config, CONFIG_FTDI_SET_DATA),);
- break;
- #else
- TU_ATTR_FALLTHROUGH;
- #endif
- }
-
- case CONFIG_FTDI_SET_DATA: {
- #if 0 // TODO set data format
- #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
- cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
- TU_ASSERT(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE),);
- break;
- #endif
- #endif
-
- TU_ATTR_FALLTHROUGH;
- }
-
- case CONFIG_FTDI_COMPLETE:
- set_config_complete(p_cdc, idx, itf_num);
- break;
-
+ case FTDI_FT232H:
+ case FTDI_FT2232H:
+ case FTDI_FT4232H:
+ case FTDI_FT4232HA:
+ case FTDI_FT232HP:
+ case FTDI_FT233HP:
+ case FTDI_FT2232HP:
+ case FTDI_FT2233HP:
+ case FTDI_FT4232HP:
+ case FTDI_FT4233HP:
default:
+ TU_VERIFY(baud <= 12000000); // else Baud rate too high!
+ if (baud >= 1200) {
+ div_value = ftdi_2232h_baud_to_divisor(baud);
+ } else {
+ div_value = ftdi_232bm_baud_to_divisor(baud);
+ }
break;
}
+
+ TU_LOG_CDC(p_cdc, "Baudrate divisor = 0x%lu", div_value);
+
+ return div_value;
}
#endif
@@ -1156,36 +1472,12 @@ static void ftdi_process_config(tuh_xfer_t* xfer) {
//--------------------------------------------------------------------+
// CP210x
//--------------------------------------------------------------------+
-
#if CFG_TUH_CDC_CP210X
-enum {
- CONFIG_CP210X_IFC_ENABLE = 0,
- CONFIG_CP210X_SET_BAUDRATE,
- CONFIG_CP210X_SET_LINE_CTL,
- CONFIG_CP210X_SET_DTR_RTS,
- CONFIG_CP210X_COMPLETE
-};
+//------------- Control Request -------------//
-static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
- // CP210x Interface includes 1 vendor interface + 2 bulk endpoints
- TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2);
- TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len);
-
- cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc);
- TU_VERIFY(p_cdc);
-
- TU_LOG_DRV("CP210x opened\r\n");
- p_cdc->serial_drid = SERIAL_DRIVER_CP210X;
-
- // endpoint pair
- tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
-
- // data endpoints expected to be in pairs
- return open_ep_stream_pair(p_cdc, desc_ep);
-}
-
-static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+static bool cp210x_set_request(cdch_interface_t * p_cdc, uint8_t command, uint16_t value,
+ uint8_t * buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
tusb_control_request_t const request = {
.bmRequestType_bit = {
.recipient = TUSB_REQ_RCPT_INTERFACE,
@@ -1194,12 +1486,12 @@ static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_
},
.bRequest = command,
.wValue = tu_htole16(value),
- .wIndex = p_cdc->bInterfaceNumber,
+ .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber),
.wLength = tu_htole16(length)
};
// use usbh enum buf since application variable does not live long enough
- uint8_t* enum_buf = NULL;
+ uint8_t * enum_buf = NULL;
if (buffer && length > 0) {
enum_buf = usbh_get_enum_buf();
@@ -1218,93 +1510,105 @@ static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_
return tuh_control_xfer(&xfer);
}
-static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+TU_ATTR_ALWAYS_INLINE static inline bool cp210x_ifc_enable(cdch_interface_t *p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data);
}
-static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- // TODO implement later
- (void) p_cdc;
- (void) line_coding;
- (void) complete_cb;
- (void) user_data;
- return false;
+TU_ATTR_ALWAYS_INLINE static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ // CP210x has the same bit coding
+ return cp210x_set_request(p_cdc, CP210X_SET_MHS,
+ (uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS | p_cdc->requested_line.control_state.value),
+ NULL, 0, complete_cb, user_data);
}
-static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- TU_LOG_DRV("CDC CP210x Set BaudRate = %" PRIu32 "\r\n", baudrate);
- uint32_t baud_le = tu_htole32(baudrate);
- p_cdc->user_control_cb = complete_cb;
- return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4,
- complete_cb ? cdch_internal_control_complete : NULL, user_data);
-}
+//------------- Driver API -------------//
-static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits,
- tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- (void) p_cdc;
- (void) stop_bits;
- (void) parity;
- (void) data_bits;
- (void) complete_cb;
- (void) user_data;
- // TODO not implemented yet
- return false;
-}
-
-static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- TU_LOG_DRV("CDC CP210x Set Control Line State\r\n");
- p_cdc->user_control_cb = complete_cb;
- return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0,
- complete_cb ? cdch_internal_control_complete : NULL, user_data);
-}
-
-static void cp210x_process_config(tuh_xfer_t* xfer) {
- uintptr_t const state = xfer->user_data;
- uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
- uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
- cdch_interface_t *p_cdc = get_itf(idx);
- TU_ASSERT(p_cdc,);
-
- switch (state) {
- case CONFIG_CP210X_IFC_ENABLE:
- TU_ASSERT(cp210x_ifc_enable(p_cdc, 1, cp210x_process_config, CONFIG_CP210X_SET_BAUDRATE),);
+// internal control complete to update state such as line state, encoding
+static void cp210x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
+ TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,);
+ switch (xfer->setup->bRequest) {
+ case CP210X_SET_MHS:
+ p_cdc->line.control_state = p_cdc->requested_line.control_state;
break;
- case CONFIG_CP210X_SET_BAUDRATE: {
- #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
- cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
- TU_ASSERT(cp210x_set_baudrate(p_cdc, line_coding.bit_rate, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL),);
+ case CP210X_SET_LINE_CTL:
+ p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits;
+ p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity;
+ p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits;
break;
- #else
- TU_ATTR_FALLTHROUGH;
- #endif
- }
- case CONFIG_CP210X_SET_LINE_CTL: {
- #if defined(CFG_TUH_CDC_LINE_CODING_ON_ENUM) && 0 // skip for now
- cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
- break;
- #else
- TU_ATTR_FALLTHROUGH;
- #endif
- }
-
- case CONFIG_CP210X_SET_DTR_RTS:
- #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
- TU_ASSERT(cp210x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, cp210x_process_config, CONFIG_CP210X_COMPLETE),);
- break;
- #else
- TU_ATTR_FALLTHROUGH;
- #endif
-
- case CONFIG_CP210X_COMPLETE:
- set_config_complete(p_cdc, idx, itf_num);
+ case CP210X_SET_BAUDRATE:
+ p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate;
break;
default: break;
}
}
+static bool cp210x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ // Not every baud rate is supported. See datasheets and AN205 "CP210x Baud Rate Support"
+ uint32_t baud_le = tu_htole32(p_cdc->requested_line.coding.bit_rate);
+ return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data);
+}
+
+static bool cp210x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8, 0);
+ uint16_t lcr = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11
+ (p_cdc->requested_line.coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding
+ (p_cdc->requested_line.coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding
+
+ return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data);
+}
+
+static bool cp210x_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ return cp210x_set_mhs(p_cdc, complete_cb, user_data);
+}
+
+//------------- Enumeration -------------//
+
+enum {
+ CONFIG_CP210X_IFC_ENABLE = 0,
+ CONFIG_CP210X_COMPLETE
+};
+
+static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
+ // CP210x Interface includes 1 vendor interface + 2 bulk endpoints
+ TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2);
+ TU_VERIFY(sizeof(tusb_desc_interface_t) + 2 * sizeof(tusb_desc_endpoint_t) <= max_len);
+
+ cdch_interface_t *p_cdc = make_new_itf(daddr, itf_desc);
+ TU_VERIFY(p_cdc);
+
+ p_cdc->serial_drid = SERIAL_DRIVER_CP210X;
+
+ // endpoint pair
+ tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
+
+ // data endpoints expected to be in pairs
+ return open_ep_stream_pair(p_cdc, desc_ep);
+}
+
+static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
+ TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS);
+ const uintptr_t state = xfer->user_data;
+
+ switch (state) {
+ case CONFIG_CP210X_IFC_ENABLE:
+ TU_ASSERT(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cdch_process_set_config, CONFIG_CP210X_COMPLETE));
+ break;
+
+ case CONFIG_CP210X_COMPLETE:
+ xfer->user_data = 0;// kick-off set line state on enum
+ cdch_process_line_state_on_enum(xfer);
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
#endif
//--------------------------------------------------------------------+
@@ -1313,13 +1617,14 @@ static void cp210x_process_config(tuh_xfer_t* xfer) {
#if CFG_TUH_CDC_CH34X
-static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits);
-static uint16_t ch34x_get_divisor_prescaler(uint32_t baval);
+static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc);
+static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t *p_cdc);
-//------------- control request -------------//
+//------------- Control Request -------------//
-static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value,
- uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+static bool ch34x_set_request(cdch_interface_t *p_cdc, uint8_t direction, uint8_t request,
+ uint16_t value, uint16_t index, uint8_t *buffer, uint16_t length,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
tusb_control_request_t const request_setup = {
.bmRequestType_bit = {
.recipient = TUSB_REQ_RCPT_DEVICE,
@@ -1327,13 +1632,13 @@ static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_
.direction = direction & 0x01u
},
.bRequest = request,
- .wValue = tu_htole16 (value),
- .wIndex = tu_htole16 (index),
- .wLength = tu_htole16 (length)
+ .wValue = tu_htole16(value),
+ .wIndex = tu_htole16(index),
+ .wLength = tu_htole16(length)
};
// use usbh enum buf since application variable does not live long enough
- uint8_t* enum_buf = NULL;
+ uint8_t *enum_buf = NULL;
if (buffer && length > 0) {
enum_buf = usbh_get_enum_buf();
@@ -1354,164 +1659,101 @@ static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_
return tuh_control_xfer(&xfer);
}
-static inline bool ch34x_control_out(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index,
- tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+TU_ATTR_ALWAYS_INLINE static inline bool ch34x_control_out(cdch_interface_t *p_cdc, uint8_t request, uint16_t value, uint16_t index,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return ch34x_set_request(p_cdc, TUSB_DIR_OUT, request, value, index, NULL, 0, complete_cb, user_data);
}
-static inline bool ch34x_control_in(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index,
- uint8_t* buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+TU_ATTR_ALWAYS_INLINE static inline bool ch34x_control_in(cdch_interface_t *p_cdc, uint8_t request, uint16_t value, uint16_t index,
+ uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return ch34x_set_request(p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize,
complete_cb, user_data);
}
-static inline bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t reg_value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+TU_ATTR_ALWAYS_INLINE static inline bool ch34x_write_reg(cdch_interface_t *p_cdc, uint16_t reg, uint16_t reg_value,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, reg, reg_value, complete_cb, user_data);
}
-//static bool ch34x_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg,
+//static bool ch34x_read_reg_request ( cdch_interface_t * p_cdc, uint16_t reg,
// uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data )
//{
// return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data );
//}
-static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate,
- tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate);
- TU_VERIFY(div_ps);
- TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps,
- complete_cb, user_data));
- return true;
-}
-
//------------- Driver API -------------//
// internal control complete to update state such as line state, encoding
-static void ch34x_control_complete(tuh_xfer_t* xfer) {
- // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber
- process_internal_control_complete(xfer, 0);
+static void ch34x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
+ TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,);
+ switch (xfer->setup->bRequest) {
+ case CH34X_REQ_WRITE_REG:
+ // register write request
+ switch (tu_le16toh(xfer->setup->wValue)) {
+ case CH34X_REG16_DIVISOR_PRESCALER:
+ // baudrate
+ p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate;
+ break;
+
+ case CH32X_REG16_LCR2_LCR:
+ // data format
+ p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits;
+ p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity;
+ p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits;
+ break;
+
+ default: break;
+ }
+ break;
+
+ case CH34X_REQ_MODEM_CTRL:
+ p_cdc->line.control_state = p_cdc->requested_line.control_state;
+ break;
+
+ default: break;
+ }
}
-static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits,
- tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- p_cdc->requested_line_coding.stop_bits = stop_bits;
- p_cdc->requested_line_coding.parity = parity;
- p_cdc->requested_line_coding.data_bits = data_bits;
-
- uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits);
+static bool ch34x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ const uint8_t lcr = ch34x_get_lcr(p_cdc);
TU_VERIFY(lcr);
- TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr,
- complete_cb ? ch34x_control_complete : NULL, user_data));
- return true;
+ return ch34x_write_reg(p_cdc, CH32X_REG16_LCR2_LCR, lcr, complete_cb, user_data);
}
-static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate,
- tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- p_cdc->requested_line_coding.bit_rate = baudrate;
- p_cdc->user_control_cb = complete_cb;
- TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, baudrate,
- complete_cb ? ch34x_control_complete : NULL, user_data));
- return true;
+static bool ch34x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ const uint16_t div_ps = ch34x_get_divisor_prescaler(p_cdc);
+ TU_VERIFY(div_ps);
+ return ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb, user_data);
}
-static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* xfer) {
- // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber
- uint8_t const itf_num = 0;
- uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
- cdch_interface_t* p_cdc = get_itf(idx);
- TU_ASSERT(p_cdc, );
-
- if (xfer->result == XFER_RESULT_SUCCESS) {
- // stage 1 success, continue to stage 2
- p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate;
- TU_ASSERT(ch34x_set_data_format(p_cdc, p_cdc->requested_line_coding.stop_bits, p_cdc->requested_line_coding.parity,
- p_cdc->requested_line_coding.data_bits, ch34x_control_complete, xfer->user_data), );
- } else {
- // stage 1 failed, notify user
- xfer->complete_cb = p_cdc->user_control_cb;
- if (xfer->complete_cb) {
- xfer->complete_cb(xfer);
- }
- }
-}
-
-// 2 stages: set baudrate (stage1) + set data format (stage2)
-static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding,
- tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- p_cdc->requested_line_coding = *line_coding;
- p_cdc->user_control_cb = complete_cb;
-
- if (complete_cb) {
- // stage 1 set baudrate
- TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, line_coding->bit_rate,
- ch34x_set_line_coding_stage1_complete, user_data));
- } else {
- // sync call
- xfer_result_t result;
-
- // stage 1 set baudrate
- TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, line_coding->bit_rate, NULL, (uintptr_t) &result));
- TU_VERIFY(result == XFER_RESULT_SUCCESS);
- p_cdc->line_coding.bit_rate = line_coding->bit_rate;
-
- // stage 2 set data format
- TU_ASSERT(ch34x_set_data_format(p_cdc, line_coding->stop_bits, line_coding->parity, line_coding->data_bits,
- NULL, (uintptr_t) &result));
- TU_VERIFY(result == XFER_RESULT_SUCCESS);
- p_cdc->line_coding.stop_bits = line_coding->stop_bits;
- p_cdc->line_coding.parity = line_coding->parity;
- p_cdc->line_coding.data_bits = line_coding->data_bits;
-
- // update transfer result, user_data is expected to point to xfer_result_t
- if (user_data) {
- *((xfer_result_t*) user_data) = result;
- }
- }
-
- return true;
-}
-
-static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state,
- tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
- uint8_t control = 0;
- if (line_state & CDC_CONTROL_LINE_STATE_RTS) {
- control |= CH34X_BIT_RTS;
- }
- if (line_state & CDC_CONTROL_LINE_STATE_DTR) {
- control |= CH34X_BIT_DTR;
- }
-
+static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
// CH34x signals are inverted
- control = ~control;
-
- p_cdc->user_control_cb = complete_cb;
- TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0,
- complete_cb ? ch34x_control_complete : NULL, user_data));
- return true;
+ uint8_t control = ~((p_cdc->requested_line.control_state.rts ? CH34X_BIT_RTS : 0) |
+ (p_cdc->requested_line.control_state.dtr ? CH34X_BIT_DTR : 0));
+ return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data);
}
//------------- Enumeration -------------//
+
enum {
CONFIG_CH34X_READ_VERSION = 0,
CONFIG_CH34X_SERIAL_INIT,
CONFIG_CH34X_SPECIAL_REG_WRITE,
CONFIG_CH34X_FLOW_CONTROL,
- CONFIG_CH34X_MODEM_CONTROL,
CONFIG_CH34X_COMPLETE
};
-static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) {
+static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) {
// CH34x Interface includes 1 vendor interface + 2 bulk + 1 interrupt endpoints
- TU_VERIFY (itf_desc->bNumEndpoints == 3);
- TU_VERIFY (sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len);
+ TU_VERIFY(itf_desc->bNumEndpoints == 3);
+ TU_VERIFY(sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len);
- cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc);
- TU_VERIFY (p_cdc);
+ cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc);
+ TU_VERIFY(p_cdc);
- TU_LOG_DRV ("CH34x opened\r\n");
p_cdc->serial_drid = SERIAL_DRIVER_CH34X;
- tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(itf_desc);
+ tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
// data endpoints expected to be in pairs
TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep));
@@ -1526,69 +1768,66 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uin
return true;
}
-static void ch34x_process_config(tuh_xfer_t* xfer) {
- // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber
- uint8_t const itf_num = 0;
- uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
- cdch_interface_t* p_cdc = get_itf(idx);
- uintptr_t const state = xfer->user_data;
- uint8_t buffer[2]; // TODO remove
- TU_ASSERT (p_cdc,);
- TU_ASSERT (xfer->result == XFER_RESULT_SUCCESS,);
+static bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
+ TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS);
+ const uintptr_t state = xfer->user_data;
switch (state) {
- case CONFIG_CH34X_READ_VERSION:
- TU_LOG_DRV("[%u] CDCh CH34x attempt to read Chip Version\r\n", p_cdc->daddr);
- TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),);
+ case CONFIG_CH34X_READ_VERSION: {
+ uint8_t* enum_buf = usbh_get_enum_buf();
+ TU_ASSERT(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, enum_buf, 2,
+ cdch_process_set_config, CONFIG_CH34X_SERIAL_INIT));
break;
+ }
case CONFIG_CH34X_SERIAL_INIT: {
// handle version read data, set CH34x line coding (incl. baudrate)
uint8_t const version = xfer->buffer[0];
- TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version);
- // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD
- TU_ASSERT (version >= 0x30,);
- // init CH34x with line coding
- cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X;
- uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate);
- TU_ASSERT(div_ps, );
- uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits);
- TU_ASSERT(lcr, );
- TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps,
- ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),);
+ TU_LOG_CDC(p_cdc, "Chip Version = 0x%02x", version);
+ // only versions >= 0x30 are tested, below 0x30 seems having other programming
+ // see drivers from WCH vendor, Linux kernel and FreeBSD
+ if (version >= 0x30) {
+ // init CH34x with line coding
+ p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X;
+ uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc);
+ uint8_t const lcr = ch34x_get_lcr(p_cdc);
+ TU_ASSERT(div_ps != 0 && lcr != 0);
+ TU_ASSERT(ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps,
+ cdch_process_set_config, CONFIG_CH34X_SPECIAL_REG_WRITE));
+ }
break;
}
case CONFIG_CH34X_SPECIAL_REG_WRITE:
// overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver
- p_cdc->line_coding = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X);
- TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),);
+ p_cdc->line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X;
+ TU_ASSERT(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007,
+ cdch_process_set_config, CONFIG_CH34X_FLOW_CONTROL));
break;
case CONFIG_CH34X_FLOW_CONTROL:
// no hardware flow control
- TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),);
- break;
-
- case CONFIG_CH34X_MODEM_CONTROL:
- // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT)
- TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),);
+ TU_ASSERT(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000,
+ cdch_process_set_config, CONFIG_CH34X_COMPLETE));
break;
case CONFIG_CH34X_COMPLETE:
- set_config_complete(p_cdc, idx, itf_num);
+ xfer->user_data = 0; // kick-off set line state on enum
+ cdch_process_line_state_on_enum(xfer);
break;
default:
- TU_ASSERT (false,);
- break;
+ return false;
}
+
+ return true;
}
-//------------- CH34x helper -------------//
+//------------- Helper -------------//
// calculate divisor and prescaler for baudrate, return it as 16-bit combined value
-static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) {
+static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t *p_cdc) {
+ uint32_t const baval = p_cdc->requested_line.coding.bit_rate;
uint8_t a;
uint8_t b;
uint32_t c;
@@ -1633,16 +1872,20 @@ static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) {
// reg divisor = a, reg prescaler = b
// According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE,
// otherwise the chip will buffer data.
- return (uint16_t) ((uint16_t)a << 8 | 0x80 | b);
+ return (uint16_t) ((uint16_t) a << 8 | 0x80 | b);
}
// calculate lcr value from data coding
-static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits) {
+static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc) {
+ uint8_t const stop_bits = p_cdc->requested_line.coding.stop_bits;
+ uint8_t const parity = p_cdc->requested_line.coding.parity;
+ uint8_t const data_bits = p_cdc->requested_line.coding.data_bits;
+
uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX;
- TU_VERIFY(data_bits >= 5 && data_bits <= 8, 0);
+ TU_VERIFY(data_bits >= 5 && data_bits <= 8);
lcr |= (uint8_t) (data_bits - 5);
- switch(parity) {
+ switch (parity) {
case CDC_LINE_CODING_PARITY_NONE:
break;
@@ -1666,7 +1909,7 @@ static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bit
}
// 1.5 stop bits not supported
- TU_VERIFY(stop_bits != CDC_LINE_CODING_STOP_BITS_1_5, 0);
+ TU_VERIFY(stop_bits != CDC_LINE_CODING_STOP_BITS_1_5);
if (stop_bits == CDC_LINE_CODING_STOP_BITS_2) {
lcr |= CH34X_LCR_STOP_BITS_2;
}
@@ -1674,7 +1917,612 @@ static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bit
return lcr;
}
-
#endif // CFG_TUH_CDC_CH34X
+//--------------------------------------------------------------------+
+// PL2303
+//--------------------------------------------------------------------+
+#if CFG_TUH_CDC_PL2303
+
+static pl2303_type_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step);
+static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]);
+
+//------------- Control Request -------------//
+static bool pl2303_set_request(cdch_interface_t *p_cdc, uint8_t request, uint8_t requesttype,
+ uint16_t value, uint16_t index, uint8_t *buffer, uint16_t length,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ tusb_control_request_t const request_setup = {
+ .bmRequestType = requesttype,
+ .bRequest = request,
+ .wValue = tu_htole16(value),
+ .wIndex = tu_htole16(index),
+ .wLength = tu_htole16(length)
+ };
+
+ // use usbh enum buf since application variable does not live long enough
+ uint8_t *enum_buf = NULL;
+
+ if (buffer && length > 0) {
+ enum_buf = usbh_get_enum_buf();
+ if (request_setup.bmRequestType_bit.direction == TUSB_DIR_OUT) {
+ tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length);
+ }
+ }
+
+ tuh_xfer_t xfer = {
+ .daddr = p_cdc->daddr,
+ .ep_addr = 0,
+ .setup = &request_setup,
+ .buffer = enum_buf,
+ .complete_cb = complete_cb,
+ .user_data = user_data
+ };
+
+ return tuh_control_xfer(&xfer);
+}
+
+static bool pl2303_vendor_read(cdch_interface_t *p_cdc, uint16_t value, uint8_t *buf,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ uint8_t request = p_cdc->pl2303.type == PL2303_TYPE_HXN ? PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST;
+ return pl2303_set_request(p_cdc, request, PL2303_VENDOR_READ_REQUEST_TYPE, value, 0, buf, 1, complete_cb, user_data);
+}
+
+static bool pl2303_vendor_write(cdch_interface_t *p_cdc, uint16_t value, uint16_t index,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ uint8_t request = p_cdc->pl2303.type == PL2303_TYPE_HXN ? PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST;
+ return pl2303_set_request(p_cdc, request, PL2303_VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, complete_cb, user_data);
+}
+
+static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ uint8_t buf = 0;
+ return pl2303_set_request(p_cdc, PL2303_VENDOR_READ_REQUEST, PL2303_VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS, 0,
+ &buf, 1, complete_cb, user_data);
+}
+
+//static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) {
+// return pl2303_set_request(p_cdc, PL2303_GET_LINE_REQUEST, PL2303_GET_LINE_REQUEST_TYPE, 0, 0, buf, PL2303_LINE_CODING_BUFSIZE);
+//}
+
+//static bool pl2303_set_break(cdch_interface_t * p_cdc, bool enable) {
+// uint16_t state = enable ? PL2303_BREAK_ON : PL2303_BREAK_OFF;
+// return pl2303_set_request(p_cdc, PL2303_BREAK_REQUEST, PL2303_BREAK_REQUEST_TYPE, state, 0, NULL, 0);
+//}
+
+static inline int pl2303_clear_halt(cdch_interface_t *p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ /* we don't care if it wasn't halted first. in fact some devices
+ * (like some ibmcam model 1 units) seem to expect hosts to make
+ * this request for iso endpoints, which can't halt!
+ */
+ return pl2303_set_request(p_cdc, TUSB_REQ_CLEAR_FEATURE, PL2303_CLEAR_HALT_REQUEST_TYPE, TUSB_REQ_FEATURE_EDPT_HALT, endp,
+ NULL, 0, complete_cb, user_data);
+}
+
+//------------- Driver API -------------//
+
+// internal control complete to update state such as line state, encoding
+static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
+ TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,);
+ if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST &&
+ xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) {
+ p_cdc->line.coding = p_cdc->requested_line.coding;
+ }
+ if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST &&
+ xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) {
+ p_cdc->line.control_state = p_cdc->requested_line.control_state;
+ }
+}
+
+static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ // the caller has to precheck, that the new line coding different than the current, else false returned
+ uint8_t buf[PL2303_LINE_CODING_BUFSIZE];
+ /*
+ * Some PL2303 are known to lose bytes if you change serial settings
+ * even to the same values as before. Thus we actually need to filter
+ * in this specific case.
+ */
+ TU_VERIFY(p_cdc->requested_line.coding.data_bits != p_cdc->line.coding.data_bits ||
+ p_cdc->requested_line.coding.stop_bits != p_cdc->line.coding.stop_bits ||
+ p_cdc->requested_line.coding.parity != p_cdc->line.coding.parity ||
+ p_cdc->requested_line.coding.bit_rate != p_cdc->line.coding.bit_rate );
+
+ /* For reference buf[6] data bits value */
+ TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8, 0);
+ buf[6] = p_cdc->requested_line.coding.data_bits;
+
+ /* For reference buf[0]:buf[3] baud rate value */
+ TU_VERIFY(pl2303_encode_baud_rate(p_cdc, &buf[0]));
+
+ /* For reference buf[4]=0 is 1 stop bits */
+ /* For reference buf[4]=1 is 1.5 stop bits */
+ /* For reference buf[4]=2 is 2 stop bits */
+ buf[4] = p_cdc->requested_line.coding.stop_bits; // PL2303 has the same coding
+
+ /* For reference buf[5]=0 is none parity */
+ /* For reference buf[5]=1 is odd parity */
+ /* For reference buf[5]=2 is even parity */
+ /* For reference buf[5]=3 is mark parity */
+ /* For reference buf[5]=4 is space parity */
+ buf[5] = p_cdc->requested_line.coding.parity; // PL2303 has the same coding
+
+ return pl2303_set_request(p_cdc, PL2303_SET_LINE_REQUEST, PL2303_SET_LINE_REQUEST_TYPE, 0, 0,
+ buf, PL2303_LINE_CODING_BUFSIZE, complete_cb, user_data);
+}
+
+static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ // PL2303 has the same bit coding
+ return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE,
+ p_cdc->requested_line.control_state.value, 0, NULL, 0, complete_cb, user_data);
+}
+
+//------------- Enumeration -------------//
+
+enum {
+ CONFIG_PL2303_DETECT_TYPE = 0,
+ CONFIG_PL2303_READ1,
+ CONFIG_PL2303_WRITE1,
+ CONFIG_PL2303_READ2,
+ CONFIG_PL2303_READ3,
+ CONFIG_PL2303_READ4,
+ CONFIG_PL2303_WRITE2,
+ CONFIG_PL2303_READ5,
+ CONFIG_PL2303_READ6,
+ CONFIG_PL2303_WRITE3,
+ CONFIG_PL2303_WRITE4,
+ CONFIG_PL2303_WRITE5,
+ CONFIG_PL2303_RESET_ENDP1,
+ CONFIG_PL2303_RESET_ENDP2,
+// CONFIG_PL2303_FLOW_CTRL_READ,
+// CONFIG_PL2303_FLOW_CTRL_WRITE,
+ CONFIG_PL2303_COMPLETE
+};
+
+static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
+ // PL2303 Interface includes 1 vendor interface + 1 interrupt endpoints + 2 bulk
+ TU_VERIFY(itf_desc->bNumEndpoints == 3);
+ TU_VERIFY(sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len);
+
+ cdch_interface_t *p_cdc = make_new_itf(daddr, itf_desc);
+ TU_VERIFY(p_cdc);
+
+ p_cdc->serial_drid = SERIAL_DRIVER_PL2303;
+ p_cdc->pl2303.quirks = 0;
+ p_cdc->pl2303.supports_hx_status = false;
+
+ tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
+
+ // Interrupt endpoint: not used for now
+ TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(desc_ep) &&
+ TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer);
+ TU_ASSERT(tuh_edpt_open(daddr, desc_ep));
+ p_cdc->ep_notif = desc_ep->bEndpointAddress;
+ desc_ep += 1;
+
+ // data endpoints expected to be in pairs
+ TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep));
+
+ return true;
+}
+
+static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
+ // state CONFIG_PL2303_READ1 may have no success due to expected stall by pl2303_supports_hx_status()
+ const uintptr_t state = xfer->user_data;
+ TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS || state == CONFIG_PL2303_READ1);
+ uint8_t* enum_buf = usbh_get_enum_buf();
+ pl2303_type_t type;
+
+ switch (state) {
+ // from here sequence overtaken from Linux Kernel function pl2303_startup()
+ case CONFIG_PL2303_DETECT_TYPE:
+ // get type and quirks (step 1)
+ type = pl2303_detect_type(p_cdc, 1);
+ TU_ASSERT(type != PL2303_TYPE_UNKNOWN);
+ if (type == PL2303_TYPE_NEED_SUPPORTS_HX_STATUS) {
+ TU_ASSERT(pl2303_supports_hx_status(p_cdc, cdch_process_set_config, CONFIG_PL2303_READ1));
+ break;
+ } else {
+ // no transfer triggered and continue with CONFIG_PL2303_READ1
+ TU_ATTR_FALLTHROUGH;
+ }
+
+ case CONFIG_PL2303_READ1:
+ // get supports_hx_status, type and quirks (step 2), do special read
+ // will not be true, if coming directly from previous case
+ if (xfer->user_data == CONFIG_PL2303_READ1 && xfer->result == XFER_RESULT_SUCCESS) {
+ p_cdc->pl2303.supports_hx_status = true;
+ }
+ type = pl2303_detect_type(p_cdc, 2); // step 2 now with supports_hx_status
+ TU_ASSERT(type != PL2303_TYPE_UNKNOWN);
+ TU_LOG_DRV(" PL2303 type detected: %u\r\n", type);
+
+ p_cdc->pl2303.type = type;
+ p_cdc->pl2303.quirks |= pl2303_type_data[type].quirks;
+
+ // purpose unknown, overtaken from Linux Kernel driver
+ if (p_cdc->pl2303.type != PL2303_TYPE_HXN) {
+ TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, enum_buf, cdch_process_set_config, CONFIG_PL2303_WRITE1));
+ break;
+ }// else: continue with next step
+ TU_ATTR_FALLTHROUGH;
+
+ case CONFIG_PL2303_WRITE1:
+ // purpose unknown, overtaken from Linux Kernel driver
+ if (p_cdc->pl2303.type != PL2303_TYPE_HXN) {
+ TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 0, cdch_process_set_config, CONFIG_PL2303_READ2));
+ break;
+ }// else: continue with next step
+ TU_ATTR_FALLTHROUGH;
+
+ case CONFIG_PL2303_READ2:
+ // purpose unknown, overtaken from Linux Kernel driver
+ if (p_cdc->pl2303.type != PL2303_TYPE_HXN) {
+ TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, enum_buf, cdch_process_set_config, CONFIG_PL2303_READ3));
+ break;
+ }// else: continue with next step
+ TU_ATTR_FALLTHROUGH;
+
+ case CONFIG_PL2303_READ3:
+ // purpose unknown, overtaken from Linux Kernel driver
+ if (p_cdc->pl2303.type != PL2303_TYPE_HXN) {
+ TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, enum_buf, cdch_process_set_config, CONFIG_PL2303_READ4));
+ break;
+ }// else: continue with next step
+ TU_ATTR_FALLTHROUGH;
+
+ case CONFIG_PL2303_READ4:
+ // purpose unknown, overtaken from Linux Kernel driver
+ if (p_cdc->pl2303.type != PL2303_TYPE_HXN) {
+ TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, enum_buf, cdch_process_set_config, CONFIG_PL2303_WRITE2));
+ break;
+ }// else: continue with next step
+ TU_ATTR_FALLTHROUGH;
+
+ case CONFIG_PL2303_WRITE2:
+ // purpose unknown, overtaken from Linux Kernel driver
+ if (p_cdc->pl2303.type != PL2303_TYPE_HXN) {
+ TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 1, cdch_process_set_config, CONFIG_PL2303_READ5));
+ break;
+ }// else: continue with next step
+ TU_ATTR_FALLTHROUGH;
+
+ case CONFIG_PL2303_READ5:
+ // purpose unknown, overtaken from Linux Kernel driver
+ if (p_cdc->pl2303.type != PL2303_TYPE_HXN) {
+ TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, enum_buf, cdch_process_set_config, CONFIG_PL2303_READ6));
+ break;
+ }// else: continue with next step
+ TU_ATTR_FALLTHROUGH;
+
+ case CONFIG_PL2303_READ6:
+ // purpose unknown, overtaken from Linux Kernel driver
+ if (p_cdc->pl2303.type != PL2303_TYPE_HXN) {
+ TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, enum_buf, cdch_process_set_config, CONFIG_PL2303_WRITE3));
+ break;
+ }// else: continue with next step
+ TU_ATTR_FALLTHROUGH;
+
+ case CONFIG_PL2303_WRITE3:
+ // purpose unknown, overtaken from Linux Kernel driver
+ if (p_cdc->pl2303.type != PL2303_TYPE_HXN) {
+ TU_ASSERT(pl2303_vendor_write(p_cdc, 0, 1, cdch_process_set_config, CONFIG_PL2303_WRITE4));
+ break;
+ }// else: continue with next step
+ TU_ATTR_FALLTHROUGH;
+
+ case CONFIG_PL2303_WRITE4:
+ // purpose unknown, overtaken from Linux Kernel driver
+ if (p_cdc->pl2303.type != PL2303_TYPE_HXN) {
+ TU_ASSERT(pl2303_vendor_write(p_cdc, 1, 0, cdch_process_set_config, CONFIG_PL2303_WRITE5));
+ break;
+ }// else: continue with next step
+ TU_ATTR_FALLTHROUGH;
+
+ case CONFIG_PL2303_WRITE5:
+ // purpose unknown, overtaken from Linux Kernel driver
+ if (p_cdc->pl2303.type != PL2303_TYPE_HXN) {
+ uint16_t const windex = (p_cdc->pl2303.quirks & PL2303_QUIRK_LEGACY) ? 0x24 : 0x44;
+ TU_ASSERT(pl2303_vendor_write(p_cdc, 2, windex, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP1));
+ break;
+ }// else: continue with next step
+ TU_ATTR_FALLTHROUGH;
+
+ // from here sequence overtaken from Linux Kernel function pl2303_open()
+ case CONFIG_PL2303_RESET_ENDP1:
+ // step 1
+ if (p_cdc->pl2303.quirks & PL2303_QUIRK_LEGACY) {
+ TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP2));
+ } else {
+ /* reset upstream data pipes */
+ if (p_cdc->pl2303.type == PL2303_TYPE_HXN) {
+ TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG,// skip CONFIG_PL2303_RESET_ENDP2, no 2nd step
+ PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE,
+ cdch_process_set_config, CONFIG_PL2303_COMPLETE));
+ } else {
+ pl2303_vendor_write(p_cdc, 8, 0, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP2);
+ }
+ }
+ break;
+
+ case CONFIG_PL2303_RESET_ENDP2:
+ // step 2
+ if (p_cdc->pl2303.quirks & PL2303_QUIRK_LEGACY) {
+ TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, cdch_process_set_config, CONFIG_PL2303_COMPLETE));
+ } else {
+ /* reset upstream data pipes */
+ if (p_cdc->pl2303.type == PL2303_TYPE_HXN) {
+ // here nothing to do, only structure of previous step overtaken for better reading and comparison
+ } else {
+ TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, cdch_process_set_config, CONFIG_PL2303_COMPLETE));
+ }
+ }
+ break;
+
+ // skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program
+ // case CONFIG_PL2303_FLOW_CTRL_READ:
+ // // read flow control register for modify & write back in next step
+ // if (p_cdc->pl2303.type == PL2303_TYPE_HXN) {
+ // TU_LOG_P_CDC ( "1\r\n" );
+ // TU_ASSERT(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf,
+ // cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE));
+ // } else {
+ // TU_LOG_P_CDC ( "2\r\n" );
+ // TU_ASSERT(pl2303_vendor_read(p_cdc, 0, &buf, cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE));
+ // }
+ // break;
+ //
+ // case CONFIG_PL2303_FLOW_CTRL_WRITE:
+ // // no flow control
+ // buf = xfer->buffer[0];
+ // if (p_cdc->pl2303.type == PL2303_TYPE_HXN) {
+ // buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK;
+ // buf |= PL2303_HXN_FLOWCTRL_NONE;
+ // TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf,
+ // cdch_process_set_config, CONFIG_PL2303_COMPLETE));
+ // } else {
+ // buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK;
+ // TU_ASSERT(pl2303_vendor_write(p_cdc, 0, buf,
+ // cdch_process_set_config, CONFIG_PL2303_COMPLETE));
+ // }
+ // break;
+
+ case CONFIG_PL2303_COMPLETE:
+ xfer->user_data = 0; // kick-off set line state on enum
+ cdch_process_line_state_on_enum(xfer);
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+//------------- Helper -------------//
+
+static pl2303_type_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step) {
+ tusb_desc_device_t desc_dev;
+ TU_VERIFY(tuh_descriptor_get_device_local(p_cdc->daddr, &desc_dev), PL2303_TYPE_UNKNOWN);
+
+ // Legacy PL2303H, variants 0 and 1 (difference unknown).
+ if (desc_dev.bDeviceClass == 0x02) {
+ return PL2303_TYPE_H; /* variant 0 */
+ }
+
+ if (desc_dev.bMaxPacketSize0 != 0x40) {
+ if (desc_dev.bDeviceClass == 0x00 || desc_dev.bDeviceClass == 0xff) {
+ return PL2303_TYPE_H; /* variant 1 */
+ }
+ return PL2303_TYPE_H; /* variant 0 */
+ }
+
+ switch (desc_dev.bcdUSB) {
+ case 0x101:
+ /* USB 1.0.1? Let's assume they meant 1.1... */
+ TU_ATTR_FALLTHROUGH;
+ case 0x110:
+ switch (desc_dev.bcdDevice) {
+ case 0x300: return PL2303_TYPE_HX;
+ case 0x400: return PL2303_TYPE_HXD;
+ default: return PL2303_TYPE_HX;
+ }
+ break;
+
+ case 0x200:
+ switch (desc_dev.bcdDevice) {
+ case 0x100: /* GC */
+ case 0x105:
+ return PL2303_TYPE_HXN;
+
+ case 0x300: /* GT / TA */
+ if (step == 1) {
+ // step 1 trigger pl2303_supports_hx_status() request
+ return PL2303_TYPE_NEED_SUPPORTS_HX_STATUS;
+ } else {
+ // step 2 use supports_hx_status
+ if (p_cdc->pl2303.supports_hx_status) {
+ return PL2303_TYPE_TA;
+ }
+ }
+ TU_ATTR_FALLTHROUGH;
+ case 0x305:
+ case 0x400: /* GL */
+ case 0x405:
+ return PL2303_TYPE_HXN;
+
+ case 0x500: /* GE / TB */
+ if (step == 1) {
+ // step 1 trigger pl2303_supports_hx_status() request
+ return PL2303_TYPE_NEED_SUPPORTS_HX_STATUS;
+ } else {
+ // step 2 use supports_hx_status
+ if (p_cdc->pl2303.supports_hx_status) {
+ return PL2303_TYPE_TB;
+ }
+ }
+ TU_ATTR_FALLTHROUGH;
+ case 0x505:
+ case 0x600: /* GS */
+ case 0x605:
+ case 0x700: /* GR */
+ case 0x705:
+ return PL2303_TYPE_HXN;
+
+ default:
+ break;
+ }
+ break;
+ default: break;
+ }
+
+ TU_LOG_CDC(p_cdc, "unknown device type bcdUSB = 0x%04x", desc_dev.bcdUSB);
+ return PL2303_TYPE_UNKNOWN;
+}
+
+/*
+ * Returns the nearest supported baud rate that can be set directly without
+ * using divisors.
+ */
+static uint32_t pl2303_get_supported_baud_rate(uint32_t baud) {
+ static const uint32_t baud_sup[] = {
+ 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600,
+ 14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800,
+ 614400, 921600, 1228800, 2457600, 3000000, 6000000
+ };
+
+ uint8_t i;
+ for (i = 0; i < TU_ARRAY_SIZE(baud_sup); ++i) {
+ if (baud_sup[i] > baud) {
+ break;
+ }
+ }
+
+ if (i == TU_ARRAY_SIZE(baud_sup)) {
+ baud = baud_sup[i - 1];
+ } else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1])) {
+ baud = baud_sup[i - 1];
+ } else {
+ baud = baud_sup[i];
+ }
+
+ return baud;
+}
+
+/*
+ * NOTE: If unsupported baud rates are set directly, the PL2303 seems to
+ * use 9600 baud.
+ */
+static uint32_t pl2303_encode_baud_rate_direct(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) {
+ uint32_t baud_le = tu_htole32(baud);
+ buf[0] = (uint8_t) ( baud_le & 0xff);
+ buf[1] = (uint8_t) ((baud_le >> 8) & 0xff);
+ buf[2] = (uint8_t) ((baud_le >> 16) & 0xff);
+ buf[3] = (uint8_t) ((baud_le >> 24) & 0xff);
+
+ return baud;
+}
+
+static uint32_t pl2303_encode_baud_rate_divisor(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) {
+ uint32_t baseline, mantissa, exponent;
+
+ /*
+ * Apparently the formula is:
+ * baudrate = 12M * 32 / (mantissa * 4^exponent)
+ * where
+ * mantissa = buf[8:0]
+ * exponent = buf[11:9]
+ */
+ baseline = 12000000 * 32;
+ mantissa = baseline / baud;
+ if (mantissa == 0)
+ mantissa = 1; /* Avoid dividing by zero if baud > 32 * 12M. */
+ exponent = 0;
+ while (mantissa >= 512) {
+ if (exponent < 7) {
+ mantissa >>= 2; /* divide by 4 */
+ exponent++;
+ } else {
+ /* Exponent is maxed. Trim mantissa and leave. */
+ mantissa = 511;
+ break;
+ }
+ }
+
+ buf[3] = 0x80;
+ buf[2] = 0;
+ buf[1] = (uint8_t) ((exponent << 1 | mantissa >> 8) & 0xff);
+ buf[0] = (uint8_t) (mantissa & 0xff);
+
+ /* Calculate and return the exact baud rate. */
+ baud = (baseline / mantissa) >> (exponent << 1);
+
+ return baud;
+}
+
+static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) {
+ uint32_t baseline, mantissa, exponent;
+
+ /*
+ * Apparently, for the TA version the formula is:
+ * baudrate = 12M * 32 / (mantissa * 2^exponent)
+ * where
+ * mantissa = buf[10:0]
+ * exponent = buf[15:13 16]
+ */
+ baseline = 12000000 * 32;
+ mantissa = baseline / baud;
+ if (mantissa == 0) {
+ mantissa = 1; /* Avoid dividing by zero if baud > 32 * 12M. */
+ }
+ exponent = 0;
+ while (mantissa >= 2048) {
+ if (exponent < 15) {
+ mantissa >>= 1; /* divide by 2 */
+ exponent++;
+ } else {
+ /* Exponent is maxed. Trim mantissa and leave. */
+ mantissa = 2047;
+ break;
+ }
+ }
+
+ buf[3] = 0x80;
+ buf[2] = (uint8_t) (exponent & 0x01);
+ buf[1] = (uint8_t) (((exponent & (uint32_t) ~0x01) << 4 | mantissa >> 8) & 0xff);
+ buf[0] = (uint8_t) (mantissa & 0xff);
+
+ /* Calculate and return the exact baud rate. */
+ baud = (baseline / mantissa) >> exponent;
+
+ return baud;
+}
+
+static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]) {
+ uint32_t baud = p_cdc->requested_line.coding.bit_rate;
+ uint32_t baud_sup;
+ const pl2303_type_data_t* type_data = &pl2303_type_data[p_cdc->pl2303.type];
+
+ TU_VERIFY(baud && baud <= type_data->max_baud_rate);
+ /*
+ * Use direct method for supported baud rates, otherwise use divisors.
+ * Newer chip types do not support divisor encoding.
+ */
+ if (type_data->no_divisors) {
+ baud_sup = baud;
+ } else {
+ baud_sup = pl2303_get_supported_baud_rate(baud);
+ }
+
+ if (baud == baud_sup) {
+ baud = pl2303_encode_baud_rate_direct(buf, baud);
+ } else if (type_data->alt_divisors) {
+ baud = pl2303_encode_baud_rate_divisor_alt(buf, baud);
+ } else {
+ baud = pl2303_encode_baud_rate_divisor(buf, baud);
+ }
+ TU_LOG_CDC(p_cdc, "real baudrate %lu", baud);
+
+ return true;
+}
+
+#endif // CFG_TUH_CDC_PL2303
+
#endif
diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h
index 8c5399534..37bfca270 100644
--- a/src/class/cdc/cdc_host.h
+++ b/src/class/cdc/cdc_host.h
@@ -37,16 +37,6 @@
// Class Driver Configuration
//--------------------------------------------------------------------+
-// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1)
-#ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
-#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0
-#endif
-
-// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
-//#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM
-//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
-//#endif
-
// RX FIFO size
#ifndef CFG_TUH_CDC_RX_BUFSIZE
#define CFG_TUH_CDC_RX_BUFSIZE TUH_EPSIZE_BULK_MPS
@@ -79,14 +69,27 @@ uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num);
// return true if index is correct and interface is currently mounted
bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info);
-// Check if a interface is mounted
+// Check if an interface is mounted
bool tuh_cdc_mounted(uint8_t idx);
+// Get local (cached) line state
+// This function should return correct values if tuh_cdc_set_control_line_state() / tuh_cdc_get_control_line_state()
+// are invoked previously or CFG_TUH_CDC_LINE_STATE_ON_ENUM is defined.
+bool tuh_cdc_get_control_line_state_local(uint8_t idx, uint16_t* line_state);
+
// Get current DTR status
-bool tuh_cdc_get_dtr(uint8_t idx);
+TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_get_dtr(uint8_t idx) {
+ uint16_t line_state;
+ TU_VERIFY(tuh_cdc_get_control_line_state_local(idx, &line_state));
+ return (line_state & CDC_CONTROL_LINE_STATE_DTR) != 0;
+}
// Get current RTS status
-bool tuh_cdc_get_rts(uint8_t idx);
+TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_get_rts(uint8_t idx) {
+ uint16_t line_state;
+ TU_VERIFY(tuh_cdc_get_control_line_state_local(idx, &line_state));
+ return (line_state & CDC_CONTROL_LINE_STATE_RTS) != 0;
+}
// Check if interface is connected (DTR active)
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) {
@@ -97,7 +100,9 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) {
// This function should return correct values if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding()
// are invoked previously or CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined.
// NOTE: This function does not make any USB transfer request to device.
-bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding);
+bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t* line_coding);
+
+#define tuh_cdc_get_local_line_coding tuh_cdc_get_line_coding_local // backward compatibility
//--------------------------------------------------------------------+
// Write API
@@ -132,18 +137,31 @@ bool tuh_cdc_peek(uint8_t idx, uint8_t* ch);
bool tuh_cdc_read_clear (uint8_t idx);
//--------------------------------------------------------------------+
-// Control Endpoint (Request) API
+// Control Request API
// Each Function will make a USB control transfer request to/from device
// - If complete_cb is provided, the function will return immediately and invoke
// the callback when request is complete.
// - If complete_cb is NULL, the function will block until request is complete.
-// - In this case, user_data should be pointed to xfer_result_t to hold the transfer result.
-// - The function will return true if transfer is successful, false otherwise.
+// In this case, user_data should be usb_xfer_result_t* to hold the transfer result.
//--------------------------------------------------------------------+
// Request to Set Control Line State: DTR (bit 0), RTS (bit 1)
bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+// Request to Set DTR
+TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ cdc_line_control_state_t line_state = { .dtr = dtr_state };
+ line_state.rts = tuh_cdc_get_rts(idx);
+ return tuh_cdc_set_control_line_state(idx, line_state.value, complete_cb, user_data);
+}
+
+// Request to Set RTS
+TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_set_rts(uint8_t idx, bool rts_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+ cdc_line_control_state_t line_state = { .rts = rts_state };
+ line_state.dtr = tuh_cdc_get_dtr(idx);
+ return tuh_cdc_set_control_line_state(idx, line_state.value, complete_cb, user_data);
+}
+
// Request to set baudrate
bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
@@ -160,17 +178,52 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding,
// bool tuh_cdc_get_line_coding(uint8_t idx, cdc_line_coding_t* coding);
// Connect by set both DTR, RTS
-TU_ATTR_ALWAYS_INLINE static inline
-bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data);
}
// Disconnect by clear both DTR, RTS
-TU_ATTR_ALWAYS_INLINE static inline
-bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data);
}
+//--------------------------------------------------------------------+
+// Control Request Sync API
+// Each Function will make a USB control transfer request to/from device the function will block until request is
+// complete. The function will return the transfer request result
+//--------------------------------------------------------------------+
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_control_line_state_sync(uint8_t idx, uint16_t line_state) {
+ TU_API_SYNC(tuh_cdc_set_control_line_state, idx, line_state);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_dtr_sync(uint8_t idx, bool dtr_state) {
+ TU_API_SYNC(tuh_cdc_set_dtr, idx, dtr_state);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_rts_sync(uint8_t idx, bool rts_state) {
+ TU_API_SYNC(tuh_cdc_set_rts, idx, rts_state);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_baudrate_sync(uint8_t idx, uint32_t baudrate) {
+ TU_API_SYNC(tuh_cdc_set_baudrate, idx, baudrate);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_data_format_sync(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits) {
+ TU_API_SYNC(tuh_cdc_set_data_format, idx, stop_bits, parity, data_bits);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_line_coding_sync(uint8_t idx, cdc_line_coding_t const* line_coding) {
+ TU_API_SYNC(tuh_cdc_set_line_coding, idx, line_coding);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_connect_sync(uint8_t idx) {
+ TU_API_SYNC(tuh_cdc_connect, idx);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_disconnect_sync(uint8_t idx) {
+ TU_API_SYNC(tuh_cdc_disconnect, idx);
+}
+
//--------------------------------------------------------------------+
// CDC APPLICATION CALLBACKS
//--------------------------------------------------------------------+
diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h
index c18066f57..0e08b0acd 100644
--- a/src/class/cdc/serial/ch34x.h
+++ b/src/class/cdc/serial/ch34x.h
@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _CH34X_H_
-#define _CH34X_H_
+#ifndef TUSB_CH34X_H
+#define TUSB_CH34X_H
// There is no official documentation for the CH34x (CH340, CH341) chips. Reference can be found
// - https://github.com/WCHSoftGroup/ch341ser_linux
@@ -34,51 +34,51 @@
// set line_coding @ enumeration
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
-#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM
+ #define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM
#else // this default is necessary to work properly
-#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X { 9600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
+ #define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X { 9600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
#endif
// USB requests
-#define CH34X_REQ_READ_VERSION 0x5F // dec 95
-#define CH34X_REQ_WRITE_REG 0x9A // dec 154
-#define CH34X_REQ_READ_REG 0x95 // dec 149
-#define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161
-#define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164
+#define CH34X_REQ_READ_VERSION 0x5F // dec 95
+#define CH34X_REQ_WRITE_REG 0x9A // dec 154
+#define CH34X_REQ_READ_REG 0x95 // dec 149
+#define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161
+#define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164
// registers
-#define CH34X_REG_BREAK 0x05
-#define CH34X_REG_PRESCALER 0x12
-#define CH34X_REG_DIVISOR 0x13
-#define CH34X_REG_LCR 0x18
-#define CH34X_REG_LCR2 0x25
-#define CH34X_REG_MCR_MSR 0x06
-#define CH34X_REG_MCR_MSR2 0x07
-#define CH34X_NBREAK_BITS 0x01
+#define CH34X_REG_BREAK 0x05
+#define CH34X_REG_PRESCALER 0x12
+#define CH34X_REG_DIVISOR 0x13
+#define CH34X_REG_LCR 0x18
+#define CH34X_REG_LCR2 0x25
+#define CH34X_REG_MCR_MSR 0x06
+#define CH34X_REG_MCR_MSR2 0x07
+#define CH34X_NBREAK_BITS 0x01
-#define CH341_REG_0x0F 0x0F // undocumented register
-#define CH341_REG_0x2C 0x2C // undocumented register
-#define CH341_REG_0x27 0x27 // hardware flow control (cts/rts)
+#define CH341_REG_0x0F 0x0F // undocumented register
+#define CH341_REG_0x2C 0x2C // undocumented register
+#define CH341_REG_0x27 0x27 // hardware flow control (cts/rts)
-#define CH34X_REG16_DIVISOR_PRESCALER TU_U16(CH34X_REG_DIVISOR, CH34X_REG_PRESCALER)
-#define CH32X_REG16_LCR2_LCR TU_U16(CH34X_REG_LCR2, CH34X_REG_LCR)
+#define CH34X_REG16_DIVISOR_PRESCALER TU_U16(CH34X_REG_DIVISOR, CH34X_REG_PRESCALER)
+#define CH32X_REG16_LCR2_LCR TU_U16(CH34X_REG_LCR2, CH34X_REG_LCR)
// modem control bits
-#define CH34X_BIT_RTS ( 1 << 6 )
-#define CH34X_BIT_DTR ( 1 << 5 )
+#define CH34X_BIT_RTS (1 << 6)
+#define CH34X_BIT_DTR (1 << 5)
// line control bits
-#define CH34X_LCR_ENABLE_RX 0x80
-#define CH34X_LCR_ENABLE_TX 0x40
-#define CH34X_LCR_MARK_SPACE 0x20
-#define CH34X_LCR_PAR_EVEN 0x10
-#define CH34X_LCR_ENABLE_PAR 0x08
-#define CH34X_LCR_PAR_MASK 0x38 // all parity bits
-#define CH34X_LCR_STOP_BITS_2 0x04
-#define CH34X_LCR_CS8 0x03
-#define CH34X_LCR_CS7 0x02
-#define CH34X_LCR_CS6 0x01
-#define CH34X_LCR_CS5 0x00
-#define CH34X_LCR_CS_MASK 0x03 // all CSx bits
+#define CH34X_LCR_ENABLE_RX 0x80
+#define CH34X_LCR_ENABLE_TX 0x40
+#define CH34X_LCR_MARK_SPACE 0x20
+#define CH34X_LCR_PAR_EVEN 0x10
+#define CH34X_LCR_ENABLE_PAR 0x08
+#define CH34X_LCR_PAR_MASK 0x38 // all parity bits
+#define CH34X_LCR_STOP_BITS_2 0x04
+#define CH34X_LCR_CS8 0x03
+#define CH34X_LCR_CS7 0x02
+#define CH34X_LCR_CS6 0x01
+#define CH34X_LCR_CS5 0x00
+#define CH34X_LCR_CS_MASK 0x03 // all CSx bits
-#endif /* _CH34X_H_ */
+#endif // TUSB_CH34X_H
diff --git a/src/class/cdc/serial/cp210x.h b/src/class/cdc/serial/cp210x.h
index 2c749f522..a0eff9e40 100644
--- a/src/class/cdc/serial/cp210x.h
+++ b/src/class/cdc/serial/cp210x.h
@@ -28,9 +28,10 @@
// Protocol details can be found at AN571: CP210x Virtual COM Port Interface
// https://www.silabs.com/documents/public/application-notes/AN571.pdf
-#define TU_CP210X_VID 0x10C4
+// parts are overtaken from vendors driver
+// https://www.silabs.com/documents/public/software/cp210x-3.1.0.tar.gz
-/* Config request codes */
+// Config request codes
#define CP210X_IFC_ENABLE 0x00
#define CP210X_SET_BAUDDIV 0x01
#define CP210X_GET_BAUDDIV 0x02
@@ -59,4 +60,55 @@
#define CP210X_SET_BAUDRATE 0x1E
#define CP210X_VENDOR_SPECIFIC 0xFF // GPIO, Recipient must be Device
+// SILABSER_IFC_ENABLE_REQUEST_CODE
+#define CP210X_UART_ENABLE 0x0001
+#define CP210X_UART_DISABLE 0x0000
+
+// SILABSER_SET_BAUDDIV_REQUEST_CODE
+#define CP210X_BAUD_RATE_GEN_FREQ 0x384000
+
+// SILABSER_SET_LINE_CTL_REQUEST_CODE
+#define CP210X_BITS_DATA_MASK 0x0f00
+#define CP210X_BITS_DATA_5 0x0500
+#define CP210X_BITS_DATA_6 0x0600
+#define CP210X_BITS_DATA_7 0x0700
+#define CP210X_BITS_DATA_8 0x0800
+#define CP210X_BITS_DATA_9 0x0900
+
+#define CP210X_BITS_PARITY_MASK 0x00f0
+#define CP210X_BITS_PARITY_NONE 0x0000
+#define CP210X_BITS_PARITY_ODD 0x0010
+#define CP210X_BITS_PARITY_EVEN 0x0020
+#define CP210X_BITS_PARITY_MARK 0x0030
+#define CP210X_BITS_PARITY_SPACE 0x0040
+
+#define CP210X_BITS_STOP_MASK 0x000f
+#define CP210X_BITS_STOP_1 0x0000
+#define CP210X_BITS_STOP_1_5 0x0001
+#define CP210X_BITS_STOP_2 0x0002
+
+// SILABSER_SET_BREAK_REQUEST_CODE
+#define CP210X_BREAK_ON 0x0001
+#define CP210X_BREAK_OFF 0x0000
+
+// SILABSER_SET_MHS_REQUEST_CODE
+#define CP210X_MCR_DTR 0x0001
+#define CP210X_MCR_RTS 0x0002
+#define CP210X_MCR_ALL 0x0003
+#define CP210X_MSR_CTS 0x0010
+#define CP210X_MSR_DSR 0x0020
+#define CP210X_MSR_RING 0x0040
+#define CP210X_MSR_DCD 0x0080
+#define CP210X_MSR_ALL 0x00F0
+
+#define CP210X_CONTROL_WRITE_DTR 0x0100UL
+#define CP210X_CONTROL_WRITE_RTS 0x0200UL
+
+#define CP210X_LSR_BREAK 0x0001
+#define CP210X_LSR_FRAMING_ERROR 0x0002
+#define CP210X_LSR_HW_OVERRUN 0x0004
+#define CP210X_LSR_QUEUE_OVERRUN 0x0008
+#define CP210X_LSR_PARITY_ERROR 0x0010
+#define CP210X_LSR_ALL 0x001F
+
#endif //TUSB_CP210X_H
diff --git a/src/class/cdc/serial/ftdi_sio.h b/src/class/cdc/serial/ftdi_sio.h
index 0825f0719..8abf74f11 100644
--- a/src/class/cdc/serial/ftdi_sio.h
+++ b/src/class/cdc/serial/ftdi_sio.h
@@ -25,222 +25,207 @@
#ifndef TUSB_FTDI_SIO_H
#define TUSB_FTDI_SIO_H
-// VID for matching FTDI devices
-#define TU_FTDI_VID 0x0403
+#include
// Commands
-#define FTDI_SIO_RESET 0 /* Reset the port */
-#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
-#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
-#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */
-#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */
-#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */
-#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */
-#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
-#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */
-#define FTDI_SIO_GET_LATENCY_TIMER 0x0a /* Get the latency timer */
-#define FTDI_SIO_SET_BITMODE 0x0b /* Set bitbang mode */
-#define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */
-#define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */
+#define FTDI_SIO_RESET 0 // Reset the port
+#define FTDI_SIO_MODEM_CTRL 1 // Set the modem control register
+#define FTDI_SIO_SET_FLOW_CTRL 2 // Set flow control register
+#define FTDI_SIO_SET_BAUD_RATE 3 // Set baud rate
+#define FTDI_SIO_SET_DATA 4 // Set the data characteristics of the port
+#define FTDI_SIO_GET_MODEM_STATUS 5 // Retrieve current value of modem status register
+#define FTDI_SIO_SET_EVENT_CHAR 6 // Set the event character
+#define FTDI_SIO_SET_ERROR_CHAR 7 // Set the error character
+#define FTDI_SIO_SET_LATENCY_TIMER 9 // Set the latency timer
+#define FTDI_SIO_GET_LATENCY_TIMER 10 // Get the latency timer
+#define FTDI_SIO_SET_BITMODE 11 // Set bitbang mode
+#define FTDI_SIO_READ_PINS 12 // Read immediate value of pins
+#define FTDI_SIO_READ_EEPROM 0x90 // Read EEPROM
-/* FTDI_SIO_RESET */
-#define FTDI_SIO_RESET_SIO 0
-#define FTDI_SIO_RESET_PURGE_RX 1
-#define FTDI_SIO_RESET_PURGE_TX 2
+// Channel indices for FT2232, FT2232H and FT4232H devices
+#define CHANNEL_A 1
+#define CHANNEL_B 2
+#define CHANNEL_C 3
+#define CHANNEL_D 4
-/*
- * BmRequestType: 0100 0000B
- * bRequest: FTDI_SIO_RESET
- * wValue: Control Value
- * 0 = Reset SIO
- * 1 = Purge RX buffer
- * 2 = Purge TX buffer
- * wIndex: Port
- * wLength: 0
- * Data: None
- *
- * The Reset SIO command has this effect:
- *
- * Sets flow control set to 'none'
- * Event char = $0D
- * Event trigger = disabled
- * Purge RX buffer
- * Purge TX buffer
- * Clear DTR
- * Clear RTS
- * baud and data format not reset
- *
- * The Purge RX and TX buffer commands affect nothing except the buffers
- *
- */
+// Port Identifier Table
+#define PIT_DEFAULT 0 // SIOA
+#define PIT_SIOA 1 // SIOA
+// The device this driver is tested with one has only one port
+#define PIT_SIOB 2 // SIOB
+#define PIT_PARALLEL 3 // Parallel
-/* FTDI_SIO_MODEM_CTRL */
-/*
- * BmRequestType: 0100 0000B
- * bRequest: FTDI_SIO_MODEM_CTRL
- * wValue: ControlValue (see below)
- * wIndex: Port
- * wLength: 0
- * Data: None
- *
- * NOTE: If the device is in RTS/CTS flow control, the RTS set by this
- * command will be IGNORED without an error being returned
- * Also - you can not set DTR and RTS with one control message
- */
+// FTDI_SIO_RESET
+#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET
+#define FTDI_SIO_RESET_REQUEST_TYPE 0x40
+#define FTDI_SIO_RESET_SIO 0
+#define FTDI_SIO_RESET_PURGE_RX 1
+#define FTDI_SIO_RESET_PURGE_TX 2
-#define FTDI_SIO_SET_DTR_MASK 0x1
-#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1)
-#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0)
-#define FTDI_SIO_SET_RTS_MASK 0x2
-#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2)
-#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0)
+// FTDI_SIO_SET_BAUDRATE
+#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_BAUDRATE_REQUEST 3
-/*
- * ControlValue
- * B0 DTR state
- * 0 = reset
- * 1 = set
- * B1 RTS state
- * 0 = reset
- * 1 = set
- * B2..7 Reserved
- * B8 DTR state enable
- * 0 = ignore
- * 1 = use DTR state
- * B9 RTS state enable
- * 0 = ignore
- * 1 = use RTS state
- * B10..15 Reserved
- */
+enum ftdi_sio_baudrate {
+ ftdi_sio_b300 = 0,
+ ftdi_sio_b600 = 1,
+ ftdi_sio_b1200 = 2,
+ ftdi_sio_b2400 = 3,
+ ftdi_sio_b4800 = 4,
+ ftdi_sio_b9600 = 5,
+ ftdi_sio_b19200 = 6,
+ ftdi_sio_b38400 = 7,
+ ftdi_sio_b57600 = 8,
+ ftdi_sio_b115200 = 9
+};
-/* FTDI_SIO_SET_FLOW_CTRL */
-#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
-#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
-#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
-#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
+// FTDI_SIO_SET_DATA
+#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
+#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8)
+#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8)
+#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8)
+#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8)
+#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8)
+#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) // same coding as ACM
+#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) // 1.5 not supported, for future use?
+#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
+#define FTDI_SIO_SET_BREAK (0x1 << 14)
-/*
- * BmRequestType: 0100 0000b
- * bRequest: FTDI_SIO_SET_FLOW_CTRL
- * wValue: Xoff/Xon
- * wIndex: Protocol/Port - hIndex is protocol / lIndex is port
- * wLength: 0
- * Data: None
- *
- * hIndex protocol is:
- * B0 Output handshaking using RTS/CTS
- * 0 = disabled
- * 1 = enabled
- * B1 Output handshaking using DTR/DSR
- * 0 = disabled
- * 1 = enabled
- * B2 Xon/Xoff handshaking
- * 0 = disabled
- * 1 = enabled
- *
- * A value of zero in the hIndex field disables handshaking
- *
- * If Xon/Xoff handshaking is specified, the hValue field should contain the
- * XOFF character and the lValue field contains the XON character.
- */
+// FTDI_SIO_MODEM_CTRL
+#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL
-/* FTDI_SIO_SET_BAUD_RATE */
-/*
- * BmRequestType: 0100 0000B
- * bRequest: FTDI_SIO_SET_BAUDRATE
- * wValue: BaudDivisor value - see below
- * wIndex: Port
- * wLength: 0
- * Data: None
- * The BaudDivisor values are calculated as follows (too complicated):
- */
+#define FTDI_SIO_SET_DTR_MASK 0x1UL
+#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1UL)
+#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0UL)
+#define FTDI_SIO_SET_RTS_MASK 0x2UL
+#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2UL)
+#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0UL)
-/* FTDI_SIO_SET_DATA */
-#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8)
-#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8)
-#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8)
-#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8)
-#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8)
-#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
-#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
-#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
-#define FTDI_SIO_SET_BREAK (0x1 << 14)
+// FTDI_SIO_SET_FLOW_CTRL
+#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL
+#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
+#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
+#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
+#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
-/*
- * BmRequestType: 0100 0000B
- * bRequest: FTDI_SIO_SET_DATA
- * wValue: Data characteristics (see below)
- * wIndex: Port
- * wLength: 0
- * Data: No
- *
- * Data characteristics
- *
- * B0..7 Number of data bits
- * B8..10 Parity
- * 0 = None
- * 1 = Odd
- * 2 = Even
- * 3 = Mark
- * 4 = Space
- * B11..13 Stop Bits
- * 0 = 1
- * 1 = 1.5
- * 2 = 2
- * B14
- * 1 = TX ON (break)
- * 0 = TX OFF (normal state)
- * B15 Reserved
- *
- */
+// FTDI_SIO_GET_LATENCY_TIMER
+#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST FTDI_SIO_GET_LATENCY_TIMER
+#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE 0xC0
-/*
-* DATA FORMAT
-*
-* IN Endpoint
-*
-* The device reserves the first two bytes of data on this endpoint to contain
-* the current values of the modem and line status registers. In the absence of
-* data, the device generates a message consisting of these two status bytes
- * every 40 ms
- *
- * Byte 0: Modem Status
-*
-* Offset Description
-* B0 Reserved - must be 1
-* B1 Reserved - must be 0
-* B2 Reserved - must be 0
-* B3 Reserved - must be 0
-* B4 Clear to Send (CTS)
-* B5 Data Set Ready (DSR)
-* B6 Ring Indicator (RI)
-* B7 Receive Line Signal Detect (RLSD)
-*
-* Byte 1: Line Status
-*
-* Offset Description
-* B0 Data Ready (DR)
-* B1 Overrun Error (OE)
-* B2 Parity Error (PE)
-* B3 Framing Error (FE)
-* B4 Break Interrupt (BI)
-* B5 Transmitter Holding Register (THRE)
-* B6 Transmitter Empty (TEMT)
-* B7 Error in RCVR FIFO
-*
-*/
-#define FTDI_RS0_CTS (1 << 4)
-#define FTDI_RS0_DSR (1 << 5)
-#define FTDI_RS0_RI (1 << 6)
-#define FTDI_RS0_RLSD (1 << 7)
+// FTDI_SIO_SET_LATENCY_TIMER
+#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST FTDI_SIO_SET_LATENCY_TIMER
+#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE 0x40
-#define FTDI_RS_DR 1
-#define FTDI_RS_OE (1<<1)
-#define FTDI_RS_PE (1<<2)
-#define FTDI_RS_FE (1<<3)
-#define FTDI_RS_BI (1<<4)
-#define FTDI_RS_THRE (1<<5)
-#define FTDI_RS_TEMT (1<<6)
-#define FTDI_RS_FIFO (1<<7)
+// FTDI_SIO_SET_EVENT_CHAR
+#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR
+#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40
+
+// FTDI_SIO_GET_MODEM_STATUS
+#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0
+#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS
+#define FTDI_SIO_CTS_MASK 0x10
+#define FTDI_SIO_DSR_MASK 0x20
+#define FTDI_SIO_RI_MASK 0x40
+#define FTDI_SIO_RLSD_MASK 0x80
+
+// FTDI_SIO_SET_BITMODE
+#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE
+
+// Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST
+#define FTDI_SIO_BITMODE_RESET 0x00
+#define FTDI_SIO_BITMODE_CBUS 0x20
+
+// FTDI_SIO_READ_PINS
+#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0
+#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS
+
+// FTDI_SIO_READ_EEPROM
+#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0
+#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM
+
+#define FTDI_FTX_CBUS_MUX_GPIO 0x8
+#define FTDI_FT232R_CBUS_MUX_GPIO 0xa
+
+#define FTDI_RS0_CTS (1 << 4)
+#define FTDI_RS0_DSR (1 << 5)
+#define FTDI_RS0_RI (1 << 6)
+#define FTDI_RS0_RLSD (1 << 7)
+
+#define FTDI_RS_DR 1
+#define FTDI_RS_OE (1 << 1)
+#define FTDI_RS_PE (1 << 2)
+#define FTDI_RS_FE (1 << 3)
+#define FTDI_RS_BI (1 << 4)
+#define FTDI_RS_THRE (1 << 5)
+#define FTDI_RS_TEMT (1 << 6)
+#define FTDI_RS_FIFO (1 << 7)
+
+// chip types and names
+typedef enum ftdi_chip_type {
+ FTDI_SIO = 0,
+// FTDI_FT232A,
+ FTDI_FT232B,
+ FTDI_FT2232C,
+ FTDI_FT232R,
+ FTDI_FT232H,
+ FTDI_FT2232H,
+ FTDI_FT4232H,
+ FTDI_FT4232HA,
+ FTDI_FT232HP,
+ FTDI_FT233HP,
+ FTDI_FT2232HP,
+ FTDI_FT2233HP,
+ FTDI_FT4232HP,
+ FTDI_FT4233HP,
+ FTDI_FTX,
+ FTDI_UNKNOWN
+} ftdi_chip_type_t;
+
+#define FTDI_CHIP_NAMES \
+ [FTDI_SIO] = "SIO", /* the serial part of FT8U100AX */ \
+/* [FTDI_FT232A] = "FT232A", */ \
+ [FTDI_FT232B] = "FT232B", \
+ [FTDI_FT2232C] = "FT2232C/D", \
+ [FTDI_FT232R] = "FT232R", \
+ [FTDI_FT232H] = "FT232H", \
+ [FTDI_FT2232H] = "FTDI_FT2232H", \
+ [FTDI_FT4232H] = "FT4232H", \
+ [FTDI_FT4232HA] = "FT4232HA", \
+ [FTDI_FT232HP] = "FT232HP", \
+ [FTDI_FT233HP] = "FT233HP", \
+ [FTDI_FT2232HP] = "FT2232HP", \
+ [FTDI_FT2233HP] = "FT2233HP", \
+ [FTDI_FT4232HP] = "FT4232HP", \
+ [FTDI_FT4233HP] = "FT4233HP", \
+ [FTDI_FTX] = "FT-X", \
+ [FTDI_UNKNOWN] = "UNKNOWN"
+
+// private interface data
+typedef struct ftdi_private {
+ ftdi_chip_type_t chip_type;
+ uint8_t channel; // channel index, or 0 for legacy types
+} ftdi_private_t;
+
+#define FTDI_OK true
+#define FTDI_FAIL false
+#define FTDI_NOT_POSSIBLE -1
+#define FTDI_REQUESTED -2
+
+// division and round function overtaken from math.h
+#define DIV_ROUND_CLOSEST(x, divisor)( \
+{ \
+ typeof(x) __x = x; \
+ typeof(divisor) __d = divisor; \
+ (((typeof(x))-1) > 0 || \
+ ((typeof(divisor))-1) > 0 || \
+ (((__x) > 0) == ((__d) > 0))) ? \
+ (((__x) + ((__d) / 2)) / (__d)) : \
+ (((__x) - ((__d) / 2)) / (__d)); \
+} \
+)
#endif //TUSB_FTDI_SIO_H
diff --git a/src/class/cdc/serial/pl2303.h b/src/class/cdc/serial/pl2303.h
new file mode 100644
index 000000000..63910c7bb
--- /dev/null
+++ b/src/class/cdc/serial/pl2303.h
@@ -0,0 +1,159 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 Heiko Kuester
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef TUSB_PL2303_H
+#define TUSB_PL2303_H
+
+#include
+#include
+
+// There is no official documentation for the PL2303 chips.
+// Reference can be found
+// - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/pl2303.h and
+// https://github.com/torvalds/linux/blob/master/drivers/usb/serial/pl2303.c
+// - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uplcom.c
+
+// quirks
+#define PL2303_QUIRK_UART_STATE_IDX0 1
+#define PL2303_QUIRK_LEGACY 2
+#define PL2303_QUIRK_ENDPOINT_HACK 4
+
+// requests and bits
+#define PL2303_SET_LINE_REQUEST_TYPE 0x21 // class request host to device interface
+#define PL2303_SET_LINE_REQUEST 0x20 // dec 32
+
+#define PL2303_SET_CONTROL_REQUEST_TYPE 0x21 // class request host to device interface
+#define PL2303_SET_CONTROL_REQUEST 0x22 // dec 34
+#define PL2303_CONTROL_DTR 0x01 // dec 1
+#define PL2303_CONTROL_RTS 0x02 // dec 2
+
+#define PL2303_BREAK_REQUEST_TYPE 0x21 // class request host to device interface
+#define PL2303_BREAK_REQUEST 0x23 // dec 35
+#define PL2303_BREAK_ON 0xffff
+#define PL2303_BREAK_OFF 0x0000
+
+#define PL2303_GET_LINE_REQUEST_TYPE 0xa1 // class request device to host interface
+#define PL2303_GET_LINE_REQUEST 0x21 // dec 33
+
+#define PL2303_VENDOR_WRITE_REQUEST_TYPE 0x40 // vendor request host to device interface
+#define PL2303_VENDOR_WRITE_REQUEST 0x01 // dec 1
+#define PL2303_VENDOR_WRITE_NREQUEST 0x80 // dec 128
+
+#define PL2303_VENDOR_READ_REQUEST_TYPE 0xc0 // vendor request device to host interface
+#define PL2303_VENDOR_READ_REQUEST 0x01 // dec 1
+#define PL2303_VENDOR_READ_NREQUEST 0x81 // dec 129
+
+#define PL2303_UART_STATE_INDEX 8
+#define PL2303_UART_STATE_MSR_MASK 0x8b
+#define PL2303_UART_STATE_TRANSIENT_MASK 0x74
+#define PL2303_UART_DCD 0x01
+#define PL2303_UART_DSR 0x02
+#define PL2303_UART_BREAK_ERROR 0x04
+#define PL2303_UART_RING 0x08
+#define PL2303_UART_FRAME_ERROR 0x10
+#define PL2303_UART_PARITY_ERROR 0x20
+#define PL2303_UART_OVERRUN_ERROR 0x40
+#define PL2303_UART_CTS 0x80
+
+#define PL2303_FLOWCTRL_MASK 0xf0
+
+#define PL2303_CLEAR_HALT_REQUEST_TYPE 0x02 // standard request host to device endpoint
+
+// registers via vendor read/write requests
+#define PL2303_READ_TYPE_HX_STATUS 0x8080
+
+#define PL2303_HXN_RESET_REG 0x07
+#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02
+#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01
+
+#define PL2303_HXN_FLOWCTRL_REG 0x0a
+#define PL2303_HXN_FLOWCTRL_MASK 0x1c
+#define PL2303_HXN_FLOWCTRL_NONE 0x1c
+#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18
+#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c
+
+// type data
+typedef enum pl2303_type {
+ PL2303_TYPE_H = 0, // 0
+ PL2303_TYPE_HX, // 1
+ PL2303_TYPE_TA, // 2
+ PL2303_TYPE_TB, // 3
+ PL2303_TYPE_HXD, // 4
+ PL2303_TYPE_HXN, // 5
+ PL2303_TYPE_COUNT,
+ PL2303_TYPE_NEED_SUPPORTS_HX_STATUS,
+ PL2303_TYPE_UNKNOWN,
+} pl2303_type_t;
+
+typedef struct pl2303_type_data {
+ uint32_t max_baud_rate;
+ uint8_t quirks;
+ uint8_t no_autoxonxoff : 1;
+ uint8_t no_divisors : 1;
+ uint8_t alt_divisors : 1;
+} pl2303_type_data_t;
+
+#define PL2303_TYPE_DATA \
+ [PL2303_TYPE_H] = { \
+ .max_baud_rate = 1228800, .quirks = PL2303_QUIRK_LEGACY, \
+ .no_autoxonxoff = 1, .no_divisors = 0, .alt_divisors = 0 \
+ }, \
+ [PL2303_TYPE_HX] = { \
+ .max_baud_rate = 6000000, .quirks = 0, \
+ .no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 0 \
+ }, \
+ [PL2303_TYPE_TA] = { \
+ .max_baud_rate = 6000000, .quirks = 0, \
+ .no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 1 \
+ }, \
+ [PL2303_TYPE_TB] = { \
+ .max_baud_rate = 12000000, .quirks = 0, \
+ .no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 1 \
+ }, \
+ [PL2303_TYPE_HXD] = { \
+ .max_baud_rate = 12000000, .quirks = 0, \
+ .no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 0 \
+ }, \
+ [PL2303_TYPE_HXN] = { \
+ .max_baud_rate = 12000000, .quirks = 0, \
+ .no_autoxonxoff = 0, .no_divisors = 1, .alt_divisors = 0 \
+ }
+
+typedef struct TU_ATTR_PACKED {
+ pl2303_type_t type;
+ uint8_t quirks;
+ bool supports_hx_status;
+} pl2303_private_t;
+
+// buffer sizes for line coding data
+#define PL2303_LINE_CODING_BUFSIZE 7
+#define PL2303_LINE_CODING_BAUDRATE_BUFSIZE 4
+
+// bulk endpoints
+#define PL2303_OUT_EP 0x02
+#define PL2303_IN_EP 0x83
+
+#endif // TUSB_PL2303_H
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/midi/midi_host.c b/src/class/midi/midi_host.c
index 4d824e04c..cd6e115ee 100644
--- a/src/class/midi/midi_host.c
+++ b/src/class/midi/midi_host.c
@@ -56,6 +56,7 @@ TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t idx, uint32_t xferred_bytes) { (void) i
typedef struct {
uint8_t daddr;
uint8_t bInterfaceNumber; // interface number of MIDI streaming
+ uint8_t iInterface;
uint8_t itf_count; // number of interface including Audio Control + MIDI streaming
uint8_t ep_in; // IN endpoint address
@@ -228,6 +229,7 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d
TU_LOG_DRV("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr);
p_midi->bInterfaceNumber = desc_itf->bInterfaceNumber;
+ p_midi->iInterface = desc_itf->iInterface;
p_midi->itf_count++;
desc_cb.desc_midi = desc_itf;
@@ -252,7 +254,9 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d
TU_LOG_DRV(" Jack %s %s descriptor \r\n",
tu_desc_subtype(p_desc) == MIDI_CS_INTERFACE_IN_JACK ? "IN" : "OUT",
p_desc[3] == MIDI_JACK_EXTERNAL ? "External" : "Embedded");
- desc_cb.desc_jack[desc_cb.jack_num++] = p_desc;
+ if (desc_cb.jack_num < TU_ARRAY_SIZE(desc_cb.desc_jack)) {
+ desc_cb.desc_jack[desc_cb.jack_num++] = p_desc;
+ }
break;
}
@@ -346,6 +350,28 @@ uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num) {
return TUSB_INDEX_INVALID_8;
}
+bool tuh_midi_itf_get_info(uint8_t idx, tuh_itf_info_t* info) {
+ midih_interface_t* p_midi = &_midi_host[idx];
+ TU_VERIFY(p_midi && info);
+
+ info->daddr = p_midi->daddr;
+
+ // re-construct descriptor
+ tusb_desc_interface_t* desc = &info->desc;
+ desc->bLength = sizeof(tusb_desc_interface_t);
+ desc->bDescriptorType = TUSB_DESC_INTERFACE;
+
+ desc->bInterfaceNumber = p_midi->bInterfaceNumber;
+ desc->bAlternateSetting = 0;
+ desc->bNumEndpoints = (uint8_t)((p_midi->ep_in != 0 ? 1:0) + (p_midi->ep_out != 0 ? 1:0));
+ desc->bInterfaceClass = TUSB_CLASS_AUDIO;
+ desc->bInterfaceSubClass = AUDIO_SUBCLASS_MIDI_STREAMING;
+ desc->bInterfaceProtocol = 0;
+ desc->iInterface = p_midi->iInterface;
+
+ return true;
+}
+
uint8_t tuh_midi_get_tx_cable_count (uint8_t idx) {
TU_VERIFY(idx < CFG_TUH_MIDI);
midih_interface_t *p_midi = &_midi_host[idx];
@@ -566,8 +592,8 @@ uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buff
break;
default:
break;
- cable_sysex_in_progress &= (uint16_t) ~cable_mask;
}
+ cable_sysex_in_progress &= (uint16_t) ~cable_mask;
} else {
// Real-time message: can be inserted into a sysex message,
// so do don't clear cable_sysex_in_progress bit
diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h
index b06bb43d7..06554a03d 100644
--- a/src/class/midi/midi_host.h
+++ b/src/class/midi/midi_host.h
@@ -69,7 +69,7 @@ typedef struct {
const tusb_desc_endpoint_t* desc_epout; // endpoint OUT descriptor, CS_ENDPOINT is right after
uint8_t jack_num;
- const uint8_t* desc_jack[16]; // list of jack descriptors (embedded + external)
+ const uint8_t* desc_jack[32]; // list of jack descriptors (embedded + external)
} tuh_midi_descriptor_cb_t;
typedef struct {
@@ -90,6 +90,10 @@ bool tuh_midi_mounted(uint8_t idx);
// return TUSB_INDEX_INVALID_8 (0xFF) if not found
uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num);
+// Get Interface information
+// return true if index is correct and interface is currently mounted
+bool tuh_midi_itf_get_info(uint8_t idx, tuh_itf_info_t* info);
+
// return the number of virtual midi cables on the device's IN endpoint
uint8_t tuh_midi_get_rx_cable_count(uint8_t idx);
diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c
index 6670045aa..747ad03ed 100644
--- a/src/class/msc/msc_device.c
+++ b/src/class/msc/msc_device.c
@@ -53,23 +53,26 @@ enum {
};
typedef struct {
- TU_ATTR_ALIGNED(4) msc_cbw_t cbw;
- TU_ATTR_ALIGNED(4) msc_csw_t csw;
+ TU_ATTR_ALIGNED(4) msc_cbw_t cbw; // 31 bytes
+ uint8_t rhport;
+ TU_ATTR_ALIGNED(4) msc_csw_t csw; // 13 bytes
uint8_t itf_num;
uint8_t ep_in;
uint8_t ep_out;
- // Bulk Only Transfer (BOT) Protocol
- uint8_t stage;
-
uint32_t total_len; // byte to be transferred, can be smaller than total_bytes in cbw
uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage
- // Sense Response Data
+ // Bulk Only Transfer (BOT) Protocol
+ uint8_t stage;
+
+ // SCSI Sense Response Data
uint8_t sense_key;
uint8_t add_sense_code;
uint8_t add_sense_qualifier;
+
+ uint8_t pending_io; // pending async IO
}mscd_interface_t;
static mscd_interface_t _mscd_itf;
@@ -82,31 +85,36 @@ CFG_TUD_MEM_SECTION static struct {
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize);
-static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc);
-
-static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc);
-static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes);
+static void proc_read10_cmd(mscd_interface_t* p_msc);
+static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes);
+static void proc_write10_cmd(mscd_interface_t* p_msc);
+static void proc_write10_host_data(mscd_interface_t* p_msc, uint32_t xferred_bytes);
+static void proc_write_io_data(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes);
+static bool proc_stage_status(mscd_interface_t* p_msc);
TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) {
return tu_bit_test(dir, 7);
}
-static inline bool send_csw(uint8_t rhport, mscd_interface_t* p_msc) {
+static inline bool send_csw(mscd_interface_t* p_msc) {
// Data residue is always = host expect - actual transferred
+ uint8_t rhport = p_msc->rhport;
p_msc->csw.data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len;
p_msc->stage = MSC_STAGE_STATUS_SENT;
memcpy(_mscd_epbuf.buf, &p_msc->csw, sizeof(msc_csw_t));
return usbd_edpt_xfer(rhport, p_msc->ep_in , _mscd_epbuf.buf, sizeof(msc_csw_t));
}
-static inline bool prepare_cbw(uint8_t rhport, mscd_interface_t* p_msc) {
+static inline bool prepare_cbw(mscd_interface_t* p_msc) {
+ uint8_t rhport = p_msc->rhport;
p_msc->stage = MSC_STAGE_CMD;
return usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_epbuf.buf, sizeof(msc_cbw_t));
}
-static void fail_scsi_op(uint8_t rhport, mscd_interface_t* p_msc, uint8_t status) {
+static void fail_scsi_op(mscd_interface_t* p_msc, uint8_t status) {
msc_cbw_t const * p_cbw = &p_msc->cbw;
msc_csw_t * p_csw = &p_msc->csw;
+ uint8_t rhport = p_msc->rhport;
p_csw->status = status;
p_csw->data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len;
@@ -177,6 +185,33 @@ static uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) {
return status;
}
+static bool proc_stage_status(mscd_interface_t *p_msc) {
+ uint8_t rhport = p_msc->rhport;
+ msc_cbw_t const *p_cbw = &p_msc->cbw;
+
+ // skip status if epin is currently stalled, will do it when received Clear Stall request
+ if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) {
+ if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) {
+ // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status
+ // TU_LOG_DRV(" SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len);
+ usbd_edpt_stall(rhport, p_msc->ep_in);
+ } else {
+ TU_ASSERT(send_csw(p_msc));
+ }
+ }
+
+ #if TU_CHECK_MCU(OPT_MCU_CXD56)
+ // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD.
+ // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and
+ // hope everything will work
+ if (usbd_edpt_stalled(rhport, p_msc->ep_in)) {
+ usbd_edpt_clear_stall(rhport, p_msc->ep_in);
+ send_csw(p_msc);
+ }
+ #endif
+ return true;
+}
+
//--------------------------------------------------------------------+
// Debug
//--------------------------------------------------------------------+
@@ -214,15 +249,51 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u
return true;
}
-static inline void set_sense_medium_not_present(uint8_t lun) {
+TU_ATTR_ALWAYS_INLINE static inline void set_sense_medium_not_present(uint8_t lun) {
// default sense is NOT READY, MEDIUM NOT PRESENT
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00);
}
+static void proc_async_io_done(void *bytes_io) {
+ mscd_interface_t *p_msc = &_mscd_itf;
+ TU_VERIFY(p_msc->pending_io, );
+ const int32_t nbytes = (int32_t) (intptr_t) bytes_io;
+ const uint8_t cmd = p_msc->cbw.command[0];
+
+ p_msc->pending_io = 0;
+ switch (cmd) {
+ case SCSI_CMD_READ_10:
+ proc_read_io_data(p_msc, nbytes);
+ break;
+
+ case SCSI_CMD_WRITE_10:
+ proc_write_io_data(p_msc, (uint32_t) nbytes, nbytes);
+ break;
+
+ default: break;
+ }
+
+ // send status if stage is transitioned to STATUS
+ if (p_msc->stage == MSC_STAGE_STATUS) {
+ proc_stage_status(p_msc);
+ }
+}
+
+bool tud_msc_async_io_done(int32_t bytes_io, bool in_isr) {
+ // Precheck to avoid queueing multiple RW done callback
+ TU_VERIFY(_mscd_itf.pending_io);
+ if (bytes_io == 0) {
+ bytes_io = TUD_MSC_RET_ERROR; // 0 is treated as error, no reason to call this with BUSY here
+ }
+ usbd_defer_func(proc_async_io_done, (void *) (intptr_t) bytes_io, in_isr);
+ return true;
+}
+
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
void mscd_init(void) {
+ TU_LOG_INT(CFG_TUD_MSC_LOG_LEVEL, sizeof(mscd_interface_t));
tu_memclr(&_mscd_itf, sizeof(mscd_interface_t));
}
@@ -245,12 +316,13 @@ uint16_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
mscd_interface_t * p_msc = &_mscd_itf;
p_msc->itf_num = itf_desc->bInterfaceNumber;
+ p_msc->rhport = rhport;
// Open endpoint pair
TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(itf_desc), 2, TUSB_XFER_BULK, &p_msc->ep_out, &p_msc->ep_in), 0);
// Prepare for Command Block Wrapper
- TU_ASSERT(prepare_cbw(rhport, p_msc), drv_len);
+ TU_ASSERT(prepare_cbw(p_msc), drv_len);
return drv_len;
}
@@ -289,14 +361,14 @@ bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
if (ep_addr == p_msc->ep_in) {
if (p_msc->stage == MSC_STAGE_STATUS) {
// resume sending SCSI status if we are in this stage previously before stalled
- TU_ASSERT(send_csw(rhport, p_msc));
+ TU_ASSERT(send_csw(p_msc));
}
} else if (ep_addr == p_msc->ep_out) {
if (p_msc->stage == MSC_STAGE_CMD) {
// part of reset recovery (probably due to invalid CBW) -> prepare for new command
// Note: skip if already queued previously
if (usbd_edpt_ready(rhport, p_msc->ep_out)) {
- TU_ASSERT(prepare_cbw(rhport, p_msc));
+ TU_ASSERT(prepare_cbw(p_msc));
}
}
}
@@ -344,7 +416,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) {
@@ -382,12 +454,12 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
uint8_t const status = rdwr10_validate_cmd(p_cbw);
if (status != MSC_CSW_STATUS_PASSED) {
- fail_scsi_op(rhport, p_msc, status);
+ fail_scsi_op(p_msc, status);
} else if (p_cbw->total_bytes) {
if (SCSI_CMD_READ_10 == p_cbw->command[0]) {
- proc_read10_cmd(rhport, p_msc);
+ proc_read10_cmd(p_msc);
} else {
- proc_write10_cmd(rhport, p_msc);
+ proc_write10_cmd(p_msc);
}
} else {
// no data transfer, only exist in complaint test suite
@@ -400,7 +472,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
if ((p_cbw->total_bytes > 0) && !is_data_in(p_cbw->dir)) {
if (p_cbw->total_bytes > CFG_TUD_MSC_EP_BUFSIZE) {
TU_LOG_DRV(" SCSI reject non READ10/WRITE10 with large data\r\n");
- fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+ fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
} else {
// Didn't check for case 9 (Ho > Dn), which requires examining scsi command first
// but it is OK to just receive data then responded with failed status
@@ -418,12 +490,12 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
if (resplen < 0) {
// unsupported command
TU_LOG_DRV(" SCSI unsupported or failed command\r\n");
- fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+ fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
} else if (resplen == 0) {
if (p_cbw->total_bytes) {
// 6.7 The 13 Cases: case 4 (Hi > Dn)
// TU_LOG_DRV(" SCSI case 4 (Hi > Dn): %lu\r\n", p_cbw->total_bytes);
- fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+ fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
} else {
// case 1 Hn = Dn: all good
p_msc->stage = MSC_STAGE_STATUS;
@@ -432,7 +504,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
if (p_cbw->total_bytes == 0) {
// 6.7 The 13 Cases: case 2 (Hn < Di)
// TU_LOG_DRV(" SCSI case 2 (Hn < Di): %lu\r\n", p_cbw->total_bytes);
- fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+ fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
} else {
// cannot return more than host expect
p_msc->total_len = tu_min32((uint32_t)resplen, p_cbw->total_bytes);
@@ -441,7 +513,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);
@@ -455,10 +528,10 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
// Data Stage is complete
p_msc->stage = MSC_STAGE_STATUS;
}else {
- proc_read10_cmd(rhport, p_msc);
+ proc_read10_cmd(p_msc);
}
} else if (SCSI_CMD_WRITE_10 == p_cbw->command[0]) {
- proc_write10_new_data(rhport, p_msc, xferred_bytes);
+ proc_write10_host_data(p_msc, xferred_bytes);
} else {
p_msc->xferred_len += xferred_bytes;
@@ -469,7 +542,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
if ( cb_result < 0 ) {
// unsupported command
TU_LOG_DRV(" SCSI unsupported command\r\n");
- fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+ fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
}else {
// TODO haven't implement this scenario any further yet
}
@@ -490,7 +563,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
break;
case MSC_STAGE_STATUS_SENT:
- // Wait for the Status phase to complete
+ // Status phase is complete
if ((ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t))) {
TU_LOG_DRV(" SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status);
// TU_LOG_MEM(CFG_TUD_MSC_LOG_LEVEL, p_csw, xferred_bytes, 2);
@@ -518,9 +591,9 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
break;
}
- TU_ASSERT(prepare_cbw(rhport, p_msc));
+ TU_ASSERT(prepare_cbw(p_msc));
} else {
- // Any xfer ended here is consider unknown error, ignore it
+ // Any xfer ended here is considered unknown error, ignore it
TU_LOG1(" Warning expect SCSI Status but received unknown data\r\n");
}
break;
@@ -529,26 +602,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
}
if (p_msc->stage == MSC_STAGE_STATUS) {
- // skip status if epin is currently stalled, will do it when received Clear Stall request
- if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) {
- if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) {
- // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status
- // TU_LOG_DRV(" SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len);
- usbd_edpt_stall(rhport, p_msc->ep_in);
- } else {
- TU_ASSERT(send_csw(rhport, p_msc));
- }
- }
-
- #if TU_CHECK_MCU(OPT_MCU_CXD56)
- // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD.
- // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and
- // hope everything will work
- if ( usbd_edpt_stalled(rhport, p_msc->ep_in) ) {
- usbd_edpt_clear_stall(rhport, p_msc->ep_in);
- send_csw(rhport, p_msc);
- }
- #endif
+ TU_ASSERT(proc_stage_status(p_msc));
}
return true;
@@ -645,8 +699,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
break;
case SCSI_CMD_READ_FORMAT_CAPACITY: {
- scsi_read_format_capacity_data_t read_fmt_capa =
- {
+ scsi_read_format_capacity_data_t read_fmt_capa = {
.list_length = 8,
.block_num = 0,
.descriptor_type = 2, // formatted media
@@ -678,8 +731,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
break;
case SCSI_CMD_INQUIRY: {
- scsi_inquiry_resp_t inquiry_rsp =
- {
+ scsi_inquiry_resp_t inquiry_rsp = {
.is_removable = 1,
.version = 2,
.response_data_format = 2,
@@ -699,8 +751,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
break;
case SCSI_CMD_MODE_SENSE_6: {
- scsi_mode_sense6_resp_t mode_resp =
- {
+ scsi_mode_sense6_resp_t mode_resp = {
.data_len = 3,
.medium_type = 0,
.write_protected = false,
@@ -721,8 +772,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
break;
case SCSI_CMD_REQUEST_SENSE: {
- scsi_sense_fixed_resp_t sense_rsp =
- {
+ scsi_sense_fixed_resp_t sense_rsp = {
.response_code = 0x70, // current, fixed format
.valid = 1
};
@@ -752,39 +802,49 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
return resplen;
}
-static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc) {
+static void proc_read10_cmd(mscd_interface_t* p_msc) {
msc_cbw_t const* p_cbw = &p_msc->cbw;
-
- // block size already verified not zero
- uint16_t const block_sz = rdwr10_get_blocksize(p_cbw);
-
- // Adjust lba with transferred bytes
+ uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); // already verified non-zero
+ // Adjust lba & offset with transferred bytes
uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz);
+ uint32_t const offset = p_msc->xferred_len % block_sz;
// remaining bytes capped at class buffer
int32_t nbytes = (int32_t)tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes - p_msc->xferred_len);
- // Application can consume smaller bytes
- uint32_t const offset = p_msc->xferred_len % block_sz;
+ p_msc->pending_io = 1;
nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes);
-
- if (nbytes < 0) {
- // negative means error -> endpoint is stalled & status in CSW set to failed
- TU_LOG_DRV(" tud_msc_read10_cb() return -1\r\n");
-
- // set sense
- set_sense_medium_not_present(p_cbw->lun);
-
- fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
- } else if (nbytes == 0) {
- // zero means not ready -> simulate an transfer complete so that this driver callback will fired again
- dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false);
- } else {
- TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_epbuf.buf, (uint16_t) nbytes),);
+ if (nbytes != TUD_MSC_RET_ASYNC) {
+ p_msc->pending_io = 0;
+ proc_read_io_data(p_msc, nbytes);
}
}
-static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc) {
+static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) {
+ const uint8_t rhport = p_msc->rhport;
+ if (nbytes > 0) {
+ TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_epbuf.buf, (uint16_t) nbytes),);
+ } else {
+ // nbytes is status
+ switch (nbytes) {
+ case TUD_MSC_RET_ERROR:
+ // error -> endpoint is stalled & status in CSW set to failed
+ TU_LOG_DRV(" IO read() failed\r\n");
+ set_sense_medium_not_present(p_msc->cbw.lun);
+ fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
+ break;
+
+ case TUD_MSC_RET_BUSY:
+ // not ready yet -> fake a transfer complete so that this driver callback will fire again
+ dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false);
+ break;
+
+ default: break;
+ }
+ }
+}
+
+static void proc_write10_cmd(mscd_interface_t* p_msc) {
msc_cbw_t const* p_cbw = &p_msc->cbw;
bool writable = true;
@@ -796,51 +856,56 @@ static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc) {
// Not writable, complete this SCSI op with error
// Sense = Write protected
tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_DATA_PROTECT, 0x27, 0x00);
- fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+ fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
return;
}
// remaining bytes capped at class buffer
uint16_t nbytes = (uint16_t)tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes - p_msc->xferred_len);
-
// Write10 callback will be called later when usb transfer complete
- TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_epbuf.buf, nbytes),);
+ TU_ASSERT(usbd_edpt_xfer(p_msc->rhport, p_msc->ep_out, _mscd_epbuf.buf, nbytes),);
}
// process new data arrived from WRITE10
-static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes) {
+static void proc_write10_host_data(mscd_interface_t* p_msc, uint32_t xferred_bytes) {
msc_cbw_t const* p_cbw = &p_msc->cbw;
+ uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); // already verified non-zero
- // block size already verified not zero
- uint16_t const block_sz = rdwr10_get_blocksize(p_cbw);
-
- // Adjust lba with transferred bytes
+ // Adjust lba & offset with transferred bytes
uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz);
-
- // Invoke callback to consume new data
uint32_t const offset = p_msc->xferred_len % block_sz;
- int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes);
+ p_msc->pending_io = 1;
+ int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes);
+ if (nbytes != TUD_MSC_RET_ASYNC) {
+ p_msc->pending_io = 0;
+ proc_write_io_data(p_msc, xferred_bytes, nbytes);
+ }
+}
+
+static void proc_write_io_data(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes) {
if (nbytes < 0) {
- // negative means error -> failed this scsi op
- TU_LOG_DRV(" tud_msc_write10_cb() return -1\r\n");
+ // nbytes is status
+ switch (nbytes) {
+ case TUD_MSC_RET_ERROR:
+ // IO error -> failed this scsi op
+ TU_LOG_DRV(" IO write() failed\r\n");
+ set_sense_medium_not_present(p_msc->cbw.lun);
+ fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED);
+ break;
- // update actual byte before failed
- p_msc->xferred_len += xferred_bytes;
-
- set_sense_medium_not_present(p_cbw->lun);
- fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
+ default: break;
+ }
} else {
if ((uint32_t)nbytes < xferred_bytes) {
- // Application consume less than what we got (including zero)
+ // Application consume less than what we got including TUD_MSC_RET_BUSY (0)
const uint32_t left_over = xferred_bytes - (uint32_t)nbytes;
if (nbytes > 0) {
- p_msc->xferred_len += (uint16_t)nbytes;
memmove(_mscd_epbuf.buf, _mscd_epbuf.buf + nbytes, left_over);
}
- // simulate a transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter
- dcd_event_xfer_complete(rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false);
+ // fake a transfer complete with adjusted parameters --> callback will be invoked with adjusted parameters
+ dcd_event_xfer_complete(p_msc->rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false);
} else {
// Application consume all bytes in our buffer
p_msc->xferred_len += xferred_bytes;
@@ -850,7 +915,7 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3
p_msc->stage = MSC_STAGE_STATUS;
} else {
// prepare to receive more data from host
- proc_write10_cmd(rhport, p_msc);
+ proc_write10_cmd(p_msc);
}
}
}
diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h
index 29acd280a..f2ea256b4 100644
--- a/src/class/msc/msc_device.h
+++ b/src/class/msc/msc_device.h
@@ -48,6 +48,13 @@
#error CFG_TUD_MSC_EP_BUFSIZE must be defined, value of a block size should work well, the more the better
#endif
+// Return value of callback functions
+enum {
+ TUD_MSC_RET_BUSY = 0, // Busy, e.g disk I/O is not ready
+ TUD_MSC_RET_ERROR = -1,
+ TUD_MSC_RET_ASYNC = -2, // Asynchronous IO
+};
+
TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct");
//--------------------------------------------------------------------+
@@ -57,38 +64,30 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct");
// Set SCSI sense response
bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier);
+// Called by Application once asynchronous I/O operation is done
+// bytes_io is number of bytes in I/O op, typically the bufsize in read/write_cb() or
+// TUD_MSC_RET_ERROR (-1) for error. Note TUD_MSC_RET_BUSY (0) will be treated as error as well.
+bool tud_msc_async_io_done(int32_t bytes_io, bool in_isr);
+
//--------------------------------------------------------------------+
// Application Callbacks (WEAK is optional)
//--------------------------------------------------------------------+
-// Invoked when received SCSI READ10 command
-// - Address = lba * BLOCK_SIZE + offset
-// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE.
-//
-// - Application fill the buffer (up to bufsize) with address contents and return number of read byte. If
-// - read < bufsize : These bytes are transferred first and callback invoked again for remaining data.
-//
-// - read == 0 : Indicate application is not ready yet e.g disk I/O busy.
-// Callback invoked again with the same parameters later on.
-//
-// - read < 0 : Indicate application error e.g invalid address. This request will be STALLed
-// and return failed status in command status wrapper phase.
+/*
+ Invoked when received SCSI READ10/WRITE10 command
+ - Address = lba * BLOCK_SIZE + offset
+ - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE.
+ - Application fill the buffer (up to bufsize) with address contents and return number of bytes read or status.
+ - 0 < ret < bufsize: These bytes are transferred first and callback will be invoked again for remaining data.
+ - TUD_MSC_RET_BUSY
+ Application is buys e.g disk I/O not ready. Callback will be invoked again with the same parameters later on.
+ - TUD_MSC_RET_ERROR
+ error such as invalid address. This request will be STALLed and scsi command will be failed
+ - TUD_MSC_RET_ASYNC
+ Data I/O will be done asynchronously in a background task. Application should return immediately.
+ tud_msc_async_io_done() must be called once IO/ is done to signal completion.
+*/
int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
-
-// Invoked when received SCSI WRITE10 command
-// - Address = lba * BLOCK_SIZE + offset
-// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE.
-//
-// - Application write data from buffer to address contents (up to bufsize) and return number of written byte. If
-// - write < bufsize : callback invoked again with remaining data later on.
-//
-// - write == 0 : Indicate application is not ready yet e.g disk I/O busy.
-// Callback invoked again with the same parameters later on.
-//
-// - write < 0 : Indicate application error e.g invalid address. This request will be STALLed
-// and return failed status in command status wrapper phase.
-//
-// TODO change buffer to const uint8_t*
int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
// Invoked when received SCSI_CMD_INQUIRY
diff --git a/src/class/net/ecm_rndis_device.c b/src/class/net/ecm_rndis_device.c
index a54e6d662..299eb97c8 100644
--- a/src/class/net/ecm_rndis_device.c
+++ b/src/class/net/ecm_rndis_device.c
@@ -81,6 +81,7 @@ typedef struct {
static netd_interface_t _netd_itf;
CFG_TUD_MEM_SECTION static netd_epbuf_t _netd_epbuf;
static bool can_xmit;
+static bool ecm_link_is_up = true; // Store link state for ECM mode
void tud_network_recv_renew(void) {
usbd_edpt_xfer(0, _netd_itf.ep_out, _netd_epbuf.rx, NETD_PACKET_SIZE);
@@ -95,7 +96,11 @@ void netd_report(uint8_t *buf, uint16_t len) {
const uint8_t rhport = 0;
len = tu_min16(len, sizeof(ecm_notify_t));
- TU_VERIFY(usbd_edpt_claim(rhport, _netd_itf.ep_notif), );
+ if (!usbd_edpt_claim(rhport, _netd_itf.ep_notif)) {
+ TU_LOG1("ECM: Failed to claim notification endpoint\n");
+ return;
+ }
+
memcpy(_netd_epbuf.notify, buf, len);
usbd_edpt_xfer(rhport, _netd_itf.ep_notif, _netd_epbuf.notify, len);
}
@@ -181,8 +186,6 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
// Open endpoint pair for RNDIS
TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in), 0);
- tud_network_init_cb();
-
// we are ready to transmit a packet
can_xmit = true;
@@ -196,11 +199,11 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
}
static void ecm_report(bool nc) {
- const ecm_notify_t ecm_notify_nc = {
+ ecm_notify_t ecm_notify_nc = {
.header = {
.bmRequestType = 0xA1,
.bRequest = 0, /* NETWORK_CONNECTION aka NetworkConnection */
- .wValue = 1, /* Connected */
+ .wValue = ecm_link_is_up ? 1 : 0, /* Use current link state */
.wLength = 0,
},
};
@@ -259,7 +262,6 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
// TODO should be merge with RNDIS's after endpoint opened
// Also should have opposite callback for application to disable network !!
- tud_network_init_cb();
can_xmit = true; // we are ready to transmit a packet
tud_network_recv_renew(); // prepare for incoming packets
}
@@ -286,7 +288,10 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
/* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */
if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) {
tud_control_xfer(rhport, request, NULL, 0);
- ecm_report(true);
+ // Only send connection notification if link is up
+ if (ecm_link_is_up) {
+ ecm_report(true);
+ }
}
} else {
if (request->bmRequestType_bit.direction == TUSB_DIR_IN) {
@@ -363,9 +368,8 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
}
if (_netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif)) {
- if (sizeof(tusb_control_request_t) == xferred_bytes) {
- ecm_report(false);
- }
+ // Notification transfer complete - endpoint is now free
+ // Don't automatically send speed change notification after link state changes
}
return true;
@@ -398,4 +402,31 @@ void tud_network_xmit(void *ref, uint16_t arg) {
do_in_xfer(_netd_epbuf.tx, len);
}
+// Set the network link state (up/down) and notify the host
+void tud_network_link_state(uint8_t rhport, bool is_up) {
+ (void)rhport;
+
+ if (_netd_itf.ecm_mode) {
+ ecm_link_is_up = is_up;
+
+ // For ECM mode, send network connection notification only
+ // Don't trigger speed change notification for link state changes
+ ecm_notify_t notify = {
+ .header = {
+ .bmRequestType = 0xA1,
+ .bRequest = 0, /* NETWORK_CONNECTION */
+ .wValue = is_up ? 1 : 0, /* 0 = disconnected, 1 = connected */
+ .wLength = 0,
+ },
+ };
+ notify.header.wIndex = _netd_itf.itf_num;
+ netd_report((uint8_t *)¬ify, sizeof(notify.header));
+ } else {
+ // For RNDIS mode, we would need to implement RNDIS status indication
+ // This is more complex and requires RNDIS_INDICATE_STATUS_MSG
+ // For now, RNDIS doesn't support dynamic link state changes
+ (void)is_up;
+ }
+}
+
#endif
diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c
index f9fda0698..02833c5f1 100644
--- a/src/class/net/ncm_device.c
+++ b/src/class/net/ncm_device.c
@@ -110,6 +110,7 @@ typedef struct {
NOTIFICATION_DONE
} notification_xmit_state; // state of notification transmission
bool notification_xmit_is_running; // notification is currently transmitted
+ bool link_is_up; // current link state
// misc
bool tud_network_recv_renew_active; // tud_network_recv_renew() is active (avoid recursive invocations)
@@ -218,7 +219,7 @@ static void notification_xmit(uint8_t rhport, bool force_next) {
.direction = TUSB_DIR_IN
},
.bRequest = CDC_NOTIF_NETWORK_CONNECTION,
- .wValue = 1 /* Connected */,
+ .wValue = ncm_interface.link_is_up ? 1 : 0, /* Dynamic link state */
.wIndex = ncm_interface.itf_num,
.wLength = 0,
},
@@ -232,6 +233,7 @@ static void notification_xmit(uint8_t rhport, bool force_next) {
ncm_interface.notification_xmit_is_running = true;
} else {
TU_LOG_DRV(" NOTIFICATION_FINISHED\n");
+ ncm_interface.notification_xmit_is_running = false;
}
} // notification_xmit
@@ -755,6 +757,32 @@ static void tud_network_recv_renew_r(uint8_t rhport) {
tud_network_recv_renew();
} // tud_network_recv_renew
+/**
+ * Set the link state and send notification to host
+ */
+void tud_network_link_state(uint8_t rhport, bool is_up) {
+ TU_LOG_DRV("tud_network_link_state(%d, %d)\n", rhport, is_up);
+
+ if (ncm_interface.link_is_up == is_up) {
+ // No change in link state
+ return;
+ }
+
+ ncm_interface.link_is_up = is_up;
+
+ // Only send notification if we have an active data interface
+ if (ncm_interface.itf_data_alt != 1) {
+ TU_LOG_DRV(" link state notification skipped (interface not active)\n");
+ return;
+ }
+
+ // Reset notification state to send link state update
+ ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED;
+
+ // Trigger notification transmission
+ notification_xmit(rhport, false);
+}
+
//-----------------------------------------------------------------------------
//
// all the netd_*() stuff (interface TinyUSB -> driver)
@@ -774,6 +802,12 @@ void netd_init(void) {
for (int i = 0; i < RECV_NTB_N; ++i) {
ncm_interface.recv_free_ntb[i] = &ncm_epbuf.recv[i].ntb;
}
+ // Default link state - can be configured via CFG_TUD_NCM_DEFAULT_LINK_UP
+ #ifdef CFG_TUD_NCM_DEFAULT_LINK_UP
+ ncm_interface.link_is_up = CFG_TUD_NCM_DEFAULT_LINK_UP;
+ #else
+ ncm_interface.link_is_up = true; // Default to link up if not set.
+ #endif
} // netd_init
/**
diff --git a/src/class/net/net_device.h b/src/class/net/net_device.h
index 4c9a92f2d..fff2623b7 100644
--- a/src/class/net/net_device.h
+++ b/src/class/net/net_device.h
@@ -87,6 +87,11 @@ void tud_network_init_cb(void);
// TODO removed later since it is not part of tinyusb stack
extern uint8_t tud_network_mac_address[6];
+//------------- NCM -------------//
+
+// Set the network link state (up/down) and notify the host
+void tud_network_link_state(uint8_t rhport, bool is_up);
+
//--------------------------------------------------------------------+
// INTERNAL USBD-CLASS DRIVER API
//--------------------------------------------------------------------+
diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c
index 2fc0ac944..7f1fd8c41 100644
--- a/src/class/vendor/vendor_device.c
+++ b/src/class/vendor/vendor_device.c
@@ -196,8 +196,8 @@ void vendord_reset(uint8_t rhport) {
uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint16_t max_len) {
TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0);
+ const uint8_t* desc_end = (const uint8_t*)desc_itf + max_len;
const uint8_t* p_desc = tu_desc_next(desc_itf);
- const uint8_t* desc_end = (uint8_t const*)desc_itf + max_len;
// Find available interface
vendord_interface_t* p_vendor = NULL;
@@ -210,26 +210,26 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uin
TU_VERIFY(p_vendor, 0);
p_vendor->itf_num = desc_itf->bInterfaceNumber;
- uint8_t found_ep = 0;
- while (found_ep < desc_itf->bNumEndpoints) {
- // skip non-endpoint descriptors
- while ( (TUSB_DESC_ENDPOINT != tu_desc_type(p_desc)) && (p_desc < desc_end) ) {
- p_desc = tu_desc_next(p_desc);
- }
- if (p_desc >= desc_end) {
- break;
- }
+ while (tu_desc_is_valid(p_desc, desc_end)) {
+ const uint8_t desc_type = tu_desc_type(p_desc);
+ if (desc_type == TUSB_DESC_INTERFACE || desc_type == TUSB_DESC_INTERFACE_ASSOCIATION) {
+ break; // end of this interface
+ } else if (desc_type == TUSB_DESC_ENDPOINT) {
+ const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc;
+ TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
- const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc;
- TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
- found_ep++;
-
- if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
- tu_edpt_stream_open(&p_vendor->tx.stream, desc_ep);
- tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf));
- } else {
- tu_edpt_stream_open(&p_vendor->rx.stream, desc_ep);
- TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream) > 0, 0); // prepare for incoming data
+ // open endpoint stream, skip if already opened
+ if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
+ if (p_vendor->tx.stream.ep_addr == 0) {
+ tu_edpt_stream_open(&p_vendor->tx.stream, desc_ep);
+ tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf));
+ }
+ } else {
+ if (p_vendor->rx.stream.ep_addr == 0) {
+ tu_edpt_stream_open(&p_vendor->rx.stream, desc_ep);
+ TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream) > 0, 0); // prepare for incoming data
+ }
+ }
}
p_desc = tu_desc_next(p_desc);
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/common/tusb_fifo.c b/src/common/tusb_fifo.c
index 5f2dcabad..ecf002b09 100644
--- a/src/common/tusb_fifo.c
+++ b/src/common/tusb_fifo.c
@@ -916,8 +916,11 @@ bool tu_fifo_clear(tu_fifo_t *f)
Overwritable mode the fifo is set to
*/
/******************************************************************************/
-bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable)
-{
+bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) {
+ if (f->overwritable == overwritable) {
+ return true;
+ }
+
_ff_lock(f->mutex_wr);
_ff_lock(f->mutex_rd);
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index a0175d664..2ee2132bf 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -312,7 +312,7 @@
#define TUP_USBIP_FSDEV_STM32
#define TUP_DCD_ENDPOINT_MAX 8
-#elif TU_CHECK_MCU(OPT_MCU_STM32H7RS)
+#elif TU_CHECK_MCU(OPT_MCU_STM32H7RS, OPT_MCU_STM32N6)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
@@ -369,6 +369,10 @@
#define TUP_DCD_ENDPOINT_MAX 7 // only 5 TX FIFO for endpoint IN
#define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
+ #if CFG_TUSB_MCU == OPT_MCU_ESP32S3
+ #define TUP_MCU_MULTIPLE_CORE 1
+ #endif
+
// Disable slave if DMA is enabled
#define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
#define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
@@ -381,6 +385,8 @@
#define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
+ #define TUP_MCU_MULTIPLE_CORE 1
+
// Disable slave if DMA is enabled
#define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
#define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
@@ -410,6 +416,7 @@
#elif TU_CHECK_MCU(OPT_MCU_RP2040)
#define TUP_DCD_EDPT_ISO_ALLOC
#define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_MCU_MULTIPLE_CORE 1
#define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb")))
diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h
index e000a4bd3..ec7aad796 100644
--- a/src/common/tusb_types.h
+++ b/src/common/tusb_types.h
@@ -278,6 +278,8 @@ typedef enum {
XFER_RESULT_INVALID
} xfer_result_t;
+#define tusb_xfer_result_t xfer_result_t
+
// TODO remove
enum {
DESC_OFFSET_LEN = 0,
@@ -345,7 +347,6 @@ typedef struct TU_ATTR_PACKED {
uint8_t iManufacturer ; ///< Index of string descriptor describing manufacturer.
uint8_t iProduct ; ///< Index of string descriptor describing product.
uint8_t iSerialNumber ; ///< Index of string descriptor describing the device's serial number.
-
uint8_t bNumConfigurations ; ///< Number of possible configurations.
} tusb_desc_device_t;
@@ -586,6 +587,12 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_subtype(void const* desc) {
return ((uint8_t const*) desc)[DESC_OFFSET_SUBTYPE];
}
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_is_valid(void const* desc, uint8_t const* desc_end) {
+ const uint8_t* desc8 = (uint8_t const*) desc;
+ return (desc8 < desc_end) && (tu_desc_next(desc) <= desc_end);
+}
+
+
// find descriptor that match byte1 (type)
uint8_t const * tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1);
diff --git a/src/device/usbd.c b/src/device/usbd.c
index fb5cec49d..ba8dd669b 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -340,15 +340,16 @@ TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8
enum { RHPORT_INVALID = 0xFFu };
tu_static uint8_t _usbd_rhport = RHPORT_INVALID;
-// Event queue
-// usbd_int_set() is used as mutex in OS NONE config
+static OSAL_SPINLOCK_DEF(_usbd_spin, usbd_int_set);
+
+// Event queue: usbd_int_set() is used as mutex in OS NONE config
OSAL_QUEUE_DEF(usbd_int_set, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t);
-tu_static osal_queue_t _usbd_q;
+static osal_queue_t _usbd_q;
// Mutex for claiming endpoint
#if OSAL_MUTEX_REQUIRED
- tu_static osal_mutex_def_t _ubsd_mutexdef;
- tu_static osal_mutex_t _usbd_mutex;
+ static osal_mutex_def_t _ubsd_mutexdef;
+ static osal_mutex_t _usbd_mutex;
#else
#define _usbd_mutex NULL
#endif
@@ -464,17 +465,36 @@ bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
return true; // skip if already initialized
}
TU_ASSERT(rh_init);
-
- TU_LOG_USBD("USBD init on controller %u, speed = %s\r\n", rhport,
- rh_init->speed == TUSB_SPEED_HIGH ? "High" : "Full");
+#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
+ char const* speed_str = 0;
+ switch (rh_init->speed) {
+ case TUSB_SPEED_HIGH:
+ speed_str = "High";
+ break;
+ case TUSB_SPEED_FULL:
+ speed_str = "Full";
+ break;
+ case TUSB_SPEED_LOW:
+ speed_str = "Low";
+ break;
+ case TUSB_SPEED_AUTO:
+ speed_str = "Auto";
+ break;
+ default:
+ break;
+ }
+ TU_LOG_USBD("USBD init on controller %u, speed = %s\r\n", rhport, speed_str);
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(usbd_device_t));
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t));
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_t));
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_edpt_stream_t));
+#endif
tu_varclr(&_usbd_dev);
_usbd_queued_setup = 0;
+ osal_spin_init(&_usbd_spin);
+
#if OSAL_MUTEX_REQUIRED
// Init device mutex
_usbd_mutex = osal_mutex_create(&_ubsd_mutexdef);
@@ -561,8 +581,7 @@ static void usbd_reset(uint8_t rhport) {
}
bool tud_task_event_ready(void) {
- // Skip if stack is not initialized
- if (!tud_inited()) return false;
+ TU_VERIFY(tud_inited()); // Skip if stack is not initialized
return !osal_queue_empty(_usbd_q);
}
@@ -684,7 +703,9 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) {
case USBD_EVENT_FUNC_CALL:
TU_LOG_USBD("\r\n");
- if (event.func_call.func) event.func_call.func(event.func_call.param);
+ if (event.func_call.func) {
+ event.func_call.func(event.func_call.param);
+ }
break;
case DCD_EVENT_SOF:
@@ -701,7 +722,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) {
#if CFG_TUSB_OS != OPT_OS_NONE && CFG_TUSB_OS != OPT_OS_PICO
// return if there is no more events, for application to run other background
- if (osal_queue_empty(_usbd_q)) return;
+ if (osal_queue_empty(_usbd_q)) { return; }
#endif
}
}
@@ -1241,17 +1262,21 @@ TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr)
// USBD API For Class Driver
//--------------------------------------------------------------------+
-void usbd_int_set(bool enabled)
-{
- if (enabled)
- {
+void usbd_int_set(bool enabled) {
+ if (enabled) {
dcd_int_enable(_usbd_rhport);
- }else
- {
+ } else {
dcd_int_disable(_usbd_rhport);
}
}
+void usbd_spin_lock(bool in_isr) {
+ osal_spin_lock(&_usbd_spin, in_isr);
+}
+void usbd_spin_unlock(bool in_isr) {
+ osal_spin_unlock(&_usbd_spin, in_isr);
+}
+
// Parse consecutive endpoint descriptors (IN & OUT)
bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in)
{
diff --git a/src/device/usbd.h b/src/device/usbd.h
index de6007fb3..e5a848809 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -244,7 +244,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ
/* CDC Union */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
/* Endpoint Notification */\
- 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 16,\
+ 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\
/* CDC Data Interface */\
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
/* Endpoint Out */\
diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h
index 190d6fd7f..5c6f9dbee 100644
--- a/src/device/usbd_pvt.h
+++ b/src/device/usbd_pvt.h
@@ -68,6 +68,8 @@ usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) TU_ATTR
typedef bool (*usbd_control_xfer_cb_t)(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
void usbd_int_set(bool enabled);
+void usbd_spin_lock(bool in_isr);
+void usbd_spin_unlock(bool in_isr);
//--------------------------------------------------------------------+
// USBD Endpoint API
diff --git a/src/host/hcd.h b/src/host/hcd.h
index 56b6fdb5d..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
//--------------------------------------------------------------------+
@@ -163,8 +156,12 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr);
//--------------------------------------------------------------------+
// Open an endpoint
+// return true if successfully opened or endpoint is currently opened
bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * ep_desc);
+// Close an endpoint
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr);
+
// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked
bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen);
@@ -182,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);
@@ -235,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 c87f058cd..ce83977c5 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
@@ -52,21 +52,25 @@ enum {
// Weak stubs: invoked if no strong implementation is available
//--------------------------------------------------------------------+
TU_ATTR_WEAK bool hcd_deinit(uint8_t rhport) {
- (void) rhport;
- return false;
+ (void) rhport; return false;
}
TU_ATTR_WEAK bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
- (void) rhport;
- (void) cfg_id;
- (void) cfg_param;
+ (void) rhport; (void) cfg_id; (void) cfg_param;
return false;
}
+TU_ATTR_WEAK void tuh_enum_descriptor_device_cb(uint8_t daddr, const tusb_desc_device_t *desc_device) {
+ (void) daddr; (void) desc_device;
+}
+
+TU_ATTR_WEAK bool tuh_enum_descriptor_configuration_cb(uint8_t daddr, uint8_t cfg_index, const tusb_desc_configuration_t *desc_config) {
+ (void) daddr; (void) cfg_index; (void) desc_config;
+ return true;
+}
+
TU_ATTR_WEAK void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
- (void) rhport;
- (void) eventid;
- (void) in_isr;
+ (void) rhport; (void) eventid; (void) in_isr;
}
TU_ATTR_WEAK bool hcd_dcache_clean(const void* addr, uint32_t data_size) {
@@ -85,27 +89,24 @@ 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;
+ tuh_bus_info_t bus_info;
- 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;
+ // Device Descriptor
+ uint16_t bcdUSB;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize0;
+ uint16_t idVendor;
+ uint16_t idProduct;
+ uint16_t bcdDevice;
+ uint8_t iManufacturer;
+ uint8_t iProduct;
+ uint8_t iSerialNumber;
+ uint8_t bNumConfigurations;
// Device State
struct TU_ATTR_PACKED {
@@ -113,23 +114,9 @@ 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;
-
- // Configuration Descriptor
- // uint8_t interface_count; // bNumInterfaces alias
-
// Endpoint & Interface
uint8_t itf2drv[CFG_TUH_INTERFACE_MAX]; // map interface number to driver (0xff is invalid)
uint8_t ep2drv[CFG_TUH_ENDPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each
@@ -146,8 +133,63 @@ 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
+
+// Spinlock for interrupt handler
+static OSAL_SPINLOCK_DEF(_usbh_spin, usbh_int_set);
+
+// 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
@@ -230,11 +272,10 @@ static usbh_class_driver_t const usbh_class_drivers[] = {
};
enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) };
-enum { CONFIG_NUM = 1 }; // default to use configuration 1
// 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)
@@ -251,66 +292,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));
@@ -318,10 +314,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);
@@ -330,7 +356,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;
@@ -341,26 +367,49 @@ 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);
+bool tuh_descriptor_get_device_local(uint8_t daddr, tusb_desc_device_t* desc_device) {
+ usbh_device_t *dev = get_device(daddr);
+ TU_VERIFY(dev && desc_device);
+
+ desc_device->bLength = sizeof(tusb_desc_device_t);
+ desc_device->bDescriptorType = TUSB_DESC_DEVICE;
+ desc_device->bcdUSB = dev->bcdUSB;
+ desc_device->bDeviceClass = dev->bDeviceClass;
+ desc_device->bDeviceSubClass = dev->bDeviceSubClass;
+ desc_device->bDeviceProtocol = dev->bDeviceProtocol;
+ desc_device->bMaxPacketSize0 = dev->bMaxPacketSize0;
+ desc_device->idVendor = dev->idVendor;
+ desc_device->idProduct = dev->idProduct;
+ desc_device->bcdDevice = dev->bcdDevice;
+ desc_device->iManufacturer = dev->iManufacturer;
+ desc_device->iProduct = dev->iProduct;
+ desc_device->iSerialNumber = dev->iSerialNumber;
+ desc_device->bNumConfigurations = dev->bNumConfigurations;
+
+ return true;
+}
+
+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);
@@ -371,7 +420,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);
}
@@ -383,26 +431,45 @@ 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) {
if (tuh_rhport_is_active(rhport)) {
return true; // skip if already initialized
}
-
- TU_LOG_USBH("USBH init on controller %u, speed = %s\r\n", rhport,
- rh_init->speed == TUSB_SPEED_HIGH ? "High" : "Full");
+#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL
+ char const* speed_str = 0;
+ switch (rh_init->speed) {
+ case TUSB_SPEED_HIGH:
+ speed_str = "High";
+ break;
+ case TUSB_SPEED_FULL:
+ speed_str = "Full";
+ break;
+ case TUSB_SPEED_LOW:
+ speed_str = "Low";
+ break;
+ case TUSB_SPEED_AUTO:
+ speed_str = "Auto";
+ break;
+ default:
+ break;
+ }
+ TU_LOG_USBH("USBH init on controller %u, speed = %s\r\n", rhport, speed_str);
+#endif
// 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));
+ osal_spin_init(&_usbh_spin);
+
// Event queue
_usbh_q = osal_queue_create(&_usbh_qdef);
TU_ASSERT(_usbh_q != NULL);
@@ -419,9 +486,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]);
@@ -438,7 +507,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);
@@ -453,10 +522,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()) {
@@ -516,50 +585,39 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
// Loop until there is no more events in the queue
while (1) {
hcd_event_t event;
- if (!osal_queue_receive(_usbh_q, &event, timeout_ms)) return;
+ if (!osal_queue_receive(_usbh_q, &event, timeout_ms)) { return; }
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: {
@@ -567,7 +625,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
@@ -606,7 +665,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 {
@@ -647,47 +706,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()
@@ -703,20 +759,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;
@@ -725,13 +776,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);
@@ -743,6 +794,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:
@@ -752,15 +804,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);
@@ -769,28 +821,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
@@ -839,7 +892,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);
@@ -848,17 +900,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);
}
@@ -870,9 +922,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) {
@@ -882,18 +935,25 @@ 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);
}
}
+void usbh_spin_lock(bool in_isr) {
+ osal_spin_lock(&_usbh_spin, in_isr);
+}
+
+void usbh_spin_unlock(bool in_isr) {
+ osal_spin_unlock(&_usbh_spin, in_isr);
+}
+
void usbh_defer_func(osal_task_func_t func, void *param, bool in_isr) {
hcd_event_t event = { 0 };
event.event_id = USBH_EVENT_FUNC_CALL;
event.func_call.func = func;
event.func_call.param = param;
-
queue_event(&event, in_isr);
}
@@ -958,7 +1018,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 {
@@ -990,6 +1050,12 @@ bool tuh_edpt_open(uint8_t dev_addr, tusb_desc_endpoint_t const* desc_ep) {
return hcd_edpt_open(usbh_get_rhport(dev_addr), dev_addr, desc_ep);
}
+bool tuh_edpt_close(uint8_t daddr, uint8_t ep_addr) {
+ TU_VERIFY(0 != tu_edpt_number(ep_addr)); // cannot close EP0
+ tuh_edpt_abort_xfer(daddr, ep_addr); // abort any pending transfer
+ return hcd_edpt_close(usbh_get_rhport(daddr), daddr, ep_addr);
+}
+
bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr) {
usbh_device_t* dev = get_device(dev_addr);
TU_VERIFY(dev);
@@ -1004,31 +1070,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;
@@ -1044,8 +1109,9 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr)
// generic helper to get a descriptor
// if blocking, user_data is pointed to xfer_result
-static bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
- tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
+TU_ATTR_ALWAYS_INLINE static inline
+bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
+ tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
tusb_control_request_t const request = {
.bmRequestType_bit = {
.recipient = TUSB_REQ_RCPT_DEVICE,
@@ -1086,7 +1152,6 @@ bool tuh_descriptor_get_configuration(uint8_t daddr, uint8_t index, void* buffer
}
//------------- String Descriptor -------------//
-
bool tuh_descriptor_get_string(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return _get_descriptor(daddr, TUSB_DESC_STRING, index, language_id, buffer, len, complete_cb, user_data);
@@ -1097,24 +1162,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
@@ -1145,6 +1210,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);
@@ -1197,102 +1289,34 @@ bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt,
return tuh_control_xfer(&xfer);
}
-//--------------------------------------------------------------------+
-// Descriptor Sync
-//--------------------------------------------------------------------+
-
-#define _CONTROL_SYNC_API(_async_func, ...) \
- xfer_result_t result = XFER_RESULT_INVALID;\
- 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) {
- _CONTROL_SYNC_API(tuh_descriptor_get, daddr, type, index, buffer, len);
-}
-
-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) {
- _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) {
- _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) {
- _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) {
- _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) {
- _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) {
- _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);
@@ -1307,22 +1331,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;
@@ -1330,41 +1353,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,
@@ -1372,9 +1398,69 @@ enum {
ENUM_CONFIG_DRIVER
};
-static bool enum_request_set_addr(void);
-static bool _parse_configuration_descriptor (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
+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) {
@@ -1388,17 +1474,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;
@@ -1406,166 +1491,218 @@ 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();
+ 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->bMaxPacketSize0 = 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->bMaxPacketSize0),); // 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->bcdUSB = desc_device->bcdUSB;
+ dev->bDeviceClass = desc_device->bDeviceClass;
+ dev->bDeviceSubClass = desc_device->bDeviceSubClass;
+ dev->bDeviceProtocol = desc_device->bDeviceProtocol;
+ dev->bMaxPacketSize0 = desc_device->bMaxPacketSize0;
+ dev->idVendor = desc_device->idVendor;
+ dev->idProduct = desc_device->idProduct;
+ dev->bcdDevice = desc_device->bcdDevice;
+ 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;
-
- 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;
@@ -1574,8 +1711,8 @@ static void process_enumeration(tuh_xfer_t* xfer) {
case ENUM_GET_9BYTE_CONFIG_DESC: {
// Get 9-byte for total length
- uint8_t const config_idx = CONFIG_NUM - 1;
- TU_LOG_USBH("Get Configuration[0] Descriptor (9 bytes)\r\n");
+ uint8_t const config_idx = 0;
+ TU_LOG_USBH("Get Configuration[%u] Descriptor (9 bytes)\r\n", config_idx);
TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9,
process_enumeration, ENUM_GET_FULL_CONFIG_DESC),);
break;
@@ -1585,35 +1722,40 @@ static void process_enumeration(tuh_xfer_t* xfer) {
uint8_t const* desc_config = _usbh_epbuf.ctrl;
// Use offsetof to avoid pointer to the odd/misaligned address
- uint16_t const total_len = tu_le16toh(
- tu_unaligned_read16(desc_config + offsetof(tusb_desc_configuration_t, wTotalLength)));
+ uint16_t const total_len = tu_le16toh(tu_unaligned_read16(desc_config + offsetof(tusb_desc_configuration_t, wTotalLength)));
// TODO not enough buffer to hold configuration descriptor
TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE,);
// Get full configuration descriptor
- uint8_t const config_idx = CONFIG_NUM - 1;
- TU_LOG_USBH("Get Configuration[0] Descriptor\r\n");
+ uint8_t const config_idx = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ TU_LOG_USBH("Get Configuration[%u] Descriptor\r\n", config_idx);
TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, total_len,
process_enumeration, ENUM_SET_CONFIG),);
break;
}
- case ENUM_SET_CONFIG:
- // tuh_desc_configuration_cb(daddr, CONFIG_NUM-1, (const tusb_desc_configuration_t*) _usbh_epbuf.ctrl);
-
- TU_ASSERT(tuh_configuration_set(daddr, CONFIG_NUM, process_enumeration, ENUM_CONFIG_DRIVER),);
+ case ENUM_SET_CONFIG: {
+ uint8_t config_idx = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ if (tuh_enum_descriptor_configuration_cb(daddr, config_idx, (const tusb_desc_configuration_t*) _usbh_epbuf.ctrl)) {
+ TU_ASSERT(tuh_configuration_set(daddr, config_idx+1, process_enumeration, ENUM_CONFIG_DRIVER),);
+ } else {
+ config_idx++;
+ TU_ASSERT(config_idx < dev->bNumConfigurations,);
+ TU_LOG_USBH("Get Configuration[%u] Descriptor (9 bytes)\r\n", config_idx);
+ TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9,
+ process_enumeration, ENUM_GET_FULL_CONFIG_DESC),);
+ }
break;
+ }
case ENUM_CONFIG_DRIVER: {
TU_LOG_USBH("Device configured\r\n");
- TU_ASSERT(dev,);
-
dev->configured = 1;
// Parse configuration & set up drivers
// driver_open() must not make any usb transfer
- TU_ASSERT(_parse_configuration_descriptor(daddr, (tusb_desc_configuration_t*) _usbh_epbuf.ctrl),);
+ TU_ASSERT(enum_parse_configuration_desc(daddr, (tusb_desc_configuration_t*) _usbh_epbuf.ctrl),);
// Start the Set Configuration process for interfaces (itf = TUSB_INDEX_INVALID_8)
// Since driver can perform control transfer within its set_config, this is done asynchronously.
@@ -1624,65 +1766,12 @@ static void process_enumeration(tuh_xfer_t* xfer) {
}
default:
- // stop enumeration if unknown state
- enum_full_complete();
+ enum_full_complete(); // stop enumeration if unknown state
break;
}
}
-
-
-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;
@@ -1695,53 +1784,15 @@ 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(void) {
- tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl;
-
- // 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 _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg) {
+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);
uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + total_len;
@@ -1802,7 +1853,7 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur
// 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);
@@ -1821,9 +1872,9 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur
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);
}
}
@@ -1858,18 +1909,20 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) {
TU_LOG_USBH("HUB address = %u is mounted\r\n", dev_addr);
}else {
// Invoke callback if available
- if (tuh_mount_cb) tuh_mount_cb(dev_addr);
+ if (tuh_mount_cb) {
+ tuh_mount_cb(dev_addr);
+ }
}
}
}
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 52b4f478c..1e9bb26bc 100644
--- a/src/host/usbh.h
+++ b/src/host/usbh.h
@@ -33,17 +33,20 @@
#include "common/tusb_common.h"
+#if CFG_TUH_MAX3421
+#include "portable/analog/max3421/hcd_max3421.h"
+#endif
+
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
// Endpoint Bulk size depending on host mx speed
-#define TUH_EPSIZE_BULK_MPS (TUD_OPT_HIGH_SPEED ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS)
+#define TUH_EPSIZE_BULK_MPS (TUH_OPT_HIGH_SPEED ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS)
// 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
@@ -76,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,
@@ -100,10 +114,13 @@ typedef union {
//--------------------------------------------------------------------+
// Invoked when enumeration get device descriptor
-// TU_ATTR_WEAK void tuh_descriptor_device_cb(uint8_t daddr, const tusb_desc_device_t *desc_device);
+// Device is not ready to communicate yet, application can copy the descriptor if needed
+void tuh_enum_descriptor_device_cb(uint8_t daddr, const tusb_desc_device_t *desc_device);
// Invoked when enumeration get configuration descriptor
-// TU_ATTR_WEAK void tuh_desc_configuration_cb(uint8_t daddr, uint8_t cfg_index, const tusb_desc_configuration_t *desc_config);
+// For multi-configuration device return false to skip, true to proceed with this configuration (may not be implemented yet)
+// Device is not ready to communicate yet, application can copy the descriptor if needed
+bool tuh_enum_descriptor_configuration_cb(uint8_t daddr, uint8_t cfg_index, const tusb_desc_configuration_t *desc_config);
// Invoked when a device is mounted (configured)
TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr);
@@ -155,8 +172,7 @@ bool tuh_inited(void);
void tuh_task_ext(uint32_t timeout_ms, bool in_isr);
// Task function should be called in main/rtos loop
-TU_ATTR_ALWAYS_INLINE static inline
-void tuh_task(void) {
+TU_ATTR_ALWAYS_INLINE static inline void tuh_task(void) {
tuh_task_ext(UINT32_MAX, false);
}
@@ -171,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
@@ -186,6 +204,9 @@ bool tuh_rhport_reset_bus(uint8_t rhport, bool active);
// Get VID/PID of device
bool tuh_vid_pid_get(uint8_t daddr, uint16_t* vid, uint16_t* pid);
+// Get local (cached) device descriptor once device is enumerated
+bool tuh_descriptor_get_device_local(uint8_t daddr, tusb_desc_device_t* desc_device);
+
// Get speed of device
tusb_speed_t tuh_speed_get(uint8_t daddr);
@@ -197,23 +218,34 @@ bool tuh_mounted(uint8_t daddr);
bool tuh_connected(uint8_t daddr);
// Check if device is suspended
-TU_ATTR_ALWAYS_INLINE static inline
-bool tuh_suspended(uint8_t daddr) {
+TU_ATTR_ALWAYS_INLINE static inline bool tuh_suspended(uint8_t daddr) {
// TODO implement suspend & resume on host
(void) daddr;
return false;
}
// Check if device is ready to communicate with
-TU_ATTR_ALWAYS_INLINE static inline
-bool tuh_ready(uint8_t daddr) {
+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
+// Each Function will make a USB transfer request to device. If
+// - complete_cb != NULL, the function will return immediately and invoke the callback when request is complete.
+// - complete_cb == NULL, the function will block until request is complete.
+// In this case, user_data should be tusb_xfer_result_t* to hold the transfer result.
//--------------------------------------------------------------------+
+// Helper to make Sync API from async one
+#define TU_API_SYNC(_async_api, ...) \
+ xfer_result_t result = XFER_RESULT_INVALID;\
+ TU_VERIFY(_async_api(__VA_ARGS__, NULL, (uintptr_t) &result), XFER_RESULT_TIMEOUT); \
+ return result
+
// Submit a control transfer
// - async: complete callback invoked when finished.
// - sync : blocking if complete callback is NULL.
@@ -227,10 +259,17 @@ bool tuh_edpt_xfer(tuh_xfer_t* xfer);
// Open a non-control endpoint
bool tuh_edpt_open(uint8_t daddr, tusb_desc_endpoint_t const * desc_ep);
+// Close a non-control endpoint, it will abort any pending transfer
+bool tuh_edpt_close(uint8_t daddr, uint8_t ep_addr);
+
// Abort a queued transfer. Note: it can only abort transfer that has not been started
// 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
@@ -298,45 +337,54 @@ bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void*
//--------------------------------------------------------------------+
// Descriptors Synchronous (blocking)
+// Sync API which is blocking until transfer is complete.
+// return transfer result
//--------------------------------------------------------------------+
-// Sync (blocking) version of tuh_descriptor_get()
-// return transfer result
-uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len);
+// Sync version of tuh_descriptor_get()
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len) {
+ TU_API_SYNC(tuh_descriptor_get, daddr, type, index, buffer, len);
+}
-// Sync (blocking) version of tuh_descriptor_get_device()
-// return transfer result
-uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len);
+// Sync version of tuh_descriptor_get_device()
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len) {
+ TU_API_SYNC(tuh_descriptor_get_device, daddr, buffer, len);
+}
-// Sync (blocking) version of tuh_descriptor_get_configuration()
-// return transfer result
-uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len);
+// Sync version of tuh_descriptor_get_configuration()
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len) {
+ TU_API_SYNC(tuh_descriptor_get_configuration, daddr, index, buffer, len);
+}
-// Sync (blocking) version of tuh_descriptor_get_hid_report()
-// return transfer result
-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);
+// Sync version of tuh_descriptor_get_hid_report()
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_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) {
+ TU_API_SYNC(tuh_descriptor_get_hid_report, daddr, itf_num, desc_type, index, buffer, len);
+}
-// Sync (blocking) version of tuh_descriptor_get_string()
-// return transfer result
-uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len);
+// Sync version of tuh_descriptor_get_string()
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len) {
+ TU_API_SYNC(tuh_descriptor_get_string, daddr, index, language_id, buffer, len);
+}
-// Sync (blocking) version of tuh_descriptor_get_string_langid()
-TU_ATTR_ALWAYS_INLINE static inline
-uint8_t tuh_descriptor_get_string_langid_sync(uint8_t daddr, void* buffer, uint16_t len) {
+// Sync version of tuh_descriptor_get_string_langid()
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_string_langid_sync(uint8_t daddr, void* buffer, uint16_t len) {
return tuh_descriptor_get_string_sync(daddr, 0, 0, buffer, len);
}
-// Sync (blocking) version of tuh_descriptor_get_manufacturer_string()
-// return transfer result
-uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
+// Sync version of tuh_descriptor_get_manufacturer_string()
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
+ TU_API_SYNC(tuh_descriptor_get_manufacturer_string, daddr, language_id, buffer, len);
+}
-// Sync (blocking) version of tuh_descriptor_get_product_string()
-// return transfer result
-uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
+// Sync version of tuh_descriptor_get_product_string()
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
+ TU_API_SYNC(tuh_descriptor_get_product_string, daddr, language_id, buffer, len);
+}
-// Sync (blocking) version of tuh_descriptor_get_serial_string()
-// return transfer result
-uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
+// Sync version of tuh_descriptor_get_serial_string()
+TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
+ TU_API_SYNC(tuh_descriptor_get_serial_string, daddr, language_id, buffer, len);
+}
#ifdef __cplusplus
}
diff --git a/src/host/usbh_pvt.h b/src/host/usbh_pvt.h
index bfa1fb2ba..cb092e5f3 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);
@@ -71,6 +71,9 @@ void usbh_int_set(bool enabled);
void usbh_defer_func(osal_task_func_t func, void *param, bool in_isr);
+void usbh_spin_lock(bool in_isr);
+void usbh_spin_unlock(bool in_isr);
+
//--------------------------------------------------------------------+
// USBH Endpoint API
//--------------------------------------------------------------------+
diff --git a/src/osal/osal.h b/src/osal/osal.h
index 38d45da44..a33280425 100644
--- a/src/osal/osal.h
+++ b/src/osal/osal.h
@@ -75,6 +75,10 @@ typedef void (*osal_task_func_t)( void * );
// OSAL Porting API
// Should be implemented as static inline function in osal_port.h header
/*
+ void osal_spin_init(osal_spinlock_t *ctx);
+ void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr)
+ void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr);
+
osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
bool osal_semaphore_delete(osal_semaphore_t semd_hdl);
bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
diff --git a/src/osal/osal_freertos.h b/src/osal/osal_freertos.h
index a3a0f3a3f..bde5ec010 100644
--- a/src/osal/osal_freertos.h
+++ b/src/osal/osal_freertos.h
@@ -42,20 +42,20 @@ extern "C" {
//--------------------------------------------------------------------+
#if configSUPPORT_STATIC_ALLOCATION
- typedef StaticSemaphore_t osal_semaphore_def_t;
- typedef StaticSemaphore_t osal_mutex_def_t;
+typedef StaticSemaphore_t osal_semaphore_def_t;
+typedef StaticSemaphore_t osal_mutex_def_t;
#else
- // not used therefore defined to smallest possible type to save space
- typedef uint8_t osal_semaphore_def_t;
- typedef uint8_t osal_mutex_def_t;
+
+// not used therefore defined to the smallest possible type to save space
+typedef uint8_t osal_semaphore_def_t;
+typedef uint8_t osal_mutex_def_t;
#endif
typedef SemaphoreHandle_t osal_semaphore_t;
typedef SemaphoreHandle_t osal_mutex_t;
typedef QueueHandle_t osal_queue_t;
-typedef struct
-{
+typedef struct {
uint16_t depth;
uint16_t item_sz;
void* buf;
@@ -83,16 +83,14 @@ typedef struct
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
-
TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) {
- if ( msec == OSAL_TIMEOUT_WAIT_FOREVER ) return portMAX_DELAY;
- if ( msec == 0 ) return 0;
+ if (msec == OSAL_TIMEOUT_WAIT_FOREVER) { return portMAX_DELAY; }
+ if (msec == 0) { return 0; }
uint32_t ticks = pdMS_TO_TICKS(msec);
- // configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms
- // we still need to delay at least 1 tick
- if ( ticks == 0 ) ticks = 1;
+ // If configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms, we still need to delay at least 1 tick
+ if (ticks == 0) { ticks = 1; }
return ticks;
}
@@ -101,10 +99,71 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
vTaskDelay(pdMS_TO_TICKS(msec));
}
+//--------------------------------------------------------------------+
+// Spinlock API
+//--------------------------------------------------------------------+
+#define OSAL_SPINLOCK_DEF(_name, _int_set) \
+ osal_spinlock_t _name
+
+#if TUSB_MCU_VENDOR_ESPRESSIF
+// Espressif critical take spinlock as argument and does not use in_isr
+typedef portMUX_TYPE osal_spinlock_t;
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
+ spinlock_initialize(ctx);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
+ if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
+ return; // single core MCU does not need to lock in ISR
+ }
+ portENTER_CRITICAL(ctx);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
+ if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
+ return; // single core MCU does not need to lock in ISR
+ }
+ portEXIT_CRITICAL(ctx);
+}
+
+#else
+
+typedef UBaseType_t osal_spinlock_t;
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
+ (void) ctx;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
+ if (in_isr) {
+ if (!TUP_MCU_MULTIPLE_CORE) {
+ (void) ctx;
+ return; // single core MCU does not need to lock in ISR
+ }
+ *ctx = taskENTER_CRITICAL_FROM_ISR();
+ } else {
+ taskENTER_CRITICAL();
+ }
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
+ if (in_isr) {
+ if (!TUP_MCU_MULTIPLE_CORE) {
+ (void) ctx;
+ return; // single core MCU does not need to lock in ISR
+ }
+ taskEXIT_CRITICAL_FROM_ISR(*ctx);
+ } else {
+ taskEXIT_CRITICAL();
+ }
+}
+
+#endif
+
//--------------------------------------------------------------------+
// Semaphore API
//--------------------------------------------------------------------+
-
TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t *semdef) {
#if configSUPPORT_STATIC_ALLOCATION
return xSemaphoreCreateBinaryStatic(semdef);
@@ -120,19 +179,12 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
- if ( !in_isr ) {
+ if (!in_isr) {
return xSemaphoreGive(sem_hdl) != 0;
} else {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
BaseType_t res = xSemaphoreGiveFromISR(sem_hdl, &xHigherPriorityTaskWoken);
-
-#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
- // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7
- if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR();
-#else
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
-#endif
-
return res != 0;
}
}
@@ -148,7 +200,6 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t c
//--------------------------------------------------------------------+
// MUTEX API (priority inheritance)
//--------------------------------------------------------------------+
-
TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) {
#if configSUPPORT_STATIC_ALLOCATION
return xSemaphoreCreateMutexStatic(mdef);
@@ -174,7 +225,6 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
//--------------------------------------------------------------------+
// QUEUE API
//--------------------------------------------------------------------+
-
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
osal_queue_t q;
@@ -201,19 +251,12 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, v
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr) {
- if ( !in_isr ) {
+ if (!in_isr) {
return xQueueSendToBack(qhdl, data, OSAL_TIMEOUT_WAIT_FOREVER) != 0;
} else {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
BaseType_t res = xQueueSendToBackFromISR(qhdl, data, &xHigherPriorityTaskWoken);
-
-#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3
- // not needed after https://github.com/espressif/esp-idf/commit/c5fd79547ac9b7bae06fa660e9f814d18d3390b7 (IDF v5)
- if ( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR();
-#else
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
-#endif
-
return res != 0;
}
}
diff --git a/src/osal/osal_mynewt.h b/src/osal/osal_mynewt.h
index 16def0d2a..ee95e684f 100644
--- a/src/osal/osal_mynewt.h
+++ b/src/osal/osal_mynewt.h
@@ -40,6 +40,32 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
os_time_delay( os_time_ms_to_ticks32(msec) );
}
+//--------------------------------------------------------------------+
+// Spinlock API
+//--------------------------------------------------------------------+
+typedef os_sr_t osal_spinlock_t;
+
+#define OSAL_SPINLOCK_DEF(_name, _int_set) \
+ osal_spinlock_t _name
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
+ (void) ctx;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
+ if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
+ return; // single core MCU does not need to lock in ISR
+ }
+ OS_ENTER_CRITICAL(*ctx);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
+ if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
+ return; // single core MCU does not need to lock in ISR
+ }
+ OS_ENTER_CRITICAL(*ctx);
+}
+
//--------------------------------------------------------------------+
// Semaphore API
//--------------------------------------------------------------------+
diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h
index 40e9bb83a..a8eb1042b 100644
--- a/src/osal/osal_none.h
+++ b/src/osal/osal_none.h
@@ -40,6 +40,33 @@ extern "C" {
TU_ATTR_WEAK void osal_task_delay(uint32_t msec);
#endif
+//--------------------------------------------------------------------+
+// Spinlock API
+//--------------------------------------------------------------------+
+typedef struct {
+ void (* interrupt_set)(bool);
+} osal_spinlock_t;
+
+// For SMP, spinlock must be locked by hardware, cannot just use interrupt
+#define OSAL_SPINLOCK_DEF(_name, _int_set) \
+ osal_spinlock_t _name = { .interrupt_set = _int_set }
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
+ (void) ctx;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
+ if (!in_isr) {
+ ctx->interrupt_set(false);
+ }
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
+ if (!in_isr) {
+ ctx->interrupt_set(true);
+ }
+}
+
//--------------------------------------------------------------------+
// Binary Semaphore API
//--------------------------------------------------------------------+
diff --git a/src/osal/osal_pico.h b/src/osal/osal_pico.h
index 315de0950..ace5907d7 100644
--- a/src/osal/osal_pico.h
+++ b/src/osal/osal_pico.h
@@ -43,6 +43,27 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
sleep_ms(msec);
}
+//--------------------------------------------------------------------+
+// Spinlock API
+//--------------------------------------------------------------------+
+typedef critical_section_t osal_spinlock_t; // pico implement critical section with spinlock
+#define OSAL_SPINLOCK_DEF(_name, _int_set) \
+ osal_spinlock_t _name
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
+ critical_section_init(ctx);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
+ (void) in_isr;
+ critical_section_enter_blocking(ctx);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
+ (void) in_isr;
+ critical_section_exit(ctx);
+}
+
//--------------------------------------------------------------------+
// Binary Semaphore API
//--------------------------------------------------------------------+
diff --git a/src/osal/osal_rtthread.h b/src/osal/osal_rtthread.h
index c27814835..a778f5425 100644
--- a/src/osal/osal_rtthread.h
+++ b/src/osal/osal_rtthread.h
@@ -42,6 +42,32 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
rt_thread_mdelay(msec);
}
+//--------------------------------------------------------------------+
+// Spinlock API
+//--------------------------------------------------------------------+
+typedef struct rt_spinlock osal_spinlock_t;
+
+#define OSAL_SPINLOCK_DEF(_name, _int_set) \
+ osal_spinlock_t _name
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
+ rt_spin_lock_init(ctx);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
+ if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
+ return; // single core MCU does not need to lock in ISR
+ }
+ rt_spin_lock(ctx);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
+ if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
+ return; // single core MCU does not need to lock in ISR
+ }
+ rt_spin_unlock(ctx);
+}
+
//--------------------------------------------------------------------+
// Semaphore API
//--------------------------------------------------------------------+
diff --git a/src/osal/osal_rtx4.h b/src/osal/osal_rtx4.h
index 35909e4d6..35860ddd5 100644
--- a/src/osal/osal_rtx4.h
+++ b/src/osal/osal_rtx4.h
@@ -56,6 +56,25 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t msec2wait(uint32_t msec) {
}
}
+//--------------------------------------------------------------------+
+// Spinlock API, stub not implemented
+//--------------------------------------------------------------------+
+typedef uint8_t osal_spinlock_t;
+#define OSAL_SPINLOCK_DEF(_name, _int_set) \
+ osal_spinlock_t _name
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
+ (void) ctx;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
+ (void) ctx; (void) in_isr;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
+ (void) ctx; (void) in_isr;
+}
+
//--------------------------------------------------------------------+
// Semaphore API
//--------------------------------------------------------------------+
diff --git a/src/osal/osal_zephyr.h b/src/osal/osal_zephyr.h
index 8ecb13c6d..91f225f79 100644
--- a/src/osal/osal_zephyr.h
+++ b/src/osal/osal_zephyr.h
@@ -35,6 +35,35 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
k_msleep(msec);
}
+//--------------------------------------------------------------------+
+// Spinlock API
+//--------------------------------------------------------------------+
+typedef struct {
+ struct k_spinlock lock;
+ k_spinlock_key_t key;
+} osal_spinlock_t;
+
+#define OSAL_SPINLOCK_DEF(_name, _int_set) \
+ osal_spinlock_t _name
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
+ (void) ctx;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
+ if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
+ return; // single core MCU does not need to lock in ISR
+ }
+ ctx->key = k_spin_lock(&ctx->lock);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
+ if (!TUP_MCU_MULTIPLE_CORE && in_isr) {
+ return; // single core MCU does not need to lock in ISR
+ }
+ k_spin_unlock(&ctx->lock, ctx->key);
+}
+
//--------------------------------------------------------------------+
// Binary Semaphore API
//--------------------------------------------------------------------+
diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c
index c5e924266..971dbd62e 100644
--- a/src/portable/analog/max3421/hcd_max3421.c
+++ b/src/portable/analog/max3421/hcd_max3421.c
@@ -28,9 +28,9 @@
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
-#include
#include "host/hcd.h"
#include "host/usbh.h"
+#include "host/usbh_pvt.h"
//--------------------------------------------------------------------+
//
@@ -233,7 +233,7 @@ typedef struct {
uint8_t hxfr;
}sndfifo_owner;
- atomic_flag busy; // busy transferring
+ bool busy_lock; // busy transferring
#if OSAL_MUTEX_REQUIRED
OSAL_MUTEX_DEF(spi_mutexdef);
@@ -252,28 +252,6 @@ static tuh_configure_max3421_t _tuh_cfg = {
.pinctl = 0, // default: negative edge interrupt
};
-//--------------------------------------------------------------------+
-// API: SPI transfer with MAX3421E
-// - spi_cs_api(), spi_xfer_api(), int_api(): must be implemented by application
-// - reg_read(), reg_write(): is implemented by this driver, can be used by application
-//--------------------------------------------------------------------+
-
-// API to control MAX3421 SPI CS
-extern void tuh_max3421_spi_cs_api(uint8_t rhport, bool active);
-
-// API to transfer data with MAX3421 SPI
-// Either tx_buf or rx_buf can be NULL, which means transfer is write or read only
-extern bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const* tx_buf, uint8_t* rx_buf, size_t xfer_bytes);
-
-// API to enable/disable MAX3421 INTR pin interrupt
-extern void tuh_max3421_int_api(uint8_t rhport, bool enabled);
-
-// API to read MAX3421's register. Implemented by TinyUSB
-uint8_t tuh_max3421_reg_read(uint8_t rhport, uint8_t reg, bool in_isr);
-
-// API to write MAX3421's register. Implemented by TinyUSB
-bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr);
-
//--------------------------------------------------------------------+
// SPI Commands and Helper
//--------------------------------------------------------------------+
@@ -349,7 +327,9 @@ TU_ATTR_ALWAYS_INLINE static inline void mode_write(uint8_t rhport, uint8_t data
}
TU_ATTR_ALWAYS_INLINE static inline void peraddr_write(uint8_t rhport, uint8_t data, bool in_isr) {
- if ( _hcd_data.peraddr == data ) return; // no need to change address
+ if (_hcd_data.peraddr == data) {
+ return; // no need to change address
+ }
_hcd_data.peraddr = data;
reg_write(rhport, PERADDR_ADDR, data, in_isr);
@@ -395,7 +375,7 @@ TU_ATTR_ALWAYS_INLINE static inline void hwfifo_setup(uint8_t rhport, const uint
static void hwfifo_receive(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_isr) {
uint8_t hirq;
- uint8_t const reg = RCVVFIFO_ADDR;
+ const uint8_t reg = RCVVFIFO_ADDR;
max3421_spi_lock(rhport, in_isr);
@@ -411,7 +391,7 @@ static void hwfifo_receive(uint8_t rhport, uint8_t * buffer, uint16_t len, bool
//--------------------------------------------------------------------+
static max3421_ep_t* find_ep_not_addr0(uint8_t daddr, uint8_t ep_num, uint8_t ep_dir) {
- uint8_t const is_out = 1-ep_dir;
+ const uint8_t is_out = 1-ep_dir;
for(size_t i=1; idaddr = daddr;
@@ -645,6 +628,21 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
return true;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport;
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr);
+ max3421_ep_t * ep = find_ep_not_addr0(daddr, ep_num, ep_dir);
+
+ if (!ep) {
+ return false; // not opened
+ }
+
+ tu_memclr(ep, sizeof(max3421_ep_t));
+
+ return true;
+}
+
/* The microcontroller repeatedly writes the SNDFIFO register R2 to load the FIFO with up to 64 data bytes.
* Then the microcontroller writes the SNDBC register, which this does three things:
* 1. Tells the MAX3421E SIE (Serial Interface Engine) how many bytes in the FIFO to send.
@@ -731,8 +729,8 @@ static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool
// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked
bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) {
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- uint8_t const ep_dir = (uint8_t) tu_edpt_dir(ep_addr);
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const uint8_t ep_dir = (uint8_t) tu_edpt_dir(ep_addr);
max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir);
TU_VERIFY(ep);
@@ -748,8 +746,17 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf
ep->xferred_len = 0;
ep->state = EP_STATE_ATTEMPT_1;
+ bool has_xfer = false;
+
+ usbh_spin_lock(false);
+ if (!_hcd_data.busy_lock) {
+ _hcd_data.busy_lock = true;
+ has_xfer = true;
+ }
+ usbh_spin_unlock(false);
+
// carry out transfer if not busy
- if (!atomic_flag_test_and_set(&_hcd_data.busy)) {
+ if (has_xfer) {
xact_generic(rhport, ep, true, false);
}
@@ -785,8 +792,17 @@ bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]
ep->xferred_len = 0;
ep->state = EP_STATE_ATTEMPT_1;
+ bool has_xfer = false;
+
+ usbh_spin_lock(false);
+ if (!_hcd_data.busy_lock) {
+ _hcd_data.busy_lock = true;
+ has_xfer = true;
+ }
+ usbh_spin_unlock(false);
+
// carry out transfer if not busy
- if (!atomic_flag_test_and_set(&_hcd_data.busy)) {
+ if (has_xfer) {
xact_setup(rhport, ep, false);
}
@@ -852,8 +868,8 @@ static void handle_connect_irq(uint8_t rhport, bool in_isr) {
}
static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t hrsl, bool in_isr) {
- uint8_t const ep_dir = 1-ep->hxfr_bm.is_out;
- uint8_t const ep_addr = tu_edpt_addr(ep->hxfr_bm.ep_num, ep_dir);
+ const uint8_t ep_dir = 1 - ep->hxfr_bm.is_out;
+ const uint8_t ep_addr = tu_edpt_addr(ep->hxfr_bm.ep_num, ep_dir);
// save data toggle
if (ep_dir) {
@@ -871,7 +887,9 @@ static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t re
xact_generic(rhport, next_ep, true, in_isr);
}else {
// no more pending
- atomic_flag_clear(&_hcd_data.busy);
+ usbh_spin_lock(in_isr);
+ _hcd_data.busy_lock = false;
+ usbh_spin_unlock(in_isr);
}
}
@@ -910,7 +928,9 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
xact_generic(rhport, next_ep, true, in_isr);
} else {
// no more pending in this frame -> clear busy
- atomic_flag_clear(&_hcd_data.busy);
+ usbh_spin_lock(in_isr);
+ _hcd_data.busy_lock = false;
+ usbh_spin_unlock(in_isr);
}
return;
@@ -1001,8 +1021,8 @@ void print_hirq(uint8_t hirq) {
// Interrupt handler
void hcd_int_handler(uint8_t rhport, bool in_isr) {
uint8_t hirq = reg_read(rhport, HIRQ_ADDR, in_isr) & _hcd_data.hien;
- if (!hirq) return;
-// print_hirq(hirq);
+ if (!hirq) { return; }
+ // print_hirq(hirq);
if (hirq & HIRQ_FRAME_IRQ) {
_hcd_data.frame_count++;
@@ -1021,8 +1041,19 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
}
// start usb transfer if not busy
- if (ep_retry != NULL && !atomic_flag_test_and_set(&_hcd_data.busy)) {
- xact_generic(rhport, ep_retry, true, in_isr);
+ if (ep_retry != NULL) {
+ bool has_xfer = false;
+
+ usbh_spin_lock(in_isr);
+ if (!_hcd_data.busy_lock) {
+ _hcd_data.busy_lock = true;
+ has_xfer = true;
+ }
+ usbh_spin_unlock(in_isr);
+
+ if (has_xfer) {
+ xact_generic(rhport, ep_retry, true, in_isr);
+ }
}
}
diff --git a/src/portable/analog/max3421/hcd_max3421.h b/src/portable/analog/max3421/hcd_max3421.h
new file mode 100644
index 000000000..4631fa21a
--- /dev/null
+++ b/src/portable/analog/max3421/hcd_max3421.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+#ifndef TUSB_HCD_MAX3421_H
+#define TUSB_HCD_MAX3421_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// SPI transfer API with MAX3421E are implemented by application
+// - spi_cs_api(), spi_xfer_api(), int_api()
+//--------------------------------------------------------------------+
+
+// API to control MAX3421 SPI CS
+extern void tuh_max3421_spi_cs_api(uint8_t rhport, bool active);
+
+// API to transfer data with MAX3421 SPI
+// Either tx_buf or rx_buf can be NULL, which means transfer is write or read only
+extern bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const* tx_buf, uint8_t* rx_buf, size_t xfer_bytes);
+
+// API to enable/disable MAX3421 INTR pin interrupt
+extern void tuh_max3421_int_api(uint8_t rhport, bool enabled);
+
+//--------------------------------------------------------------------+
+// API for read/write MAX3421 registers
+// are implemented by this driver, can be used by application
+//--------------------------------------------------------------------+
+
+// API to read MAX3421's register. Implemented by TinyUSB
+uint8_t tuh_max3421_reg_read(uint8_t rhport, uint8_t reg, bool in_isr);
+
+// API to write MAX3421's register. Implemented by TinyUSB
+bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
index a716dc24c..244f5a2d4 100644
--- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c
+++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
@@ -239,7 +239,11 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
usbmode |= USBMODE_CM_DEVICE;
dcd_reg->USBMODE = usbmode;
+#ifdef CFG_TUD_CI_HS_VBUS_CHARGE
+ dcd_reg->OTGSC = OTGSC_VBUS_CHARGE | OTGSC_OTG_TERMINATION;
+#else
dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION;
+#endif
#if !TUD_OPT_HIGH_SPEED
dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED;
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 01bbf62bf..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"
@@ -62,8 +63,7 @@
#define QHD_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX + CFG_TUH_HUB)
#define QTD_MAX QHD_MAX
-typedef struct
-{
+typedef struct {
ehci_link_t period_framelist[FRAMELIST_SIZE];
// TODO only implement 1 ms & 2 ms & 4 ms, 8 ms (framelist)
@@ -139,6 +139,12 @@ static ehci_qhd_t* qhd_get_from_addr (uint8_t dev_addr, uint8_t ep_addr);
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd);
static void qhd_remove_qtd(ehci_qhd_t *qhd);
+TU_ATTR_ALWAYS_INLINE static inline bool qhd_is_periodic(ehci_qhd_t const *qhd) {
+ return qhd->int_smask != 0;
+}
+TU_ATTR_ALWAYS_INLINE static inline uint8_t qhd_ep_addr(ehci_qhd_t const *qhd) {
+ return tu_edpt_addr(qhd->ep_number, qhd->pid);
+}
TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t* qtd_control(uint8_t dev_addr);
TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t* qtd_find_free (void);
@@ -146,9 +152,10 @@ static void qtd_init (ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes)
TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_get_period_head(uint8_t rhport, uint32_t interval_ms);
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* list_get_async_head(uint8_t rhport);
-TU_ATTR_ALWAYS_INLINE static inline void list_insert (ehci_link_t *current, ehci_link_t *new, uint8_t new_type);
TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_next (ehci_link_t const *p_link);
-static void list_remove_qhd_by_daddr(ehci_link_t* list_head, uint8_t dev_addr);
+TU_ATTR_ALWAYS_INLINE static inline void list_insert (ehci_link_t *current, ehci_link_t *entry, uint8_t type);
+TU_ATTR_ALWAYS_INLINE static inline void list_remove(ehci_link_t* head, ehci_link_t* prev, ehci_qhd_t* qhd);
+static void list_remove_qhd_by_addr(ehci_link_t *list_head, uint8_t dev_addr, uint8_t ep_addr);
static void ehci_disable_schedule(ehci_registers_t* regs, bool is_period) {
// maybe have a timeout for status
@@ -175,15 +182,12 @@ static void ehci_enable_schedule(ehci_registers_t* regs, bool is_period) {
//--------------------------------------------------------------------+
// HCD API
//--------------------------------------------------------------------+
-
-uint32_t hcd_frame_number(uint8_t rhport)
-{
+uint32_t hcd_frame_number(uint8_t rhport) {
(void) rhport;
return (ehci_data.uframe_number + ehci_data.regs->frame_index) >> 3;
}
-void hcd_port_reset(uint8_t rhport)
-{
+void hcd_port_reset(uint8_t rhport) {
(void) rhport;
ehci_registers_t* regs = ehci_data.regs;
@@ -204,8 +208,7 @@ void hcd_port_reset(uint8_t rhport)
regs->portsc = portsc;
}
-void hcd_port_reset_end(uint8_t rhport)
-{
+void hcd_port_reset_end(uint8_t rhport) {
(void) rhport;
ehci_registers_t* regs = ehci_data.regs;
@@ -221,32 +224,29 @@ void hcd_port_reset_end(uint8_t rhport)
regs->portsc = portsc;
}
-bool hcd_port_connect_status(uint8_t rhport)
-{
+bool hcd_port_connect_status(uint8_t rhport) {
(void) rhport;
return ehci_data.regs->portsc_bm.current_connect_status;
}
-tusb_speed_t hcd_port_speed_get(uint8_t rhport)
-{
+tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
(void) rhport;
return (tusb_speed_t) ehci_data.regs->portsc_bm.nxp_port_speed; // NXP specific port speed
}
// Close all opened endpoint belong to this device
-void hcd_device_close(uint8_t rhport, uint8_t daddr)
-{
+void hcd_device_close(uint8_t rhport, uint8_t daddr) {
// skip dev0
if (daddr == 0) {
return;
}
- // Remove from async list
- list_remove_qhd_by_daddr((ehci_link_t *) list_get_async_head(rhport), daddr);
+ // Remove from async list all endpoints of this device
+ list_remove_qhd_by_addr((ehci_link_t *) list_get_async_head(rhport), daddr, TUSB_INDEX_INVALID_8);
- // Remove from all interval period list
- for(uint8_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++) {
- list_remove_qhd_by_daddr((ehci_link_t *) &ehci_data.period_head_arr[i], daddr);
+ // Remove from all interval period list of this device
+ for (uint8_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++) {
+ list_remove_qhd_by_addr((ehci_link_t *) &ehci_data.period_head_arr[i], daddr, TUSB_INDEX_INVALID_8);
}
// Async doorbell (EHCI 4.8.2 for operational details)
@@ -358,12 +358,10 @@ bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
}
#if 0
-static void ehci_stop(uint8_t rhport)
-{
+static void ehci_stop(uint8_t rhport) {
(void) rhport;
ehci_registers_t* regs = ehci_data.regs;
-
regs->command_bm.run_stop = 0;
// USB Spec: controller has to stop within 16 uframe = 2 frames
@@ -375,41 +373,46 @@ static void ehci_stop(uint8_t rhport)
// Endpoint API
//--------------------------------------------------------------------+
-bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
-{
- (void) rhport;
-
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) {
// TODO not support ISO yet
TU_ASSERT (ep_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
//------------- Prepare Queue Head -------------//
- ehci_qhd_t *p_qhd = (ep_desc->bEndpointAddress == 0) ? qhd_control(dev_addr) : qhd_find_free();
+ ehci_qhd_t *p_qhd;
+ if (ep_desc->bEndpointAddress == 0) {
+ p_qhd = qhd_control(dev_addr);
+ } else {
+ if (NULL != qhd_get_from_addr(dev_addr, ep_desc->bEndpointAddress)) {
+ return true; // already opened
+ }
+ p_qhd = qhd_find_free();
+ }
TU_ASSERT(p_qhd);
-
qhd_init(p_qhd, dev_addr, ep_desc);
- // control of dev0 is always present as async head
- if ( dev_addr == 0 ) return true;
+ // control of dev0 always exists as async head
+ if (dev_addr == 0) {
+ return true;
+ }
// Insert to list
ehci_link_t * list_head = NULL;
-
- switch (ep_desc->bmAttributes.xfer)
- {
+ switch (ep_desc->bmAttributes.xfer) {
case TUSB_XFER_CONTROL:
case TUSB_XFER_BULK:
- list_head = (ehci_link_t*) list_get_async_head(rhport);
- break;
+ list_head = (ehci_link_t *) list_get_async_head(rhport);
+ break;
case TUSB_XFER_INTERRUPT:
list_head = list_get_period_head(rhport, p_qhd->interval_ms);
- break;
+ break;
case TUSB_XFER_ISOCHRONOUS:
// TODO iso is not supported
- break;
+ break;
- default: break;
+ default:
+ break;
}
TU_ASSERT(list_head);
@@ -421,8 +424,23 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
return true;
}
-bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
-{
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ ehci_qhd_t* qhd = qhd_get_from_addr(daddr, ep_addr);
+ TU_VERIFY(qhd != NULL);
+
+ ehci_link_t * list_head;
+ if (qhd_is_periodic(qhd)) {
+ // interrupt endpoint
+ list_head = list_get_period_head(rhport, qhd->interval_ms);;
+ } else {
+ list_head = (ehci_link_t *) list_get_async_head(rhport);
+ }
+
+ list_remove_qhd_by_addr(list_head, daddr, ep_addr);
+ return true;
+}
+
+bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) {
(void) rhport;
ehci_qhd_t* qhd = &ehci_data.control[dev_addr].qhd;
@@ -444,14 +462,14 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
return true;
}
-bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
-{
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) {
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
ehci_qhd_t* qhd = qhd_get_from_addr(dev_addr, ep_addr);
+ TU_VERIFY(qhd != NULL);
ehci_qtd_t* qtd;
if (epnum == 0) {
@@ -540,8 +558,7 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
// This isr mean it is safe to modify previously removed queue head from async list.
// In tinyusb, queue head is only removed when device is unplugged.
TU_ATTR_ALWAYS_INLINE static inline
-void async_advance_isr(uint8_t rhport)
-{
+void async_advance_isr(uint8_t rhport) {
(void) rhport;
ehci_qhd_t *qhd_pool = ehci_data.qhd_pool;
@@ -612,8 +629,7 @@ void qhd_xfer_complete_isr(ehci_qhd_t * qhd) {
}
TU_ATTR_ALWAYS_INLINE static inline
-void proccess_async_xfer_isr(ehci_qhd_t * const list_head)
-{
+void proccess_async_xfer_isr(ehci_qhd_t * const list_head) {
ehci_qhd_t *qhd = list_head;
do {
@@ -623,8 +639,7 @@ void proccess_async_xfer_isr(ehci_qhd_t * const list_head)
}
TU_ATTR_ALWAYS_INLINE static inline
-void process_period_xfer_isr(uint8_t rhport, uint32_t interval_ms)
-{
+void process_period_xfer_isr(uint8_t rhport, uint32_t interval_ms) {
uint32_t const period_1ms_addr = (uint32_t) list_get_period_head(rhport, 1u);
ehci_link_t next_link = *list_get_period_head(rhport, interval_ms);
@@ -726,51 +741,55 @@ TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_next(ehci_link_t const *p_
return (ehci_link_t*) tu_align32(p_link->address);
}
-TU_ATTR_ALWAYS_INLINE static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type)
-{
- new->address = current->address;
- current->address = ((uint32_t) new) | (new_type << 1);
+TU_ATTR_ALWAYS_INLINE static inline void list_insert(ehci_link_t *current, ehci_link_t *entry, uint8_t type) {
+ entry->address = current->address;
+ current->address = ((uint32_t) entry) | (type << 1);
}
-// Remove all queue head belong to this device address
-static void list_remove_qhd_by_daddr(ehci_link_t* list_head, uint8_t dev_addr) {
- ehci_link_t* prev = list_head;
+// Remove a queue head from the list.
+// Per EHCI 4.8.2 the removed qhd's next is linked to list head (which always reachable by Host Controller)
+// TODO support iTD/siTD
+TU_ATTR_ALWAYS_INLINE static inline void list_remove(ehci_link_t* head, ehci_link_t* prev, ehci_qhd_t* qhd) {
+ // TODO deactivate all TD, wait for QHD to inactive before removal
+ prev->address = qhd->next.address;
+
+ // link the removed qhd's next to list head
+ qhd->next.address = ((uint32_t) head) | (EHCI_QTYPE_QHD << 1);
+
+ if (qhd_is_periodic(qhd)) {
+ // period list queue element is guarantee to be free in the next frame (1 ms)
+ qhd->used = 0;
+ } else {
+ // async list use async advance handshake. Mark as removing, will completely re-usable when async advance isr occurs
+ qhd->removing = 1;
+ }
+
+ hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
+ hcd_dcache_clean(prev, sizeof(ehci_qhd_t));
+}
+
+// Remove queue head belong to this device address
+static void list_remove_qhd_by_addr(ehci_link_t *list_head, uint8_t dev_addr, uint8_t ep_addr) {
+ ehci_link_t *prev = list_head;
while (prev && !prev->terminate) {
- ehci_qhd_t* qhd = (ehci_qhd_t*) (uintptr_t) list_next(prev);
+ ehci_qhd_t *qhd = (ehci_qhd_t *) (uintptr_t) list_next(prev);
// done if loop back to head
- if ( (uintptr_t) qhd == (uintptr_t) list_head) {
+ if ((uintptr_t) qhd == (uintptr_t) list_head) {
break;
}
- if ( qhd->dev_addr == dev_addr ) {
- // TODO deactivate all TD, wait for QHD to inactive before removal
- prev->address = qhd->next.address;
-
- // EHCI 4.8.2 link the removed qhd's next to async head (which always reachable by Host Controller)
- qhd->next.address = ((uint32_t) list_head) | (EHCI_QTYPE_QHD << 1);
-
- if ( qhd->int_smask )
- {
- // period list queue element is guarantee to be free in the next frame (1 ms)
- qhd->used = 0;
- }else
- {
- // async list use async advance handshake
- // mark as removing, will completely re-usable when async advance isr occurs
- qhd->removing = 1;
- }
-
- hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
- hcd_dcache_clean(prev, sizeof(ehci_qhd_t));
- }else {
+ // ep_addr is 0xff means all endpoints of this device address
+ if (qhd->dev_addr == dev_addr &&
+ (ep_addr == TUSB_INDEX_INVALID_8 || qhd_ep_addr(qhd) == ep_addr)) {
+ list_remove(list_head, prev, qhd);
+ } else {
prev = list_next(prev);
}
}
}
-
//--------------------------------------------------------------------+
// Queue Header helper
//--------------------------------------------------------------------+
@@ -782,8 +801,10 @@ TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_control(uint8_t dev_addr) {
// Find a free queue head
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t *qhd_find_free(void) {
- for ( uint32_t i = 0; i < QHD_MAX; i++ ) {
- if ( !ehci_data.qhd_pool[i].used ) return &ehci_data.qhd_pool[i];
+ for (uint32_t i = 0; i < QHD_MAX; i++) {
+ if (!ehci_data.qhd_pool[i].used) {
+ return &ehci_data.qhd_pool[i];
+ }
}
return NULL;
}
@@ -800,10 +821,9 @@ static ehci_qhd_t *qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr) {
}
ehci_qhd_t *qhd_pool = ehci_data.qhd_pool;
-
- for ( uint32_t i = 0; i < QHD_MAX; i++ ) {
- if ( (qhd_pool[i].dev_addr == dev_addr) &&
- ep_addr == tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) ) {
+ for (uint32_t i = 0; i < QHD_MAX; i++) {
+ if ((qhd_pool[i].dev_addr == dev_addr) &&
+ ep_addr == qhd_ep_addr(&qhd_pool[i])) {
return &qhd_pool[i];
}
}
@@ -812,15 +832,14 @@ static ehci_qhd_t *qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr) {
}
// Init queue head with endpoint descriptor
-static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
-{
+static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) {
// address 0 is used as async head, which always on the list --> cannot be cleared (ehci halted otherwise)
if (dev_addr != 0) {
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;
@@ -828,45 +847,49 @@ 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 asyn list head
+ 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);
p_qhd->fl_ctrl_ep_flag = ((xfer_type == TUSB_XFER_CONTROL) && (p_qhd->ep_speed != TUSB_SPEED_HIGH)) ? 1 : 0;
p_qhd->nak_reload = 0;
- // Bulk/Control -> smask = cmask = 0
- // TODO Isochronous
- if (TUSB_XFER_INTERRUPT == xfer_type)
- {
- if (TUSB_SPEED_HIGH == p_qhd->ep_speed)
- {
- TU_ASSERT( interval <= 16, );
- if ( interval < 4) // sub millisecond interval
- {
- p_qhd->interval_ms = 0;
- p_qhd->int_smask = (interval == 1) ? TU_BIN8(11111111) :
- (interval == 2) ? TU_BIN8(10101010) : TU_BIN8(01000100);
- }else
- {
- p_qhd->interval_ms = (uint8_t) tu_min16( 1 << (interval-4), 255 );
- p_qhd->int_smask = TU_BIT(interval % 8);
+ switch (xfer_type) {
+ case TUSB_XFER_CONTROL:
+ case TUSB_XFER_BULK:
+ p_qhd->int_smask = p_qhd->fl_int_cmask = 0;
+ break;
+
+ case TUSB_XFER_INTERRUPT:
+ if (TUSB_SPEED_HIGH == p_qhd->ep_speed) {
+ TU_ASSERT(interval <= 16, );
+ if (interval < 4) {
+ // sub millisecond interval
+ p_qhd->interval_ms = 0;
+ p_qhd->int_smask = (interval == 1) ? TU_BIN8(11111111) :
+ (interval == 2) ? TU_BIN8(10101010): TU_BIN8(01000100);
+ } else {
+ p_qhd->interval_ms = (uint8_t) tu_min16(1 << (interval - 4), 255);
+ p_qhd->int_smask = TU_BIT(interval % 8);
+ }
+ } else {
+ TU_ASSERT(0 != interval, );
+ // Full/Low: 4.12.2.1 (EHCI) case 1 schedule start split at 1 us & complete split at 2,3,4 uframes
+ p_qhd->int_smask = 0x01;
+ p_qhd->fl_int_cmask = TU_BIN8(11100);
+ p_qhd->interval_ms = interval;
}
- }else
- {
- TU_ASSERT( 0 != interval, );
- // Full/Low: 4.12.2.1 (EHCI) case 1 schedule start split at 1 us & complete split at 2,3,4 uframes
- p_qhd->int_smask = 0x01;
- p_qhd->fl_int_cmask = TU_BIN8(11100);
- p_qhd->interval_ms = interval;
- }
- }else
- {
- p_qhd->int_smask = p_qhd->fl_int_cmask = 0;
+ break;
+
+ case TUSB_XFER_ISOCHRONOUS:
+ // TODO not support ISO yet
+ break;
+
+ 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 -------------//
@@ -880,8 +903,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
p_qhd->qtd_overlay.next.terminate = 1;
p_qhd->qtd_overlay.alternate.terminate = 1;
- if (TUSB_XFER_BULK == xfer_type && p_qhd->ep_speed == TUSB_SPEED_HIGH && p_qhd->pid == EHCI_PID_OUT)
- {
+ if (TUSB_XFER_BULK == xfer_type && p_qhd->ep_speed == TUSB_SPEED_HIGH && p_qhd->pid == EHCI_PID_OUT) {
p_qhd->qtd_overlay.ping_err = 1; // do PING for Highspeed Bulk OUT, EHCI section 4.11
}
}
diff --git a/src/portable/ehci/ehci.h b/src/portable/ehci/ehci.h
index 457adc1d3..87659701b 100644
--- a/src/portable/ehci/ehci.h
+++ b/src/portable/ehci/ehci.h
@@ -49,15 +49,14 @@
// TODO merge OHCI with EHCI
enum {
- EHCI_MAX_ITD = 4,
+ EHCI_MAX_ITD = 4,
EHCI_MAX_SITD = 16
};
//--------------------------------------------------------------------+
// EHCI Data Structure
//--------------------------------------------------------------------+
-enum
-{
+enum {
EHCI_QTYPE_ITD = 0 ,
EHCI_QTYPE_QHD ,
EHCI_QTYPE_SITD ,
@@ -65,8 +64,7 @@ enum
};
/// EHCI PID
-enum
-{
+enum {
EHCI_PID_OUT = 0 ,
EHCI_PID_IN ,
EHCI_PID_SETUP
@@ -74,187 +72,182 @@ enum
/// Link pointer
typedef union {
- uint32_t address;
- struct {
- uint32_t terminate : 1;
- uint32_t type : 2;
- };
-}ehci_link_t;
+ uint32_t address;
+ struct {
+ uint32_t terminate : 1;
+ uint32_t type : 2;
+ };
+} ehci_link_t;
TU_VERIFY_STATIC( sizeof(ehci_link_t) == 4, "size is not correct" );
/// Queue Element Transfer Descriptor
/// Qtd is used to declare overlay in ehci_qhd_t -> cannot be declared with TU_ATTR_ALIGNED(32)
-typedef struct
-{
- // Word 0: Next QTD Pointer
- ehci_link_t next;
+typedef struct {
+ // Word 0 Next QTD Pointer
+ ehci_link_t next;
- // Word 1: Alternate Next QTD Pointer (not used)
- union{
- ehci_link_t alternate;
- struct {
- uint32_t : 5;
- uint32_t used : 1;
- uint32_t : 10;
- uint32_t expected_bytes : 16;
- };
- };
+ // Word 1 Alternate Next QTD Pointer (not used)
+ union {
+ ehci_link_t alternate;
+ struct {
+ uint32_t : 5;
+ uint32_t used : 1;
+ uint32_t : 10;
+ uint32_t expected_bytes : 16;
+ };
+ };
- // Word 2: qTQ Token
- volatile uint32_t ping_err : 1 ; ///< For Highspeed: 0 Out, 1 Ping. Full/Slow used as error indicator
- volatile uint32_t non_hs_split_state : 1 ; ///< Used by HC to track the state of split transaction
- volatile uint32_t non_hs_missed_uframe : 1 ; ///< HC misses a complete split transaction
- volatile uint32_t xact_err : 1 ; ///< Error (Timeout, CRC, Bad PID ... )
- volatile uint32_t babble_err : 1 ; ///< Babble detected, also set Halted bit to 1
- volatile uint32_t buffer_err : 1 ; ///< Data overrun/underrun error
- volatile uint32_t halted : 1 ; ///< Serious error or STALL received
- volatile uint32_t active : 1 ; ///< Start transfer, clear by HC when complete
+ // Word 2 qTQ Token
+ volatile uint32_t ping_err : 1; // For Highspeed: 0 Out, 1 Ping. Full/Slow used as error indicator
+ volatile uint32_t non_hs_split_state : 1; // Used by HC to track the state of split transaction
+ volatile uint32_t non_hs_missed_uframe : 1; // HC misses a complete split transaction
+ volatile uint32_t xact_err : 1; // Error (Timeout, CRC, Bad PID ... )
+ volatile uint32_t babble_err : 1; // Babble detected, also set Halted bit to 1
+ volatile uint32_t buffer_err : 1; // Data overrun/underrun error
+ volatile uint32_t halted : 1; // Serious error or STALL received
+ volatile uint32_t active : 1; // Start transfer, clear by HC when complete
- uint32_t pid : 2 ; ///< 0: OUT, 1: IN, 2 Setup
- volatile uint32_t err_count : 2 ; ///< Error Counter of consecutive errors
- volatile uint32_t current_page : 3 ; ///< Index into the qTD buffer pointer list
- uint32_t int_on_complete : 1 ; ///< Interrupt on complete
- volatile uint32_t total_bytes : 15 ; ///< Transfer bytes, decreased during transaction
- volatile uint32_t data_toggle : 1 ; ///< Data Toggle bit
+ uint32_t pid : 2; // 0: OUT, 1: IN, 2 Setup
+ volatile uint32_t err_count : 2; // Error Counter of consecutive errors
+ volatile uint32_t current_page : 3; // Index into the qTD buffer pointer list
+ uint32_t int_on_complete : 1; // Interrupt on complete
+ volatile uint32_t total_bytes : 15; // Transfer bytes, decreased during transaction
+ volatile uint32_t data_toggle : 1; // Data Toggle bit
-
- /// Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page
- uint32_t buffer[5];
+ // Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address.
+ // The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page
+ uint32_t buffer[5];
} ehci_qtd_t;
TU_VERIFY_STATIC( sizeof(ehci_qtd_t) == 32, "size is not correct" );
/// Queue Head
-typedef struct TU_ATTR_ALIGNED(32)
-{
- // Word 0: Next QHD
- ehci_link_t next;
+typedef struct TU_ATTR_ALIGNED(32) {
+ // Word 0 Next QHD
+ ehci_link_t next;
- // Word 1: Endpoint Characteristics
- uint32_t dev_addr : 7 ; ///< device address
- uint32_t fl_inactive_next_xact : 1 ; ///< Only valid for Periodic with Full/Slow speed
- uint32_t ep_number : 4 ; ///< EP number
- uint32_t ep_speed : 2 ; ///< 0: Full, 1: Low, 2: High
- uint32_t data_toggle_control : 1 ; ///< 0: use DT in qHD, 1: use DT in qTD
- uint32_t head_list_flag : 1 ; ///< Head of the queue
- uint32_t max_packet_size : 11 ; ///< Max packet size
- uint32_t fl_ctrl_ep_flag : 1 ; ///< 1 if is Full/Low speed control endpoint
- uint32_t nak_reload : 4 ; ///< Used by HC
+ // Word 1 Endpoint Characteristics
+ uint32_t dev_addr : 7; // device address
+ uint32_t fl_inactive_next_xact : 1; // Only valid for Periodic with Full/Slow speed
+ uint32_t ep_number : 4; // EP number
+ uint32_t ep_speed : 2; // Full (0), Low (1), High (2)
+ uint32_t data_toggle_control : 1; // 0 use DT in qHD, 1 use DT in qTD
+ uint32_t head_list_flag : 1; // Head of the queue
+ uint32_t max_packet_size : 11; // Max packet size
+ uint32_t fl_ctrl_ep_flag : 1; // 1 if is Full/Low speed control endpoint
+ uint32_t nak_reload : 4; // Used by HC
- // Word 2: Endpoint Capabilities
- uint32_t int_smask : 8 ; ///< Interrupt Schedule Mask
- uint32_t fl_int_cmask : 8 ; ///< Split Completion Mask for Full/Slow speed
- uint32_t fl_hub_addr : 7 ; ///< Hub Address for Full/Slow speed
- uint32_t fl_hub_port : 7 ; ///< Hub Port for Full/Slow speed
- uint32_t mult : 2 ; ///< Transaction per micro frame
+ // Word 2 Endpoint Capabilities
+ uint32_t int_smask : 8; // Interrupt Schedule Mask
+ uint32_t fl_int_cmask : 8; // Split Completion Mask for Full/Slow speed
+ uint32_t fl_hub_addr : 7; // Hub Address for Full/Slow speed
+ uint32_t fl_hub_port : 7; // Hub Port for Full/Slow speed
+ uint32_t mult : 2; // Transaction per micro frame
- // Word 3: Current qTD Pointer
- volatile uint32_t qtd_addr;
+ // Word 3 Current qTD Pointer
+ volatile uint32_t qtd_addr;
- // Word 4-11: Transfer Overlay
- volatile ehci_qtd_t qtd_overlay;
+ // Word 4-11 Transfer Overlay
+ volatile ehci_qtd_t qtd_overlay;
- //--------------------------------------------------------------------+
- /// Due to the fact QHD is 32 bytes aligned but occupies only 48 bytes
- /// thus there are 16 bytes padding free that we can make use of.
//--------------------------------------------------------------------+
- uint8_t used;
- uint8_t removing; // removed from asyn list, waiting for async advance
- uint8_t pid;
- uint8_t interval_ms; // polling interval in frames (or millisecond)
+ /// Due to the fact QHD is 32 bytes aligned but occupies only 48 bytes
+ /// thus there are 16 bytes padding free that we can make use of.
+ //--------------------------------------------------------------------+
+ uint8_t used;
+ uint8_t removing;// removed from asyn list, waiting for async advance
+ uint8_t pid;
+ uint8_t interval_ms;// polling interval in frames (or millisecond)
- uint8_t TU_RESERVED[4];
+ uint8_t TU_RESERVED[4];
// Attached TD management, note usbh will only queue 1 TD per QHD.
// buffer for dcache invalidate since td's buffer is modified by HC and finding initial buffer address is not trivial
uint32_t attached_buffer;
- ehci_qtd_t * volatile attached_qtd;
+ ehci_qtd_t *volatile attached_qtd;
} ehci_qhd_t;
-
TU_VERIFY_STATIC( sizeof(ehci_qhd_t) == 64, "size is not correct" );
/// Highspeed Isochronous Transfer Descriptor (section 3.3)
typedef struct TU_ATTR_ALIGNED(32) {
- // Word 0: Next Link Pointer
- ehci_link_t next;
+ // Word 0: Next Link Pointer
+ ehci_link_t next;
- // Word 1-8: iTD Transaction Status and Control List
- struct {
- // iTD Control
- volatile uint32_t offset : 12 ; ///< This field is a value that is an offset, expressed in bytes, from the beginning of a buffer.
- volatile uint32_t page_select : 3 ; ///< These bits are set by software to indicate which of the buffer page pointers the offset field in this slot should be concatenated to produce the starting memory address for this transaction. The valid range of values for this field is 0 to 6
- uint32_t int_on_complete : 1 ; ///< If this bit is set to a one, it specifies that when this transaction completes, the Host Controller should issue an interrupt at the next interrupt threshold
- volatile uint32_t length : 12 ; ///< For an OUT, this field is the number of data bytes the host controller will send during the transaction. The host controller is not required to update this field to reflect the actual number of bytes transferred during the transfer
- ///< For an IN, the initial value of the field is the number of bytes the host expects the endpoint to deliver. During the status update, the host controller writes back the number of bytes successfully received. The value in this register is the actual byte count
- // iTD Status
- volatile uint32_t error : 1 ; ///< Set to a one by the Host Controller during status update in the case where the host did not receive a valid response from the device (Timeout, CRC, Bad PID, etc.). This bit may only be set for isochronous IN transactions.
- volatile uint32_t babble_err : 1 ; ///< Set to a 1 by the Host Controller during status update when a babble is detected during the transaction
- volatile uint32_t buffer_err : 1 ; ///< Set to a 1 by the Host Controller during status update to indicate that the Host Controller is unable to keep up with the reception of incoming data (overrun) or is unable to supply data fast enough during transmission (underrun).
- volatile uint32_t active : 1 ; ///< Set to 1 by software to enable the execution of an isochronous transaction by the Host Controller
- } xact[8];
+ // Word 1-8: iTD Transaction Status and Control List
+ struct {
+ // iTD Control
+ volatile uint32_t offset : 12; // offset in bytes, from the beginning of a buffer.
+ volatile uint32_t page_select : 3; // buffer page pointers the offset field in this slot should be concatenated to produce the starting memory address for this transaction. The valid range of values for this field is 0 to 6
+ uint32_t int_on_complete : 1; // If this bit is set to a one, it specifies that when this transaction completes, the Host Controller should issue an interrupt at the next interrupt threshold
+ volatile uint32_t length : 12; // For an OUT, this field is the number of data bytes the host controller will send during the transaction. The host controller is not required to update this field to reflect the actual number of bytes transferred during the transfer
+ // For an IN, the initial value of the field is the number of bytes the host expects the endpoint to deliver. During the status update, the host controller writes back the number of bytes successfully received. The value in this register is the actual byte count
+ // iTD Status
+ volatile uint32_t error : 1; // Set to a one by the Host Controller during status update in the case where the host did not receive a valid response from the device (Timeout, CRC, Bad PID, etc.). This bit may only be set for isochronous IN transactions.
+ volatile uint32_t babble_err : 1; // Set to a 1 by the Host Controller during status update when a babble is detected during the transaction
+ volatile uint32_t buffer_err : 1; // Set to a 1 by the Host Controller during status update to indicate that the Host Controller is unable to keep up with the reception of incoming data (overrun) or is unable to supply data fast enough during transmission (underrun).
+ volatile uint32_t active : 1; // Set to 1 by software to enable the execution of an isochronous transaction by the Host Controller
+ } xact[8];
- // Word 9-15 Buffer Page Pointer List (Plus)
- uint32_t BufferPointer[7];
+ // Word 9-15 Buffer Page Pointer List (Plus)
+ uint32_t BufferPointer[7];
-// // FIXME: Store meta data into buffer pointer reserved for saving memory
-// /*---------- HCD Area ----------*/
-// uint32_t used;
-// uint32_t IhdIdx;
-// uint32_t reserved[6];
+ // FIXME: Store meta data into buffer pointer reserved for saving memory
+ //---------- HCD Area ----------
+ // uint32_t used;
+ // uint32_t IhdIdx;
+ // uint32_t reserved[6];
} ehci_itd_t;
-
TU_VERIFY_STATIC( sizeof(ehci_itd_t) == 64, "size is not correct" );
/// Split (Full-Speed) Isochronous Transfer Descriptor
-typedef struct TU_ATTR_ALIGNED(32)
-{
+typedef struct TU_ATTR_ALIGNED(32) {
// Word 0: Next Link Pointer
- ehci_link_t next;
+ ehci_link_t next;
- // Word 1: siTD Endpoint Characteristics
- uint32_t dev_addr : 7; ///< This field selects the specific device serving as the data source or sink.
- uint32_t : 1; ///< reserved
- uint32_t ep_number : 4; ///< This 4-bit field selects the particular endpoint number on the device serving as the data source or sink.
- uint32_t : 4; ///< This field is reserved and should be set to zero.
- uint32_t hub_addr : 7; ///< This field holds the device address of the transaction translators’ hub.
- uint32_t : 1; ///< reserved
- uint32_t port_number : 7; ///< This field is the port number of the recipient transaction translator.
- uint32_t direction : 1; ///< 0 = OUT; 1 = IN. This field encodes whether the full-speed transaction should be an IN or OUT.
+ // Word 1: siTD Endpoint Characteristics
+ uint32_t dev_addr : 7; ///< This field selects the specific device serving as the data source or sink.
+ uint32_t : 1; ///< reserved
+ uint32_t ep_number : 4; ///< This 4-bit field selects the particular endpoint number on the device serving as the data source or sink.
+ uint32_t : 4; ///< This field is reserved and should be set to zero.
+ uint32_t hub_addr : 7; ///< This field holds the device address of the transaction translators’ hub.
+ uint32_t : 1; ///< reserved
+ uint32_t port_number : 7; ///< This field is the port number of the recipient transaction translator.
+ uint32_t direction : 1; ///< 0 = OUT; 1 = IN. This field encodes whether the full-speed transaction should be an IN or OUT.
- // Word 2: Micro-frame Schedule Control
- uint8_t int_smask ; ///< This field (along with the Activeand SplitX-statefields in the Statusbyte) are used to determine during which micro-frames the host controller should execute complete-split transactions
- uint8_t fl_int_cmask; ///< This field (along with the Activeand SplitX-statefields in the Statusbyte) are used to determine during which micro-frames the host controller should execute start-split transactions.
- uint16_t reserved ; ///< reserved
+ // Word 2: Micro-frame Schedule Control
+ uint8_t int_smask ; ///< This field (along with the Activeand SplitX-statefields in the Statusbyte) are used to determine during which micro-frames the host controller should execute complete-split transactions
+ uint8_t fl_int_cmask; ///< This field (along with the Activeand SplitX-statefields in the Statusbyte) are used to determine during which micro-frames the host controller should execute start-split transactions.
+ uint16_t reserved ; ///< reserved
- // Word 3: siTD Transfer Status and Control
- // Status [7:0] TODO identical to qTD Token'status --> refactor later
- volatile uint32_t : 1 ; // reserved
- volatile uint32_t split_state : 1 ;
- volatile uint32_t missed_uframe : 1 ;
- volatile uint32_t xact_err : 1 ;
- volatile uint32_t babble_err : 1 ;
- volatile uint32_t buffer_err : 1 ;
- volatile uint32_t error : 1 ;
- volatile uint32_t active : 1 ;
- // Micro-frame Schedule Control
- volatile uint32_t cmask_progress : 8 ; ///< This field is used by the host controller to record which split-completes have been executed. See Section 4.12.3.3.2 for behavioral requirements.
- volatile uint32_t total_bytes : 10 ; ///< This field is initialized by software to the total number of bytes expected in this transfer. Maximum value is 1023
- volatile uint32_t : 4 ; ///< reserved
- volatile uint32_t page_select : 1 ; ///< Used to indicate which data page pointer should be concatenated with the CurrentOffsetfield to construct a data buffer pointer
- uint32_t int_on_complete : 1 ; ///< Do not interrupt when transaction is complete. 1 = Do interrupt when transaction is complete
- uint32_t : 0 ; // padding to the end of current storage unit
+ // Word 3: siTD Transfer Status and Control
+ // Status [7:0] TODO identical to qTD Token'status --> refactor later
+ volatile uint32_t : 1 ; // reserved
+ volatile uint32_t split_state : 1 ;
+ volatile uint32_t missed_uframe : 1 ;
+ volatile uint32_t xact_err : 1 ;
+ volatile uint32_t babble_err : 1 ;
+ volatile uint32_t buffer_err : 1 ;
+ volatile uint32_t error : 1 ;
+ volatile uint32_t active : 1 ;
+ // Micro-frame Schedule Control
+ volatile uint32_t cmask_progress : 8 ; ///< This field is used by the host controller to record which split-completes have been executed. See Section 4.12.3.3.2 for behavioral requirements.
+ volatile uint32_t total_bytes : 10 ; ///< This field is initialized by software to the total number of bytes expected in this transfer. Maximum value is 1023
+ volatile uint32_t : 4 ; ///< reserved
+ volatile uint32_t page_select : 1 ; ///< Used to indicate which data page pointer should be concatenated with the CurrentOffsetfield to construct a data buffer pointer
+ uint32_t int_on_complete : 1 ; ///< Do not interrupt when transaction is complete. 1 = Do interrupt when transaction is complete
+ uint32_t : 0 ; // padding to the end of current storage unit
- /// Word 4-5: Buffer Pointer List
- uint32_t buffer[2]; // buffer[1] TP: Transaction Position - T-Count: Transaction Count
+ /// Word 4-5: Buffer Pointer List
+ uint32_t buffer[2]; // buffer[1] TP: Transaction Position - T-Count: Transaction Count
- /*---------- Word 6 ----------*/
- ehci_link_t back;
+ /*---------- Word 6 ----------*/
+ ehci_link_t back;
- /// SITD is 32-byte aligned but occupies only 28 --> 4 bytes for storing extra data
- uint8_t used;
- uint8_t ihd_idx;
- uint8_t reserved2[2];
+ /// SITD is 32-byte aligned but occupies only 28 --> 4 bytes for storing extra data
+ uint8_t used;
+ uint8_t ihd_idx;
+ uint8_t reserved2[2];
} ehci_sitd_t;
TU_VERIFY_STATIC( sizeof(ehci_sitd_t) == 32, "size is not correct" );
@@ -315,8 +308,7 @@ enum {
EHCI_PORTSC_MASK_OVER_CURRENT_CHANGE
};
-typedef volatile struct
-{
+typedef volatile struct {
union {
uint32_t command; // 0x00
diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c
index 1c0740193..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;
@@ -804,6 +805,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
return true;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
{
(void)rhport;
diff --git a/src/portable/nxp/khci/hcd_khci.c b/src/portable/nxp/khci/hcd_khci.c
index 056dbf40b..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
@@ -541,6 +542,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
return true;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
/* The address of buffer must be aligned to 4 byte boundary. And it must be at least 4 bytes long.
* DMA writes data in 4 byte unit */
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
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/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
index 7d5cfb5b0..7c637ce0c 100644
--- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
+++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
@@ -297,7 +297,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
dcd_reg->EPLISTSTART = (uint32_t) _dcd.ep;
dcd_reg->DATABUFSTART = tu_align((uint32_t) &_dcd, TU_BIT(22)); // 22-bit alignment
- dcd_reg->INTSTAT |= dcd_reg->INTSTAT; // clear all pending interrupt
+ dcd_reg->INTSTAT = dcd_reg->INTSTAT; // clear all pending interrupt
dcd_reg->INTEN = INT_DEVICE_STATUS_MASK;
dcd_reg->DEVCMDSTAT |= DEVCMDSTAT_DEVICE_ENABLE_MASK | DEVCMDSTAT_DEVICE_CONNECT_MASK |
DEVCMDSTAT_RESET_CHANGE_MASK | DEVCMDSTAT_CONNECT_CHANGE_MASK | DEVCMDSTAT_SUSPEND_CHANGE_MASK;
@@ -563,7 +563,8 @@ void dcd_int_handler(uint8_t rhport)
uint32_t const cmd_stat = dcd_reg->DEVCMDSTAT;
- uint32_t int_status = dcd_reg->INTSTAT & dcd_reg->INTEN;
+ uint32_t int_status = dcd_reg->INTSTAT;
+ int_status &= dcd_reg->INTEN;
dcd_reg->INTSTAT = int_status; // Acknowledge handled interrupt
if (int_status == 0) return;
diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c
index ce35eab70..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;
@@ -451,7 +452,6 @@ static void td_insert_to_ed(ohci_ed_t* p_ed, ohci_gtd_t * p_gtd)
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
-
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
{
(void) rhport;
@@ -486,6 +486,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
return true;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
{
(void) rhport;
diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
index 6422afff1..d59a2b4ee 100644
--- a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
+++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
@@ -114,14 +114,19 @@ 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);
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ uint8_t const pio_rhport = RHPORT_PIO(rhport);
+ return pio_usb_host_endpoint_close(pio_rhport, daddr, ep_addr);
+}
+
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen) {
uint8_t const pio_rhport = RHPORT_PIO(rhport);
return pio_usb_host_endpoint_transfer(pio_rhport, dev_addr, ep_addr, buffer, buflen);
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index 478c6e789..cd8c905d5 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -514,7 +514,6 @@ void hcd_int_disable(uint8_t rhport)
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
-
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
{
(void) rhport;
@@ -535,6 +534,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
return true;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
{
(void) rhport;
diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c
index 4c81b05be..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;
}
@@ -718,6 +719,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
return true;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
{
bool r;
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index c461d9a79..5f86d6b76 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -39,14 +39,9 @@
#define DWC2_DEBUG 2
#include "device/dcd.h"
+#include "device/usbd_pvt.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
//--------------------------------------------------------------------+
@@ -58,6 +53,7 @@ typedef struct {
uint8_t interval;
} xfer_ctl_t;
+// This variable is modified from ISR context, so it must be protected by critical section
static xfer_ctl_t xfer_status[DWC2_EP_MAX][2];
#define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir])
@@ -79,6 +75,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 +108,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 +257,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];
@@ -321,6 +323,9 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
}
}
+// Since this function returns void, it is not possible to return a boolean success message
+// We must make sure that this function is not called when the EP is disabled
+// Must be called from critical section
static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uint8_t dir) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, dir);
@@ -343,31 +348,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 +406,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 {
@@ -428,6 +425,11 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
// Clear A override, force B Valid
dwc2->gotgctl = (dwc2->gotgctl & ~GOTGCTL_AVALOEN) | GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL;
+#if CFG_TUSB_MCU == OPT_MCU_STM32N6
+ // No hardware detection of Vbus B-session is available on the STM32N6
+ dwc2->stm32_gccfg |= STM32_GCCFG_VBVALOVAL;
+#endif
+
// Enable required interrupts
dwc2->gintmsk |= GINTMSK_OTGINT | GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM;
@@ -539,6 +541,8 @@ void dcd_edpt_close_all(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
+ usbd_spin_lock(false);
+
_dcd_data.allocated_epin_count = 0;
// Disable non-control interrupt
@@ -556,8 +560,9 @@ void dcd_edpt_close_all(uint8_t rhport) {
dfifo_flush_tx(dwc2, 0x10); // all tx fifo
dfifo_flush_rx(dwc2);
-
dfifo_device_init(rhport); // re-init dfifo
+
+ usbd_spin_unlock(false);
}
bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
@@ -575,21 +580,31 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpo
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
-
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = buffer;
- xfer->ff = NULL;
- xfer->total_len = total_bytes;
+ bool ret;
- // EP0 can only handle one packet
- if (epnum == 0) {
- _dcd_data.ep0_pending[dir] = total_bytes;
+ usbd_spin_lock(false);
+
+ if (xfer->max_size == 0) {
+ ret = false; // Endpoint is closed
+ } else {
+ xfer->buffer = buffer;
+ xfer->ff = NULL;
+ xfer->total_len = total_bytes;
+
+ // EP0 can only handle one packet
+ if (epnum == 0) {
+ _dcd_data.ep0_pending[dir] = total_bytes;
+ }
+
+ // Schedule packets to be sent within interrupt
+ edpt_schedule_packets(rhport, epnum, dir);
+ ret = true;
}
- // Schedule packets to be sent within interrupt
- edpt_schedule_packets(rhport, epnum, dir);
+ usbd_spin_unlock(false);
- return true;
+ return ret;
}
// The number of bytes has to be given explicitly to allow more flexible control of how many
@@ -602,17 +617,27 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
-
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = NULL;
- xfer->ff = ff;
- xfer->total_len = total_bytes;
+ bool ret;
- // Schedule packets to be sent within interrupt
- // TODO xfer fifo may only available for slave mode
- edpt_schedule_packets(rhport, epnum, dir);
+ usbd_spin_lock(false);
- return true;
+ if (xfer->max_size == 0) {
+ ret = false; // Endpoint is closed
+ } else {
+ xfer->buffer = NULL;
+ xfer->ff = ff;
+ xfer->total_len = total_bytes;
+
+ // Schedule packets to be sent within interrupt
+ // TODO xfer fifo may only available for slave mode
+ edpt_schedule_packets(rhport, epnum, dir);
+ ret = true;
+ }
+
+ usbd_spin_unlock(false);
+
+ return ret;
}
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
@@ -639,9 +664,10 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
//--------------------------------------------------------------------
// 7.4.1 Initialization on USB Reset
+// Must be called from critical section
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 +697,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 +719,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 +766,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 +793,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 +807,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 +870,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 +895,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 +927,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 +964,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];
@@ -983,14 +1017,16 @@ static void handle_ep_irq(uint8_t rhport, uint8_t dir) {
*/
void dcd_int_handler(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
-
const uint32_t gintmask = dwc2->gintmsk;
const uint32_t gintsts = dwc2->gintsts & gintmask;
if (gintsts & GINTSTS_USBRST) {
// USBRST is start of reset.
dwc2->gintsts = GINTSTS_USBRST;
+
+ usbd_spin_lock(true);
handle_bus_reset(rhport);
+ usbd_spin_unlock(true);
}
if (gintsts & GINTSTS_ENUMDNE) {
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_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h
index 3309760ff..49b8c54cb 100644
--- a/src/portable/synopsys/dwc2/dwc2_esp32.h
+++ b/src/portable/synopsys/dwc2/dwc2_esp32.h
@@ -55,8 +55,8 @@ static const dwc2_controller_t _dwc2_controller[] = {
// On ESP32 for consistency we associate
// - Port0 to OTG_FS, and Port1 to OTG_HS
static const dwc2_controller_t _dwc2_controller[] = {
-{ .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_OTG11_CH0_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 },
-{ .reg_base = DWC2_HS_REG_BASE, .irqnum = ETS_USB_OTG_INTR_SOURCE, .ep_count = 16, .ep_in_count = 8, .ep_fifo_size = 4096 }
+ { .reg_base = DWC2_FS_REG_BASE, .irqnum = ETS_USB_OTG11_CH0_INTR_SOURCE, .ep_count = 7, .ep_in_count = 5, .ep_fifo_size = 1024 },
+ { .reg_base = DWC2_HS_REG_BASE, .irqnum = ETS_USB_OTG_INTR_SOURCE, .ep_count = 16, .ep_in_count = 8, .ep_fifo_size = 4096 }
};
#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_info.md b/src/portable/synopsys/dwc2/dwc2_info.md
index dec021f59..595c89b75 100644
--- a/src/portable/synopsys/dwc2/dwc2_info.md
+++ b/src/portable/synopsys/dwc2/dwc2_info.md
@@ -1,58 +1,58 @@
-| | BCM2711 (Pi4) | EFM32GG | ESP32-S2/S3 | ESP32-P4 | ST F207/F407/411/429 FS | ST F407/429 HS | ST F412/76x FS | ST F723/L4P5 FS | ST F723 HS | ST F76x HS | ST H743/H750 | ST L476 FS | ST U5A5 HS | XMC4500 | GD32VF103 |
-|:---------------------------|:----------------|:-------------|:--------------|:-------------|:--------------------------|:-----------------|:-----------------|:------------------|:-------------|:-------------|:---------------|:-------------|:-------------|:-------------|:------------|
-| GUID | 0x2708A000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00001200 | 0x00001100 | 0x00002000 | 0x00003000 | 0x00003100 | 0x00002100 | 0x00002300 | 0x00002000 | 0x00005000 | 0x00AEC000 | 0x00001000 |
-| GSNPSID | 0x4F54280A | 0x4F54330A | 0x4F54400A | 0x4F54400A | 0x4F54281A | 0x4F54281A | 0x4F54320A | 0x4F54330A | 0x4F54330A | 0x4F54320A | 0x4F54330A | 0x4F54310A | 0x4F54411A | 0x4F54292A | 0x00000000 |
-| - specs version | 2.80a | 3.30a | 4.00a | 4.00a | 2.81a | 2.81a | 3.20a | 3.30a | 3.30a | 3.20a | 3.30a | 3.10a | 4.11a | 2.92a | 0.00W |
-| GHWCFG1 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 |
-| GHWCFG2 | 0x228DDD50 | 0x228F5910 | 0x224DD930 | 0x215FFFD0 | 0x229DCD20 | 0x229ED590 | 0x229ED520 | 0x229ED520 | 0x229FE1D0 | 0x229FE190 | 0x229FE190 | 0x229ED520 | 0x228FE052 | 0x228F5930 | 0x00000000 |
-| - op_mode | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | noHNP noSRP | HNP SRP | HNP SRP |
-| - arch | DMA internal | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | Slave only | Slave only | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | DMA internal | Slave only |
-| - single_point | hub | hub | n/a | hub | n/a | hub | n/a | n/a | hub | hub | hub | n/a | hub | n/a | hub |
-| - hs_phy_type | UTMI+ | n/a | n/a | UTMI+/ULPI | n/a | ULPI | n/a | n/a | UTMI+/ULPI | ULPI | ULPI | n/a | UTMI+ | n/a | n/a |
-| - fs_phy_type | Dedicated | Dedicated | Dedicated | Shared ULPI | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | n/a | Dedicated | n/a |
-| - num_dev_ep | 7 | 6 | 6 | 15 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
-| - num_host_ch | 7 | 13 | 7 | 15 | 7 | 11 | 11 | 11 | 15 | 15 | 15 | 11 | 15 | 13 | 0 |
-| - period_channel_support | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - enable_dynamic_fifo | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - mul_proc_intrpt | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
-| - reserved21 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - nptx_q_depth | 8 | 8 | 4 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
-| - ptx_q_depth | 8 | 8 | 8 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
-| - token_q_depth | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 |
-| - otg_enable_ic_usb | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| GHWCFG3 | 0x0FF000E8 | 0x01F204E8 | 0x00C804B5 | 0x03805EB5 | 0x020001E8 | 0x03F403E8 | 0x0200D1E8 | 0x0200D1E8 | 0x03EED2E8 | 0x03EED2E8 | 0x03B8D2E8 | 0x0200D1E8 | 0x03B882E8 | 0x027A01E5 | 0x00000000 |
-| - xfer_size_width | 8 | 8 | 5 | 5 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 5 | 0 |
-| - packet_size_width | 6 | 6 | 3 | 3 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 0 |
-| - otg_enable | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - i2c_enable | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
-| - vendor_ctrl_itf | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 |
-| - optional_feature_removed | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - synch_reset | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - otg_adp_support | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
-| - otg_enable_hsic | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - battery_charger_support | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
-| - lpm_mode | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
-| - dfifo_depth | 4080 | 498 | 200 | 896 | 512 | 1012 | 512 | 512 | 1006 | 1006 | 952 | 512 | 952 | 634 | 0 |
-| GHWCFG4 | 0x1FF00020 | 0x1BF08030 | 0xD3F0A030 | 0xDFF1A030 | 0x0FF08030 | 0x17F00030 | 0x17F08030 | 0x17F08030 | 0x23F00030 | 0x23F00030 | 0xE3F00030 | 0x17F08030 | 0xE2103E30 | 0xDBF08030 | 0x00000000 |
-| - num_dev_period_in_ep | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - partial_powerdown | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - ahb_freq_min | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - extended_hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - reserved8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - enhanced_lpm_support1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - service_interval_flow | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - ipg_isoc_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - acg_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - enhanced_lpm_support | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
-| - phy_data_width | 8 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8 bit | 8/16 bit | 8/16 bit | 8 bit | 8 bit | 8 bit | 8/16 bit | 8 bit | 8/16 bit | 8 bit |
-| - ctrl_ep_num | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-| - iddg_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - vbus_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
-| - a_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
-| - b_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
-| - session_end_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
-| - dedicated_fifos | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
-| - num_dev_in_eps | 7 | 6 | 4 | 7 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
-| - dma_desc_enable | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
-| - dma_desc_dynamic | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
+| | BCM2711 (Pi4) | EFM32GG | ESP32-S2/S3 | ESP32-P4 | ST F207/F407/411/429 FS | ST F407/429 HS | ST F412/76x FS | ST F723/L4P5 FS | ST F723 HS | ST F76x HS | ST H743/H750 | ST L476 FS | ST U5A5/H7RS/N6 HS | XMC4500 | GD32VF103 |
+|:---------------------------|:----------------|:-------------|:--------------|:-------------|:--------------------------|:-----------------|:-----------------|:------------------|:-------------|:-------------|:---------------|:-------------|:---------------------|:-------------|:------------|
+| GUID | 0x2708A000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00001200 | 0x00001100 | 0x00002000 | 0x00003000 | 0x00003100 | 0x00002100 | 0x00002300 | 0x00002000 | 0x00005000 | 0x00AEC000 | 0x00001000 |
+| GSNPSID | 0x4F54280A | 0x4F54330A | 0x4F54400A | 0x4F54400A | 0x4F54281A | 0x4F54281A | 0x4F54320A | 0x4F54330A | 0x4F54330A | 0x4F54320A | 0x4F54330A | 0x4F54310A | 0x4F54411A | 0x4F54292A | 0x00000000 |
+| - specs version | 2.80a | 3.30a | 4.00a | 4.00a | 2.81a | 2.81a | 3.20a | 3.30a | 3.30a | 3.20a | 3.30a | 3.10a | 4.11a | 2.92a | 0.00W |
+| GHWCFG1 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 | 0x00000000 |
+| GHWCFG2 | 0x228DDD50 | 0x228F5910 | 0x224DD930 | 0x215FFFD0 | 0x229DCD20 | 0x229ED590 | 0x229ED520 | 0x229ED520 | 0x229FE1D0 | 0x229FE190 | 0x229FE190 | 0x229ED520 | 0x228FE052 | 0x228F5930 | 0x00000000 |
+| - op_mode | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | HNP SRP | noHNP noSRP | HNP SRP | HNP SRP |
+| - arch | DMA internal | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | Slave only | Slave only | DMA internal | DMA internal | DMA internal | Slave only | DMA internal | DMA internal | Slave only |
+| - single_point | hub | hub | n/a | hub | n/a | hub | n/a | n/a | hub | hub | hub | n/a | hub | n/a | hub |
+| - hs_phy_type | UTMI+ | n/a | n/a | UTMI+/ULPI | n/a | ULPI | n/a | n/a | UTMI+/ULPI | ULPI | ULPI | n/a | UTMI+ | n/a | n/a |
+| - fs_phy_type | Dedicated | Dedicated | Dedicated | Shared ULPI | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | Dedicated | n/a | Dedicated | n/a |
+| - num_dev_ep | 7 | 6 | 6 | 15 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
+| - num_host_ch | 7 | 13 | 7 | 15 | 7 | 11 | 11 | 11 | 15 | 15 | 15 | 11 | 15 | 13 | 0 |
+| - period_channel_support | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - enable_dynamic_fifo | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - mul_proc_intrpt | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
+| - reserved21 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - nptx_q_depth | 8 | 8 | 4 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
+| - ptx_q_depth | 8 | 8 | 8 | 4 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 2 |
+| - token_q_depth | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 0 |
+| - otg_enable_ic_usb | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| GHWCFG3 | 0x0FF000E8 | 0x01F204E8 | 0x00C804B5 | 0x03805EB5 | 0x020001E8 | 0x03F403E8 | 0x0200D1E8 | 0x0200D1E8 | 0x03EED2E8 | 0x03EED2E8 | 0x03B8D2E8 | 0x0200D1E8 | 0x03B882E8 | 0x027A01E5 | 0x00000000 |
+| - xfer_size_width | 8 | 8 | 5 | 5 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 5 | 0 |
+| - packet_size_width | 6 | 6 | 3 | 3 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 0 |
+| - otg_enable | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - i2c_enable | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
+| - vendor_ctrl_itf | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 |
+| - optional_feature_removed | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - synch_reset | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - otg_adp_support | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
+| - otg_enable_hsic | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - battery_charger_support | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
+| - lpm_mode | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
+| - dfifo_depth | 4080 | 498 | 200 | 896 | 512 | 1012 | 512 | 512 | 1006 | 1006 | 952 | 512 | 952 | 634 | 0 |
+| GHWCFG4 | 0x1FF00020 | 0x1BF08030 | 0xD3F0A030 | 0xDFF1A030 | 0x0FF08030 | 0x17F00030 | 0x17F08030 | 0x17F08030 | 0x23F00030 | 0x23F00030 | 0xE3F00030 | 0x17F08030 | 0xE2103E30 | 0xDBF08030 | 0x00000000 |
+| - num_dev_period_in_ep | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - partial_powerdown | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - ahb_freq_min | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - extended_hibernation | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - reserved8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - enhanced_lpm_support1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - service_interval_flow | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - ipg_isoc_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - acg_support | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - enhanced_lpm_support | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| - phy_data_width | 8 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8/16 bit | 8 bit | 8/16 bit | 8/16 bit | 8 bit | 8 bit | 8 bit | 8/16 bit | 8 bit | 8/16 bit | 8 bit |
+| - ctrl_ep_num | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| - iddg_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - vbus_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - a_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - b_valid_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - session_end_filter | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| - dedicated_fifos | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
+| - num_dev_in_eps | 7 | 6 | 4 | 7 | 3 | 5 | 5 | 5 | 8 | 8 | 8 | 5 | 8 | 6 | 0 |
+| - dma_desc_enable | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
+| - dma_desc_dynamic | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
diff --git a/src/portable/synopsys/dwc2/dwc2_info.py b/src/portable/synopsys/dwc2/dwc2_info.py
index 25edcf22d..3b1993cc5 100755
--- a/src/portable/synopsys/dwc2/dwc2_info.py
+++ b/src/portable/synopsys/dwc2/dwc2_info.py
@@ -21,7 +21,7 @@ dwc2_reg_value = {
'ST F76x HS': [0x2100, 0x4F54320A, 0, 0x229FE190, 0x03EED2E8, 0x23F00030],
'ST H743/H750': [0x2300, 0x4F54330A, 0, 0x229FE190, 0x03B8D2E8, 0xE3F00030],
'ST L476 FS': [0x2000, 0x4F54310A, 0, 0x229ED520, 0x0200D1E8, 0x17F08030],
- 'ST U5A5 HS': [0x5000, 0x4F54411A, 0, 0x228FE052, 0x03B882E8, 0xE2103E30],
+ 'ST U5A5/H7RS/N6 HS': [0x5000, 0x4F54411A, 0, 0x228FE052, 0x03B882E8, 0xE2103E30],
'XMC4500': [0xAEC000, 0x4F54292A, 0, 0x228F5930, 0x027A01E5, 0xDBF08030],
'GD32VF103': [0x1000, 0, 0, 0, 0, 0],
}
diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h
index c11c1eb05..dc4251c29 100644
--- a/src/portable/synopsys/dwc2/dwc2_stm32.h
+++ b/src/portable/synopsys/dwc2/dwc2_stm32.h
@@ -77,6 +77,17 @@ extern "C" {
#define EP_MAX_HS 9
#define EP_FIFO_SIZE_HS 4096
+#elif CFG_TUSB_MCU == OPT_MCU_STM32N6
+ #include "stm32n6xx.h"
+ #define EP_MAX_FS 9
+ #define EP_FIFO_SIZE_FS 4096
+
+ #define EP_MAX_HS 9
+ #define EP_FIFO_SIZE_HS 4096
+
+ #define USB_OTG_HS_PERIPH_BASE USB1_OTG_HS_BASE
+ #define OTG_HS_IRQn USB1_OTG_HS_IRQn
+
#elif CFG_TUSB_MCU == OPT_MCU_STM32F7
#include "stm32f7xx.h"
#define EP_MAX_FS 6
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 b13479b02..257fa2833 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);
@@ -372,6 +381,10 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
// force host mode and wait for mode switch
dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FDMOD) | GUSBCFG_FHMOD;
+#if CFG_TUSB_MCU == OPT_MCU_STM32N6
+ // No hardware detection of Vbus B-session is available on the STM32N6
+ dwc2->stm32_gccfg &= ~STM32_GCCFG_VBVALOVAL;
+#endif
while ((dwc2->gintsts & GINTSTS_CMOD) != GINTSTS_CMODE_HOST) {}
// configure fixed-allocated fifo scheme
@@ -381,7 +394,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 +474,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 +486,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 +495,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;
@@ -506,13 +519,19 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t*
return true;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
// 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.
@@ -520,9 +539,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;
@@ -535,7 +555,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;
@@ -548,13 +568,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) {
@@ -585,7 +608,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;
}
}
@@ -694,18 +717,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 {
@@ -714,18 +742,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
@@ -756,13 +790,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];
@@ -796,25 +830,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;
}
@@ -831,23 +866,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;
}
@@ -866,43 +904,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;
@@ -922,23 +961,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);
}
@@ -951,7 +996,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) {
@@ -968,9 +1013,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;
}
}
@@ -989,6 +1042,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;
@@ -996,8 +1052,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;
@@ -1007,13 +1063,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;
@@ -1028,33 +1085,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
@@ -1069,6 +1131,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;
@@ -1104,16 +1168,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;
}
}
@@ -1129,14 +1195,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
@@ -1144,7 +1210,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);
@@ -1156,7 +1222,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);
@@ -1165,8 +1231,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);
}
}
@@ -1177,6 +1243,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
static bool handle_sof_irq(uint8_t rhport, bool in_isr) {
(void) in_isr;
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+ dwc2->gintsts = GINTSTS_SOF; // Clear the SOF interrupt flag
bool more_isr = false;
@@ -1185,7 +1252,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)) {
@@ -1204,10 +1271,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;
@@ -1215,11 +1282,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) {
@@ -1236,9 +1303,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;
@@ -1251,21 +1318,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;
@@ -1324,6 +1389,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 d8bca196f..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
@@ -36,24 +37,19 @@
// optional hcd configuration, called by tuh_configure()
bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
- (void) rhport;
- (void) cfg_id;
- (void) cfg_param;
-
+ (void) rhport; (void) cfg_id; (void) cfg_param;
return false;
}
// Initialize controller to host mode
bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
- (void) rhport;
- (void) rh_init;
+ (void) rhport; (void) rh_init;
return false;
}
// Interrupt Handler
void hcd_int_handler(uint8_t rhport, bool in_isr) {
- (void) rhport;
- (void) in_isr;
+ (void) rhport; (void) in_isr;
}
// Enable USB interrupt
@@ -69,7 +65,6 @@ void hcd_int_disable(uint8_t rhport) {
// Get frame number (1ms)
uint32_t hcd_frame_number(uint8_t rhport) {
(void) rhport;
-
return 0;
}
@@ -80,7 +75,6 @@ uint32_t hcd_frame_number(uint8_t rhport) {
// Get the current connect status of roothub port
bool hcd_port_connect_status(uint8_t rhport) {
(void) rhport;
-
return false;
}
@@ -98,14 +92,12 @@ void hcd_port_reset_end(uint8_t rhport) {
// Get port link speed
tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
(void) rhport;
-
return TUSB_SPEED_FULL;
}
// HCD closes all opened endpoints belong to this device
void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
- (void) rhport;
- (void) dev_addr;
+ (void) rhport; (void) dev_addr;
}
//--------------------------------------------------------------------+
@@ -114,49 +106,42 @@ 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;
+ (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;
}
+bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ (void) rhport; (void) daddr; (void) ep_addr;
+ return false; // TODO not implemented yet
+}
+
// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked
bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) {
- (void) rhport;
- (void) dev_addr;
- (void) ep_addr;
- (void) buffer;
- (void) buflen;
-
+ (void) rhport; (void) dev_addr; (void) ep_addr; (void) buffer; (void) buflen;
return false;
}
// Abort a queued transfer. Note: it can only abort transfer that has not been started
// Return true if a queued transfer is aborted, false if there is no transfer to abort
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
- (void) rhport;
- (void) dev_addr;
- (void) ep_addr;
-
+ (void) rhport; (void) dev_addr; (void) ep_addr;
return false;
}
// Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) {
- (void) rhport;
- (void) dev_addr;
- (void) setup_packet;
-
+ (void) rhport; (void) dev_addr; (void) setup_packet;
return false;
}
// clear stall, data toggle is also reset to DATA0
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
- (void) rhport;
- (void) dev_addr;
- (void) ep_addr;
-
+ (void) rhport; (void) dev_addr; (void) ep_addr;
return false;
}
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 29fdcb0d6..867babc33 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
@@ -94,6 +94,7 @@
#define OPT_MCU_STM32U0 316 ///< ST U0
#define OPT_MCU_STM32H7RS 317 ///< ST F7RS
#define OPT_MCU_STM32C0 318 ///< ST C0
+#define OPT_MCU_STM32N6 319 ///< ST N6
// Sony
#define OPT_MCU_CXD56 400 ///< SONY CXD56
@@ -195,6 +196,7 @@
// Analog Devices
#define OPT_MCU_MAX32690 2400 ///< ADI MAX32690
+#define OPT_MCU_MAX32665 2401 ///< ADI MAX32666/5
#define OPT_MCU_MAX32666 2401 ///< ADI MAX32666/5
#define OPT_MCU_MAX32650 2402 ///< ADI MAX32650/1/2
#define OPT_MCU_MAX78002 2403 ///< ADI MAX78002
@@ -267,6 +269,15 @@
#define CFG_TUD_DWC2_DMA_ENABLE CFG_TUD_DWC2_DMA_ENABLE_DEFAULT
#endif
+// Enable CI_HS VBUS Charge. Set this to 1 if the USB_VBUS pin is not connected to 5V VBUS (note: 3.3V is insufficient).
+#ifndef CFG_TUD_CI_HS_VBUS_CHARGE
+ #ifndef CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT
+ #define CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT 0
+ #endif
+
+ #define CFG_TUD_CI_HS_VBUS_CHARGE CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT
+#endif
+
// Enable DWC2 Slave mode for host
#ifndef CFG_TUH_DWC2_SLAVE_ENABLE
#ifndef CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
@@ -591,9 +602,22 @@
// List of product IDs that can use the FTDI CDC driver. 0x0403 is FTDI's VID
#ifndef CFG_TUH_CDC_FTDI_VID_PID_LIST
#define CFG_TUH_CDC_FTDI_VID_PID_LIST \
- {0x0403, 0x6001}, {0x0403, 0x6006}, {0x0403, 0x6010}, {0x0403, 0x6011}, \
- {0x0403, 0x6014}, {0x0403, 0x6015}, {0x0403, 0x8372}, {0x0403, 0xFBFA}, \
- {0x0403, 0xCD18}
+ {0x0403, 0x6001}, /* Similar device to SIO above */ \
+ {0x0403, 0x6006}, /* FTDI's alternate PID for above */ \
+ {0x0403, 0x6010}, /* Dual channel device */ \
+ {0x0403, 0x6011}, /* Quad channel hi-speed device */ \
+ {0x0403, 0x6014}, /* Single channel hi-speed device */ \
+ {0x0403, 0x6015}, /* FT-X series (FT201X, FT230X, FT231X, etc) */ \
+ {0x0403, 0x6040}, /* Dual channel hi-speed device with PD */ \
+ {0x0403, 0x6041}, /* Quad channel hi-speed device with PD */ \
+ {0x0403, 0x6042}, /* Dual channel hi-speed device with PD */ \
+ {0x0403, 0x6043}, /* Quad channel hi-speed device with PD */ \
+ {0x0403, 0x6044}, /* Dual channel hi-speed device with PD */ \
+ {0x0403, 0x6045}, /* Dual channel hi-speed device with PD */ \
+ {0x0403, 0x6048}, /* Quad channel automotive grade hi-speed device */ \
+ {0x0403, 0x8372}, /* Product Id SIO application of 8U100AX */ \
+ {0x0403, 0xFBFA}, /* Product ID for FT232RL */ \
+ {0x0403, 0xCD18}, /* ??? */
#endif
// CP210X is not part of CDC class, only to re-use CDC driver API
@@ -604,7 +628,9 @@
// List of product IDs that can use the CP210X CDC driver. 0x10C4 is Silicon Labs' VID
#ifndef CFG_TUH_CDC_CP210X_VID_PID_LIST
#define CFG_TUH_CDC_CP210X_VID_PID_LIST \
- {0x10C4, 0xEA60}, {0x10C4, 0xEA70}
+ { 0x10C4, 0xEA60 }, /* Silicon Labs factory default */ \
+ { 0x10C4, 0xEA61 }, /* Silicon Labs factory default */ \
+ { 0x10C4, 0xEA70 } /* Silicon Labs Dual Port factory default */
#endif
#ifndef CFG_TUH_CDC_CH34X
@@ -624,6 +650,24 @@
{ 0x9986, 0x7523 } /* overtaken from Linux Kernel driver /drivers/usb/serial/ch341.c */
#endif
+#ifndef CFG_TUH_CDC_PL2303
+ // PL2303 is not part of CDC class, only to re-use CDC driver API
+ #define CFG_TUH_CDC_PL2303 0
+#endif
+
+#ifndef CFG_TUH_CDC_PL2303_VID_PID_QUIRKS_LIST
+ // List of product IDs that can use the PL2303 CDC driver
+ #define CFG_TUH_CDC_PL2303_VID_PID_LIST \
+ { 0x067b, 0x2303 }, /* initial 2303 */ \
+ { 0x067b, 0x2304 }, /* TB */ \
+ { 0x067b, 0x23a3 }, /* GC */ \
+ { 0x067b, 0x23b3 }, /* GB */ \
+ { 0x067b, 0x23c3 }, /* GT */ \
+ { 0x067b, 0x23d3 }, /* GL */ \
+ { 0x067b, 0x23e3 }, /* GE */ \
+ { 0x067b, 0x23f3 } /* GS */
+#endif
+
#ifndef CFG_TUH_HID
#define CFG_TUH_HID 0
#endif
diff --git a/test/fuzz/device/net/Makefile b/test/fuzz/device/net/Makefile
index 4e99604ad..2161ad3f1 100644
--- a/test/fuzz/device/net/Makefile
+++ b/test/fuzz/device/net/Makefile
@@ -1,5 +1,3 @@
-DEPS_SUBMODULES += lib/lwip
-
include ../../make.mk
# suppress warning caused by lwip
diff --git a/test/fuzz/make.mk b/test/fuzz/make.mk
index b7b6d6a75..e9aa80bf1 100644
--- a/test/fuzz/make.mk
+++ b/test/fuzz/make.mk
@@ -124,11 +124,5 @@ endif
# Log level is mapped to TUSB DEBUG option
ifneq ($(LOG),)
- CMAKE_DEFSYM += -DLOG=$(LOG)
CFLAGS += -DCFG_TUSB_DEBUG=$(LOG)
endif
-
-# Logger: default is uart, can be set to rtt or swo
-ifneq ($(LOGGER),)
- CMAKE_DEFSYM += -DLOGGER=$(LOGGER)
-endif
diff --git a/test/fuzz/rules.mk b/test/fuzz/rules.mk
index ee91c706d..562969663 100644
--- a/test/fuzz/rules.mk
+++ b/test/fuzz/rules.mk
@@ -142,7 +142,7 @@ endif
# get depenecies
.PHONY: get-deps
get-deps:
- $(PYTHON) $(TOP)/tools/get_deps.py $(DEPS_SUBMODULES)
+ $(PYTHON) $(TOP)/tools/get_deps.py $(FAMILY)
size: $(BUILD)/$(PROJECT)
-@echo ''
diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py
index a9f5dc1e1..f292bca15 100755
--- a/test/hil/hil_test.py
+++ b/test/hil/hil_test.py
@@ -81,7 +81,7 @@ def get_serial_dev(id, vendor_str, product_str, ifnum):
return f'/dev/serial/by-id/usb-{vendor_str}_{product_str}_{id}-if{ifnum:02d}'
else:
# just use id: mostly for cp210x/ftdi flasher
- pattern = f'/dev/serial/by-id/usb-*_{id}-if{ifnum:02d}*'
+ pattern = f'/dev/serial/by-id/usb-*_{id}-if*'
port_list = glob.glob(pattern)
return port_list[0]
@@ -98,20 +98,18 @@ def get_hid_dev(id, vendor_str, product_str, event):
def open_serial_dev(port):
timeout = ENUM_TIMEOUT
ser = None
- while timeout:
+ while timeout > 0:
if os.path.exists(port):
try:
- # slight delay since kernel may occupy the port briefly
- time.sleep(0.5)
- timeout = timeout - 0.5
ser = serial.Serial(port, baudrate=115200, timeout=5)
break
except serial.SerialException:
+ print(f'serial {port} not reaady {timeout} sec')
pass
- time.sleep(0.5)
- timeout = timeout - 0.5
+ time.sleep(0.1)
+ timeout -= 0.1
- assert timeout, f'Cannot open port f{port}' if os.path.exists(port) else f'Port {port} not existed'
+ assert timeout > 0, f'Cannot open port f{port}' if os.path.exists(port) else f'Port {port} not existed'
return ser
@@ -119,7 +117,7 @@ def read_disk_file(uid, lun, fname):
# open_fs("fat://{dev}) require 'pip install pyfatfs'
dev = get_disk_dev(uid, 'TinyUSB', lun)
timeout = ENUM_TIMEOUT
- while timeout:
+ while timeout > 0:
if os.path.exists(dev):
fat = fs.open_fs(f'fat://{dev}?read_only=true')
try:
@@ -132,7 +130,7 @@ def read_disk_file(uid, lun, fname):
time.sleep(1)
timeout -= 1
- assert timeout, f'Storage {dev} not existed'
+ assert timeout > 0, f'Storage {dev} not existed'
return None
@@ -202,14 +200,14 @@ def reset_stflash(board):
def flash_openocd(board, firmware):
flasher = board['flasher']
ret = run_cmd(f'openocd -c "tcl_port disabled" -c "gdb_port disabled" -c "adapter serial {flasher["uid"]}" '
- f'{flasher["args"]} -c init -c halt -c "program {firmware}.elf verify" -c reset -c exit')
+ f'{flasher["args"]} -c "init; halt; program {firmware}.elf verify; reset; exit"')
return ret
def reset_openocd(board):
flasher = board['flasher']
ret = run_cmd(f'openocd -c "tcl_port disabled" -c "gdb_port disabled" -c "adapter serial {flasher["uid"]}" '
- f'{flasher["args"]} -c "reset exit"')
+ f'{flasher["args"]} -c "init; reset run; exit"')
return ret
@@ -304,11 +302,11 @@ def test_dual_host_info_to_device_cdc(board):
ser = open_serial_dev(port)
# read from cdc, first line should contain vid/pid and serial
- data = ser.read(1000)
+ data = ser.read(10000)
ser.close()
if len(data) == 0:
assert False, 'No data from device'
- lines = data.decode('utf-8').splitlines()
+ lines = data.decode('utf-8', errors='ignore').splitlines()
enum_dev_sn = []
for l in lines:
@@ -319,6 +317,7 @@ def test_dual_host_info_to_device_cdc(board):
if set(declared_devs) != set(enum_dev_sn):
failed_msg = f'Expected {declared_devs}, Enumerated {enum_dev_sn}'
+ print('\n'.join(lines))
assert False, failed_msg
return 0
@@ -337,12 +336,12 @@ def test_host_device_info(board):
ret = globals()[f'reset_{flasher["name"].lower()}'](board)
assert ret.returncode == 0, 'Failed to reset device'
- data = ser.read(1000)
+ data = ser.read(10000)
ser.close()
if len(data) == 0:
assert False, 'No data from device'
+ lines = data.decode('utf-8', errors='ignore').splitlines()
- lines = data.decode('utf-8').splitlines()
enum_dev_sn = []
for l in lines:
vid_pid_sn = re.search(r'ID ([0-9a-fA-F]+):([0-9a-fA-F]+) SN (\w+)', l)
@@ -352,8 +351,8 @@ def test_host_device_info(board):
if set(declared_devs) != set(enum_dev_sn):
failed_msg = f'Expected {declared_devs}, Enumerated {enum_dev_sn}'
+ print('\n'.join(lines))
assert False, failed_msg
-
return 0
@@ -419,7 +418,7 @@ def test_device_dfu(board):
# Wait device enum
timeout = ENUM_TIMEOUT
- while timeout:
+ while timeout > 0:
ret = run_cmd(f'dfu-util -l')
stdout = ret.stdout.decode()
if f'serial="{uid}"' in stdout and 'Found DFU: [cafe:4000]' in stdout:
@@ -427,7 +426,7 @@ def test_device_dfu(board):
time.sleep(1)
timeout = timeout - 1
- assert timeout, 'Device not available'
+ assert timeout > 0, 'Device not available'
f_dfu0 = f'dfu0_{uid}'
f_dfu1 = f'dfu1_{uid}'
@@ -460,7 +459,7 @@ def test_device_dfu_runtime(board):
# Wait device enum
timeout = ENUM_TIMEOUT
- while timeout:
+ while timeout > 0:
ret = run_cmd(f'dfu-util -l')
stdout = ret.stdout.decode()
if f'serial="{uid}"' in stdout and 'Found Runtime: [cafe:4000]' in stdout:
@@ -468,7 +467,7 @@ def test_device_dfu_runtime(board):
time.sleep(1)
timeout = timeout - 1
- assert timeout, 'Device not available'
+ assert timeout > 0, 'Device not available'
def test_device_hid_boot_interface(board):
@@ -478,13 +477,13 @@ def test_device_hid_boot_interface(board):
mouse2 = get_hid_dev(uid, 'TinyUSB', 'TinyUSB_Device', 'if01-mouse')
# Wait device enum
timeout = ENUM_TIMEOUT
- while timeout:
+ while timeout > 0:
if os.path.exists(kbd) and os.path.exists(mouse1) and os.path.exists(mouse2):
break
time.sleep(1)
timeout = timeout - 1
- assert timeout, 'HID device not available'
+ assert timeout > 0, 'HID device not available'
def test_device_hid_composite_freertos(id):
@@ -515,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']
@@ -538,54 +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
-
- # 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+1}')
- time.sleep(1)
- else:
- print(f'Flashing failed, retry {i+1}')
- 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 7393226eb..11b118cea 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",
@@ -44,23 +46,11 @@
"args": "-device nrf52840_xxaa"
}
},
- {
- "name": "max32666fthr",
- "uid": "0C81464124010B20FF0A08CC2C",
- "tests": {
- "device": true, "host": false, "dual": false
- },
- "flasher": {
- "name": "openocd_adi",
- "uid": "E6614C311B597D32",
- "args": "-f interface/cmsis-dap.cfg -f target/max32665.cfg"
- }
- },
{
"name": "metro_m4_express",
"uid": "9995AD485337433231202020FF100A34",
"tests": {
- "device": true, "host": false, "dual": false,
+ "device": true, "host": false, "dual": true,
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002130"}]
},
"flasher": {
@@ -69,6 +59,19 @@
"args": "-device ATSAMD51J19"
}
},
+ {
+ "name": "mimxrt1064_evk",
+ "uid": "BAE96FB95AFA6DBB8F00005002001200",
+ "tests": {
+ "device": true, "host": true, "dual": true,
+ "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023299"}]
+ },
+ "flasher": {
+ "name": "jlink",
+ "uid": "000725299165",
+ "args": "-device MIMXRT1064xxx6A"
+ }
+ },
{
"name": "lpcxpresso11u37",
"uid": "17121919",
@@ -98,8 +101,11 @@
{
"name": "raspberry_pi_pico",
"uid": "E6614C311B764A37",
+ "build" : {
+ "flags_on": ["CFG_TUH_RPI_PIO_USB"]
+ },
"tests": {
- "device": true, "host": false, "dual": false,
+ "device": true, "host": true, "dual": true,
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002470"}]
},
"flasher": {
@@ -108,11 +114,28 @@
"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",
+ "build" : {
+ "flags_on": ["CFG_TUH_RPI_PIO_USB"]
+ },
"tests": {
- "device": true, "host": false, "dual": false,
+ "device": true, "host": true, "dual": true,
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "533D004242"}]
},
"flasher": {
@@ -157,9 +180,9 @@
"device": true, "host": false, "dual": false
},
"flasher": {
- "name": "stlink",
+ "name": "openocd",
"uid": "004C00343137510F39383538",
- "args": ""
+ "args": "-f interface/stlink.cfg -f target/stm32h7x.cfg"
}
},
{
@@ -176,6 +199,18 @@
}
],
"boards-skip": [
+ {
+ "name": "max32666fthr",
+ "uid": "0C81464124010B20FF0A08CC2C",
+ "tests": {
+ "device": true, "host": false, "dual": false
+ },
+ "flasher": {
+ "name": "openocd_adi",
+ "uid": "E6614C311B597D32",
+ "args": "-f interface/cmsis-dap.cfg -f target/max32665.cfg"
+ }
+ },
{
"name": "stm32f769disco",
"uid": "21002F000F51363531383437",
diff --git a/tools/build.py b/tools/build.py
index 633d2b582..f639fba81 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -23,6 +23,7 @@ build_separator = '-' * 95
build_status = [STATUS_OK, STATUS_FAILED, STATUS_SKIPPED]
verbose = False
+parallel_jobs = os.cpu_count()
# -----------------------------
# Helper
@@ -100,23 +101,25 @@ def cmake_board(board, toolchain, build_flags_on):
if build_utils.skip_example(example, board):
ret[2] += 1
else:
- rcmd = run_cmd(f'cmake examples/{example} -B {build_dir}/{example} -G "Ninja" '
- f'-DBOARD={board} {build_flags}')
- if rcmd.returncode == 0:
- rcmd = run_cmd(f'cmake --build {build_dir}/{example}')
+ rcmd = run_cmd(f'idf.py -C examples/{example} -B {build_dir}/{example} -G Ninja '
+ f'-DBOARD={board} {build_flags} build')
ret[0 if rcmd.returncode == 0 else 1] += 1
else:
- rcmd = run_cmd(f'cmake examples -B {build_dir} -G "Ninja" -DBOARD={board} -DCMAKE_BUILD_TYPE=MinSizeRel '
+ rcmd = run_cmd(f'cmake examples -B {build_dir} -G Ninja -DBOARD={board} -DCMAKE_BUILD_TYPE=MinSizeRel '
f'-DTOOLCHAIN={toolchain} {build_flags}')
if rcmd.returncode == 0:
cmd = f"cmake --build {build_dir}"
- # circleci docker return $nproc as 36 core, limit parallel according to resource class. Required for IAR, also prevent crashed/killed by docker
+ njobs = parallel_jobs
+
+ # circleci docker return $nproc as 36 core, limit parallel according to resource class.
+ # Required for IAR, also prevent crashed/killed by docker
if os.getenv('CIRCLECI'):
resource_class = { 'small': 1, 'medium': 2, 'medium+': 3, 'large': 4 }
for rc in resource_class:
if rc in os.getenv('CIRCLE_JOB'):
- cmd += f' --parallel {resource_class[rc]}'
+ njobs = resource_class[rc]
break
+ cmd += f' --parallel {njobs}'
rcmd = run_cmd(cmd)
ret[0 if rcmd.returncode == 0 else 1] += 1
@@ -151,16 +154,21 @@ def make_one_example(example, board, make_option):
def make_board(board, toolchain):
print(build_separator)
- all_examples = get_examples(find_family(board))
+ family = find_family(board);
+ all_examples = get_examples(family)
start_time = time.monotonic()
ret = [0, 0, 0]
- with Pool(processes=os.cpu_count()) as pool:
- pool_args = list((map(lambda e, b=board, o=f"TOOLCHAIN={toolchain}": [e, b, o], all_examples)))
- r = pool.starmap(make_one_example, pool_args)
- # sum all element of same index (column sum)
- ret = list(map(sum, list(zip(*r))))
- example = 'all'
- print_build_result(board, example, 0 if ret[1] == 0 else 1, time.monotonic() - start_time)
+ if family == 'espressif' or family == 'rp2040':
+ # espressif and rp2040 do not support make, use cmake instead
+ final_status = 2
+ else:
+ with Pool(processes=os.cpu_count()) as pool:
+ pool_args = list((map(lambda e, b=board, o=f"TOOLCHAIN={toolchain}": [e, b, o], all_examples)))
+ r = pool.starmap(make_one_example, pool_args)
+ # sum all element of same index (column sum)
+ ret = list(map(sum, list(zip(*r))))
+ final_status = 0 if ret[1] == 0 else 1
+ print_build_result(board, 'all', final_status, time.monotonic() - start_time)
return ret
@@ -182,9 +190,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()
@@ -206,6 +219,7 @@ def build_family(family, toolchain, build_system, build_flags_on, one_per_family
# -----------------------------
def main():
global verbose
+ global parallel_jobs
parser = argparse.ArgumentParser()
parser.add_argument('families', nargs='*', default=[], help='Families to build')
@@ -214,6 +228,7 @@ def main():
parser.add_argument('-s', '--build-system', default='cmake', help='Build system to use, default is cmake')
parser.add_argument('-f1', '--build-flags-on', action='append', default=[], help='Build flag to pass to build system')
parser.add_argument('-1', '--one-per-family', action='store_true', default=False, help='Build only one random board inside a family')
+ parser.add_argument('-j', '--jobs', type=int, default=os.cpu_count(), help='Number of jobs to run in parallel')
parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
args = parser.parse_args()
@@ -224,6 +239,7 @@ def main():
build_flags_on = args.build_flags_on
one_per_family = args.one_per_family
verbose = args.verbose
+ parallel_jobs = args.jobs
if len(families) == 0 and len(boards) == 0:
print("Please specify families or board to build")
diff --git a/tools/build_utils.py b/tools/build_utils.py
index 2998f940d..d80ceea7c 100755
--- a/tools/build_utils.py
+++ b/tools/build_utils.py
@@ -26,6 +26,8 @@ def skip_example(example, board):
# family.mk
family_mk = family_dir / "family.mk"
+ if not family_mk.exists():
+ family_mk = family_dir / "family.cmake"
mk_contents = family_mk.read_text()
# Find the mcu, first in family mk then board mk
diff --git a/tools/get_deps.py b/tools/get_deps.py
index b82abac4f..6a36ef35d 100755
--- a/tools/get_deps.py
+++ b/tools/get_deps.py
@@ -25,9 +25,9 @@ deps_optional = {
'hw/mcu/allwinner': ['https://github.com/hathach/allwinner_driver.git',
'8e5e89e8e132c0fd90e72d5422e5d3d68232b756',
'fc100s'],
- 'hw/mcu/analog/max32' : ['https://github.com/analogdevicesinc/msdk.git',
+ 'hw/mcu/analog/msdk' : ['https://github.com/analogdevicesinc/msdk.git',
'b20b398d3e5e2007594e54a74ba3d2a2e50ddd75',
- 'max32650 max32666 max32690 max78002'],
+ 'maxim'],
'hw/mcu/bridgetek/ft9xx/ft90x-sdk': ['https://github.com/BRTSG-FOSS/ft90x-sdk.git',
'91060164afe239fcb394122e8bf9eb24d3194eb1',
'brtmm90x'],
@@ -55,11 +55,11 @@ deps_optional = {
'hw/mcu/nxp/lpcopen': ['https://github.com/hathach/nxp_lpcopen.git',
'b41cf930e65c734d8ec6de04f1d57d46787c76ae',
'lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43'],
- 'hw/mcu/nxp/mcux-sdk': ['https://github.com/hathach/mcux-sdk.git',
- '144f1eb7ea8c06512e12f12b27383601c0272410',
+ 'hw/mcu/nxp/mcux-sdk': ['https://github.com/nxp-mcuxpresso/mcux-sdk',
+ 'a1bdae309a14ec95a4f64a96d3315a4f89c397c6',
'kinetis_k kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx imxrt'],
- 'hw/mcu/raspberry_pi/Pico-PIO-USB': ['https://github.com/hathach/Pico-PIO-USB.git',
- '9c8df3083b62c0a678f3bd3d8a7e773932622d4b',
+ 'hw/mcu/raspberry_pi/Pico-PIO-USB': ['https://github.com/sekigon-gonnoc/Pico-PIO-USB.git',
+ '3c1eec341a5232640e4c00628b889b641af34b28',
'rp2040'],
'hw/mcu/renesas/fsp': ['https://github.com/renesas/fsp.git',
'edcc97d684b6f716728a60d7a6fea049d9870bd6',
@@ -103,6 +103,9 @@ deps_optional = {
'hw/mcu/st/cmsis_device_h7': ['https://github.com/STMicroelectronics/cmsis_device_h7.git',
'60dc2c913203dc8629dc233d4384dcc41c91e77f',
'stm32h7'],
+ 'hw/mcu/st/cmsis_device_h7rs': ['https://github.com/STMicroelectronics/cmsis_device_h7rs.git',
+ '832649d1fd09bd901e9f68e979522e5c209ebf20',
+ 'stm32h7rs'],
'hw/mcu/st/cmsis_device_h5': ['https://github.com/STMicroelectronics/cmsis_device_h5.git',
'cd2d1d579743de57b88ccaf61a968b9c05848ffc',
'stm32h5'],
@@ -118,15 +121,21 @@ deps_optional = {
'hw/mcu/st/cmsis_device_l5': ['https://github.com/STMicroelectronics/cmsis_device_l5.git',
'd922865fc0326a102c26211c44b8e42f52c1e53d',
'stm32l5'],
+ 'hw/mcu/st/cmsis_device_n6': ['https://github.com/STMicroelectronics/cmsis-device-n6.git',
+ 'f818b00f775444e8d19ef6cad822534c345e054f',
+ 'stm32n6'],
'hw/mcu/st/cmsis_device_u5': ['https://github.com/STMicroelectronics/cmsis_device_u5.git',
'5ad9797c54ec3e55eff770fc9b3cd4a1aefc1309',
'stm32u5'],
'hw/mcu/st/cmsis_device_wb': ['https://github.com/STMicroelectronics/cmsis_device_wb.git',
- '9c5d1920dd9fabbe2548e10561d63db829bb744f',
+ 'd6a7fa2e7de084f5e5e47f2ab88b022fe9b50e5a',
'stm32wb'],
'hw/mcu/st/stm32-mfxstm32l152': ['https://github.com/STMicroelectronics/stm32-mfxstm32l152.git',
'7f4389efee9c6a655b55e5df3fceef5586b35f9b',
'stm32h7'],
+ 'hw/mcu/st/stm32-tcpp0203': ['https://github.com/STMicroelectronics/stm32-tcpp0203.git',
+ '9918655bff176ac3046ccf378b5c7bbbc6a38d15',
+ 'stm32h7rs stm32n6'],
'hw/mcu/st/stm32c0xx_hal_driver': ['https://github.com/STMicroelectronics/stm32c0xx_hal_driver.git',
'41253e2f1d7ae4a4d0c379cf63f5bcf71fcf8eb3',
'stm32c0'],
@@ -157,6 +166,9 @@ deps_optional = {
'hw/mcu/st/stm32h7xx_hal_driver': ['https://github.com/STMicroelectronics/stm32h7xx_hal_driver.git',
'd8461b980b59b1625207d8c4f2ce0a9c2a7a3b04',
'stm32h7'],
+ 'hw/mcu/st/stm32h7rsxx_hal_driver': ['https://github.com/STMicroelectronics/stm32h7rsxx-hal-driver.git',
+ '7ca2e07ca21bc66b53654e845b4c85c884343b60',
+ 'stm32h7rs'],
'hw/mcu/st/stm32h5xx_hal_driver': ['https://github.com/STMicroelectronics/stm32h5xx_hal_driver.git',
'2cf77de584196d619cec1b4586c3b9e2820a254e',
'stm32h5'],
@@ -172,6 +184,9 @@ deps_optional = {
'hw/mcu/st/stm32l5xx_hal_driver': ['https://github.com/STMicroelectronics/stm32l5xx_hal_driver.git',
'675c32a75df37f39d50d61f51cb0dcf53f07e1cb',
'stm32l5'],
+ 'hw/mcu/st/stm32n6xx_hal_driver': ['https://github.com/STMicroelectronics/stm32n6xx-hal-driver.git',
+ '49f9989d10cf6817d4b07ac01848956b46bd0fd6',
+ 'stm32n6'],
'hw/mcu/st/stm32u5xx_hal_driver': ['https://github.com/STMicroelectronics/stm32u5xx_hal_driver.git',
'4d93097a67928e9377e655ddd14622adc31b9770',
'stm32u5'],
@@ -198,7 +213,7 @@ deps_optional = {
'imxrt kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx mm32 msp432e4 nrf saml2x '
'lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43 '
'stm32c0 stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32g0 stm32g4 stm32h5 '
- 'stm32h7 stm32l0 stm32l1 stm32l4 stm32l5 stm32u5 stm32wb '
+ 'stm32h7 stm32h7rs stm32l0 stm32l1 stm32l4 stm32l5 stm32n6 stm32u5 stm32wb '
'sam3x samd11 samd21 samd51 samd5x_e5x same5x same7x saml2x samg '
'tm4c '],
'lib/CMSIS_6': ['https://github.com/ARM-software/CMSIS_6.git',
@@ -243,11 +258,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")