Merge branch 'master' into h7rs

This commit is contained in:
HiFiPhile
2025-05-15 21:40:36 +02:00
95 changed files with 2150 additions and 1945 deletions

View File

@@ -20,12 +20,12 @@ jobs:
BUILDSYSTEM_TOOLCHAIN=(
"cmake arm-clang"
"cmake esp-idf"
"make aarch64-gcc"
"make arm-gcc"
"make msp430-gcc"
"make riscv-gcc"
"make rx-gcc"
"cmake esp-idf"
)
# only build IAR if not forked PR, since IAR token is not shared

View File

@@ -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"

View File

@@ -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:

View File

@@ -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: |
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

View File

@@ -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"
}

View File

@@ -8,8 +8,8 @@ on:
- 'examples/**'
- 'lib/**'
- 'hw/**'
- 'tools/get_deps.py'
- 'tools/build.py'
- 'tools/get_deps.py'
- '.github/actions/**'
- '.github/workflows/build.yml'
- '.github/workflows/build_util.yml'
@@ -21,8 +21,9 @@ on:
- 'examples/**'
- 'lib/**'
- 'hw/**'
- 'tools/get_deps.py'
- 'test/hil/**'
- 'tools/build.py'
- 'tools/get_deps.py'
- '.github/actions/**'
- '.github/workflows/build.yml'
- '.github/workflows/build_util.yml'
@@ -31,11 +32,20 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
HIL_JSON: test/hil/tinyusb.json
jobs:
# ---------------------------------------
#
# Build
#
# ---------------------------------------
set-matrix:
runs-on: ubuntu-latest
outputs:
json: ${{ steps.set-matrix-json.outputs.matrix }}
hil_json: ${{ steps.set-matrix-json.outputs.hil_matrix }}
steps:
- name: Checkout TinyUSB
uses: actions/checkout@v4
@@ -43,9 +53,14 @@ jobs:
- name: Generate matrix json
id: set-matrix-json
run: |
# build matrix
MATRIX_JSON=$(python .github/workflows/ci_set_matrix.py)
echo "matrix=$MATRIX_JSON"
echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT
# hil matrix
HIL_MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py ${{ env.HIL_JSON }})
echo "hil_matrix=$HIL_MATRIX_JSON"
echo "hil_matrix=$HIL_MATRIX_JSON" >> $GITHUB_OUTPUT
# ---------------------------------------
# Build CMake
@@ -85,7 +100,7 @@ jobs:
- 'msp430-gcc'
- 'riscv-gcc'
- 'rx-gcc'
- 'esp-idf' # build-system is ignored
- 'esp-idf'
with:
build-system: 'make'
toolchain: ${{ matrix.toolchain }}
@@ -110,37 +125,26 @@ jobs:
one-per-family: true
# ---------------------------------------
# Build IAR on HFP self-hosted
# Since IAR Token secret is not passed to forked PR, only build on PR from the same repo
# Build IAR
# Since IAR Token secret is not passed to forked PR, only build non-forked PR with make.
# cmake is built by circle-ci. Due to IAR limit capacity, only build oe per family
# ---------------------------------------
arm-iar:
if: github.repository_owner == 'hathach' && github.event_name == 'push'
if: false # disable for now since we got reach capacity limit too often
#if: github.event_name == 'push' && github.repository_owner == 'hathach'
needs: set-matrix
runs-on: [self-hosted, Linux, X64, hifiphile]
env:
BUILD_ARGS: ${{ join(fromJSON(needs.set-matrix.outputs.json)['arm-iar'], ' ') }}
IAR_LMS_CLOUD_URL: ${{ vars.IAR_LMS_CLOUD_URL }}
IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }}
steps:
- name: Clean workspace
run: |
echo "Cleaning up previous run"
rm -rf "${{ github.workspace }}"
mkdir -p "${{ github.workspace }}"
- name: Toolchain version
run: |
echo IAR_LMS_CLOUD_URL=$IAR_LMS_CLOUD_URL
iccarm --version
- name: Checkout TinyUSB
uses: actions/checkout@v4
- name: Get Dependencies
run: python3 tools/get_deps.py $BUILD_ARGS
- name: Build
run: python3 tools/build.py --one-per-family --toolchain iar $BUILD_ARGS
uses: ./.github/workflows/build_util.yml
secrets: inherit
strategy:
fail-fast: false
matrix:
build-system:
- 'make'
with:
build-system: ${{ matrix.build-system }}
toolchain: 'arm-iar'
build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)['arm-iar']) }}
one-per-family: true
# ---------------------------------------
# Zephyr
@@ -162,3 +166,107 @@ jobs:
run: |
west build -b pca10056 -d examples/device/cdc_msc/build examples/device/cdc_msc -- -DRTOS=zephyr
west build -b pca10056 -d examples/device/msc_dual_lun/build examples/device/msc_dual_lun -- -DRTOS=zephyr
# ---------------------------------------
#
# Hardware in the loop (HIL)
# Run on PR only (hil-tinyusb), hil-hfp only run on non-forked PR
# ---------------------------------------
# ---------------------------------------
# Build arm-gcc
# ---------------------------------------
hil-build:
if: |
github.repository_owner == 'hathach' &&
(github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch')
needs: set-matrix
uses: ./.github/workflows/build_util.yml
strategy:
fail-fast: false
matrix:
toolchain:
- 'arm-gcc'
- 'esp-idf'
with:
build-system: 'cmake'
toolchain: ${{ matrix.toolchain }}
build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.hil_json)[matrix.toolchain]) }}
one-per-family: true
upload-artifacts: true
# ---------------------------------------
# Hardware in the loop (HIL)
# self-hosted on local VM, for attached hardware checkout HIL_JSON
# ---------------------------------------
hil-tinyusb:
if: |
github.repository_owner == 'hathach' &&
(github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch')
needs: hil-build
runs-on: [self-hosted, X64, hathach, hardware-in-the-loop]
steps:
- name: Clean workspace
run: |
echo "Cleaning up previous run"
rm -rf "${{ github.workspace }}"
mkdir -p "${{ github.workspace }}"
- name: Checkout TinyUSB
uses: actions/checkout@v4
with:
sparse-checkout: test/hil
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
path: cmake-build
merge-multiple: true
- name: Test on actual hardware
run: |
ls cmake-build/
python3 test/hil/hil_test.py ${{ env.HIL_JSON }}
# ---------------------------------------
# Hardware in the loop (HIL)
# self-hosted by HFP, build with IAR toolchain, for attached hardware checkout test/hil/hfp.json
# Since IAR Token secret is not passed to forked PR, only build non-forked PR
# ---------------------------------------
hil-hfp:
if: |
github.repository_owner == 'hathach' &&
github.event.pull_request.head.repo.fork == false &&
(github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch')
runs-on: [self-hosted, Linux, X64, hifiphile]
env:
IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }}
steps:
- name: Clean workspace
run: |
echo "Cleaning up previous run"
rm -rf "${{ github.workspace }}"3
mkdir -p "${{ github.workspace }}"
- name: Toolchain version
run: |
iccarm --version
- name: Checkout TinyUSB
uses: actions/checkout@v4
- name: Get build boards
run: |
MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py test/hil/hfp.json)
BUILD_ARGS=$(echo $MATRIX_JSON | jq -r '.["arm-gcc"] | join(" ")')
echo "BUILD_ARGS=$BUILD_ARGS"
echo "BUILD_ARGS=$BUILD_ARGS" >> $GITHUB_ENV
- name: Get Dependencies
run: python3 tools/get_deps.py $BUILD_ARGS
- name: Build
run: python3 tools/build.py --toolchain iar $BUILD_ARGS
- name: Test on actual hardware (hardware in the loop)
run: python3 test/hil/hil_test.py hfp.json

View File

@@ -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 }}

View File

@@ -44,9 +44,10 @@ family_list = {
"stm32l0 stm32l4": ["arm-gcc", "arm-clang", "arm-iar"],
"stm32u5 stm32wb": ["arm-gcc", "arm-clang", "arm-iar"],
"xmc4000": ["arm-gcc"],
"-bespressif_kaluga_1": ["esp-idf"],
"-bespressif_s3_devkitm": ["esp-idf"],
"-bespressif_p4_function_ev": ["esp-idf"],
"-bespressif_s2_devkitc": ["esp-idf"],
# S3, P4 will be built by hil test
# "-bespressif_s3_devkitm": ["esp-idf"],
# "-bespressif_p4_function_ev": ["esp-idf"],
}

View File

@@ -66,7 +66,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -93,7 +93,7 @@ jobs:
./.github/workflows/codeql-buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
upload: false
@@ -129,7 +129,7 @@ jobs:
sarif_file: ${{ steps.step1.outputs.sarif-output }}
category: "/language:${{matrix.language}}"
- name: Archive CodeQL results
- name: Upload CodeQL results as an artifact
uses: actions/upload-artifact@v4
with:
name: codeql-results

View File

@@ -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

10
.idea/cmake.xml generated
View File

@@ -6,13 +6,13 @@
<configuration PROFILE_NAME="raspberrypi_zero2" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=raspberrypi_zero2 -DLOG=1" />
<configuration PROFILE_NAME="raspberrypi_cm4" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=raspberrypi_cm4 -DLOG=1" />
<configuration PROFILE_NAME="raspberry_pi_pico" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=raspberry_pi_pico -DLOG=1" />
<configuration PROFILE_NAME="raspberry_pi_pico2" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=raspberry_pi_pico2 -DLOG=1" />
<configuration PROFILE_NAME="raspberry_pi_pico2_riscv" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=raspberry_pi_pico2_riscv -DLOG=1" />
<configuration PROFILE_NAME="raspberry_pi_pico-pio_host" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=raspberry_pi_pico -DLOG=1 -DCFLAGS_CLI=&quot;-DCFG_TUH_RPI_PIO_USB=1&quot;" />
<configuration PROFILE_NAME="raspberry_pi_pico2" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=raspberry_pi_pico2 -DLOG=1" />
<configuration PROFILE_NAME="raspberry_pi_pico2-pio_host" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=raspberry_pi_pico2 -DLOG=1 -DCFLAGS_CLI=&quot;-DCFG_TUH_RPI_PIO_USB=1&quot;" />
<configuration PROFILE_NAME="feather_rp2040" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=pico_sdk -DPICO_BOARD=adafruit_feather_rp2040 -DLOG=1" />
<configuration PROFILE_NAME="feather_rp2040_max3421" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=feather_rp2040_max3421 -DLOG=1" />
<configuration PROFILE_NAME="metro_rp2040" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=pico_sdk -DPICO_BOARD=adafruit_metro_rp2040 -DLOG=1 -DMAX3421_HOST=1" />
<configuration PROFILE_NAME="adafruit_metro_rp2350" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=adafruit_metro_rp2350 -DLOG=1" />
<configuration PROFILE_NAME="adafruit_metro_rp2350" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=adafruit_metro_rp2350 -DLOG=1 -DCFLAGS_CLI=&quot;-DCFG_TUH_RPI_PIO_USB=1&quot;" />
<configuration PROFILE_NAME="adafruit_fruit_jam" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=adafruit_fruit_jam -DLOG=1 -DCFLAGS_CLI=&quot;-DCFG_TUH_RPI_PIO_USB=1&quot;" />
<configuration PROFILE_NAME="adafruit_feather_esp32_v2" ENABLED="false" TOOLCHAIN_NAME="ESP-IDF" GENERATION_OPTIONS="-DBOARD=adafruit_feather_esp32_v2 -DMAX3421_HOST=1 -DLOG=1">
<ADDITIONAL_GENERATION_ENVIRONMENT>
@@ -94,7 +94,8 @@
<configuration PROFILE_NAME="metro m7 1011 sd" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m7_1011_sd -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" />
<configuration PROFILE_NAME="metro_m7_1011" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m7_1011 -DLOG=1 -DLOGGER=RTT" />
<configuration PROFILE_NAME="rt1010 evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1010_evk -DLOG=1 -DLOGGER=RTT" />
<configuration PROFILE_NAME="mimxrt1060_evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1060_evk -DLOG=1 -DLOGGER=RTT" />
<configuration PROFILE_NAME="mimxrt1060_evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1060_evk -DLOG=1" />
<configuration PROFILE_NAME="mimxrt1064_evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1064_evk" />
<configuration PROFILE_NAME="rt1170 evkb" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1170_evkb -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" />
<configuration PROFILE_NAME="stm32f072disco" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32f072disco -DLOG=0 -DLOGGER=RTT" />
<configuration PROFILE_NAME="stm32f103_mini_2" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32f103_mini_2 -DLOG=1 -DLOGGGER=RTT" />
@@ -166,7 +167,6 @@
<configuration PROFILE_NAME="max32650fthr" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=max32650fthr -DLOG=0 -DLOGGER=RTT" />
<configuration PROFILE_NAME="max32666fthr" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=max32666fthr -DLOG=0 -DLOGGER=RTT" />
<configuration PROFILE_NAME="max32690evkit" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=max32690evkit -DLOG=1 -DLOGGER=RTT" />
<configuration PROFILE_NAME="mimxrt1064_evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1064_evk" />
</configurations>
</component>
</project>

14
.idea/debugServers/esp32s2.xml generated Normal file
View File

@@ -0,0 +1,14 @@
<component name="DebugServers">
<generic-debug-target name="esp32s2" uniqueID="254eff00-2acf-48fe-b255-1d0c0c9c4a7a">
<debugger version="1">
<debugger kind="GDB">$USER_HOME$/.espressif/tools/xtensa-esp-elf-gdb/14.2_20240403/xtensa-esp-elf-gdb/bin/xtensa-esp32s2-elf-gdb</debugger>
<env />
</debugger>
<gdbserver exe="$USER_HOME$/.espressif/tools/openocd-esp32/v0.12.0-esp32-20241016/openocd-esp32/bin/openocd" args="-f board/esp32s2-kaluga-1.cfg">
<env />
</gdbserver>
<console port="4444" />
<target download-type="NONE" reset-command="monitor reset halt" reset-before="false" />
<connection extended-remote="false" remote-string="tcp::3333" warmup-ms="500" />
</generic-debug-target>
</component>

View File

@@ -1,5 +1,5 @@
<component name="DebugServers">
<generic-debug-target name="rp2350" uniqueID="939fdf16-9c30-4261-8435-3e8df7fd5800" selected="true">
<generic-debug-target name="rp2350" uniqueID="939fdf16-9c30-4261-8435-3e8df7fd5800">
<debugger version="1">
<debugger kind="GDB" isBundled="true" />
<env />

View File

@@ -5,7 +5,7 @@
<env />
</debugger>
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
<console port="2334" type="RTT" />
<console port="19021" />
<target device="MIMXRT1062xxx6A" reset-before="false" />
<connection extended-remote="false" port="4444" warmup-ms="500" />
<swo />

View File

@@ -5,7 +5,7 @@
<env />
</debugger>
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
<console port="2334" type="RTT" />
<console port="19021" />
<target device="MIMXRT1064xxx6A" reset-before="false" />
<connection extended-remote="false" port="4444" warmup-ms="500" />
<swo />

View File

@@ -5,7 +5,7 @@
<env />
</debugger>
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
<console port="2334" type="RTT" />
<console port="19021" />
<target device="ATSAMD21G18A" reset-before="false" />
<connection extended-remote="false" port="4444" warmup-ms="500" />
<swo />

View File

@@ -5,7 +5,7 @@
<env />
</debugger>
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
<console port="2334" type="RTT" />
<console port="19021" />
<target device="ATSAMD51J19A" reset-before="false" />
<connection extended-remote="false" port="4444" warmup-ms="500" />
<swo />

13
.idea/debugServers/stm32f769.xml generated Normal file
View File

@@ -0,0 +1,13 @@
<component name="DebugServers">
<jlink-debug-target name="stm32f769" uniqueID="7a47302f-f7e5-434b-b20b-78e95318dd0c">
<debugger version="1">
<debugger kind="GDB" isBundled="true" />
<env />
</debugger>
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
<console port="19021" />
<target device="STM32F769NI" reset-before="false" frequency="16000" />
<connection extended-remote="false" port="4444" warmup-ms="500" />
<swo />
</jlink-debug-target>
</component>

13
.idea/debugServers/stm32h563.xml generated Normal file
View File

@@ -0,0 +1,13 @@
<component name="DebugServers">
<jlink-debug-target name="stm32h563" uniqueID="a3e9293d-113b-48b3-b83d-dd4249984abe">
<debugger version="1">
<debugger kind="GDB" isBundled="true" />
<env />
</debugger>
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
<console port="19021" />
<target device="STM32H562ZI" reset-before="false" frequency="16000" />
<connection extended-remote="false" port="4444" warmup-ms="500" />
<swo />
</jlink-debug-target>
</component>

13
.idea/debugServers/stm32h743.xml generated Normal file
View File

@@ -0,0 +1,13 @@
<component name="DebugServers">
<jlink-debug-target name="stm32h743" uniqueID="6d6a3ed6-f66d-4f6a-9e70-6aafe5c971d0">
<debugger version="1">
<debugger kind="GDB" isBundled="true" />
<env />
</debugger>
<gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
<console port="19021" />
<target device="STM32H743XI" reset-before="false" frequency="16000" />
<connection extended-remote="false" port="4444" warmup-ms="500" />
<swo />
</jlink-debug-target>
</component>

View File

@@ -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 "")

View File

@@ -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")

View File

@@ -40,8 +40,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
};
@@ -49,8 +48,7 @@ enum
#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;
@@ -96,8 +94,7 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x55, 0xAA},
//------------- Block1: FAT12 Table -------------//
{
@@ -121,8 +118,7 @@ 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";
@@ -136,8 +132,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,8 +147,7 @@ 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;
@@ -163,18 +157,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,8 +175,7 @@ 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
@@ -205,8 +194,7 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buff
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
@@ -218,8 +206,7 @@ bool tud_msc_is_writable_cb (uint8_t lun)
// 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
@@ -229,7 +216,9 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
uint8_t *addr = msc_disk[lba] + offset;
memcpy(addr, buffer, bufsize);
#else
(void) lba; (void) offset; (void) buffer;
(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

View File

@@ -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,7 +282,9 @@ 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)
(void) lun;
@@ -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

View File

@@ -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;
}

View File

@@ -78,6 +78,22 @@ static void print_device_info(uint8_t daddr, const tusb_desc_device_t* desc_devi
void led_blinking_task(void);
void cdc_task(void);
#define cdc_printf(...) \
do { \
char _tempbuf[256]; \
char* _bufptr = _tempbuf; \
uint32_t count = (uint32_t) sprintf(_tempbuf, __VA_ARGS__); \
while (count > 0) { \
uint32_t wr_count = tud_cdc_write(_bufptr, count); \
count -= wr_count; \
_bufptr += wr_count; \
if (count > 0){ \
tud_task(); \
tud_cdc_write_flush(); \
} \
} \
} while(0)
/*------------- MAIN -------------*/
int main(void) {
board_init();
@@ -160,22 +176,6 @@ void cdc_task(void) {
//--------------------------------------------------------------------+
// Host Get device information
//--------------------------------------------------------------------+
#define cdc_printf(...) \
do { \
char _tempbuf[256]; \
char* _bufptr = _tempbuf; \
uint32_t count = (uint32_t) sprintf(_tempbuf, __VA_ARGS__); \
while (count > 0) { \
uint32_t wr_count = tud_cdc_write(_bufptr, count); \
count -= wr_count; \
_bufptr += wr_count; \
if (count > 0){ \
tud_task();\
tud_cdc_write_flush(); \
} \
} \
} while(0)
static void print_device_info(uint8_t daddr, const tusb_desc_device_t* desc_device) {
// Get String descriptor using Sync API
uint16_t serial[64];
@@ -232,12 +232,14 @@ void tuh_enum_descriptor_device_cb(uint8_t daddr, tusb_desc_device_t const* desc
}
void tuh_mount_cb(uint8_t daddr) {
printf("mounted device %u\r\n", daddr);
cdc_printf("mounted device %u\r\n", daddr);
tud_cdc_write_flush();
is_print[daddr] = true;
}
void tuh_umount_cb(uint8_t daddr) {
printf("unmounted device %u\r\n", daddr);
cdc_printf("unmounted device %u\r\n", daddr);
tud_cdc_write_flush();
is_print[daddr] = false;
}
@@ -249,7 +251,9 @@ void led_blinking_task(void) {
static bool led_state = false;
// Blink every interval ms
if (board_millis() - start_ms < blink_interval_ms) return; // not enough time
if (board_millis() - start_ms < blink_interval_ms) {
return;// not enough time
}
start_ms += blink_interval_ms;
board_led_write(led_state);
@@ -300,7 +304,9 @@ static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
}
static void print_utf16(uint16_t *temp_buf, size_t buf_len) {
if ((temp_buf[0] & 0xff) == 0) return; // empty
if ((temp_buf[0] & 0xff) == 0) {
return;// empty
}
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
size_t utf8_len = (size_t) _count_utf8_bytes(temp_buf + 1, utf16_len);
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len);

View File

@@ -29,11 +29,6 @@
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
// If your host terminal support ansi escape code such as TeraTerm
// it can be use to simulate mouse cursor movement within terminal
#define USE_ANSI_ESCAPE 0
#define MAX_REPORT 4
static uint8_t const keycode2ascii[128][2] = {HID_KEYCODE_TO_ASCII};
@@ -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);
@@ -130,25 +125,22 @@ 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 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
@@ -166,55 +158,22 @@ static void process_kbd_report(hid_keyboard_report_t const *report)
//--------------------------------------------------------------------+
static void cursor_movement(int8_t x, int8_t y, int8_t wheel) {
#if USE_ANSI_ESCAPE
// Move X using ansi escape
if ( x < 0)
{
printf(ANSI_CURSOR_BACKWARD(%d), (-x)); // move left
}else if ( x > 0)
{
printf(ANSI_CURSOR_FORWARD(%d), x); // move right
}
// Move Y using ansi escape
if ( y < 0)
{
printf(ANSI_CURSOR_UP(%d), (-y)); // move up
}else if ( y > 0)
{
printf(ANSI_CURSOR_DOWN(%d), y); // move down
}
// Scroll using ansi escape
if (wheel < 0)
{
printf(ANSI_SCROLL_UP(%d), (-wheel)); // scroll up
}else if (wheel > 0)
{
printf(ANSI_SCROLL_DOWN(%d), wheel); // scroll down
}
printf("\r\n");
#else
printf("(%d %d %d)\r\n", x, y, wheel);
#endif
}
static void process_mouse_report(hid_mouse_report_t const * report)
{
static 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' : '-');
}
//------------- cursor movement -------------//
// cursor movement
cursor_movement(report->x, report->y, report->wheel);
}
@@ -263,18 +222,23 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c
if (rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP) {
switch (rpt_info->usage) {
case HID_USAGE_DESKTOP_KEYBOARD:
TU_LOG1("HID receive keyboard report\r\n");
TU_LOG2("HID receive keyboard report\r\n");
// Assume keyboard follow boot report layout
process_kbd_report((hid_keyboard_report_t const *) report);
break;
case HID_USAGE_DESKTOP_MOUSE:
TU_LOG1("HID receive mouse report\r\n");
TU_LOG2("HID receive mouse report\r\n");
// Assume mouse follow boot report layout
process_mouse_report((hid_mouse_report_t const *) report);
break;
default:
printf("report[%u] ", rpt_info->report_id);
for (uint8_t i = 0; i < len; i++) {
printf("%02X ", report[i]);
}
printf("\r\n");
break;
}
}

View File

@@ -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");
}

View File

@@ -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

View File

@@ -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",

View File

@@ -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 \

View File

@@ -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 \

View File

@@ -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
}

View File

@@ -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

View File

@@ -36,7 +36,7 @@
extern "C" {
#endif
#define NEOPIXEL_PIN 48
#define NEOPIXEL_PIN 38
#define BUTTON_PIN 0
#define BUTTON_STATE_ACTIVE 0

View File

@@ -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

View File

@@ -92,10 +92,10 @@ void board_init(void) {
usb_init();
#endif
#ifdef HIL_DEVICE_HOST_MUX_PIN
gpio_reset_pin(HIL_DEVICE_HOST_MUX_PIN);
gpio_set_direction(HIL_DEVICE_HOST_MUX_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(HIL_DEVICE_HOST_MUX_PIN, CFG_TUD_ENABLED ? HIL_DEVICE_STATE : (1-HIL_DEVICE_STATE));
#ifdef HIL_TS3USB30_MODE_PIN
gpio_reset_pin(HIL_TS3USB30_MODE_PIN);
gpio_set_direction(HIL_TS3USB30_MODE_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(HIL_TS3USB30_MODE_PIN, CFG_TUD_ENABLED ? HIL_TS3USB30_MODE_DEVICE : (1-HIL_TS3USB30_MODE_DEVICE));
#endif
#if CFG_TUH_ENABLED && CFG_TUH_MAX3421

View File

@@ -34,6 +34,6 @@ endif ()
set(EXTRA_COMPONENT_DIRS "src" "${CMAKE_CURRENT_LIST_DIR}/boards" "${CMAKE_CURRENT_LIST_DIR}/components")
# set SDKCONFIG for each IDF Target
set(SDKCONFIG ${CMAKE_SOURCE_DIR}/sdkconfig.${IDF_TARGET})
set(SDKCONFIG ${CMAKE_BINARY_DIR}/sdkconfig)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)

View File

@@ -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

View File

@@ -15,7 +15,7 @@ CFLAGS += \
LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs
# mcu driver cause following warnings
CFLAGS += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=unused-variable -Wno-error=cast-qual
CFLAGS_GCC += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=unused-variable -Wno-error=cast-qual
MCU_DIR = hw/mcu/nxp/lpcopen/lpc15xx/lpc_chip_15xx

View File

@@ -13,7 +13,7 @@ CFLAGS += \
-DRTC_EV_SUPPORT=0
# lpc_types.h cause following errors
CFLAGS += -Wno-error=strict-prototypes -Wno-error=cast-qual
CFLAGS_GCC += -Wno-error=strict-prototypes -Wno-error=cast-qual
# caused by freeRTOS port !!
CFLAGS += -Wno-error=maybe-uninitialized

View File

@@ -12,7 +12,7 @@ CFLAGS += \
-DCFG_TUSB_MCU=OPT_MCU_LPC18XX
# mcu driver cause following warnings
CFLAGS += -Wno-error=unused-parameter -Wno-error=cast-qual
CFLAGS_GCC += -Wno-error=unused-parameter -Wno-error=cast-qual
LDFLAGS_GCC += --specs=nosys.specs --specs=nano.specs

View File

@@ -13,7 +13,7 @@ CFLAGS += \
-DCFG_TUSB_MCU=OPT_MCU_LPC40XX
# mcu driver cause following warnings
CFLAGS += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=cast-qual
CFLAGS_GCC += -Wno-error=strict-prototypes -Wno-error=unused-parameter -Wno-error=cast-qual
LDFLAGS_GCC += --specs=nosys.specs --specs=nano.specs

View File

@@ -5,14 +5,14 @@ include ${TOP}/${BOARD_PATH}/board.mk
CPU_CORE ?= cortex-m4
CFLAGS += \
-flto \
-nostdlib \
-DCORE_M4 \
-D__USE_LPCOPEN \
-DCFG_TUSB_MCU=OPT_MCU_LPC43XX
# mcu driver cause following warnings
CFLAGS += \
CFLAGS_GCC += \
-flto \
-nostdlib \
-Wno-error=unused-parameter \
-Wno-error=cast-qual \
-Wno-error=incompatible-pointer-types \

View File

@@ -0,0 +1,2 @@
set(PICO_PLATFORM rp2040)
set(PICO_BOARD pico_w)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1,5 +1,4 @@
ST_FAMILY = f2
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
@@ -14,11 +13,10 @@ CPU_CORE ?= cortex-m3
CFLAGS += \
-DCFG_TUSB_MCU=OPT_MCU_STM32F2
# mcu driver cause following warnings
CFLAGS_GCC += \
-flto \
# mcu driver cause following warnings
CFLAGS_GCC += -Wno-error=sign-compare
-Wno-error=sign-compare
LDFLAGS_GCC += \
-nostdlib -nostartfiles \
@@ -40,3 +38,10 @@ INC += \
$(TOP)/$(ST_CMSIS)/Include \
$(TOP)/$(ST_HAL_DRIVER)/Inc \
$(TOP)/$(BOARD_PATH)
# Startup
SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_${MCU_VARIANT}.s
SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_${MCU_VARIANT}.s
# Linker
LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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 \

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -57,5 +57,12 @@ INC += \
$(TOP)/$(ST_HAL_DRIVER)/Inc \
$(TOP)/$(BOARD_PATH)
# Startup
SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_$(MCU_VARIANT).s
SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT).s
# Linker
LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash.icf
# flash target using on-board stlink
flash: flash-stlink

View File

@@ -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
@@ -81,7 +86,10 @@ 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*)
@@ -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/ :
{
@@ -165,5 +170,13 @@ 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
/* 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
}

View File

@@ -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) {
}

View File

@@ -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

View File

@@ -672,7 +672,7 @@ void cdch_close(uint8_t daddr) {
bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) {
// TODO handle stall response, retry failed transfer ...
TU_ASSERT(event == XFER_RESULT_SUCCESS);
TU_VERIFY(event == XFER_RESULT_SUCCESS);
uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr);
cdch_interface_t * p_cdc = get_itf(idx);

View File

@@ -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));
}
}

View File

@@ -344,7 +344,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
msc_csw_t * p_csw = &p_msc->csw;
switch (p_msc->stage) {
case MSC_STAGE_CMD:
case MSC_STAGE_CMD: {
//------------- new CBW received -------------//
// Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it
if (ep_addr != p_msc->ep_out) {
@@ -442,6 +442,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
}
}
break;
}
case MSC_STAGE_DATA:
TU_LOG_DRV(" SCSI Data [Lun%u]\r\n", p_cbw->lun);

View File

@@ -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; i<p_table->count; 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;
}

View File

@@ -90,13 +90,6 @@ typedef struct {
};
} hcd_event_t;
typedef struct {
uint8_t rhport;
uint8_t hub_addr;
uint8_t hub_port;
uint8_t speed;
} hcd_devtree_info_t;
//--------------------------------------------------------------------+
// Memory API
//--------------------------------------------------------------------+
@@ -186,13 +179,6 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr);
// USBH implemented API
//--------------------------------------------------------------------+
// Get device tree information of a device
// USB device tree can be complicated and manged by USBH, this help HCD to retrieve
// needed topology info to carry out its work
extern void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info);
//------------- Event API -------------//
// Called by HCD to notify stack
extern void hcd_event_handler(hcd_event_t const* event, bool in_isr);
@@ -239,4 +225,4 @@ void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred
}
#endif
#endif /* _TUSB_HCD_H_ */
#endif

View File

@@ -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];
}
@@ -146,6 +148,19 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
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,11 +184,28 @@ 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));
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;
}
//--------------------------------------------------------------------+
// CLASS-USBH API (don't require to verify parameters)
//--------------------------------------------------------------------+
@@ -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,59 +394,80 @@ 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) {
static void process_new_status(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) {
if (xfer->result != XFER_RESULT_SUCCESS) {
TU_ASSERT(hub_edpt_status_xfer(daddr),);
}
return;
}
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);
const uintptr_t state = xfer->user_data;
bool processed = false; // true if new status is processed
// Clear port status change interrupts
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;
}
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, connection_clear_conn_change_complete, 0);
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, port_clear_feature_complete_stub, 0);
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, port_clear_feature_complete_stub, 0);
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, port_clear_feature_complete_stub, 0);
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, port_clear_feature_complete_stub, 0);
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;
}
if (!processed) {
@@ -418,57 +475,4 @@ static void port_get_status_complete(tuh_xfer_t *xfer) {
}
}
static void connection_clear_conn_change_complete (tuh_xfer_t* xfer) {
const uint8_t daddr = xfer->daddr;
if (xfer->result != XFER_RESULT_SUCCESS) {
TU_ASSERT(hub_edpt_status_xfer(daddr), );
return;
}
hub_interface_t *p_hub = get_hub_itf(daddr);
const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
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
}
return;
}
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);
}
#endif

View File

@@ -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);

File diff suppressed because it is too large Load Diff

View File

@@ -47,7 +47,6 @@
// forward declaration
struct tuh_xfer_s;
typedef struct tuh_xfer_s tuh_xfer_t;
typedef void (*tuh_xfer_cb_t)(tuh_xfer_t* xfer);
// Note1: layout and order of this will be changed in near future
@@ -80,6 +79,17 @@ typedef struct {
tusb_desc_interface_t desc;
} tuh_itf_info_t;
typedef struct {
uint8_t rhport;
uint8_t hub_addr;
uint8_t hub_port;
uint8_t speed;
} tuh_bus_info_t;
// backward compatibility for hcd_devtree_info_t, maybe removed in the future
#define hcd_devtree_info_t tuh_bus_info_t
#define hcd_devtree_get_info(_daddr, _bus_info) tuh_bus_info_get(_daddr, _bus_info)
// ConfigID for tuh_configure()
enum {
TUH_CFGID_INVALID = 0,
@@ -177,6 +187,8 @@ extern void hcd_int_handler(uint8_t rhport, bool in_isr);
#define _tuh_int_handler_arg0() TU_VERIFY_STATIC(false, "tuh_int_handler() must have 1 or 2 arguments")
#define _tuh_int_handler_arg1(_rhport) hcd_int_handler(_rhport, true)
#define _tuh_int_handler_arg2(_rhport, _in_isr) hcd_int_handler(_rhport, _in_isr)
// 1st argument is rhport (mandatory), 2nd argument in_isr (optional)
#define tuh_int_handler(...) TU_FUNC_OPTIONAL_ARG(_tuh_int_handler, __VA_ARGS__)
// Check if roothub port is initialized and active as a host
@@ -214,6 +226,9 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_ready(uint8_t daddr) {
return tuh_mounted(daddr) && !tuh_suspended(daddr);
}
// Get bus information of device
bool tuh_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info);
//--------------------------------------------------------------------+
// Transfer API
//--------------------------------------------------------------------+
@@ -238,6 +253,10 @@ bool tuh_edpt_close(uint8_t daddr, uint8_t ep_addr);
// Return true if a queued transfer is aborted, false if there is no transfer to abort
bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr);
// Set Address (control transfer)
bool tuh_address_set(uint8_t daddr, uint8_t new_addr,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Set Configuration (control transfer)
// config_num = 0 will un-configure device. Note: config_num = config_descriptor_index + 1
// true on success, false if there is on-going control transfer or incorrect parameters

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -34,6 +34,7 @@
#include "osal/osal.h"
#include "host/hcd.h"
#include "host/usbh.h"
#include "ehci_api.h"
#include "ehci.h"
@@ -837,8 +838,8 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
tu_memclr(p_qhd, sizeof(ehci_qhd_t));
}
hcd_devtree_info_t devtree_info;
hcd_devtree_get_info(dev_addr, &devtree_info);
tuh_bus_info_t bus_info;
tuh_bus_info_get(dev_addr, &bus_info);
uint8_t const xfer_type = ep_desc->bmAttributes.xfer;
uint8_t const interval = ep_desc->bInterval;
@@ -846,7 +847,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
p_qhd->dev_addr = dev_addr;
p_qhd->fl_inactive_next_xact = 0;
p_qhd->ep_number = tu_edpt_number(ep_desc->bEndpointAddress);
p_qhd->ep_speed = devtree_info.speed;
p_qhd->ep_speed = bus_info.speed;
p_qhd->data_toggle_control= (xfer_type == TUSB_XFER_CONTROL) ? 1 : 0;
p_qhd->head_list_flag = (dev_addr == 0) ? 1 : 0; // addr0's endpoint is the static async list head
p_qhd->max_packet_size = tu_edpt_packet_size(ep_desc);
@@ -887,8 +888,8 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
default: break;
}
p_qhd->fl_hub_addr = devtree_info.hub_addr;
p_qhd->fl_hub_port = devtree_info.hub_port;
p_qhd->fl_hub_addr = bus_info.hub_addr;
p_qhd->fl_hub_port = bus_info.hub_port;
p_qhd->mult = 1; // TODO not use high bandwidth/park mode yet
//------------- HCD Management Data -------------//

View File

@@ -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;

View File

@@ -36,6 +36,7 @@
#endif
#include "host/hcd.h"
#include "host/usbh.h"
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION

View File

@@ -31,6 +31,7 @@
#include "chip.h"
#include "host/hcd.h"
#include "host/usbh.h"
void hcd_int_enable(uint8_t rhport)
{

View File

@@ -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;

View File

@@ -114,9 +114,9 @@ void hcd_int_disable(uint8_t rhport) {
//--------------------------------------------------------------------+
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *desc_ep) {
hcd_devtree_info_t dev_tree;
hcd_devtree_get_info(dev_addr, &dev_tree);
bool const need_pre = (dev_tree.hub_addr && dev_tree.speed == TUSB_SPEED_LOW);
tuh_bus_info_t bus_info;
tuh_bus_info_get(dev_addr, &bus_info);
bool const need_pre = (bus_info.hub_addr && bus_info.speed == TUSB_SPEED_LOW);
uint8_t const pio_rhport = RHPORT_PIO(rhport);
return pio_usb_host_endpoint_open(pio_rhport, dev_addr, (uint8_t const *) desc_ep, need_pre);

View File

@@ -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;
}

View File

@@ -41,12 +41,6 @@
#include "device/dcd.h"
#include "dwc2_common.h"
#if TU_CHECK_MCU(OPT_MCU_GD32VF103)
#define DWC2_EP_COUNT(_dwc2) DWC2_EP_MAX
#else
#define DWC2_EP_COUNT(_dwc2) ((_dwc2)->ghwcfg2_bm.num_dev_ep + 1)
#endif
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM
//--------------------------------------------------------------------+
@@ -79,6 +73,16 @@ CFG_TUD_MEM_SECTION static struct {
TUD_EPBUF_DEF(setup_packet, 8);
} _dcd_usbbuf;
TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_ep_count(const dwc2_regs_t* dwc2) {
#if TU_CHECK_MCU(OPT_MCU_GD32VF103)
return DWC2_EP_MAX;
#else
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
return ghwcfg2.num_dev_ep + 1;
#endif
}
//--------------------------------------------------------------------
// DMA
//--------------------------------------------------------------------
@@ -102,7 +106,8 @@ bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
TU_ATTR_ALWAYS_INLINE static inline bool dma_device_enabled(const dwc2_regs_t* dwc2) {
(void) dwc2;
// Internal DMA only
return CFG_TUD_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA;
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
return CFG_TUD_DWC2_DMA_ENABLE && ghwcfg2.arch == GHWCFG2_ARCH_INTERNAL_DMA;
}
static void dma_setup_prepare(uint8_t rhport) {
@@ -250,20 +255,15 @@ static void edpt_activate(uint8_t rhport, const tusb_desc_endpoint_t* p_endpoint
xfer->interval = p_endpoint_desc->bInterval;
// Endpoint control
union {
uint32_t value;
dwc2_depctl_t bm;
} depctl;
depctl.value = 0;
depctl.bm.mps = xfer->max_size;
depctl.bm.active = 1;
depctl.bm.type = p_endpoint_desc->bmAttributes.xfer;
dwc2_depctl_t depctl = {.value = 0};
depctl.mps = xfer->max_size;
depctl.active = 1;
depctl.type = p_endpoint_desc->bmAttributes.xfer;
if (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS) {
depctl.bm.set_data0_iso_even = 1;
depctl.set_data0_iso_even = 1;
}
if (dir == TUSB_DIR_IN) {
depctl.bm.tx_fifo_num = epnum;
depctl.tx_fifo_num = epnum;
}
dwc2_dep_t* dep = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][epnum];
@@ -343,31 +343,22 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
}
// transfer size: A full OUT transfer (multiple packets, possibly) triggers XFRC.
union {
uint32_t value;
dwc2_ep_tsize_t bm;
} deptsiz;
deptsiz.value = 0;
deptsiz.bm.xfer_size = total_bytes;
deptsiz.bm.packet_count = num_packets;
dwc2_ep_tsize_t deptsiz = {.value = 0};
deptsiz.xfer_size = total_bytes;
deptsiz.packet_count = num_packets;
dep->tsiz = deptsiz.value;
// control
union {
dwc2_depctl_t bm;
uint32_t value;
} depctl;
depctl.value = dep->ctl;
depctl.bm.clear_nak = 1;
depctl.bm.enable = 1;
if (depctl.bm.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) {
const uint32_t odd_now = (dwc2->dsts_bm.frame_number & 1u);
dwc2_depctl_t depctl = {.value = dep->ctl};
depctl.clear_nak = 1;
depctl.enable = 1;
if (depctl.type == DEPCTL_EPTYPE_ISOCHRONOUS && xfer->interval == 1) {
const dwc2_dsts_t dsts = {.value = dwc2->dsts};
const uint32_t odd_now = dsts.frame_number & 1u;
if (odd_now) {
depctl.bm.set_data0_iso_even = 1;
depctl.set_data0_iso_even = 1;
} else {
depctl.bm.set_data1_iso_odd = 1;
depctl.set_data1_iso_odd = 1;
}
}
@@ -410,7 +401,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
// XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required
// when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347)
if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) {
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
if (ghwcfg2.hs_phy_type == GHWCFG2_HSPHY_ULPI) {
dcfg |= DCFG_XCVRDLY;
}
} else {
@@ -641,7 +633,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
// 7.4.1 Initialization on USB Reset
static void handle_bus_reset(uint8_t rhport) {
dwc2_regs_t *dwc2 = DWC2_REG(rhport);
const uint8_t ep_count = DWC2_EP_COUNT(dwc2);
const uint8_t ep_count = dwc2_ep_count(dwc2);
tu_memclr(xfer_status, sizeof(xfer_status));
@@ -671,7 +663,9 @@ static void handle_bus_reset(uint8_t rhport) {
dfifo_device_init(rhport);
// 5. Reset device address
dwc2->dcfg_bm.address = 0;
dwc2_dcfg_t dcfg = {.value = dwc2->dcfg};
dcfg.address = 0;
dwc2->dcfg = dcfg.value;
// Fixed both control EP0 size to 64 bytes
dwc2->epin[0].ctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos);
@@ -691,8 +685,9 @@ static void handle_bus_reset(uint8_t rhport) {
static void handle_enum_done(uint8_t rhport) {
dwc2_regs_t *dwc2 = DWC2_REG(rhport);
const dwc2_dsts_t dsts = {.value = dwc2->dsts};
tusb_speed_t speed;
switch (dwc2->dsts_bm.enum_speed) {
switch (dsts.enum_speed) {
case DCFG_SPEED_HIGH:
speed = TUSB_SPEED_HIGH;
break;
@@ -737,12 +732,12 @@ static void handle_rxflvl_irq(uint8_t rhport) {
const volatile uint32_t* rx_fifo = dwc2->fifo[0];
// Pop control word off FIFO
const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm;
const uint8_t epnum = grxstsp_bm.ep_ch_num;
const dwc2_grxstsp_t grxstsp = {.value = dwc2->grxstsp};
const uint8_t epnum = grxstsp.ep_ch_num;
dwc2_dep_t* epout = &dwc2->epout[epnum];
switch (grxstsp_bm.packet_status) {
switch (grxstsp.packet_status) {
case GRXSTS_PKTSTS_GLOBAL_OUT_NAK:
// Global OUT NAK: do nothing
break;
@@ -764,7 +759,7 @@ static void handle_rxflvl_irq(uint8_t rhport) {
case GRXSTS_PKTSTS_RX_DATA: {
// Out packet received
const uint16_t byte_count = grxstsp_bm.byte_count;
const uint16_t byte_count = grxstsp.byte_count;
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
if (byte_count) {
@@ -778,7 +773,8 @@ static void handle_rxflvl_irq(uint8_t rhport) {
// short packet, minus remaining bytes (xfer_size)
if (byte_count < xfer->max_size) {
xfer->total_len -= epout->tsiz_bm.xfer_size;
const dwc2_ep_tsize_t tsiz = {.value = epout->tsiz};
xfer->total_len -= tsiz.xfer_size;
if (epnum == 0) {
xfer->total_len -= _dcd_data.ep0_pending[TUSB_DIR_OUT];
_dcd_data.ep0_pending[TUSB_DIR_OUT] = 0;
@@ -840,11 +836,13 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep
// - 64 bytes or
// - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL)
if (diepint_bm.txfifo_empty && (dwc2->diepempmsk & (1 << epnum))) {
const uint16_t remain_packets = epin->tsiz_bm.packet_count;
dwc2_ep_tsize_t tsiz = {.value = epin->tsiz};
const uint16_t remain_packets = tsiz.packet_count;
// Process every single packet (only whole packets can be written to fifo)
for (uint16_t i = 0; i < remain_packets; i++) {
const uint16_t remain_bytes = (uint16_t) epin->tsiz_bm.xfer_size;
tsiz.value = epin->tsiz;
const uint16_t remain_bytes = (uint16_t) tsiz.xfer_size;
const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size);
// Check if dtxfsts has enough space available
@@ -863,7 +861,8 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep
}
// Turn off TXFE if all bytes are written.
if (epin->tsiz_bm.xfer_size == 0) {
tsiz.value = epin->tsiz;
if (tsiz.xfer_size == 0) {
dwc2->diepempmsk &= ~(1 << epnum);
}
}
@@ -894,7 +893,8 @@ static void handle_epout_dma(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepi
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
// determine actual received bytes
const uint16_t remain = epout->tsiz_bm.xfer_size;
const dwc2_ep_tsize_t tsiz = {.value = epout->tsiz};
const uint16_t remain = tsiz.xfer_size;
xfer->total_len -= remain;
// this is ZLP, so prepare EP0 for next setup
@@ -930,7 +930,7 @@ static void handle_epin_dma(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diepin
static void handle_ep_irq(uint8_t rhport, uint8_t dir) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const bool is_dma = dma_device_enabled(dwc2);
const uint8_t ep_count = DWC2_EP_COUNT(dwc2);
const uint8_t ep_count = dwc2_ep_count(dwc2);
const uint8_t daint_offset = (dir == TUSB_DIR_IN) ? DAINT_IEPINT_Pos : DAINT_OEPINT_Pos;
dwc2_dep_t* ep_base = &dwc2->ep[dir == TUSB_DIR_IN ? 0 : 1][0];

View File

@@ -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

View File

@@ -184,7 +184,9 @@ enum {
//--------------------------------------------------------------------
// Common Register Bitfield
//--------------------------------------------------------------------
typedef struct TU_ATTR_PACKED {
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
@@ -210,10 +212,13 @@ typedef struct TU_ATTR_PACKED {
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 {
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
@@ -225,10 +230,13 @@ typedef struct TU_ATTR_PACKED {
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 {
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
@@ -241,10 +249,13 @@ typedef struct TU_ATTR_PACKED {
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 {
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
@@ -281,10 +292,13 @@ typedef struct TU_ATTR_PACKED {
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 {
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)
@@ -296,21 +310,26 @@ typedef struct TU_ATTR_PACKED {
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 {
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 {
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
@@ -326,10 +345,13 @@ typedef struct TU_ATTR_PACKED {
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 {
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
@@ -342,10 +364,13 @@ typedef struct TU_ATTR_PACKED {
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 {
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
@@ -368,24 +393,26 @@ typedef struct TU_ATTR_PACKED {
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 {
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 {
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
@@ -393,10 +420,13 @@ typedef struct TU_ATTR_PACKED {
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 {
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
@@ -412,10 +442,13 @@ typedef struct TU_ATTR_PACKED {
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 {
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
@@ -427,49 +460,50 @@ typedef struct TU_ATTR_PACKED {
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 {
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 {
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 {
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
@@ -478,7 +512,9 @@ typedef struct {
//--------------------------------------------------------------------
// Device Register Bitfield
//--------------------------------------------------------------------
typedef struct TU_ATTR_PACKED {
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
@@ -490,13 +526,16 @@ typedef struct TU_ATTR_PACKED {
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 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 {
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
@@ -515,10 +554,13 @@ typedef struct TU_ATTR_PACKED {
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 {
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
@@ -526,10 +568,13 @@ typedef struct TU_ATTR_PACKED {
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 {
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
@@ -546,15 +591,18 @@ typedef struct TU_ATTR_PACKED {
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
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
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 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
@@ -565,10 +613,13 @@ typedef struct TU_ATTR_PACKED {
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 {
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
@@ -586,13 +637,17 @@ typedef struct TU_ATTR_PACKED {
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 {
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;
@@ -636,34 +684,16 @@ TU_VERIFY_STATIC(sizeof(dwc2_dep_t) == 0x20, "incorrect size");
// CSR Register Map
//--------------------------------------------------------------------
typedef struct {
//------------- Core Global -------------//
union {
//------------- Core Global -------------
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
union {
volatile uint32_t dieptxf0; // 028 EP0 Tx FIFO Size
@@ -671,7 +701,6 @@ typedef struct {
};
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
@@ -683,14 +712,8 @@ typedef struct {
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;
};
union {
volatile uint32_t ghwcfg4; // 050 User Hardware Configuration4
volatile dwc2_ghwcfg4_t ghwcfg4_bm;
@@ -704,54 +727,30 @@ typedef struct {
volatile uint32_t dieptxf[15]; // 104..13C Device Periodic Transmit FIFO Size
uint32_t reserved140[176]; // 140..3FF
//------------ Host -------------//
//------------ 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 Channel -------------//
//------------- Host Channel --------
dwc2_channel_t channel[16]; // 500..6FF Host Channels 0-15
uint32_t reserved700[64]; // 700..7FF
//------------- Device -----------//
union {
//------------- Device -----------
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
@@ -761,15 +760,15 @@ typedef struct {
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
// 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 -------------//
//------------- Device Endpoint -----
union {
dwc2_dep_t ep[2][16]; // 0: IN, 1 OUT
struct {
@@ -779,12 +778,12 @@ typedef struct {
};
uint32_t reservedd00[64]; // D00..DFF
//------------- Power Clock -------------//
//------------- 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 -------------//
//------------- FIFOs -------------
// Word-accessed only using first pointer since it auto shift
volatile uint32_t fifo[16][0x400]; // 1000..FFFF Endpoint FIFO
} dwc2_regs_t;

View File

@@ -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 {
@@ -78,8 +77,8 @@ 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 next_pid : 2; // PID for next transfer
uint32_t next_do_ping : 1; // Do PING for next transfer if possible (highspeed OUT)
// uint32_t : 9;
};
@@ -97,7 +96,6 @@ typedef struct {
uint8_t err_count : 3;
uint8_t period_split_nyet_count : 3;
uint8_t halted_nyet : 1;
uint8_t halted_sof_schedule : 1;
};
uint8_t result;
@@ -116,9 +114,15 @@ hcd_data_t _hcd_data;
//--------------------------------------------------------------------
//
//--------------------------------------------------------------------
TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_channel_count(const dwc2_regs_t* dwc2) {
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
return tu_min8(ghwcfg2.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc2) {
tusb_speed_t speed;
switch(dwc2->hprt_bm.speed) {
const dwc2_hprt_t hprt = {.value = dwc2->hprt};
switch(hprt.speed) {
case HPRT_SPEED_HIGH: speed = TUSB_SPEED_HIGH; break;
case HPRT_SPEED_FULL: speed = TUSB_SPEED_FULL; break;
case HPRT_SPEED_LOW : speed = TUSB_SPEED_LOW ; break;
@@ -133,7 +137,8 @@ TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc
TU_ATTR_ALWAYS_INLINE static inline bool dma_host_enabled(const dwc2_regs_t* dwc2) {
(void) dwc2;
// Internal DMA only
return CFG_TUH_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA;
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
return CFG_TUH_DWC2_DMA_ENABLE && ghwcfg2.arch == GHWCFG2_ARCH_INTERNAL_DMA;
}
#if CFG_TUH_MEM_DCACHE_ENABLE
@@ -155,7 +160,7 @@ bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
// Allocate a channel for new transfer
TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) {
const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
const uint8_t max_channel = dwc2_channel_count(dwc2);
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
if (!xfer->allocated) {
@@ -168,15 +173,18 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) {
}
// Check if is periodic (interrupt/isochronous)
TU_ATTR_ALWAYS_INLINE static inline bool edpt_is_periodic(uint8_t ep_type) {
return ep_type == HCCHAR_EPTYPE_INTERRUPT || ep_type == HCCHAR_EPTYPE_ISOCHRONOUS;
TU_ATTR_ALWAYS_INLINE static inline bool channel_is_periodic(uint32_t hcchar) {
const dwc2_channel_char_t hcchar_bm = {.value = hcchar};
return hcchar_bm.ep_type == HCCHAR_EPTYPE_INTERRUPT || hcchar_bm.ep_type == HCCHAR_EPTYPE_ISOCHRONOUS;
}
TU_ATTR_ALWAYS_INLINE static inline uint8_t req_queue_avail(const dwc2_regs_t* dwc2, bool is_period) {
if (is_period) {
return dwc2->hptxsts_bm.req_queue_available;
const dwc2_hptxsts_t hptxsts = {.value = dwc2->hptxsts};
return hptxsts.req_queue_available;
} else {
return dwc2->hnptxsts_bm.req_queue_available;
const dwc2_hnptxsts_t hnptxsts = {.value = dwc2->hnptxsts};
return hnptxsts.req_queue_available;
}
}
@@ -188,7 +196,7 @@ TU_ATTR_ALWAYS_INLINE static inline void channel_dealloc(dwc2_regs_t* dwc2, uint
TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) {
// disable also require request queue
TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type)));
TU_ASSERT(req_queue_avail(dwc2, channel_is_periodic(channel->hcchar)));
channel->hcintmsk |= HCINT_HALTED;
channel->hcchar |= HCCHAR_CHDIS | HCCHAR_CHENA; // must set both CHDIS and CHENA
return true;
@@ -196,18 +204,18 @@ TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2
// attempt to send IN token to receive data
TU_ATTR_ALWAYS_INLINE static inline bool channel_send_in_token(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) {
TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type)));
TU_ASSERT(req_queue_avail(dwc2, channel_is_periodic(channel->hcchar)));
channel->hcchar |= HCCHAR_CHENA;
return true;
}
// Find currently enabled channel. Note: EP0 is bidirectional
TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_find_enabled(dwc2_regs_t* dwc2, uint8_t dev_addr, uint8_t ep_num, uint8_t ep_dir) {
const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
const uint8_t max_channel = dwc2_channel_count(dwc2);
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
if (_hcd_data.xfer[ch_id].allocated) {
const dwc2_channel_char_t hcchar_bm = dwc2->channel[ch_id].hcchar_bm;
if (hcchar_bm.dev_addr == dev_addr && hcchar_bm.ep_num == ep_num && (ep_num == 0 || hcchar_bm.ep_dir == ep_dir)) {
const dwc2_channel_char_t hcchar = {.value = dwc2->channel[ch_id].hcchar};
if (hcchar.dev_addr == dev_addr && hcchar.ep_num == ep_num && (ep_num == 0 || hcchar.ep_dir == ep_dir)) {
return ch_id;
}
}
@@ -304,12 +312,13 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t cal_next_pid(uint8_t pid, uint8_t pa
static void dfifo_host_init(uint8_t rhport) {
const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
// Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per channel
const bool is_dma = dma_host_enabled(dwc2);
uint16_t dfifo_top = dwc2_controller->ep_fifo_size/4;
if (is_dma) {
dfifo_top -= dwc2->ghwcfg2_bm.num_host_ch;
dfifo_top -= ghwcfg2.num_host_ch;
}
// fixed allocation for now, improve later:
@@ -319,7 +328,7 @@ static void dfifo_host_init(uint8_t rhport) {
uint32_t ptx_largest = is_highspeed ? TUSB_EPSIZE_ISO_HS_MAX/4 : 256/4;
uint16_t nptxfsiz = 2 * nptx_largest;
uint16_t rxfsiz = 2 * (ptx_largest + 2) + dwc2->ghwcfg2_bm.num_host_ch;
uint16_t rxfsiz = 2 * (ptx_largest + 2) + ghwcfg2.num_host_ch;
TU_ASSERT(dfifo_top >= (nptxfsiz + rxfsiz),);
uint16_t ptxfsiz = dfifo_top - (nptxfsiz + rxfsiz);
@@ -381,7 +390,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
dwc2->hprt = HPRT_POWER; // turn on VBUS
// Enable required interrupts
dwc2->gintmsk |= GINTSTS_OTGINT | GINTSTS_CONIDSTSCHNG | GINTSTS_HPRTINT | GINTSTS_HCINT;
dwc2->gintmsk |= GINTSTS_OTGINT | GINTSTS_CONIDSTSCHNG | GINTSTS_HPRTINT | GINTSTS_HCINT | GINTSTS_DISCINT;
// NPTX can hold at least 2 packet, change interrupt level to half-empty
uint32_t gahbcfg = dwc2->gahbcfg & ~GAHBCFG_TX_FIFO_EPMTY_LVL;
@@ -461,8 +470,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t*
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const tusb_speed_t rh_speed = hprt_speed_get(dwc2);
hcd_devtree_info_t devtree_info;
hcd_devtree_get_info(dev_addr, &devtree_info);
tuh_bus_info_t bus_info;
tuh_bus_info_get(dev_addr, &bus_info);
// find a free endpoint
const uint8_t ep_id = edpt_alloc();
@@ -473,7 +482,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t*
hcchar_bm->ep_size = tu_edpt_packet_size(desc_ep);
hcchar_bm->ep_num = tu_edpt_number(desc_ep->bEndpointAddress);
hcchar_bm->ep_dir = tu_edpt_dir(desc_ep->bEndpointAddress);
hcchar_bm->low_speed_dev = (devtree_info.speed == TUSB_SPEED_LOW) ? 1 : 0;
hcchar_bm->low_speed_dev = (bus_info.speed == TUSB_SPEED_LOW) ? 1 : 0;
hcchar_bm->ep_type = desc_ep->bmAttributes.xfer; // ep_type matches TUSB_XFER_*
hcchar_bm->err_multi_count = 0;
hcchar_bm->dev_addr = dev_addr;
@@ -482,21 +491,21 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t*
hcchar_bm->enable = 1;
dwc2_channel_split_t* hcsplt_bm = &edpt->hcsplt_bm;
hcsplt_bm->hub_port = devtree_info.hub_port;
hcsplt_bm->hub_addr = devtree_info.hub_addr;
hcsplt_bm->hub_port = bus_info.hub_port;
hcsplt_bm->hub_addr = bus_info.hub_addr;
hcsplt_bm->xact_pos = 0;
hcsplt_bm->split_compl = 0;
hcsplt_bm->split_en = (rh_speed == TUSB_SPEED_HIGH && devtree_info.speed != TUSB_SPEED_HIGH) ? 1 : 0;
hcsplt_bm->split_en = (rh_speed == TUSB_SPEED_HIGH && bus_info.speed != TUSB_SPEED_HIGH) ? 1 : 0;
edpt->speed = devtree_info.speed;
edpt->speed = bus_info.speed;
edpt->next_pid = HCTSIZ_PID_DATA0;
if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
edpt->uframe_interval = 1 << (desc_ep->bInterval - 1);
if (devtree_info.speed == TUSB_SPEED_FULL) {
if (bus_info.speed == TUSB_SPEED_FULL) {
edpt->uframe_interval <<= 3;
}
} else if (desc_ep->bmAttributes.xfer == TUSB_XFER_INTERRUPT) {
if (devtree_info.speed == TUSB_SPEED_HIGH) {
if (bus_info.speed == TUSB_SPEED_HIGH) {
edpt->uframe_interval = 1 << (desc_ep->bInterval - 1);
} else {
edpt->uframe_interval = desc_ep->bInterval << 3;
@@ -514,10 +523,11 @@ bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
// clean up channel after part of transfer is done but the whole urb is not complete
static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) {
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
const dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
edpt->next_pid = channel->hctsiz_bm.pid; // save PID
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
edpt->next_pid = hctsiz.pid; // save PID
/* Since hctsiz.xfersize field reflects the number of bytes transferred via the AHB, not the USB)
* For IN: we can use hctsiz.xfersize as remaining bytes.
@@ -525,9 +535,10 @@ static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) {
* number of packets that have been transferred via the USB. This is always an integral number of packets if the
* transfer was halted before its normal completion.
*/
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
const uint16_t total_packets = cal_packet_count(edpt->buflen, channel->hcchar_bm.ep_size);
const uint16_t actual_bytes = (total_packets - remain_packets) * channel->hcchar_bm.ep_size;
const uint16_t remain_packets = hctsiz.packet_count;
const dwc2_channel_char_t hcchar = {.value = channel->hcchar};
const uint16_t total_packets = cal_packet_count(edpt->buflen, hcchar.ep_size);
const uint16_t actual_bytes = (total_packets - remain_packets) * hcchar.ep_size;
xfer->fifo_bytes = 0;
xfer->xferred_bytes += actual_bytes;
@@ -540,7 +551,7 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) {
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
dwc2_channel_char_t* hcchar_bm = &edpt->hcchar_bm;
dwc2_channel_t* channel = &dwc2->channel[ch_id];
bool const is_period = edpt_is_periodic(hcchar_bm->ep_type);
bool const is_period = channel_is_periodic(edpt->hcchar);
// clear previous state
xfer->fifo_bytes = 0;
@@ -553,13 +564,16 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) {
// hctsiz: zero length packet still count as 1
const uint16_t packet_count = cal_packet_count(edpt->buflen, hcchar_bm->ep_size);
uint32_t hctsiz = (edpt->next_pid << HCTSIZ_PID_Pos) | (packet_count << HCTSIZ_PKTCNT_Pos) | edpt->buflen;
if (edpt->do_ping && edpt->speed == TUSB_SPEED_HIGH &&
dwc2_channel_tsize_t hctsiz = {.value = 0};
hctsiz.pid = edpt->next_pid; // next PID is set in transfer complete interrupt
hctsiz.packet_count = packet_count;
hctsiz.xfer_size = edpt->buflen;
if (edpt->next_do_ping && edpt->speed == TUSB_SPEED_HIGH &&
edpt->next_pid != HCTSIZ_PID_SETUP && hcchar_bm->ep_dir == TUSB_DIR_OUT) {
hctsiz |= HCTSIZ_DOPING;
hctsiz.do_ping = 1;
}
channel->hctsiz = hctsiz;
edpt->do_ping = 0;
channel->hctsiz = hctsiz.value;
edpt->next_do_ping = 0;
// pre-calculate next PID based on packet count, adjusted in transfer complete interrupt if short packet
if (hcchar_bm->ep_num == 0) {
@@ -590,7 +604,7 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) {
hcintmsk |= HCINT_BABBLE_ERR | HCINT_DATATOGGLE_ERR | HCINT_ACK;
} else {
hcintmsk |= HCINT_NYET;
if (edpt->hcsplt_bm.split_en) {
if (edpt->hcsplt_bm.split_en || hctsiz.do_ping) {
hcintmsk |= HCINT_ACK;
}
}
@@ -699,18 +713,23 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
//--------------------------------------------------------------------
// HCD Event Handler
//--------------------------------------------------------------------
// retry an IN transfer, channel must be halted
static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hcint) {
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
dwc2_channel_char_t hcchar = {.value = channel->hcchar};
if (edpt_is_periodic(channel->hcchar_bm.ep_type)){
if (channel_is_periodic(hcchar.value)){
const dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
// retry immediately for periodic split NYET if we haven't reach max retry
if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) {
if (hcsplt.split_en && hcsplt.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) {
xfer->period_split_nyet_count++;
xfer->halted_nyet = 0;
if (xfer->period_split_nyet_count < HCD_XFER_PERIOD_SPLIT_NYET_MAX) {
channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
channel->hcchar = hcchar.value;
channel_send_in_token(dwc2, channel);
return;
} else {
@@ -719,18 +738,24 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
}
}
// for periodic, de-allocate channel, enable SOF set frame counter for later transfer
edpt->next_pid = channel->hctsiz_bm.pid; // save PID
edpt->uframe_countdown = edpt->uframe_interval;
dwc2->gintmsk |= GINTSTS_SOF;
if (hcint & HCINT_HALTED) {
const uint32_t ucount = (hprt_speed_get(dwc2) == TUSB_SPEED_HIGH ? 1 : 8);
if (edpt->uframe_interval == ucount) {
// retry on next frame if bInterval is 1
hcchar.odd_frame = 1 - (dwc2->hfnum & 1);
channel->hcchar = hcchar.value;
channel_send_in_token(dwc2, channel);
} else {
// otherwise, de-allocate channel, enable SOF set frame counter for later transfer
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
edpt->next_pid = hctsiz.pid; // save PID
edpt->uframe_countdown = edpt->uframe_interval - ucount;
// enable SOF interrupt if not already enabled
if (!(dwc2->gintmsk & GINTMSK_SOFM)) {
dwc2->gintsts = GINTSTS_SOF;
dwc2->gintmsk |= GINTMSK_SOFM;
}
// already halted, de-allocate channel (called from DMA isr)
channel_dealloc(dwc2, ch_id);
} else {
// disable channel first if not halted (called slave isr)
xfer->halted_sof_schedule = 1;
channel_disable(dwc2, channel);
}
} else {
// for control/bulk: retry immediately
@@ -761,13 +786,13 @@ static void handle_rxflvl_irq(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
// Pop control word off FIFO
const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm;
const uint8_t ch_id = grxstsp_bm.ep_ch_num;
const dwc2_grxstsp_t grxstsp = {.value= dwc2->grxstsp};
const uint8_t ch_id = grxstsp.ep_ch_num;
switch (grxstsp_bm.packet_status) {
switch (grxstsp.packet_status) {
case GRXSTS_PKTSTS_RX_DATA: {
// In packet received, pop this entry --> ACK interrupt
const uint16_t byte_count = grxstsp_bm.byte_count;
const uint16_t byte_count = grxstsp.byte_count;
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,);
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
@@ -801,25 +826,26 @@ static void handle_rxflvl_irq(uint8_t rhport) {
// return true if there is still pending data and need more ISR
static bool handle_txfifo_empty(dwc2_regs_t* dwc2, bool is_periodic) {
// Use period txsts for both p/np to get request queue space available (1-bit difference, it is small enough)
volatile dwc2_hptxsts_t* txsts_bm = (volatile dwc2_hptxsts_t*) (is_periodic ? &dwc2->hptxsts : &dwc2->hnptxsts);
const dwc2_hptxsts_t txsts = {.value = (is_periodic ? dwc2->hptxsts : dwc2->hnptxsts)};
const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
const uint8_t max_channel = dwc2_channel_count(dwc2);
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
dwc2_channel_t* channel = &dwc2->channel[ch_id];
const dwc2_channel_char_t hcchar = {.value = channel->hcchar};
// skip writing to FIFO if channel is expecting halted.
if (!(channel->hcintmsk & HCINT_HALTED) && (channel->hcchar_bm.ep_dir == TUSB_DIR_OUT)) {
if (!(channel->hcintmsk & HCINT_HALTED) && (hcchar.ep_dir == TUSB_DIR_OUT)) {
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX);
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
const uint16_t remain_packets = hctsiz.packet_count;
for (uint16_t i = 0; i < remain_packets; i++) {
const uint16_t remain_bytes = edpt->buflen - xfer->fifo_bytes;
const uint16_t xact_bytes = tu_min16(remain_bytes, channel->hcchar_bm.ep_size);
const uint16_t xact_bytes = tu_min16(remain_bytes, hcchar.ep_size);
// skip if there is not enough space in FIFO and RequestQueue.
// Packet's last word written to FIFO will trigger a request queue
if ((xact_bytes > (txsts_bm->fifo_available << 2)) || (txsts_bm->req_queue_available == 0)) {
if ((xact_bytes > (txsts.fifo_available << 2)) || (txsts.req_queue_available == 0)) {
return true;
}
@@ -836,23 +862,26 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
bool is_done = false;
// if (channel->hcsplt_bm.split_en) {
// if (hcsplt.split_en) {
// if (edpt->hcchar_bm.ep_num == 1) {
// TU_LOG1("Frame %u, ch %u: ep %u, hcint 0x%04lX ", dwc2->hfnum_bm.num, ch_id, channel->hcchar_bm.ep_num, hcint);
// TU_LOG1("Frame %u, ch %u: ep %u, hcint 0x%04lX ", dwc2->hfnum_bm.num, ch_id, hcsplt.ep_num, hcint);
// print_hcint(hcint);
// }
if (hcint & HCINT_XFER_COMPLETE) {
if (edpt->hcchar_bm.ep_num != 0) {
edpt->next_pid = channel->hctsiz_bm.pid; // save pid (already toggled)
edpt->next_pid = hctsiz.pid; // save pid (already toggled)
}
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
if (channel->hcsplt_bm.split_en && remain_packets && xfer->fifo_bytes == edpt->hcchar_bm.ep_size) {
const uint16_t remain_packets = hctsiz.packet_count;
if (hcsplt.split_en && remain_packets && xfer->fifo_bytes == edpt->hcchar_bm.ep_size) {
// Split can only complete 1 transaction (up to 1 packet) at a time, schedule more
channel->hcsplt_bm.split_compl = 0;
hcsplt.split_compl = 0;
channel->hcsplt = hcsplt.value;
} else {
xfer->result = XFER_RESULT_SUCCESS;
}
@@ -871,43 +900,44 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h
channel_disable(dwc2, channel);
} else if (hcint & HCINT_NYET) {
// restart complete split
channel->hcsplt_bm.split_compl = 1;
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
xfer->halted_nyet = 1;
channel_disable(dwc2, channel);
} else if (hcint & HCINT_NAK) {
// NAK received, re-enable channel if request queue is available
if (channel->hcsplt_bm.split_en) {
channel->hcsplt_bm.split_compl = 0; // restart with start-split
// NAK received, disable channel to flush all posted request and try again
if (hcsplt.split_en) {
hcsplt.split_compl = 0; // restart with start-split
channel->hcsplt = hcsplt.value;
}
channel_disable(dwc2, channel);
} else if (hcint & HCINT_ACK) {
xfer->err_count = 0;
if (channel->hcsplt_bm.split_en) {
if (!channel->hcsplt_bm.split_compl) {
if (hcsplt.split_en) {
if (!hcsplt.split_compl) {
// start split is ACK --> do complete split
channel->hcintmsk |= HCINT_NYET;
channel->hcsplt_bm.split_compl = 1;
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
channel_send_in_token(dwc2, channel);
} else {
// do nothing for complete split with DATA, this will trigger XferComplete and handled there
}
} else {
// ACK with data
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
const uint16_t remain_packets = hctsiz.packet_count;
if (remain_packets) {
// still more packet to receive, also reset to start split
channel->hcsplt_bm.split_compl = 0;
hcsplt.split_compl = 0;
channel->hcsplt = hcsplt.value;
channel_send_in_token(dwc2, channel);
}
}
} else if (hcint & HCINT_HALTED) {
channel->hcintmsk &= ~HCINT_HALTED;
if (xfer->halted_sof_schedule) {
// de-allocate channel but does not complete xfer, we schedule it in the SOF interrupt
channel_dealloc(dwc2, ch_id);
} else if (xfer->result != XFER_RESULT_INVALID) {
if (xfer->result != XFER_RESULT_INVALID) {
is_done = true;
} else if (xfer->err_count == HCD_XFER_ERROR_MAX) {
xfer->result = XFER_RESULT_FAILED;
@@ -927,23 +957,29 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
bool is_done = false;
if (hcint & HCINT_XFER_COMPLETE) {
is_done = true;
xfer->result = XFER_RESULT_SUCCESS;
channel->hcintmsk &= ~HCINT_ACK;
if (hcint & HCINT_NYET) {
// complete transfer with NYET, do ping next time
edpt->next_do_ping = 1;
}
} else if (hcint & HCINT_STALL) {
xfer->result = XFER_RESULT_STALLED;
channel_disable(dwc2, channel);
} else if (hcint & HCINT_NYET) {
xfer->err_count = 0;
if (channel->hcsplt_bm.split_en) {
if (hcsplt.split_en) {
// retry complete split
channel->hcsplt_bm.split_compl = 1;
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
channel->hcchar |= HCCHAR_CHENA;
} else {
edpt->do_ping = 1;
edpt->next_do_ping = 1;
channel_xfer_out_wrapup(dwc2, ch_id);
channel_disable(dwc2, channel);
}
@@ -956,7 +992,7 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t
channel->hcintmsk |= HCINT_ACK;
} else {
// NAK disable channel to flush all posted request and try again
edpt->do_ping = 1;
edpt->next_do_ping = 1;
xfer->err_count = 0;
}
} else if (hcint & HCINT_HALTED) {
@@ -973,9 +1009,17 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t
} else if (hcint & HCINT_ACK) {
xfer->err_count = 0;
channel->hcintmsk &= ~HCINT_ACK;
if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) {
// start split is ACK --> do complete split
channel->hcsplt_bm.split_compl = 1;
if (hcsplt.split_en) {
if (!hcsplt.split_compl) {
// ACK for start split --> do complete split
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
channel->hcchar |= HCCHAR_CHENA;
}
} else {
// ACK interrupt is only enabled for Split and PING
// ACK for PING, which mean device is ready to receive data
channel->hctsiz &= ~HCTSIZ_DOPING; // HC already cleared PING bit, but we clear anyway
channel->hcchar |= HCCHAR_CHENA;
}
}
@@ -994,6 +1038,9 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
dwc2_channel_char_t hcchar = {.value = channel->hcchar};
dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
bool is_done = false;
@@ -1001,8 +1048,8 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
if (hcint & HCINT_HALTED) {
if (hcint & (HCINT_XFER_COMPLETE | HCINT_STALL | HCINT_BABBLE_ERR)) {
const uint16_t remain_bytes = (uint16_t) channel->hctsiz_bm.xfer_size;
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
const uint16_t remain_bytes = (uint16_t) hctsiz.xfer_size;
const uint16_t remain_packets = hctsiz.packet_count;
const uint16_t actual_len = edpt->buflen - remain_bytes;
xfer->xferred_bytes += actual_len;
@@ -1012,13 +1059,14 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
xfer->result = XFER_RESULT_STALLED;
} else if (hcint & HCINT_BABBLE_ERR) {
xfer->result = XFER_RESULT_FAILED;
} else if (channel->hcsplt_bm.split_en && remain_packets && actual_len == edpt->hcchar_bm.ep_size) {
} else if (hcsplt.split_en && remain_packets && actual_len == hcchar.ep_size) {
// Split can only complete 1 transaction (up to 1 packet) at a time, schedule more
is_done = false;
edpt->buffer += actual_len;
edpt->buflen -= actual_len;
channel->hcsplt_bm.split_compl = 0;
hcsplt.split_compl = 0;
channel->hcsplt = hcsplt.value;
channel_xfer_in_retry(dwc2, ch_id, hcint);
} else {
xfer->result = XFER_RESULT_SUCCESS;
@@ -1033,33 +1081,38 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
xfer->result = XFER_RESULT_FAILED;
} else {
channel->hcintmsk |= HCINT_ACK | HCINT_NAK | HCINT_DATATOGGLE_ERR;
channel->hcsplt_bm.split_compl = 0;
hcsplt.split_compl = 0;
channel->hcsplt = hcsplt.value;
channel_xfer_in_retry(dwc2, ch_id, hcint);
}
} else if (hcint & HCINT_NYET) {
// Must handle nyet before nak or ack. Could get a nyet at the same time as either of those on a BULK/CONTROL
// OUT that started with a PING. The nyet takes precedence.
if (channel->hcsplt_bm.split_en) {
if (hcsplt.split_en) {
// split not yet mean hub has no data, retry complete split
channel->hcsplt_bm.split_compl = 1;
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
channel_xfer_in_retry(dwc2, ch_id, hcint);
}
} else if (hcint & HCINT_ACK) {
xfer->err_count = 0;
channel->hcintmsk &= ~HCINT_ACK;
if (channel->hcsplt_bm.split_en) {
if (hcsplt.split_en) {
// start split is ACK --> do complete split
// TODO: for ISO must use xact_pos to plan complete split based on microframe (up to 187.5 bytes/uframe)
channel->hcsplt_bm.split_compl = 1;
if (edpt_is_periodic(channel->hcchar_bm.ep_type)) {
channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
if (channel_is_periodic(channel->hcchar)) {
hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
channel->hcchar = hcchar.value;
}
channel_send_in_token(dwc2, channel);
}
} else if (hcint & (HCINT_NAK | HCINT_DATATOGGLE_ERR)) {
xfer->err_count = 0;
channel->hcintmsk &= ~(HCINT_NAK | HCINT_DATATOGGLE_ERR);
channel->hcsplt_bm.split_compl = 0; // restart with start-split
hcsplt.split_compl = 0; // restart with start-split
channel->hcsplt = hcsplt.value;
channel_xfer_in_retry(dwc2, ch_id, hcint);
} else if (hcint & HCINT_FARME_OVERRUN) {
// retry start-split in next binterval
@@ -1074,6 +1127,8 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
const dwc2_channel_char_t hcchar = {.value = channel->hcchar};
dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
bool is_done = false;
@@ -1109,16 +1164,18 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc
}
}
} else if (hcint & HCINT_NYET) {
if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl) {
if (hcsplt.split_en && hcsplt.split_compl) {
// split not yet mean hub has no data, retry complete split
channel->hcsplt_bm.split_compl = 1;
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
channel->hcchar |= HCCHAR_CHENA;
}
} else if (hcint & HCINT_ACK) {
xfer->err_count = 0;
if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) {
if (hcsplt.split_en && !hcsplt.split_compl) {
// start split is ACK --> do complete split
channel->hcsplt_bm.split_compl = 1;
hcsplt.split_compl = 1;
channel->hcsplt = hcsplt.value;
channel->hcchar |= HCCHAR_CHENA;
}
}
@@ -1134,14 +1191,14 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc
static void handle_channel_irq(uint8_t rhport, bool in_isr) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const bool is_dma = dma_host_enabled(dwc2);
const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
const uint8_t max_channel = dwc2_channel_count(dwc2);
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
if (tu_bit_test(dwc2->haint, ch_id)) {
dwc2_channel_t* channel = &dwc2->channel[ch_id];
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,);
dwc2_channel_char_t hcchar_bm = channel->hcchar_bm;
dwc2_channel_char_t hcchar = {.value = channel->hcchar};
const uint32_t hcint = channel->hcint;
channel->hcint = hcint; // clear interrupt
@@ -1149,7 +1206,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
bool is_done = false;
if (is_dma) {
#if CFG_TUH_DWC2_DMA_ENABLE
if (hcchar_bm.ep_dir == TUSB_DIR_OUT) {
if (hcchar.ep_dir == TUSB_DIR_OUT) {
is_done = handle_channel_out_dma(dwc2, ch_id, hcint);
} else {
is_done = handle_channel_in_dma(dwc2, ch_id, hcint);
@@ -1161,7 +1218,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
#endif
} else {
#if CFG_TUH_DWC2_SLAVE_ENABLE
if (hcchar_bm.ep_dir == TUSB_DIR_OUT) {
if (hcchar.ep_dir == TUSB_DIR_OUT) {
is_done = handle_channel_out_slave(dwc2, ch_id, hcint);
} else {
is_done = handle_channel_in_slave(dwc2, ch_id, hcint);
@@ -1170,8 +1227,8 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
}
if (is_done) {
const uint8_t ep_addr = tu_edpt_addr(hcchar_bm.ep_num, hcchar_bm.ep_dir);
hcd_event_xfer_complete(hcchar_bm.dev_addr, ep_addr, xfer->xferred_bytes, xfer->result, in_isr);
const uint8_t ep_addr = tu_edpt_addr(hcchar.ep_num, hcchar.ep_dir);
hcd_event_xfer_complete(hcchar.dev_addr, ep_addr, xfer->xferred_bytes, (xfer_result_t)xfer->result, in_isr);
channel_dealloc(dwc2, ch_id);
}
}
@@ -1191,7 +1248,7 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) {
for(uint8_t ep_id = 0; ep_id < CFG_TUH_DWC2_ENDPOINT_MAX; ep_id++) {
hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
if (edpt->hcchar_bm.enable && edpt_is_periodic(edpt->hcchar_bm.ep_type) && edpt->uframe_countdown > 0) {
if (edpt->hcchar_bm.enable && channel_is_periodic(edpt->hcchar) && edpt->uframe_countdown > 0) {
edpt->uframe_countdown -= tu_min32(ucount, edpt->uframe_countdown);
if (edpt->uframe_countdown == 0) {
if (!edpt_xfer_kickoff(dwc2, ep_id)) {
@@ -1210,10 +1267,10 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) {
static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
uint32_t hcfg = dwc2->hcfg & ~HCFG_FSLS_PHYCLK_SEL;
const dwc2_gusbcfg_t gusbcfg_bm = dwc2->gusbcfg_bm;
const dwc2_gusbcfg_t gusbcfg = {.value = dwc2->gusbcfg};
uint32_t phy_clock;
if (gusbcfg_bm.phy_sel) {
if (gusbcfg.phy_sel) {
phy_clock = 48; // dedicated FS is 48Mhz
if (speed == TUSB_SPEED_LOW) {
hcfg |= HCFG_FSLS_PHYCLK_SEL_6MHZ;
@@ -1221,11 +1278,11 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
hcfg |= HCFG_FSLS_PHYCLK_SEL_48MHZ;
}
} else {
if (gusbcfg_bm.ulpi_utmi_sel) {
if (gusbcfg.ulpi_utmi_sel) {
phy_clock = 60; // ULPI 8-bit is 60Mhz
} else {
// UTMI+ 16-bit is 30Mhz, 8-bit is 60Mhz
phy_clock = gusbcfg_bm.phy_if16 ? 30 : 60;
phy_clock = gusbcfg.phy_if16 ? 30 : 60;
// Enable UTMI+ low power mode 48Mhz external clock if not highspeed
if (speed == TUSB_SPEED_HIGH) {
@@ -1242,9 +1299,9 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
uint32_t hfir = dwc2->hfir & ~HFIR_FRIVL_Msk;
if (speed == TUSB_SPEED_HIGH) {
hfir |= 125*phy_clock;
hfir |= 125*phy_clock - 1; // The "- 1" is the correct value. The Synopsys databook was corrected in 3.30a
} else {
hfir |= 1000*phy_clock;
hfir |= 1000*phy_clock - 1;
}
dwc2->hfir = hfir;
@@ -1257,21 +1314,19 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
*/
static void handle_hprt_irq(uint8_t rhport, bool in_isr) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
uint32_t hprt = dwc2->hprt & ~HPRT_W1_MASK;
const dwc2_hprt_t hprt_bm = dwc2->hprt_bm;
const dwc2_hprt_t hprt_bm = {.value = dwc2->hprt};
uint32_t hprt = hprt_bm.value & ~HPRT_W1_MASK;
if (dwc2->hprt & HPRT_CONN_DETECT) {
if (hprt_bm.conn_detected) {
// Port Connect Detect
hprt |= HPRT_CONN_DETECT;
if (hprt_bm.conn_status) {
hcd_event_device_attach(rhport, in_isr);
} else {
hcd_event_device_remove(rhport, in_isr);
}
}
if (dwc2->hprt & HPRT_ENABLE_CHANGE) {
if (hprt_bm.enable_change) {
// Port enable change
hprt |= HPRT_ENABLE_CHANGE;
@@ -1330,6 +1385,15 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
handle_channel_irq(rhport, in_isr);
}
if (gintsts & GINTSTS_DISCINT) {
// Device disconnected
dwc2->gintsts = GINTSTS_DISCINT;
if (!(dwc2->hprt & HPRT_CONN_STATUS)) {
hcd_event_device_remove(rhport, in_isr);
}
}
#if CFG_TUH_DWC2_SLAVE_ENABLE
// RxFIFO non-empty interrupt handling
if (gintsts & GINTSTS_RXFLVL) {

View File

@@ -29,6 +29,7 @@
#if CFG_TUH_ENABLED && CFG_TUSB_MCU == OPT_MCU_NONE
#include "host/hcd.h"
#include "host/usbh.h"
//--------------------------------------------------------------------+
// Controller API
@@ -106,6 +107,11 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
// Open an endpoint
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) {
(void) rhport; (void) dev_addr; (void) ep_desc;
// NOTE: ep_desc is allocated on the stack when called from usbh_edpt_control_open()
// You need to copy the data into a local variable who maintains the state of the endpoint and transfer.
// Check _hcd_data in hcd_dwc2.c for example.
return false;
}

View File

@@ -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

View File

@@ -514,6 +514,63 @@ host_test = [
]
def test_example(board, f1, example):
"""
Test example firmware
:param board: board dict
:param f1: flags on
:param example: example name
:return: 0 if success/skip, 1 if failed
"""
name = board['name']
err_count = 0
f1_str = ""
if f1 != "":
f1_str = '-f1_' + f1.replace(' ', '_')
fw_dir = f'{TINYUSB_ROOT}/cmake-build/cmake-build-{name}{f1_str}/{example}'
if not os.path.exists(fw_dir):
fw_dir = f'{TINYUSB_ROOT}/examples/cmake-build-{name}{f1_str}/{example}'
fw_name = f'{fw_dir}/{os.path.basename(example)}'
print(f'{name+f1_str:40} {example:30} ... ', end='')
if not os.path.exists(fw_dir) or not (os.path.exists(f'{fw_name}.elf') or os.path.exists(f'{fw_name}.bin')):
print('Skip (no binary)')
return 0
if verbose:
print(f'Flashing {fw_name}.elf')
# flash firmware. It may fail randomly, retry a few times
max_rety = 3
for i in range(max_rety):
ret = globals()[f'flash_{board["flasher"]["name"].lower()}'](board, fw_name)
if ret.returncode == 0:
try:
globals()[f'test_{example.replace("/", "_")}'](board)
print('OK')
break
except Exception as e:
if i == max_rety - 1:
err_count += 1
print(STATUS_FAILED)
print(f' {e}')
else:
print()
print(f' Test failed: {e}, retry {i+2}/{max_rety}')
time.sleep(1)
else:
print(f'Flashing failed, retry {i+2}/{max_rety}')
time.sleep(1)
if ret.returncode != 0:
err_count += 1
print(f'Flash {STATUS_FAILED}')
return err_count
def test_board(board):
name = board['name']
flasher = board['flasher']
@@ -537,57 +594,17 @@ def test_board(board):
test_list.remove(skip)
print(f'{name:25} {skip:30} ... Skip')
# board_test is added last to disable board's usb
test_list.append('device/board_test')
err_count = 0
flags_on_list = [""]
if 'build' in board and 'flags_on' in board['build']:
flags_on_list = board['build']['flags_on']
for f1 in flags_on_list:
f1_str = ""
if f1 != "":
f1_str = '-f1_' + f1.replace(' ', '_')
for test in test_list:
fw_dir = f'{TINYUSB_ROOT}/cmake-build/cmake-build-{name}{f1_str}/{test}'
if not os.path.exists(fw_dir):
fw_dir = f'{TINYUSB_ROOT}/examples/cmake-build-{name}{f1_str}/{test}'
fw_name = f'{fw_dir}/{os.path.basename(test)}'
print(f'{name+f1_str:40} {test:30} ... ', end='')
err_count += test_example(board, f1, test)
if not os.path.exists(fw_dir) or not (os.path.exists(f'{fw_name}.elf') or os.path.exists(f'{fw_name}.bin')):
print('Skip (no binary)')
continue
if verbose:
print(f'Flashing {fw_name}.elf')
# flash firmware. It may fail randomly, retry a few times
max_rety = 2
for i in range(max_rety):
ret = globals()[f'flash_{flasher["name"].lower()}'](board, fw_name)
if ret.returncode == 0:
try:
globals()[f'test_{test.replace("/", "_")}'](board)
print('OK')
break
except Exception as e:
if i == max_rety - 1:
err_count += 1
print(STATUS_FAILED)
print(f' {e}')
else:
print()
print(f' Test failed: {e}, retry {i+2}/{max_rety}')
time.sleep(1)
else:
print(f'Flashing failed, retry {i+2}/{max_rety}')
time.sleep(1)
if ret.returncode != 0:
err_count += 1
print(f'Flash {STATUS_FAILED}')
# flash board_test last to disable board's usb
test_example(board, flags_on_list[0], 'device/board_test')
return err_count

View File

@@ -21,16 +21,18 @@
"name": "espressif_s3_devkitm",
"uid": "84F703C084E4",
"build" : {
"flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE"]
"flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE"]
},
"tests": {
"only": ["device/cdc_msc_freertos", "device/hid_composite_freertos"]
"only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"],
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2005402"}]
},
"flasher": {
"name": "esptool",
"uid": "3ea619acd1cdeb11a0a0b806e93fd3f1",
"args": "-b 1500000"
}
},
"comment": "Use TS3USB30 mux to test both device and host"
},
{
"name": "feather_nrf52840_express",
@@ -124,6 +126,20 @@
"args": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\""
}
},
{
"name": "raspberry_pi_pico_w",
"uid": "E6614C311B764A37",
"tests": {
"device": false, "host": true, "dual": false,
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023934"}]
},
"flasher": {
"name": "openocd",
"uid": "E6633861A3819D38",
"args": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\""
},
"comment": "Test native host"
},
{
"name": "raspberry_pi_pico2",
"uid": "560AE75E1C7152C9",

View File

@@ -182,9 +182,14 @@ def build_boards_list(boards, toolchain, build_system, build_flags_on):
def build_family(family, toolchain, build_system, build_flags_on, one_per_family, boards):
skip_ci = ['pico_sdk']
if os.getenv('GITHUB_ACTIONS') or os.getenv('CIRCLECI'):
skip_ci_file = Path(f"hw/bsp/{family}/skip_ci.txt")
if skip_ci_file.exists():
skip_ci = skip_ci_file.read_text().split()
all_boards = []
for entry in os.scandir(f"hw/bsp/{family}/boards"):
if entry.is_dir() and entry.name != 'pico_sdk':
if entry.is_dir() and not entry.name in skip_ci:
all_boards.append(entry.name)
all_boards.sort()

View File

@@ -59,7 +59,7 @@ deps_optional = {
'144f1eb7ea8c06512e12f12b27383601c0272410',
'kinetis_k kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx imxrt'],
'hw/mcu/raspberry_pi/Pico-PIO-USB': ['https://github.com/hathach/Pico-PIO-USB.git',
'810653f66adadba3e0e4b4b56d5167ac4f7fdbf7',
'032a469e79f6a4ba40760d7868e6db26e15002d7',
'rp2040'],
'hw/mcu/renesas/fsp': ['https://github.com/renesas/fsp.git',
'edcc97d684b6f716728a60d7a6fea049d9870bd6',
@@ -125,7 +125,7 @@ deps_optional = {
'5ad9797c54ec3e55eff770fc9b3cd4a1aefc1309',
'stm32u5'],
'hw/mcu/st/cmsis_device_wb': ['https://github.com/STMicroelectronics/cmsis_device_wb.git',
'9c5d1920dd9fabbe2548e10561d63db829bb744f',
'd6a7fa2e7de084f5e5e47f2ab88b022fe9b50e5a',
'stm32wb'],
'hw/mcu/st/stm32-mfxstm32l152': ['https://github.com/STMicroelectronics/stm32-mfxstm32l152.git',
'7f4389efee9c6a655b55e5df3fceef5586b35f9b',
@@ -249,11 +249,13 @@ def get_a_dep(d):
p.mkdir(parents=True)
run_cmd(f"{git_cmd} init")
run_cmd(f"{git_cmd} remote add origin {url}")
head = None
else:
# Check if commit is already fetched
result = run_cmd(f"{git_cmd} rev-parse HEAD")
head = result.stdout.decode("utf-8").splitlines()[0]
run_cmd(f"{git_cmd} reset --hard")
if commit != head:
run_cmd(f"{git_cmd} fetch --depth 1 origin {commit}")
run_cmd(f"{git_cmd} checkout FETCH_HEAD")