Merge branch 'master' into h7rs
This commit is contained in:
@@ -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
|
||||
|
@@ -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"
|
||||
|
13
.github/actions/setup_toolchain/action.yml
vendored
13
.github/actions/setup_toolchain/action.yml
vendored
@@ -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:
|
||||
|
@@ -23,17 +23,25 @@ runs:
|
||||
if: steps.cache-toolchain-download.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
mkdir -p ~/cache/${{ inputs.toolchain }}
|
||||
wget --progress=dot:giga ${{ inputs.toolchain_url }} -O toolchain.tar.gz
|
||||
|
||||
if [[ ${{ inputs.toolchain }} == rx-gcc ]]; then
|
||||
mv toolchain.tar.gz toolchain.run
|
||||
wget --progress=dot:giga ${{ inputs.toolchain_url }} -O toolchain.run
|
||||
chmod +x toolchain.run
|
||||
./toolchain.run -p ~/cache/${{ inputs.toolchain }}/gnurx -y
|
||||
elif [[ ${{ inputs.toolchain }} == arm-iar ]]; then
|
||||
wget --progress=dot:giga ${{ inputs.toolchain_url }} -O ~/cache/${{ inputs.toolchain }}/cxarm.deb
|
||||
else
|
||||
wget --progress=dot:giga ${{ inputs.toolchain_url }} -O toolchain.tar.gz
|
||||
tar -C ~/cache/${{ inputs.toolchain }} -xaf toolchain.tar.gz
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Set Toolchain Path
|
||||
- name: Setup Toolchain
|
||||
run: |
|
||||
echo >> $GITHUB_PATH `echo ~/cache/${{ inputs.toolchain }}/*/bin`
|
||||
if [[ ${{ inputs.toolchain }} == arm-iar ]]; then
|
||||
sudo apt-get install -y ~/cache/${{ inputs.toolchain }}/cxarm.deb
|
||||
echo >> $GITHUB_PATH "/opt/iar/cxarm/arm/bin"
|
||||
else
|
||||
echo >> $GITHUB_PATH `echo ~/cache/${{ inputs.toolchain }}/*/bin`
|
||||
fi
|
||||
shell: bash
|
||||
|
9
.github/actions/setup_toolchain/toolchain.json
vendored
Normal file
9
.github/actions/setup_toolchain/toolchain.json
vendored
Normal 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"
|
||||
}
|
170
.github/workflows/build.yml
vendored
170
.github/workflows/build.yml
vendored
@@ -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
|
||||
|
2
.github/workflows/build_util.yml
vendored
2
.github/workflows/build_util.yml
vendored
@@ -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 }}
|
||||
|
7
.github/workflows/ci_set_matrix.py
vendored
7
.github/workflows/ci_set_matrix.py
vendored
@@ -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"],
|
||||
}
|
||||
|
||||
|
||||
|
6
.github/workflows/codeql.yml
vendored
6
.github/workflows/codeql.yml
vendored
@@ -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
|
||||
|
130
.github/workflows/hil_test.yml
vendored
130
.github/workflows/hil_test.yml
vendored
@@ -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
10
.idea/cmake.xml
generated
@@ -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="-DCFG_TUH_RPI_PIO_USB=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-pio_host" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=raspberry_pi_pico2 -DLOG=1 -DCFLAGS_CLI="-DCFG_TUH_RPI_PIO_USB=1"" />
|
||||
<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="-DCFG_TUH_RPI_PIO_USB=1"" />
|
||||
<configuration PROFILE_NAME="adafruit_fruit_jam" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=adafruit_fruit_jam -DLOG=1 -DCFLAGS_CLI="-DCFG_TUH_RPI_PIO_USB=1"" />
|
||||
<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
14
.idea/debugServers/esp32s2.xml
generated
Normal 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>
|
2
.idea/debugServers/rp2350.xml
generated
2
.idea/debugServers/rp2350.xml
generated
@@ -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 />
|
||||
|
2
.idea/debugServers/rt1060.xml
generated
2
.idea/debugServers/rt1060.xml
generated
@@ -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 />
|
||||
|
2
.idea/debugServers/rt1064.xml
generated
2
.idea/debugServers/rt1064.xml
generated
@@ -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 />
|
||||
|
2
.idea/debugServers/sam21.xml
generated
2
.idea/debugServers/sam21.xml
generated
@@ -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 />
|
||||
|
2
.idea/debugServers/sam51.xml
generated
2
.idea/debugServers/sam51.xml
generated
@@ -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
13
.idea/debugServers/stm32f769.xml
generated
Normal 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
13
.idea/debugServers/stm32h563.xml
generated
Normal 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
13
.idea/debugServers/stm32h743.xml
generated
Normal 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>
|
@@ -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 "")
|
||||
|
@@ -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")
|
||||
|
@@ -40,17 +40,15 @@ static bool ejected = false;
|
||||
If you find any bugs or get any questions, feel free to file an\r\n\
|
||||
issue at github.com/hathach/tinyusb"
|
||||
|
||||
enum
|
||||
{
|
||||
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount
|
||||
enum {
|
||||
DISK_BLOCK_NUM = 16,// 8KB is the smallest size that windows allow to mount
|
||||
DISK_BLOCK_SIZE = 512
|
||||
};
|
||||
|
||||
#ifdef CFG_EXAMPLE_MSC_READONLY
|
||||
const
|
||||
#endif
|
||||
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
|
||||
{
|
||||
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
|
||||
//------------- Block0: Boot Sector -------------//
|
||||
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
|
||||
// sector_per_cluster = 1; reserved_sectors = 1;
|
||||
@@ -59,60 +57,59 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
|
||||
// drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
|
||||
// filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
|
||||
// FAT magic code at offset 510-511
|
||||
{
|
||||
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
|
||||
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T' , 'i' , 'n' , 'y' , 'U' ,
|
||||
'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
|
||||
{
|
||||
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
|
||||
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U',
|
||||
'S', 'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
|
||||
|
||||
// Zero up to 2 last bytes of FAT magic code
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Zero up to 2 last bytes of FAT magic code
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
|
||||
},
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA},
|
||||
|
||||
//------------- Block1: FAT12 Table -------------//
|
||||
{
|
||||
0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
|
||||
{
|
||||
0xF8, 0xFF, 0xFF, 0xFF, 0x0F// // first 2 entries must be F8FF, third entry is cluster end of readme file
|
||||
},
|
||||
|
||||
//------------- Block2: Root Directory -------------//
|
||||
{
|
||||
// first entry is volume label
|
||||
'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x08, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// second entry is readme file
|
||||
'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D,
|
||||
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
|
||||
sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes)
|
||||
{
|
||||
// first entry is volume label
|
||||
'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// second entry is readme file
|
||||
'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, 0x52, 0x6D,
|
||||
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
|
||||
sizeof(README_CONTENTS) - 1, 0x00, 0x00, 0x00// readme's files size (4 Bytes)
|
||||
},
|
||||
|
||||
//------------- Block3: Readme Content -------------//
|
||||
@@ -121,23 +118,21 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
|
||||
|
||||
// Invoked when received SCSI_CMD_INQUIRY
|
||||
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
|
||||
{
|
||||
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
|
||||
(void) lun;
|
||||
|
||||
const char vid[] = "TinyUSB";
|
||||
const char pid[] = "Mass Storage";
|
||||
const char rev[] = "1.0";
|
||||
|
||||
memcpy(vendor_id , vid, strlen(vid));
|
||||
memcpy(product_id , pid, strlen(pid));
|
||||
memcpy(vendor_id, vid, strlen(vid));
|
||||
memcpy(product_id, pid, strlen(pid));
|
||||
memcpy(product_rev, rev, strlen(rev));
|
||||
}
|
||||
|
||||
// Invoked when received Test Unit Ready command.
|
||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||
bool tud_msc_test_unit_ready_cb(uint8_t lun)
|
||||
{
|
||||
bool tud_msc_test_unit_ready_cb(uint8_t lun) {
|
||||
(void) lun;
|
||||
|
||||
// RAM disk is ready until ejected
|
||||
@@ -152,29 +147,24 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun)
|
||||
|
||||
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
|
||||
// Application update block count and block size
|
||||
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
|
||||
{
|
||||
void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) {
|
||||
(void) lun;
|
||||
|
||||
*block_count = DISK_BLOCK_NUM;
|
||||
*block_size = DISK_BLOCK_SIZE;
|
||||
*block_size = DISK_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
// Invoked when received Start Stop Unit command
|
||||
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
|
||||
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
|
||||
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
|
||||
{
|
||||
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
|
||||
(void) lun;
|
||||
(void) power_condition;
|
||||
|
||||
if ( load_eject )
|
||||
{
|
||||
if (start)
|
||||
{
|
||||
if (load_eject) {
|
||||
if (start) {
|
||||
// load disk storage
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
// unload disk storage
|
||||
ejected = true;
|
||||
}
|
||||
@@ -185,52 +175,51 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
|
||||
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) {
|
||||
(void) lun;
|
||||
|
||||
// out of ramdisk
|
||||
if ( lba >= DISK_BLOCK_NUM ) {
|
||||
if (lba >= DISK_BLOCK_NUM) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check for overflow of offset + bufsize
|
||||
if ( offset + bufsize > DISK_BLOCK_SIZE ) {
|
||||
if (offset + bufsize > DISK_BLOCK_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t const* addr = msc_disk[lba] + offset;
|
||||
uint8_t const *addr = msc_disk[lba] + offset;
|
||||
memcpy(buffer, addr, bufsize);
|
||||
|
||||
return (int32_t) bufsize;
|
||||
}
|
||||
|
||||
bool tud_msc_is_writable_cb (uint8_t lun)
|
||||
{
|
||||
bool tud_msc_is_writable_cb(uint8_t lun) {
|
||||
(void) lun;
|
||||
|
||||
#ifdef CFG_EXAMPLE_MSC_READONLY
|
||||
#ifdef CFG_EXAMPLE_MSC_READONLY
|
||||
return false;
|
||||
#else
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and return number of written bytes
|
||||
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
|
||||
(void) lun;
|
||||
|
||||
// out of ramdisk
|
||||
if ( lba >= DISK_BLOCK_NUM ) return -1;
|
||||
if (lba >= DISK_BLOCK_NUM) return -1;
|
||||
|
||||
#ifndef CFG_EXAMPLE_MSC_READONLY
|
||||
uint8_t* addr = msc_disk[lba] + offset;
|
||||
#ifndef CFG_EXAMPLE_MSC_READONLY
|
||||
uint8_t *addr = msc_disk[lba] + offset;
|
||||
memcpy(addr, buffer, bufsize);
|
||||
#else
|
||||
(void) lba; (void) offset; (void) buffer;
|
||||
#endif
|
||||
#else
|
||||
(void) lba;
|
||||
(void) offset;
|
||||
(void) buffer;
|
||||
#endif
|
||||
|
||||
return (int32_t) bufsize;
|
||||
}
|
||||
@@ -238,42 +227,18 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
|
||||
// Callback invoked when received an SCSI command not in built-in list below
|
||||
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
|
||||
// - READ10 and WRITE10 has their own callbacks
|
||||
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
|
||||
{
|
||||
// read10 & write10 has their own callback and MUST not be handled here
|
||||
int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) {
|
||||
(void) buffer;
|
||||
(void) bufsize;
|
||||
|
||||
void const* response = NULL;
|
||||
int32_t resplen = 0;
|
||||
|
||||
// most scsi handled is input
|
||||
bool in_xfer = true;
|
||||
|
||||
switch (scsi_cmd[0])
|
||||
{
|
||||
switch (scsi_cmd[0]) {
|
||||
default:
|
||||
// Set Sense = Invalid Command Operation
|
||||
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
|
||||
|
||||
// negative means error -> tinyusb could stall and/or response with failed status
|
||||
resplen = -1;
|
||||
break;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// return resplen must not larger than bufsize
|
||||
if ( resplen > bufsize ) resplen = bufsize;
|
||||
|
||||
if ( response && (resplen > 0) )
|
||||
{
|
||||
if(in_xfer)
|
||||
{
|
||||
memcpy(buffer, response, (size_t) resplen);
|
||||
}else
|
||||
{
|
||||
// SCSI output
|
||||
}
|
||||
}
|
||||
|
||||
return (int32_t) resplen;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -55,8 +55,7 @@ If you find any bugs or get any questions, feel free to file an\r\n\
|
||||
issue at github.com/hathach/tinyusb"
|
||||
|
||||
|
||||
MSC_CONST uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
|
||||
{
|
||||
MSC_CONST uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
|
||||
//------------- Block0: Boot Sector -------------//
|
||||
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
|
||||
// sector_per_cluster = 1; reserved_sectors = 1;
|
||||
@@ -283,9 +282,11 @@ bool tud_msc_is_writable_cb(uint8_t lun) {
|
||||
// Process data in buffer to disk's storage and return number of written bytes
|
||||
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
|
||||
// out of ramdisk
|
||||
if (lba >= DISK_BLOCK_NUM) return -1;
|
||||
if (lba >= DISK_BLOCK_NUM) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(CFG_EXAMPLE_MSC_READONLY) || defined(CFG_EXAMPLE_MSC_DUAL_READONLY)
|
||||
#if defined(CFG_EXAMPLE_MSC_READONLY) || defined(CFG_EXAMPLE_MSC_DUAL_READONLY)
|
||||
(void) lun;
|
||||
(void) lba;
|
||||
(void) offset;
|
||||
@@ -302,11 +303,8 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
|
||||
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
|
||||
// - READ10 and WRITE10 has their own callbacks (MUST not be handled here)
|
||||
int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
|
||||
void const* response = NULL;
|
||||
int32_t resplen = 0;
|
||||
|
||||
// most scsi handled is input
|
||||
bool in_xfer = true;
|
||||
(void) buffer;
|
||||
(void) bufsize;
|
||||
|
||||
switch (scsi_cmd[0]) {
|
||||
default:
|
||||
@@ -316,19 +314,6 @@ int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, u
|
||||
// negative means error -> tinyusb could stall and/or response with failed status
|
||||
return -1;
|
||||
}
|
||||
|
||||
// return resplen must not larger than bufsize
|
||||
if (resplen > bufsize) resplen = bufsize;
|
||||
|
||||
if (response && (resplen > 0)) {
|
||||
if (in_xfer) {
|
||||
memcpy(buffer, response, (size_t) resplen);
|
||||
} else {
|
||||
// SCSI output
|
||||
}
|
||||
}
|
||||
|
||||
return resplen;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -29,14 +29,9 @@
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
#define MAX_REPORT 4
|
||||
|
||||
// If your host terminal support ansi escape code such as TeraTerm
|
||||
// it can be use to simulate mouse cursor movement within terminal
|
||||
#define USE_ANSI_ESCAPE 0
|
||||
|
||||
#define MAX_REPORT 4
|
||||
|
||||
static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII };
|
||||
static uint8_t const keycode2ascii[128][2] = {HID_KEYCODE_TO_ASCII};
|
||||
|
||||
// Each HID instance can has multiple reports
|
||||
static struct {
|
||||
@@ -45,8 +40,8 @@ static struct {
|
||||
} hid_info[CFG_TUH_HID];
|
||||
|
||||
static void process_kbd_report(hid_keyboard_report_t const *report);
|
||||
static void process_mouse_report(hid_mouse_report_t const * report);
|
||||
static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
|
||||
static void process_mouse_report(hid_mouse_report_t const *report);
|
||||
static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len);
|
||||
|
||||
void hid_app_task(void) {
|
||||
// nothing to do
|
||||
@@ -70,7 +65,7 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_re
|
||||
|
||||
printf("HID Interface Protocol = %s\r\n", protocol_str[itf_protocol]);
|
||||
|
||||
// By default host stack will use activate boot protocol on supported interface.
|
||||
// By default, host stack will use boot protocol on supported interface.
|
||||
// Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser)
|
||||
if (itf_protocol == HID_ITF_PROTOCOL_NONE) {
|
||||
hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT, desc_report, desc_len);
|
||||
@@ -121,7 +116,7 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// look up new key in previous keys
|
||||
static inline bool find_key_in_report(hid_keyboard_report_t const* report, uint8_t keycode) {
|
||||
static inline bool find_key_in_report(hid_keyboard_report_t const *report, uint8_t keycode) {
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
if (report->keycode[i] == keycode) {
|
||||
return true;
|
||||
@@ -130,28 +125,25 @@ static inline bool find_key_in_report(hid_keyboard_report_t const* report, uint8
|
||||
return false;
|
||||
}
|
||||
|
||||
static void process_kbd_report(hid_keyboard_report_t const *report)
|
||||
{
|
||||
static hid_keyboard_report_t prev_report = { 0, 0, {0} }; // previous report to check key released
|
||||
static void process_kbd_report(hid_keyboard_report_t const *report) {
|
||||
static hid_keyboard_report_t prev_report = {0, 0, {0}};// previous report to check key released
|
||||
|
||||
//------------- example code ignore control (non-printable) key affects -------------//
|
||||
for(uint8_t i=0; i<6; i++)
|
||||
{
|
||||
if ( report->keycode[i] )
|
||||
{
|
||||
if ( find_key_in_report(&prev_report, report->keycode[i]) )
|
||||
{
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
if (report->keycode[i]) {
|
||||
if (find_key_in_report(&prev_report, report->keycode[i])) {
|
||||
// exist in previous report means the current key is holding
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
// not existed in previous report means the current key is pressed
|
||||
bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
|
||||
uint8_t ch = keycode2ascii[report->keycode[i]][is_shift ? 1 : 0];
|
||||
putchar(ch);
|
||||
if ( ch == '\r' ) putchar('\n'); // added new line for enter key
|
||||
if (ch == '\r') {
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
#ifndef __ICCARM__ // TODO IAR doesn't support stream control ?
|
||||
fflush(stdout); // flush right away, else nanolib will wait for newline
|
||||
#ifndef __ICCARM__ // TODO IAR doesn't support stream control ?
|
||||
fflush(stdout);// flush right away, else nanolib will wait for newline
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -166,55 +158,22 @@ static void process_kbd_report(hid_keyboard_report_t const *report)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static void cursor_movement(int8_t x, int8_t y, int8_t wheel) {
|
||||
#if USE_ANSI_ESCAPE
|
||||
// Move X using ansi escape
|
||||
if ( x < 0)
|
||||
{
|
||||
printf(ANSI_CURSOR_BACKWARD(%d), (-x)); // move left
|
||||
}else if ( x > 0)
|
||||
{
|
||||
printf(ANSI_CURSOR_FORWARD(%d), x); // move right
|
||||
}
|
||||
|
||||
// Move Y using ansi escape
|
||||
if ( y < 0)
|
||||
{
|
||||
printf(ANSI_CURSOR_UP(%d), (-y)); // move up
|
||||
}else if ( y > 0)
|
||||
{
|
||||
printf(ANSI_CURSOR_DOWN(%d), y); // move down
|
||||
}
|
||||
|
||||
// Scroll using ansi escape
|
||||
if (wheel < 0)
|
||||
{
|
||||
printf(ANSI_SCROLL_UP(%d), (-wheel)); // scroll up
|
||||
}else if (wheel > 0)
|
||||
{
|
||||
printf(ANSI_SCROLL_DOWN(%d), wheel); // scroll down
|
||||
}
|
||||
|
||||
printf("\r\n");
|
||||
#else
|
||||
printf("(%d %d %d)\r\n", x, y, wheel);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void process_mouse_report(hid_mouse_report_t const * report)
|
||||
{
|
||||
static hid_mouse_report_t prev_report = { 0 };
|
||||
static void process_mouse_report(hid_mouse_report_t const *report) {
|
||||
static hid_mouse_report_t prev_report = {0};
|
||||
|
||||
//------------- button state -------------//
|
||||
// button state
|
||||
uint8_t button_changed_mask = report->buttons ^ prev_report.buttons;
|
||||
if ( button_changed_mask & report->buttons)
|
||||
{
|
||||
if (button_changed_mask & report->buttons) {
|
||||
printf(" %c%c%c ",
|
||||
report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-',
|
||||
report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-',
|
||||
report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-');
|
||||
report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-',
|
||||
report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-',
|
||||
report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-');
|
||||
}
|
||||
|
||||
//------------- cursor movement -------------//
|
||||
// cursor movement
|
||||
cursor_movement(report->x, report->y, report->wheel);
|
||||
}
|
||||
|
||||
@@ -263,18 +222,23 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c
|
||||
if (rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP) {
|
||||
switch (rpt_info->usage) {
|
||||
case HID_USAGE_DESKTOP_KEYBOARD:
|
||||
TU_LOG1("HID receive keyboard report\r\n");
|
||||
TU_LOG2("HID receive keyboard report\r\n");
|
||||
// Assume keyboard follow boot report layout
|
||||
process_kbd_report((hid_keyboard_report_t const *) report);
|
||||
break;
|
||||
|
||||
case HID_USAGE_DESKTOP_MOUSE:
|
||||
TU_LOG1("HID receive mouse report\r\n");
|
||||
TU_LOG2("HID receive mouse report\r\n");
|
||||
// Assume mouse follow boot report layout
|
||||
process_mouse_report((hid_mouse_report_t const *) report);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("report[%u] ", rpt_info->report_id);
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
printf("%02X ", report[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -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");
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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",
|
||||
|
@@ -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 \
|
||||
|
@@ -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 \
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -36,7 +36,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NEOPIXEL_PIN 48
|
||||
#define NEOPIXEL_PIN 38
|
||||
|
||||
#define BUTTON_PIN 0
|
||||
#define BUTTON_STATE_ACTIVE 0
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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 \
|
||||
|
2
hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.cmake
Normal file
2
hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
set(PICO_PLATFORM rp2040)
|
||||
set(PICO_BOARD pico_w)
|
70
hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.h
Normal file
70
hw/bsp/rp2040/boards/raspberry_pi_pico_w/board.h
Normal 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
|
7
hw/bsp/rp2040/skip_ci.txt
Normal file
7
hw/bsp/rp2040/skip_ci.txt
Normal 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
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -80,7 +80,7 @@ void OTG_HS_IRQHandler(void) {
|
||||
}
|
||||
|
||||
#ifdef TRACE_ETM
|
||||
void trace_etm_init(void) {
|
||||
static void trace_etm_init(void) {
|
||||
// H7 trace pin is PE2 to PE6
|
||||
GPIO_InitTypeDef gpio_init;
|
||||
gpio_init.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;
|
||||
@@ -94,7 +94,7 @@ void trace_etm_init(void) {
|
||||
DBGMCU->CR |= DBGMCU_CR_DBG_TRACECKEN | DBGMCU_CR_DBG_CKD1EN | DBGMCU_CR_DBG_CKD3EN;
|
||||
}
|
||||
#else
|
||||
#define trace_etm_init()
|
||||
#define trace_etm_init()
|
||||
#endif
|
||||
|
||||
void board_init(void) {
|
||||
|
@@ -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 \
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -3,21 +3,26 @@
|
||||
**
|
||||
** File : stm32wb55xx_flash_cm4.ld
|
||||
**
|
||||
** Abstract : System Workbench Minimal System calls file
|
||||
** Author : STM32CubeIDE
|
||||
**
|
||||
** For more information about which c-functions
|
||||
** need which of these lowlevel functions
|
||||
** please consult the Newlib libc-manual
|
||||
** Abstract : Linker script for STM32WB55xx Device
|
||||
** 1024Kbytes FLASH
|
||||
** 128Kbytes RAM
|
||||
**
|
||||
** Environment : System Workbench for MCU
|
||||
** Set heap size, stack size and stack location according
|
||||
** to application requirements.
|
||||
**
|
||||
** Distribution: The file is distributed “as is,” without any warranty
|
||||
** Set memory bank area and size if external memory is used.
|
||||
**
|
||||
** Target : STMicroelectronics STM32
|
||||
**
|
||||
** Distribution: The file is distributed as is without any warranty
|
||||
** of any kind.
|
||||
**
|
||||
*****************************************************************************
|
||||
** @attention
|
||||
**
|
||||
** Copyright (c) 2019 STMicroelectronics.
|
||||
** Copyright (c) 2019-2022 STMicroelectronics.
|
||||
** All rights reserved.
|
||||
**
|
||||
** This software is licensed under terms that can be found in the LICENSE file
|
||||
@@ -33,7 +38,7 @@ ENTRY(Reset_Handler)
|
||||
/* Highest address of the user mode stack */
|
||||
_estack = 0x20030000; /* end of RAM */
|
||||
/* Generate a link error if heap and stack don't fit into RAM */
|
||||
_Min_Heap_Size = 0x400; /* required amount of heap */
|
||||
_Min_Heap_Size = 0x400; /* required amount of heap */
|
||||
_Min_Stack_Size = 0x1000; /* required amount of stack */
|
||||
|
||||
/* Specify the memory areas */
|
||||
@@ -81,14 +86,17 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
} >FLASH
|
||||
.ARM : {
|
||||
__exidx_start = .;
|
||||
*(.ARM.exidx*)
|
||||
__exidx_end = .;
|
||||
} >FLASH
|
||||
|
||||
.preinit_array :
|
||||
.preinit_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array*))
|
||||
@@ -124,7 +132,6 @@ SECTIONS
|
||||
_edata = .; /* define a global symbol at data end */
|
||||
} >RAM1 AT> FLASH
|
||||
|
||||
|
||||
/* Uninitialized data section */
|
||||
. = ALIGN(4);
|
||||
.bss :
|
||||
@@ -152,8 +159,6 @@ SECTIONS
|
||||
. = ALIGN(8);
|
||||
} >RAM1
|
||||
|
||||
|
||||
|
||||
/* Remove information from the standard libraries */
|
||||
/DISCARD/ :
|
||||
{
|
||||
@@ -163,7 +168,15 @@ SECTIONS
|
||||
}
|
||||
|
||||
.ARM.attributes 0 : { *(.ARM.attributes) }
|
||||
MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED
|
||||
MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED
|
||||
MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED
|
||||
MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED
|
||||
MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED
|
||||
|
||||
/* used by the startup to initialize .MB_MEM2 data */
|
||||
_siMB_MEM2 = LOADADDR(.MB_MEM2);
|
||||
.MB_MEM2 :
|
||||
{
|
||||
_sMB_MEM2 = . ;
|
||||
*(MB_MEM2) ;
|
||||
_eMB_MEM2 = . ;
|
||||
} >RAM_SHARED AT> FLASH
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
|
@@ -344,7 +344,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
|
||||
msc_csw_t * p_csw = &p_msc->csw;
|
||||
|
||||
switch (p_msc->stage) {
|
||||
case MSC_STAGE_CMD:
|
||||
case MSC_STAGE_CMD: {
|
||||
//------------- new CBW received -------------//
|
||||
// Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it
|
||||
if (ep_addr != p_msc->ep_out) {
|
||||
@@ -441,7 +441,8 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
case MSC_STAGE_DATA:
|
||||
TU_LOG_DRV(" SCSI Data [Lun%u]\r\n", p_cbw->lun);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
230
src/host/hub.c
230
src/host/hub.c
@@ -57,9 +57,11 @@ typedef struct {
|
||||
TUH_EPBUF_DEF(ctrl_buf, CFG_TUH_HUB_BUFSIZE);
|
||||
} hub_epbuf_t;
|
||||
|
||||
static tuh_xfer_cb_t user_complete_cb = NULL;
|
||||
static hub_interface_t hub_itfs[CFG_TUH_HUB];
|
||||
CFG_TUH_MEM_SECTION static hub_epbuf_t hub_epbufs[CFG_TUH_HUB];
|
||||
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline hub_interface_t* get_hub_itf(uint8_t daddr) {
|
||||
return &hub_itfs[daddr-1-CFG_TUH_DEVICE_MAX];
|
||||
}
|
||||
@@ -142,10 +144,23 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
|
||||
};
|
||||
|
||||
TU_LOG_DRV("HUB Set Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port);
|
||||
TU_ASSERT( tuh_control_xfer(&xfer) );
|
||||
TU_ASSERT(tuh_control_xfer(&xfer));
|
||||
return true;
|
||||
}
|
||||
|
||||
static void port_get_status_complete (tuh_xfer_t* xfer) {
|
||||
if (xfer->result == XFER_RESULT_SUCCESS) {
|
||||
hub_interface_t* p_hub = get_hub_itf(xfer->daddr);
|
||||
p_hub->port_status = *((const hub_port_status_response_t *) (uintptr_t) xfer->buffer);
|
||||
}
|
||||
|
||||
xfer->complete_cb = user_complete_cb;
|
||||
user_complete_cb = NULL;
|
||||
if (xfer->complete_cb) {
|
||||
xfer->complete_cb(xfer);
|
||||
}
|
||||
}
|
||||
|
||||
bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
|
||||
tusb_control_request_t const request = {
|
||||
@@ -169,8 +184,25 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
|
||||
.user_data = user_data
|
||||
};
|
||||
|
||||
if (hub_port != 0) {
|
||||
// intercept complete callback to save port status, ignore resp
|
||||
hub_epbuf_t* p_epbuf = get_hub_epbuf(hub_addr);
|
||||
xfer.complete_cb = port_get_status_complete;
|
||||
xfer.buffer = p_epbuf->ctrl_buf;
|
||||
user_complete_cb = complete_cb;
|
||||
} else {
|
||||
user_complete_cb = NULL;
|
||||
}
|
||||
|
||||
TU_LOG_DRV("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port);
|
||||
TU_VERIFY( tuh_control_xfer(&xfer) );
|
||||
TU_VERIFY(tuh_control_xfer(&xfer));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hub_port_get_status_local(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp) {
|
||||
(void) hub_port;
|
||||
hub_interface_t* p_hub = get_hub_itf(hub_addr);
|
||||
*resp = p_hub->port_status;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -238,10 +270,10 @@ bool hub_edpt_status_xfer(uint8_t daddr) {
|
||||
static void config_set_port_power (tuh_xfer_t* xfer);
|
||||
static void config_port_power_complete (tuh_xfer_t* xfer);
|
||||
|
||||
bool hub_set_config(uint8_t dev_addr, uint8_t itf_num) {
|
||||
hub_interface_t* p_hub = get_hub_itf(dev_addr);
|
||||
bool hub_set_config(uint8_t daddr, uint8_t itf_num) {
|
||||
hub_interface_t* p_hub = get_hub_itf(daddr);
|
||||
TU_ASSERT(itf_num == p_hub->itf_num);
|
||||
hub_epbuf_t* p_epbuf = get_hub_epbuf(dev_addr);
|
||||
hub_epbuf_t* p_epbuf = get_hub_epbuf(daddr);
|
||||
|
||||
// Get Hub Descriptor
|
||||
tusb_control_request_t const request = {
|
||||
@@ -257,7 +289,7 @@ bool hub_set_config(uint8_t dev_addr, uint8_t itf_num) {
|
||||
};
|
||||
|
||||
tuh_xfer_t xfer = {
|
||||
.daddr = dev_addr,
|
||||
.daddr = daddr,
|
||||
.ep_addr = 0,
|
||||
.setup = &request,
|
||||
.buffer = p_epbuf->ctrl_buf,
|
||||
@@ -312,11 +344,15 @@ static void config_port_power_complete (tuh_xfer_t* xfer) {
|
||||
//--------------------------------------------------------------------+
|
||||
// Connection Changes
|
||||
//--------------------------------------------------------------------+
|
||||
static void get_status_complete (tuh_xfer_t* xfer);
|
||||
static void port_get_status_complete (tuh_xfer_t* xfer);
|
||||
static void port_clear_feature_complete_stub(tuh_xfer_t* xfer);
|
||||
static void connection_clear_conn_change_complete (tuh_xfer_t* xfer);
|
||||
static void connection_port_reset_complete (tuh_xfer_t* xfer);
|
||||
enum {
|
||||
STATE_IDLE = 0,
|
||||
STATE_HUB_STATUS,
|
||||
STATE_CLEAR_CHANGE,
|
||||
STATE_CHECK_CONN,
|
||||
STATE_COMPLETE
|
||||
};
|
||||
|
||||
static void process_new_status(tuh_xfer_t* xfer);
|
||||
|
||||
// callback as response of interrupt endpoint polling
|
||||
bool hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
|
||||
@@ -337,12 +373,12 @@ bool hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t
|
||||
processed = false;
|
||||
} else if (tu_bit_test(status_change, 0)) {
|
||||
// Hub bit 0 is for the hub device events
|
||||
processed = hub_get_status(daddr, p_epbuf->ctrl_buf, get_status_complete, 0);
|
||||
processed = hub_get_status(daddr, p_epbuf->ctrl_buf, process_new_status, STATE_HUB_STATUS);
|
||||
} else {
|
||||
// Hub bits 1 to n are hub port events
|
||||
for (uint8_t port=1; port <= p_hub->bNbrPorts; port++) {
|
||||
if (tu_bit_test(status_change, port)) {
|
||||
processed = hub_port_get_status(daddr, port, p_epbuf->ctrl_buf, port_get_status_complete, 0);
|
||||
processed = hub_port_get_status(daddr, port, NULL, process_new_status, STATE_CLEAR_CHANGE);
|
||||
break; // after completely processed one port, we will re-queue the status poll and handle next one
|
||||
}
|
||||
}
|
||||
@@ -358,117 +394,85 @@ bool hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t
|
||||
return true;
|
||||
}
|
||||
|
||||
static void port_clear_feature_complete_stub(tuh_xfer_t* xfer) {
|
||||
hub_edpt_status_xfer(xfer->daddr);
|
||||
}
|
||||
|
||||
static void get_status_complete(tuh_xfer_t *xfer) {
|
||||
const uint8_t daddr = xfer->daddr;
|
||||
|
||||
bool processed = false; // true if new status is processed
|
||||
if (xfer->result == XFER_RESULT_SUCCESS) {
|
||||
hub_status_response_t hub_status = *((const hub_status_response_t *) (uintptr_t) xfer->buffer);
|
||||
|
||||
TU_LOG_DRV("HUB Got hub status, addr = %u, status = %04x\r\n", daddr, hub_status.change.value);
|
||||
|
||||
if (hub_status.change.local_power_source) {
|
||||
TU_LOG_DRV(" Local Power Change\r\n");
|
||||
processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_LOCAL_POWER_CHANGE, port_clear_feature_complete_stub, 0);
|
||||
} else if (hub_status.change.over_current) {
|
||||
TU_LOG_DRV(" Over Current\r\n");
|
||||
processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_OVER_CURRENT_CHANGE, port_clear_feature_complete_stub, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!processed) {
|
||||
TU_ASSERT(hub_edpt_status_xfer(daddr), );
|
||||
}
|
||||
}
|
||||
|
||||
static void port_get_status_complete(tuh_xfer_t *xfer) {
|
||||
const uint8_t daddr = xfer->daddr;
|
||||
bool processed = false; // true if new status is processed
|
||||
|
||||
if (xfer->result == XFER_RESULT_SUCCESS) {
|
||||
const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
hub_interface_t *p_hub = get_hub_itf(daddr);
|
||||
p_hub->port_status = *((const hub_port_status_response_t *) (uintptr_t) xfer->buffer);
|
||||
|
||||
// Clear port status change interrupts
|
||||
if (p_hub->port_status.change.connection) {
|
||||
// Connection change
|
||||
// Port is powered and enabled
|
||||
//TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, );
|
||||
|
||||
// Acknowledge Port Connection Change
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete, 0);
|
||||
} else if (p_hub->port_status.change.port_enable) {
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_ENABLE_CHANGE, port_clear_feature_complete_stub, 0);
|
||||
} else if (p_hub->port_status.change.suspend) {
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_SUSPEND_CHANGE, port_clear_feature_complete_stub, 0);
|
||||
} else if (p_hub->port_status.change.over_current) {
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_OVER_CURRENT_CHANGE, port_clear_feature_complete_stub, 0);
|
||||
} else if (p_hub->port_status.change.reset) {
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_RESET_CHANGE, port_clear_feature_complete_stub, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!processed) {
|
||||
TU_ASSERT(hub_edpt_status_xfer(daddr), );
|
||||
}
|
||||
}
|
||||
|
||||
static void connection_clear_conn_change_complete (tuh_xfer_t* xfer) {
|
||||
static void process_new_status(tuh_xfer_t* xfer) {
|
||||
const uint8_t daddr = xfer->daddr;
|
||||
|
||||
if (xfer->result != XFER_RESULT_SUCCESS) {
|
||||
TU_ASSERT(hub_edpt_status_xfer(daddr), );
|
||||
TU_ASSERT(hub_edpt_status_xfer(daddr),);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
hub_interface_t *p_hub = get_hub_itf(daddr);
|
||||
const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
const uintptr_t state = xfer->user_data;
|
||||
bool processed = false; // true if new status is processed
|
||||
|
||||
if (p_hub->port_status.status.connection) {
|
||||
// Reset port if attach event
|
||||
hub_port_reset(daddr, port_num, connection_port_reset_complete, 0);
|
||||
} else {
|
||||
// submit detach event
|
||||
const hcd_event_t event = {
|
||||
.rhport = usbh_get_rhport(daddr),
|
||||
.event_id = HCD_EVENT_DEVICE_REMOVE,
|
||||
.connection = {
|
||||
.hub_addr = daddr,
|
||||
.hub_port = port_num
|
||||
}
|
||||
};
|
||||
hcd_event_handler(&event, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void connection_port_reset_complete (tuh_xfer_t* xfer) {
|
||||
const uint8_t daddr = xfer->daddr;
|
||||
|
||||
if (xfer->result != XFER_RESULT_SUCCESS) {
|
||||
// retry port reset if failed
|
||||
if (!tuh_control_xfer(xfer)) {
|
||||
TU_ASSERT(hub_edpt_status_xfer(daddr), ); // back to status poll if failed to queue request
|
||||
switch (state) {
|
||||
case STATE_HUB_STATUS: {
|
||||
hub_status_response_t hub_status = *((const hub_status_response_t *) (uintptr_t) xfer->buffer);
|
||||
TU_LOG_DRV("HUB Got hub status, addr = %u, status = %04x\r\n", daddr, hub_status.change.value);
|
||||
if (hub_status.change.local_power_source) {
|
||||
TU_LOG_DRV(" Local Power Change\r\n");
|
||||
processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_LOCAL_POWER_CHANGE,
|
||||
process_new_status, STATE_COMPLETE);
|
||||
} else if (hub_status.change.over_current) {
|
||||
TU_LOG_DRV(" Over Current\r\n");
|
||||
processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_OVER_CURRENT_CHANGE,
|
||||
process_new_status, STATE_COMPLETE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
||||
case STATE_CLEAR_CHANGE:
|
||||
// Get port status complete --> clear change
|
||||
if (p_hub->port_status.change.connection) {
|
||||
// Connection change
|
||||
// Port is powered and enabled
|
||||
//TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, );
|
||||
|
||||
// Acknowledge Port Connection Change
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE,
|
||||
process_new_status, STATE_CHECK_CONN);
|
||||
} else if (p_hub->port_status.change.port_enable) {
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_ENABLE_CHANGE,
|
||||
process_new_status, STATE_COMPLETE);
|
||||
} else if (p_hub->port_status.change.suspend) {
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_SUSPEND_CHANGE,
|
||||
process_new_status, STATE_COMPLETE);
|
||||
} else if (p_hub->port_status.change.over_current) {
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_OVER_CURRENT_CHANGE,
|
||||
process_new_status, STATE_COMPLETE);
|
||||
} else if (p_hub->port_status.change.reset) {
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_RESET_CHANGE,
|
||||
process_new_status, STATE_COMPLETE);
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_CHECK_CONN: {
|
||||
const hcd_event_t event = {
|
||||
.rhport = usbh_get_rhport(daddr),
|
||||
.event_id = p_hub->port_status.status.connection ? HCD_EVENT_DEVICE_ATTACH : HCD_EVENT_DEVICE_REMOVE,
|
||||
.connection = {
|
||||
.hub_addr = daddr,
|
||||
.hub_port = port_num
|
||||
}
|
||||
};
|
||||
hcd_event_handler(&event, false);
|
||||
// skip status for attach event, usbh will do it after handled this enumeration
|
||||
processed = (event.event_id == HCD_EVENT_DEVICE_ATTACH);
|
||||
break;
|
||||
}
|
||||
|
||||
case STATE_COMPLETE:
|
||||
default:
|
||||
processed = false; // complete this status, queue next status
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
|
||||
// submit attach event
|
||||
hcd_event_t event = {
|
||||
.rhport = usbh_get_rhport(daddr),
|
||||
.event_id = HCD_EVENT_DEVICE_ATTACH,
|
||||
.connection = {
|
||||
.hub_addr = daddr,
|
||||
.hub_port = port_num
|
||||
}
|
||||
};
|
||||
hcd_event_handler(&event, false);
|
||||
if (!processed) {
|
||||
TU_ASSERT(hub_edpt_status_xfer(daddr),);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -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);
|
||||
|
||||
|
995
src/host/usbh.c
995
src/host/usbh.c
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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 -------------//
|
||||
|
@@ -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;
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#endif
|
||||
|
||||
#include "host/hcd.h"
|
||||
#include "host/usbh.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
|
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "chip.h"
|
||||
#include "host/hcd.h"
|
||||
#include "host/usbh.h"
|
||||
|
||||
void hcd_int_enable(uint8_t rhport)
|
||||
{
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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];
|
||||
|
||||
|
@@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,7 @@
|
||||
#define DWC2_DEBUG 2
|
||||
|
||||
#include "host/hcd.h"
|
||||
#include "host/usbh.h"
|
||||
#include "dwc2_common.h"
|
||||
|
||||
// Max number of endpoints application can open, can be larger than DWC2_CHANNEL_COUNT_MAX
|
||||
@@ -44,8 +45,6 @@
|
||||
#endif
|
||||
|
||||
#define DWC2_CHANNEL_COUNT_MAX 16 // absolute max channel count
|
||||
#define DWC2_CHANNEL_COUNT(_dwc2) tu_min8((_dwc2)->ghwcfg2_bm.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX)
|
||||
|
||||
TU_VERIFY_STATIC(CFG_TUH_DWC2_ENDPOINT_MAX <= 255, "currently only use 8-bit for index");
|
||||
|
||||
enum {
|
||||
@@ -77,9 +76,9 @@ typedef struct {
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint32_t uframe_interval : 18; // micro-frame interval
|
||||
uint32_t speed : 2;
|
||||
uint32_t next_pid : 2;
|
||||
uint32_t do_ping : 1;
|
||||
uint32_t speed : 2;
|
||||
uint32_t next_pid : 2; // PID for next transfer
|
||||
uint32_t next_do_ping : 1; // Do PING for next transfer if possible (highspeed OUT)
|
||||
// uint32_t : 9;
|
||||
};
|
||||
|
||||
@@ -97,7 +96,6 @@ typedef struct {
|
||||
uint8_t err_count : 3;
|
||||
uint8_t period_split_nyet_count : 3;
|
||||
uint8_t halted_nyet : 1;
|
||||
uint8_t halted_sof_schedule : 1;
|
||||
};
|
||||
uint8_t result;
|
||||
|
||||
@@ -116,9 +114,15 @@ hcd_data_t _hcd_data;
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_channel_count(const dwc2_regs_t* dwc2) {
|
||||
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
|
||||
return tu_min8(ghwcfg2.num_host_ch + 1, DWC2_CHANNEL_COUNT_MAX);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc2) {
|
||||
tusb_speed_t speed;
|
||||
switch(dwc2->hprt_bm.speed) {
|
||||
const dwc2_hprt_t hprt = {.value = dwc2->hprt};
|
||||
switch(hprt.speed) {
|
||||
case HPRT_SPEED_HIGH: speed = TUSB_SPEED_HIGH; break;
|
||||
case HPRT_SPEED_FULL: speed = TUSB_SPEED_FULL; break;
|
||||
case HPRT_SPEED_LOW : speed = TUSB_SPEED_LOW ; break;
|
||||
@@ -133,7 +137,8 @@ TU_ATTR_ALWAYS_INLINE static inline tusb_speed_t hprt_speed_get(dwc2_regs_t* dwc
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool dma_host_enabled(const dwc2_regs_t* dwc2) {
|
||||
(void) dwc2;
|
||||
// Internal DMA only
|
||||
return CFG_TUH_DWC2_DMA_ENABLE && dwc2->ghwcfg2_bm.arch == GHWCFG2_ARCH_INTERNAL_DMA;
|
||||
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
|
||||
return CFG_TUH_DWC2_DMA_ENABLE && ghwcfg2.arch == GHWCFG2_ARCH_INTERNAL_DMA;
|
||||
}
|
||||
|
||||
#if CFG_TUH_MEM_DCACHE_ENABLE
|
||||
@@ -155,7 +160,7 @@ bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
|
||||
|
||||
// Allocate a channel for new transfer
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) {
|
||||
const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
|
||||
const uint8_t max_channel = dwc2_channel_count(dwc2);
|
||||
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
|
||||
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
|
||||
if (!xfer->allocated) {
|
||||
@@ -168,15 +173,18 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) {
|
||||
}
|
||||
|
||||
// Check if is periodic (interrupt/isochronous)
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool edpt_is_periodic(uint8_t ep_type) {
|
||||
return ep_type == HCCHAR_EPTYPE_INTERRUPT || ep_type == HCCHAR_EPTYPE_ISOCHRONOUS;
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool channel_is_periodic(uint32_t hcchar) {
|
||||
const dwc2_channel_char_t hcchar_bm = {.value = hcchar};
|
||||
return hcchar_bm.ep_type == HCCHAR_EPTYPE_INTERRUPT || hcchar_bm.ep_type == HCCHAR_EPTYPE_ISOCHRONOUS;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint8_t req_queue_avail(const dwc2_regs_t* dwc2, bool is_period) {
|
||||
if (is_period) {
|
||||
return dwc2->hptxsts_bm.req_queue_available;
|
||||
const dwc2_hptxsts_t hptxsts = {.value = dwc2->hptxsts};
|
||||
return hptxsts.req_queue_available;
|
||||
} else {
|
||||
return dwc2->hnptxsts_bm.req_queue_available;
|
||||
const dwc2_hnptxsts_t hnptxsts = {.value = dwc2->hnptxsts};
|
||||
return hnptxsts.req_queue_available;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +196,7 @@ TU_ATTR_ALWAYS_INLINE static inline void channel_dealloc(dwc2_regs_t* dwc2, uint
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) {
|
||||
// disable also require request queue
|
||||
TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type)));
|
||||
TU_ASSERT(req_queue_avail(dwc2, channel_is_periodic(channel->hcchar)));
|
||||
channel->hcintmsk |= HCINT_HALTED;
|
||||
channel->hcchar |= HCCHAR_CHDIS | HCCHAR_CHENA; // must set both CHDIS and CHENA
|
||||
return true;
|
||||
@@ -196,18 +204,18 @@ TU_ATTR_ALWAYS_INLINE static inline bool channel_disable(const dwc2_regs_t* dwc2
|
||||
|
||||
// attempt to send IN token to receive data
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool channel_send_in_token(const dwc2_regs_t* dwc2, dwc2_channel_t* channel) {
|
||||
TU_ASSERT(req_queue_avail(dwc2, edpt_is_periodic(channel->hcchar_bm.ep_type)));
|
||||
TU_ASSERT(req_queue_avail(dwc2, channel_is_periodic(channel->hcchar)));
|
||||
channel->hcchar |= HCCHAR_CHENA;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find currently enabled channel. Note: EP0 is bidirectional
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_find_enabled(dwc2_regs_t* dwc2, uint8_t dev_addr, uint8_t ep_num, uint8_t ep_dir) {
|
||||
const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
|
||||
const uint8_t max_channel = dwc2_channel_count(dwc2);
|
||||
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
|
||||
if (_hcd_data.xfer[ch_id].allocated) {
|
||||
const dwc2_channel_char_t hcchar_bm = dwc2->channel[ch_id].hcchar_bm;
|
||||
if (hcchar_bm.dev_addr == dev_addr && hcchar_bm.ep_num == ep_num && (ep_num == 0 || hcchar_bm.ep_dir == ep_dir)) {
|
||||
const dwc2_channel_char_t hcchar = {.value = dwc2->channel[ch_id].hcchar};
|
||||
if (hcchar.dev_addr == dev_addr && hcchar.ep_num == ep_num && (ep_num == 0 || hcchar.ep_dir == ep_dir)) {
|
||||
return ch_id;
|
||||
}
|
||||
}
|
||||
@@ -304,12 +312,13 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t cal_next_pid(uint8_t pid, uint8_t pa
|
||||
static void dfifo_host_init(uint8_t rhport) {
|
||||
const dwc2_controller_t* dwc2_controller = &_dwc2_controller[rhport];
|
||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||
const dwc2_ghwcfg2_t ghwcfg2 = {.value = dwc2->ghwcfg2};
|
||||
|
||||
// Scatter/Gather DMA mode is not yet supported. Buffer DMA only need 1 words per channel
|
||||
const bool is_dma = dma_host_enabled(dwc2);
|
||||
uint16_t dfifo_top = dwc2_controller->ep_fifo_size/4;
|
||||
if (is_dma) {
|
||||
dfifo_top -= dwc2->ghwcfg2_bm.num_host_ch;
|
||||
dfifo_top -= ghwcfg2.num_host_ch;
|
||||
}
|
||||
|
||||
// fixed allocation for now, improve later:
|
||||
@@ -319,7 +328,7 @@ static void dfifo_host_init(uint8_t rhport) {
|
||||
uint32_t ptx_largest = is_highspeed ? TUSB_EPSIZE_ISO_HS_MAX/4 : 256/4;
|
||||
|
||||
uint16_t nptxfsiz = 2 * nptx_largest;
|
||||
uint16_t rxfsiz = 2 * (ptx_largest + 2) + dwc2->ghwcfg2_bm.num_host_ch;
|
||||
uint16_t rxfsiz = 2 * (ptx_largest + 2) + ghwcfg2.num_host_ch;
|
||||
TU_ASSERT(dfifo_top >= (nptxfsiz + rxfsiz),);
|
||||
uint16_t ptxfsiz = dfifo_top - (nptxfsiz + rxfsiz);
|
||||
|
||||
@@ -381,7 +390,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
||||
dwc2->hprt = HPRT_POWER; // turn on VBUS
|
||||
|
||||
// Enable required interrupts
|
||||
dwc2->gintmsk |= GINTSTS_OTGINT | GINTSTS_CONIDSTSCHNG | GINTSTS_HPRTINT | GINTSTS_HCINT;
|
||||
dwc2->gintmsk |= GINTSTS_OTGINT | GINTSTS_CONIDSTSCHNG | GINTSTS_HPRTINT | GINTSTS_HCINT | GINTSTS_DISCINT;
|
||||
|
||||
// NPTX can hold at least 2 packet, change interrupt level to half-empty
|
||||
uint32_t gahbcfg = dwc2->gahbcfg & ~GAHBCFG_TX_FIFO_EPMTY_LVL;
|
||||
@@ -461,8 +470,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t*
|
||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||
const tusb_speed_t rh_speed = hprt_speed_get(dwc2);
|
||||
|
||||
hcd_devtree_info_t devtree_info;
|
||||
hcd_devtree_get_info(dev_addr, &devtree_info);
|
||||
tuh_bus_info_t bus_info;
|
||||
tuh_bus_info_get(dev_addr, &bus_info);
|
||||
|
||||
// find a free endpoint
|
||||
const uint8_t ep_id = edpt_alloc();
|
||||
@@ -473,7 +482,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t*
|
||||
hcchar_bm->ep_size = tu_edpt_packet_size(desc_ep);
|
||||
hcchar_bm->ep_num = tu_edpt_number(desc_ep->bEndpointAddress);
|
||||
hcchar_bm->ep_dir = tu_edpt_dir(desc_ep->bEndpointAddress);
|
||||
hcchar_bm->low_speed_dev = (devtree_info.speed == TUSB_SPEED_LOW) ? 1 : 0;
|
||||
hcchar_bm->low_speed_dev = (bus_info.speed == TUSB_SPEED_LOW) ? 1 : 0;
|
||||
hcchar_bm->ep_type = desc_ep->bmAttributes.xfer; // ep_type matches TUSB_XFER_*
|
||||
hcchar_bm->err_multi_count = 0;
|
||||
hcchar_bm->dev_addr = dev_addr;
|
||||
@@ -482,21 +491,21 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t*
|
||||
hcchar_bm->enable = 1;
|
||||
|
||||
dwc2_channel_split_t* hcsplt_bm = &edpt->hcsplt_bm;
|
||||
hcsplt_bm->hub_port = devtree_info.hub_port;
|
||||
hcsplt_bm->hub_addr = devtree_info.hub_addr;
|
||||
hcsplt_bm->hub_port = bus_info.hub_port;
|
||||
hcsplt_bm->hub_addr = bus_info.hub_addr;
|
||||
hcsplt_bm->xact_pos = 0;
|
||||
hcsplt_bm->split_compl = 0;
|
||||
hcsplt_bm->split_en = (rh_speed == TUSB_SPEED_HIGH && devtree_info.speed != TUSB_SPEED_HIGH) ? 1 : 0;
|
||||
hcsplt_bm->split_en = (rh_speed == TUSB_SPEED_HIGH && bus_info.speed != TUSB_SPEED_HIGH) ? 1 : 0;
|
||||
|
||||
edpt->speed = devtree_info.speed;
|
||||
edpt->speed = bus_info.speed;
|
||||
edpt->next_pid = HCTSIZ_PID_DATA0;
|
||||
if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
|
||||
edpt->uframe_interval = 1 << (desc_ep->bInterval - 1);
|
||||
if (devtree_info.speed == TUSB_SPEED_FULL) {
|
||||
if (bus_info.speed == TUSB_SPEED_FULL) {
|
||||
edpt->uframe_interval <<= 3;
|
||||
}
|
||||
} else if (desc_ep->bmAttributes.xfer == TUSB_XFER_INTERRUPT) {
|
||||
if (devtree_info.speed == TUSB_SPEED_HIGH) {
|
||||
if (bus_info.speed == TUSB_SPEED_HIGH) {
|
||||
edpt->uframe_interval = 1 << (desc_ep->bInterval - 1);
|
||||
} else {
|
||||
edpt->uframe_interval = desc_ep->bInterval << 3;
|
||||
@@ -514,10 +523,11 @@ bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
|
||||
// clean up channel after part of transfer is done but the whole urb is not complete
|
||||
static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) {
|
||||
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
|
||||
dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
const dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
|
||||
|
||||
edpt->next_pid = channel->hctsiz_bm.pid; // save PID
|
||||
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
|
||||
edpt->next_pid = hctsiz.pid; // save PID
|
||||
|
||||
/* Since hctsiz.xfersize field reflects the number of bytes transferred via the AHB, not the USB)
|
||||
* For IN: we can use hctsiz.xfersize as remaining bytes.
|
||||
@@ -525,9 +535,10 @@ static void channel_xfer_out_wrapup(dwc2_regs_t* dwc2, uint8_t ch_id) {
|
||||
* number of packets that have been transferred via the USB. This is always an integral number of packets if the
|
||||
* transfer was halted before its normal completion.
|
||||
*/
|
||||
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
|
||||
const uint16_t total_packets = cal_packet_count(edpt->buflen, channel->hcchar_bm.ep_size);
|
||||
const uint16_t actual_bytes = (total_packets - remain_packets) * channel->hcchar_bm.ep_size;
|
||||
const uint16_t remain_packets = hctsiz.packet_count;
|
||||
const dwc2_channel_char_t hcchar = {.value = channel->hcchar};
|
||||
const uint16_t total_packets = cal_packet_count(edpt->buflen, hcchar.ep_size);
|
||||
const uint16_t actual_bytes = (total_packets - remain_packets) * hcchar.ep_size;
|
||||
|
||||
xfer->fifo_bytes = 0;
|
||||
xfer->xferred_bytes += actual_bytes;
|
||||
@@ -540,7 +551,7 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) {
|
||||
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
|
||||
dwc2_channel_char_t* hcchar_bm = &edpt->hcchar_bm;
|
||||
dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
bool const is_period = edpt_is_periodic(hcchar_bm->ep_type);
|
||||
bool const is_period = channel_is_periodic(edpt->hcchar);
|
||||
|
||||
// clear previous state
|
||||
xfer->fifo_bytes = 0;
|
||||
@@ -553,13 +564,16 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) {
|
||||
|
||||
// hctsiz: zero length packet still count as 1
|
||||
const uint16_t packet_count = cal_packet_count(edpt->buflen, hcchar_bm->ep_size);
|
||||
uint32_t hctsiz = (edpt->next_pid << HCTSIZ_PID_Pos) | (packet_count << HCTSIZ_PKTCNT_Pos) | edpt->buflen;
|
||||
if (edpt->do_ping && edpt->speed == TUSB_SPEED_HIGH &&
|
||||
dwc2_channel_tsize_t hctsiz = {.value = 0};
|
||||
hctsiz.pid = edpt->next_pid; // next PID is set in transfer complete interrupt
|
||||
hctsiz.packet_count = packet_count;
|
||||
hctsiz.xfer_size = edpt->buflen;
|
||||
if (edpt->next_do_ping && edpt->speed == TUSB_SPEED_HIGH &&
|
||||
edpt->next_pid != HCTSIZ_PID_SETUP && hcchar_bm->ep_dir == TUSB_DIR_OUT) {
|
||||
hctsiz |= HCTSIZ_DOPING;
|
||||
hctsiz.do_ping = 1;
|
||||
}
|
||||
channel->hctsiz = hctsiz;
|
||||
edpt->do_ping = 0;
|
||||
channel->hctsiz = hctsiz.value;
|
||||
edpt->next_do_ping = 0;
|
||||
|
||||
// pre-calculate next PID based on packet count, adjusted in transfer complete interrupt if short packet
|
||||
if (hcchar_bm->ep_num == 0) {
|
||||
@@ -590,7 +604,7 @@ static bool channel_xfer_start(dwc2_regs_t* dwc2, uint8_t ch_id) {
|
||||
hcintmsk |= HCINT_BABBLE_ERR | HCINT_DATATOGGLE_ERR | HCINT_ACK;
|
||||
} else {
|
||||
hcintmsk |= HCINT_NYET;
|
||||
if (edpt->hcsplt_bm.split_en) {
|
||||
if (edpt->hcsplt_bm.split_en || hctsiz.do_ping) {
|
||||
hcintmsk |= HCINT_ACK;
|
||||
}
|
||||
}
|
||||
@@ -699,18 +713,23 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
//--------------------------------------------------------------------
|
||||
// HCD Event Handler
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// retry an IN transfer, channel must be halted
|
||||
static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hcint) {
|
||||
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
|
||||
dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
|
||||
dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
dwc2_channel_char_t hcchar = {.value = channel->hcchar};
|
||||
|
||||
if (edpt_is_periodic(channel->hcchar_bm.ep_type)){
|
||||
if (channel_is_periodic(hcchar.value)){
|
||||
const dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
|
||||
// retry immediately for periodic split NYET if we haven't reach max retry
|
||||
if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) {
|
||||
if (hcsplt.split_en && hcsplt.split_compl && (hcint & HCINT_NYET || xfer->halted_nyet)) {
|
||||
xfer->period_split_nyet_count++;
|
||||
xfer->halted_nyet = 0;
|
||||
if (xfer->period_split_nyet_count < HCD_XFER_PERIOD_SPLIT_NYET_MAX) {
|
||||
channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
|
||||
hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
|
||||
channel->hcchar = hcchar.value;
|
||||
channel_send_in_token(dwc2, channel);
|
||||
return;
|
||||
} else {
|
||||
@@ -719,18 +738,24 @@ static void channel_xfer_in_retry(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
|
||||
}
|
||||
}
|
||||
|
||||
// for periodic, de-allocate channel, enable SOF set frame counter for later transfer
|
||||
edpt->next_pid = channel->hctsiz_bm.pid; // save PID
|
||||
edpt->uframe_countdown = edpt->uframe_interval;
|
||||
dwc2->gintmsk |= GINTSTS_SOF;
|
||||
|
||||
if (hcint & HCINT_HALTED) {
|
||||
const uint32_t ucount = (hprt_speed_get(dwc2) == TUSB_SPEED_HIGH ? 1 : 8);
|
||||
if (edpt->uframe_interval == ucount) {
|
||||
// retry on next frame if bInterval is 1
|
||||
hcchar.odd_frame = 1 - (dwc2->hfnum & 1);
|
||||
channel->hcchar = hcchar.value;
|
||||
channel_send_in_token(dwc2, channel);
|
||||
} else {
|
||||
// otherwise, de-allocate channel, enable SOF set frame counter for later transfer
|
||||
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
|
||||
edpt->next_pid = hctsiz.pid; // save PID
|
||||
edpt->uframe_countdown = edpt->uframe_interval - ucount;
|
||||
// enable SOF interrupt if not already enabled
|
||||
if (!(dwc2->gintmsk & GINTMSK_SOFM)) {
|
||||
dwc2->gintsts = GINTSTS_SOF;
|
||||
dwc2->gintmsk |= GINTMSK_SOFM;
|
||||
}
|
||||
// already halted, de-allocate channel (called from DMA isr)
|
||||
channel_dealloc(dwc2, ch_id);
|
||||
} else {
|
||||
// disable channel first if not halted (called slave isr)
|
||||
xfer->halted_sof_schedule = 1;
|
||||
channel_disable(dwc2, channel);
|
||||
}
|
||||
} else {
|
||||
// for control/bulk: retry immediately
|
||||
@@ -761,13 +786,13 @@ static void handle_rxflvl_irq(uint8_t rhport) {
|
||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||
|
||||
// Pop control word off FIFO
|
||||
const dwc2_grxstsp_t grxstsp_bm = dwc2->grxstsp_bm;
|
||||
const uint8_t ch_id = grxstsp_bm.ep_ch_num;
|
||||
const dwc2_grxstsp_t grxstsp = {.value= dwc2->grxstsp};
|
||||
const uint8_t ch_id = grxstsp.ep_ch_num;
|
||||
|
||||
switch (grxstsp_bm.packet_status) {
|
||||
switch (grxstsp.packet_status) {
|
||||
case GRXSTS_PKTSTS_RX_DATA: {
|
||||
// In packet received, pop this entry --> ACK interrupt
|
||||
const uint16_t byte_count = grxstsp_bm.byte_count;
|
||||
const uint16_t byte_count = grxstsp.byte_count;
|
||||
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
|
||||
TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,);
|
||||
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
|
||||
@@ -801,25 +826,26 @@ static void handle_rxflvl_irq(uint8_t rhport) {
|
||||
// return true if there is still pending data and need more ISR
|
||||
static bool handle_txfifo_empty(dwc2_regs_t* dwc2, bool is_periodic) {
|
||||
// Use period txsts for both p/np to get request queue space available (1-bit difference, it is small enough)
|
||||
volatile dwc2_hptxsts_t* txsts_bm = (volatile dwc2_hptxsts_t*) (is_periodic ? &dwc2->hptxsts : &dwc2->hnptxsts);
|
||||
const dwc2_hptxsts_t txsts = {.value = (is_periodic ? dwc2->hptxsts : dwc2->hnptxsts)};
|
||||
|
||||
const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
|
||||
const uint8_t max_channel = dwc2_channel_count(dwc2);
|
||||
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
|
||||
dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
const dwc2_channel_char_t hcchar = {.value = channel->hcchar};
|
||||
// skip writing to FIFO if channel is expecting halted.
|
||||
if (!(channel->hcintmsk & HCINT_HALTED) && (channel->hcchar_bm.ep_dir == TUSB_DIR_OUT)) {
|
||||
if (!(channel->hcintmsk & HCINT_HALTED) && (hcchar.ep_dir == TUSB_DIR_OUT)) {
|
||||
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
|
||||
TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX);
|
||||
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
|
||||
|
||||
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
|
||||
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
|
||||
const uint16_t remain_packets = hctsiz.packet_count;
|
||||
for (uint16_t i = 0; i < remain_packets; i++) {
|
||||
const uint16_t remain_bytes = edpt->buflen - xfer->fifo_bytes;
|
||||
const uint16_t xact_bytes = tu_min16(remain_bytes, channel->hcchar_bm.ep_size);
|
||||
const uint16_t xact_bytes = tu_min16(remain_bytes, hcchar.ep_size);
|
||||
|
||||
// skip if there is not enough space in FIFO and RequestQueue.
|
||||
// Packet's last word written to FIFO will trigger a request queue
|
||||
if ((xact_bytes > (txsts_bm->fifo_available << 2)) || (txsts_bm->req_queue_available == 0)) {
|
||||
if ((xact_bytes > (txsts.fifo_available << 2)) || (txsts.req_queue_available == 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -836,23 +862,26 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h
|
||||
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
|
||||
dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
|
||||
dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
|
||||
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
|
||||
bool is_done = false;
|
||||
|
||||
// if (channel->hcsplt_bm.split_en) {
|
||||
// if (hcsplt.split_en) {
|
||||
// if (edpt->hcchar_bm.ep_num == 1) {
|
||||
// TU_LOG1("Frame %u, ch %u: ep %u, hcint 0x%04lX ", dwc2->hfnum_bm.num, ch_id, channel->hcchar_bm.ep_num, hcint);
|
||||
// TU_LOG1("Frame %u, ch %u: ep %u, hcint 0x%04lX ", dwc2->hfnum_bm.num, ch_id, hcsplt.ep_num, hcint);
|
||||
// print_hcint(hcint);
|
||||
// }
|
||||
|
||||
if (hcint & HCINT_XFER_COMPLETE) {
|
||||
if (edpt->hcchar_bm.ep_num != 0) {
|
||||
edpt->next_pid = channel->hctsiz_bm.pid; // save pid (already toggled)
|
||||
edpt->next_pid = hctsiz.pid; // save pid (already toggled)
|
||||
}
|
||||
|
||||
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
|
||||
if (channel->hcsplt_bm.split_en && remain_packets && xfer->fifo_bytes == edpt->hcchar_bm.ep_size) {
|
||||
const uint16_t remain_packets = hctsiz.packet_count;
|
||||
if (hcsplt.split_en && remain_packets && xfer->fifo_bytes == edpt->hcchar_bm.ep_size) {
|
||||
// Split can only complete 1 transaction (up to 1 packet) at a time, schedule more
|
||||
channel->hcsplt_bm.split_compl = 0;
|
||||
hcsplt.split_compl = 0;
|
||||
channel->hcsplt = hcsplt.value;
|
||||
} else {
|
||||
xfer->result = XFER_RESULT_SUCCESS;
|
||||
}
|
||||
@@ -871,43 +900,44 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h
|
||||
channel_disable(dwc2, channel);
|
||||
} else if (hcint & HCINT_NYET) {
|
||||
// restart complete split
|
||||
channel->hcsplt_bm.split_compl = 1;
|
||||
hcsplt.split_compl = 1;
|
||||
channel->hcsplt = hcsplt.value;
|
||||
xfer->halted_nyet = 1;
|
||||
channel_disable(dwc2, channel);
|
||||
} else if (hcint & HCINT_NAK) {
|
||||
// NAK received, re-enable channel if request queue is available
|
||||
if (channel->hcsplt_bm.split_en) {
|
||||
channel->hcsplt_bm.split_compl = 0; // restart with start-split
|
||||
// NAK received, disable channel to flush all posted request and try again
|
||||
if (hcsplt.split_en) {
|
||||
hcsplt.split_compl = 0; // restart with start-split
|
||||
channel->hcsplt = hcsplt.value;
|
||||
}
|
||||
|
||||
channel_disable(dwc2, channel);
|
||||
} else if (hcint & HCINT_ACK) {
|
||||
xfer->err_count = 0;
|
||||
|
||||
if (channel->hcsplt_bm.split_en) {
|
||||
if (!channel->hcsplt_bm.split_compl) {
|
||||
if (hcsplt.split_en) {
|
||||
if (!hcsplt.split_compl) {
|
||||
// start split is ACK --> do complete split
|
||||
channel->hcintmsk |= HCINT_NYET;
|
||||
channel->hcsplt_bm.split_compl = 1;
|
||||
hcsplt.split_compl = 1;
|
||||
channel->hcsplt = hcsplt.value;
|
||||
channel_send_in_token(dwc2, channel);
|
||||
} else {
|
||||
// do nothing for complete split with DATA, this will trigger XferComplete and handled there
|
||||
}
|
||||
} else {
|
||||
// ACK with data
|
||||
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
|
||||
const uint16_t remain_packets = hctsiz.packet_count;
|
||||
if (remain_packets) {
|
||||
// still more packet to receive, also reset to start split
|
||||
channel->hcsplt_bm.split_compl = 0;
|
||||
hcsplt.split_compl = 0;
|
||||
channel->hcsplt = hcsplt.value;
|
||||
channel_send_in_token(dwc2, channel);
|
||||
}
|
||||
}
|
||||
} else if (hcint & HCINT_HALTED) {
|
||||
channel->hcintmsk &= ~HCINT_HALTED;
|
||||
if (xfer->halted_sof_schedule) {
|
||||
// de-allocate channel but does not complete xfer, we schedule it in the SOF interrupt
|
||||
channel_dealloc(dwc2, ch_id);
|
||||
} else if (xfer->result != XFER_RESULT_INVALID) {
|
||||
if (xfer->result != XFER_RESULT_INVALID) {
|
||||
is_done = true;
|
||||
} else if (xfer->err_count == HCD_XFER_ERROR_MAX) {
|
||||
xfer->result = XFER_RESULT_FAILED;
|
||||
@@ -927,23 +957,29 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t
|
||||
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
|
||||
dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
|
||||
dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
|
||||
bool is_done = false;
|
||||
|
||||
if (hcint & HCINT_XFER_COMPLETE) {
|
||||
is_done = true;
|
||||
xfer->result = XFER_RESULT_SUCCESS;
|
||||
channel->hcintmsk &= ~HCINT_ACK;
|
||||
if (hcint & HCINT_NYET) {
|
||||
// complete transfer with NYET, do ping next time
|
||||
edpt->next_do_ping = 1;
|
||||
}
|
||||
} else if (hcint & HCINT_STALL) {
|
||||
xfer->result = XFER_RESULT_STALLED;
|
||||
channel_disable(dwc2, channel);
|
||||
} else if (hcint & HCINT_NYET) {
|
||||
xfer->err_count = 0;
|
||||
if (channel->hcsplt_bm.split_en) {
|
||||
if (hcsplt.split_en) {
|
||||
// retry complete split
|
||||
channel->hcsplt_bm.split_compl = 1;
|
||||
hcsplt.split_compl = 1;
|
||||
channel->hcsplt = hcsplt.value;
|
||||
channel->hcchar |= HCCHAR_CHENA;
|
||||
} else {
|
||||
edpt->do_ping = 1;
|
||||
edpt->next_do_ping = 1;
|
||||
channel_xfer_out_wrapup(dwc2, ch_id);
|
||||
channel_disable(dwc2, channel);
|
||||
}
|
||||
@@ -956,7 +992,7 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t
|
||||
channel->hcintmsk |= HCINT_ACK;
|
||||
} else {
|
||||
// NAK disable channel to flush all posted request and try again
|
||||
edpt->do_ping = 1;
|
||||
edpt->next_do_ping = 1;
|
||||
xfer->err_count = 0;
|
||||
}
|
||||
} else if (hcint & HCINT_HALTED) {
|
||||
@@ -973,9 +1009,17 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t
|
||||
} else if (hcint & HCINT_ACK) {
|
||||
xfer->err_count = 0;
|
||||
channel->hcintmsk &= ~HCINT_ACK;
|
||||
if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) {
|
||||
// start split is ACK --> do complete split
|
||||
channel->hcsplt_bm.split_compl = 1;
|
||||
if (hcsplt.split_en) {
|
||||
if (!hcsplt.split_compl) {
|
||||
// ACK for start split --> do complete split
|
||||
hcsplt.split_compl = 1;
|
||||
channel->hcsplt = hcsplt.value;
|
||||
channel->hcchar |= HCCHAR_CHENA;
|
||||
}
|
||||
} else {
|
||||
// ACK interrupt is only enabled for Split and PING
|
||||
// ACK for PING, which mean device is ready to receive data
|
||||
channel->hctsiz &= ~HCTSIZ_DOPING; // HC already cleared PING bit, but we clear anyway
|
||||
channel->hcchar |= HCCHAR_CHENA;
|
||||
}
|
||||
}
|
||||
@@ -994,6 +1038,9 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
|
||||
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
|
||||
dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
|
||||
dwc2_channel_char_t hcchar = {.value = channel->hcchar};
|
||||
dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
|
||||
const dwc2_channel_tsize_t hctsiz = {.value = channel->hctsiz};
|
||||
|
||||
bool is_done = false;
|
||||
|
||||
@@ -1001,8 +1048,8 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
|
||||
|
||||
if (hcint & HCINT_HALTED) {
|
||||
if (hcint & (HCINT_XFER_COMPLETE | HCINT_STALL | HCINT_BABBLE_ERR)) {
|
||||
const uint16_t remain_bytes = (uint16_t) channel->hctsiz_bm.xfer_size;
|
||||
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
|
||||
const uint16_t remain_bytes = (uint16_t) hctsiz.xfer_size;
|
||||
const uint16_t remain_packets = hctsiz.packet_count;
|
||||
const uint16_t actual_len = edpt->buflen - remain_bytes;
|
||||
xfer->xferred_bytes += actual_len;
|
||||
|
||||
@@ -1012,13 +1059,14 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
|
||||
xfer->result = XFER_RESULT_STALLED;
|
||||
} else if (hcint & HCINT_BABBLE_ERR) {
|
||||
xfer->result = XFER_RESULT_FAILED;
|
||||
} else if (channel->hcsplt_bm.split_en && remain_packets && actual_len == edpt->hcchar_bm.ep_size) {
|
||||
} else if (hcsplt.split_en && remain_packets && actual_len == hcchar.ep_size) {
|
||||
// Split can only complete 1 transaction (up to 1 packet) at a time, schedule more
|
||||
is_done = false;
|
||||
edpt->buffer += actual_len;
|
||||
edpt->buflen -= actual_len;
|
||||
|
||||
channel->hcsplt_bm.split_compl = 0;
|
||||
hcsplt.split_compl = 0;
|
||||
channel->hcsplt = hcsplt.value;
|
||||
channel_xfer_in_retry(dwc2, ch_id, hcint);
|
||||
} else {
|
||||
xfer->result = XFER_RESULT_SUCCESS;
|
||||
@@ -1033,33 +1081,38 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
|
||||
xfer->result = XFER_RESULT_FAILED;
|
||||
} else {
|
||||
channel->hcintmsk |= HCINT_ACK | HCINT_NAK | HCINT_DATATOGGLE_ERR;
|
||||
channel->hcsplt_bm.split_compl = 0;
|
||||
hcsplt.split_compl = 0;
|
||||
channel->hcsplt = hcsplt.value;
|
||||
channel_xfer_in_retry(dwc2, ch_id, hcint);
|
||||
}
|
||||
} else if (hcint & HCINT_NYET) {
|
||||
// Must handle nyet before nak or ack. Could get a nyet at the same time as either of those on a BULK/CONTROL
|
||||
// OUT that started with a PING. The nyet takes precedence.
|
||||
if (channel->hcsplt_bm.split_en) {
|
||||
if (hcsplt.split_en) {
|
||||
// split not yet mean hub has no data, retry complete split
|
||||
channel->hcsplt_bm.split_compl = 1;
|
||||
hcsplt.split_compl = 1;
|
||||
channel->hcsplt = hcsplt.value;
|
||||
channel_xfer_in_retry(dwc2, ch_id, hcint);
|
||||
}
|
||||
} else if (hcint & HCINT_ACK) {
|
||||
xfer->err_count = 0;
|
||||
channel->hcintmsk &= ~HCINT_ACK;
|
||||
if (channel->hcsplt_bm.split_en) {
|
||||
if (hcsplt.split_en) {
|
||||
// start split is ACK --> do complete split
|
||||
// TODO: for ISO must use xact_pos to plan complete split based on microframe (up to 187.5 bytes/uframe)
|
||||
channel->hcsplt_bm.split_compl = 1;
|
||||
if (edpt_is_periodic(channel->hcchar_bm.ep_type)) {
|
||||
channel->hcchar_bm.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
|
||||
hcsplt.split_compl = 1;
|
||||
channel->hcsplt = hcsplt.value;
|
||||
if (channel_is_periodic(channel->hcchar)) {
|
||||
hcchar.odd_frame = 1 - (dwc2->hfnum & 1); // transfer on next frame
|
||||
channel->hcchar = hcchar.value;
|
||||
}
|
||||
channel_send_in_token(dwc2, channel);
|
||||
}
|
||||
} else if (hcint & (HCINT_NAK | HCINT_DATATOGGLE_ERR)) {
|
||||
xfer->err_count = 0;
|
||||
channel->hcintmsk &= ~(HCINT_NAK | HCINT_DATATOGGLE_ERR);
|
||||
channel->hcsplt_bm.split_compl = 0; // restart with start-split
|
||||
hcsplt.split_compl = 0; // restart with start-split
|
||||
channel->hcsplt = hcsplt.value;
|
||||
channel_xfer_in_retry(dwc2, ch_id, hcint);
|
||||
} else if (hcint & HCINT_FARME_OVERRUN) {
|
||||
// retry start-split in next binterval
|
||||
@@ -1074,6 +1127,8 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc
|
||||
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
|
||||
dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
|
||||
const dwc2_channel_char_t hcchar = {.value = channel->hcchar};
|
||||
dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
|
||||
|
||||
bool is_done = false;
|
||||
|
||||
@@ -1109,16 +1164,18 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc
|
||||
}
|
||||
}
|
||||
} else if (hcint & HCINT_NYET) {
|
||||
if (channel->hcsplt_bm.split_en && channel->hcsplt_bm.split_compl) {
|
||||
if (hcsplt.split_en && hcsplt.split_compl) {
|
||||
// split not yet mean hub has no data, retry complete split
|
||||
channel->hcsplt_bm.split_compl = 1;
|
||||
hcsplt.split_compl = 1;
|
||||
channel->hcsplt = hcsplt.value;
|
||||
channel->hcchar |= HCCHAR_CHENA;
|
||||
}
|
||||
} else if (hcint & HCINT_ACK) {
|
||||
xfer->err_count = 0;
|
||||
if (channel->hcsplt_bm.split_en && !channel->hcsplt_bm.split_compl) {
|
||||
if (hcsplt.split_en && !hcsplt.split_compl) {
|
||||
// start split is ACK --> do complete split
|
||||
channel->hcsplt_bm.split_compl = 1;
|
||||
hcsplt.split_compl = 1;
|
||||
channel->hcsplt = hcsplt.value;
|
||||
channel->hcchar |= HCCHAR_CHENA;
|
||||
}
|
||||
}
|
||||
@@ -1134,14 +1191,14 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc
|
||||
static void handle_channel_irq(uint8_t rhport, bool in_isr) {
|
||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||
const bool is_dma = dma_host_enabled(dwc2);
|
||||
const uint8_t max_channel = DWC2_CHANNEL_COUNT(dwc2);
|
||||
const uint8_t max_channel = dwc2_channel_count(dwc2);
|
||||
|
||||
for (uint8_t ch_id = 0; ch_id < max_channel; ch_id++) {
|
||||
if (tu_bit_test(dwc2->haint, ch_id)) {
|
||||
dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
|
||||
TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,);
|
||||
dwc2_channel_char_t hcchar_bm = channel->hcchar_bm;
|
||||
dwc2_channel_char_t hcchar = {.value = channel->hcchar};
|
||||
|
||||
const uint32_t hcint = channel->hcint;
|
||||
channel->hcint = hcint; // clear interrupt
|
||||
@@ -1149,7 +1206,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
|
||||
bool is_done = false;
|
||||
if (is_dma) {
|
||||
#if CFG_TUH_DWC2_DMA_ENABLE
|
||||
if (hcchar_bm.ep_dir == TUSB_DIR_OUT) {
|
||||
if (hcchar.ep_dir == TUSB_DIR_OUT) {
|
||||
is_done = handle_channel_out_dma(dwc2, ch_id, hcint);
|
||||
} else {
|
||||
is_done = handle_channel_in_dma(dwc2, ch_id, hcint);
|
||||
@@ -1161,7 +1218,7 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
|
||||
#endif
|
||||
} else {
|
||||
#if CFG_TUH_DWC2_SLAVE_ENABLE
|
||||
if (hcchar_bm.ep_dir == TUSB_DIR_OUT) {
|
||||
if (hcchar.ep_dir == TUSB_DIR_OUT) {
|
||||
is_done = handle_channel_out_slave(dwc2, ch_id, hcint);
|
||||
} else {
|
||||
is_done = handle_channel_in_slave(dwc2, ch_id, hcint);
|
||||
@@ -1170,8 +1227,8 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
|
||||
}
|
||||
|
||||
if (is_done) {
|
||||
const uint8_t ep_addr = tu_edpt_addr(hcchar_bm.ep_num, hcchar_bm.ep_dir);
|
||||
hcd_event_xfer_complete(hcchar_bm.dev_addr, ep_addr, xfer->xferred_bytes, xfer->result, in_isr);
|
||||
const uint8_t ep_addr = tu_edpt_addr(hcchar.ep_num, hcchar.ep_dir);
|
||||
hcd_event_xfer_complete(hcchar.dev_addr, ep_addr, xfer->xferred_bytes, (xfer_result_t)xfer->result, in_isr);
|
||||
channel_dealloc(dwc2, ch_id);
|
||||
}
|
||||
}
|
||||
@@ -1191,7 +1248,7 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) {
|
||||
|
||||
for(uint8_t ep_id = 0; ep_id < CFG_TUH_DWC2_ENDPOINT_MAX; ep_id++) {
|
||||
hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
|
||||
if (edpt->hcchar_bm.enable && edpt_is_periodic(edpt->hcchar_bm.ep_type) && edpt->uframe_countdown > 0) {
|
||||
if (edpt->hcchar_bm.enable && channel_is_periodic(edpt->hcchar) && edpt->uframe_countdown > 0) {
|
||||
edpt->uframe_countdown -= tu_min32(ucount, edpt->uframe_countdown);
|
||||
if (edpt->uframe_countdown == 0) {
|
||||
if (!edpt_xfer_kickoff(dwc2, ep_id)) {
|
||||
@@ -1210,10 +1267,10 @@ static bool handle_sof_irq(uint8_t rhport, bool in_isr) {
|
||||
static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
|
||||
uint32_t hcfg = dwc2->hcfg & ~HCFG_FSLS_PHYCLK_SEL;
|
||||
|
||||
const dwc2_gusbcfg_t gusbcfg_bm = dwc2->gusbcfg_bm;
|
||||
const dwc2_gusbcfg_t gusbcfg = {.value = dwc2->gusbcfg};
|
||||
uint32_t phy_clock;
|
||||
|
||||
if (gusbcfg_bm.phy_sel) {
|
||||
if (gusbcfg.phy_sel) {
|
||||
phy_clock = 48; // dedicated FS is 48Mhz
|
||||
if (speed == TUSB_SPEED_LOW) {
|
||||
hcfg |= HCFG_FSLS_PHYCLK_SEL_6MHZ;
|
||||
@@ -1221,11 +1278,11 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
|
||||
hcfg |= HCFG_FSLS_PHYCLK_SEL_48MHZ;
|
||||
}
|
||||
} else {
|
||||
if (gusbcfg_bm.ulpi_utmi_sel) {
|
||||
if (gusbcfg.ulpi_utmi_sel) {
|
||||
phy_clock = 60; // ULPI 8-bit is 60Mhz
|
||||
} else {
|
||||
// UTMI+ 16-bit is 30Mhz, 8-bit is 60Mhz
|
||||
phy_clock = gusbcfg_bm.phy_if16 ? 30 : 60;
|
||||
phy_clock = gusbcfg.phy_if16 ? 30 : 60;
|
||||
|
||||
// Enable UTMI+ low power mode 48Mhz external clock if not highspeed
|
||||
if (speed == TUSB_SPEED_HIGH) {
|
||||
@@ -1242,9 +1299,9 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
|
||||
|
||||
uint32_t hfir = dwc2->hfir & ~HFIR_FRIVL_Msk;
|
||||
if (speed == TUSB_SPEED_HIGH) {
|
||||
hfir |= 125*phy_clock;
|
||||
hfir |= 125*phy_clock - 1; // The "- 1" is the correct value. The Synopsys databook was corrected in 3.30a
|
||||
} else {
|
||||
hfir |= 1000*phy_clock;
|
||||
hfir |= 1000*phy_clock - 1;
|
||||
}
|
||||
|
||||
dwc2->hfir = hfir;
|
||||
@@ -1257,21 +1314,19 @@ static void port0_enable(dwc2_regs_t* dwc2, tusb_speed_t speed) {
|
||||
*/
|
||||
static void handle_hprt_irq(uint8_t rhport, bool in_isr) {
|
||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||
uint32_t hprt = dwc2->hprt & ~HPRT_W1_MASK;
|
||||
const dwc2_hprt_t hprt_bm = dwc2->hprt_bm;
|
||||
const dwc2_hprt_t hprt_bm = {.value = dwc2->hprt};
|
||||
uint32_t hprt = hprt_bm.value & ~HPRT_W1_MASK;
|
||||
|
||||
if (dwc2->hprt & HPRT_CONN_DETECT) {
|
||||
if (hprt_bm.conn_detected) {
|
||||
// Port Connect Detect
|
||||
hprt |= HPRT_CONN_DETECT;
|
||||
|
||||
if (hprt_bm.conn_status) {
|
||||
hcd_event_device_attach(rhport, in_isr);
|
||||
} else {
|
||||
hcd_event_device_remove(rhport, in_isr);
|
||||
}
|
||||
}
|
||||
|
||||
if (dwc2->hprt & HPRT_ENABLE_CHANGE) {
|
||||
if (hprt_bm.enable_change) {
|
||||
// Port enable change
|
||||
hprt |= HPRT_ENABLE_CHANGE;
|
||||
|
||||
@@ -1330,6 +1385,15 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
|
||||
handle_channel_irq(rhport, in_isr);
|
||||
}
|
||||
|
||||
if (gintsts & GINTSTS_DISCINT) {
|
||||
// Device disconnected
|
||||
dwc2->gintsts = GINTSTS_DISCINT;
|
||||
|
||||
if (!(dwc2->hprt & HPRT_CONN_STATUS)) {
|
||||
hcd_event_device_remove(rhport, in_isr);
|
||||
}
|
||||
}
|
||||
|
||||
#if CFG_TUH_DWC2_SLAVE_ENABLE
|
||||
// RxFIFO non-empty interrupt handling
|
||||
if (gintsts & GINTSTS_RXFLVL) {
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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",
|
||||
|
@@ -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()
|
||||
|
||||
|
@@ -59,7 +59,7 @@ deps_optional = {
|
||||
'144f1eb7ea8c06512e12f12b27383601c0272410',
|
||||
'kinetis_k kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx imxrt'],
|
||||
'hw/mcu/raspberry_pi/Pico-PIO-USB': ['https://github.com/hathach/Pico-PIO-USB.git',
|
||||
'810653f66adadba3e0e4b4b56d5167ac4f7fdbf7',
|
||||
'032a469e79f6a4ba40760d7868e6db26e15002d7',
|
||||
'rp2040'],
|
||||
'hw/mcu/renesas/fsp': ['https://github.com/renesas/fsp.git',
|
||||
'edcc97d684b6f716728a60d7a6fea049d9870bd6',
|
||||
@@ -125,7 +125,7 @@ deps_optional = {
|
||||
'5ad9797c54ec3e55eff770fc9b3cd4a1aefc1309',
|
||||
'stm32u5'],
|
||||
'hw/mcu/st/cmsis_device_wb': ['https://github.com/STMicroelectronics/cmsis_device_wb.git',
|
||||
'9c5d1920dd9fabbe2548e10561d63db829bb744f',
|
||||
'd6a7fa2e7de084f5e5e47f2ab88b022fe9b50e5a',
|
||||
'stm32wb'],
|
||||
'hw/mcu/st/stm32-mfxstm32l152': ['https://github.com/STMicroelectronics/stm32-mfxstm32l152.git',
|
||||
'7f4389efee9c6a655b55e5df3fceef5586b35f9b',
|
||||
@@ -249,11 +249,13 @@ def get_a_dep(d):
|
||||
p.mkdir(parents=True)
|
||||
run_cmd(f"{git_cmd} init")
|
||||
run_cmd(f"{git_cmd} remote add origin {url}")
|
||||
head = None
|
||||
else:
|
||||
# Check if commit is already fetched
|
||||
result = run_cmd(f"{git_cmd} rev-parse HEAD")
|
||||
head = result.stdout.decode("utf-8").splitlines()[0]
|
||||
run_cmd(f"{git_cmd} reset --hard")
|
||||
|
||||
# Check if commit is already fetched
|
||||
result = run_cmd(f"{git_cmd} rev-parse HEAD")
|
||||
head = result.stdout.decode("utf-8").splitlines()[0]
|
||||
run_cmd(f"{git_cmd} reset --hard")
|
||||
if commit != head:
|
||||
run_cmd(f"{git_cmd} fetch --depth 1 origin {commit}")
|
||||
run_cmd(f"{git_cmd} checkout FETCH_HEAD")
|
||||
|
Reference in New Issue
Block a user